packages feed

yesod-core-1.7.0.0: test/YesodCoreTest/ParamFocusSplit/Runtime.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -Wno-orphans #-}

-- | Runtime + round-trip coverage for a *parameterized* top-level site whose
-- nested route block is split into its own module with
-- 'setFocusOnNestedRoute'. Before this fixture the
-- @parameterized + setFocusOnNestedRoute@ corner was never compiled by any
-- test, and the focused 'RouteAttrsNested' instance head was built from a bare
-- constructor (no type argument applied) — a guaranteed kind error for a
-- parameterized site. The parent dispatch is generated here with
-- 'setParameterizedSubroute', so it must *delegate* to the @SubR a@ fragment
-- instances compiled in "YesodCoreTest.ParamFocusSplit.SubR"; the build itself
-- is the split-delegation assertion and the WAI rows confirm dispatch.
module YesodCoreTest.ParamFocusSplit.Runtime
    ( specs
    ) where

import Data.Text (Text)
import Test.Hspec
import qualified Data.ByteString.Lazy as L
import qualified Network.HTTP.Types as H
import Yesod.Core

import YesodCoreTest.ParamFocusSplit.Resources
-- Brings the split 'SubR' datatype + its nested dispatch / parse / render /
-- attrs instances into scope. Importing the datatype (not @SubR ()@) is what
-- lets the parent splice's delegation probe resolve 'SubR' and delegate to the
-- imported instance instead of regenerating (and demanding) its handlers.
import YesodCoreTest.ParamFocusSplit.SubR (SubR (..))
import YesodCoreTest.RuntimeHarness (assertRequestFor)

-- The parent splice: generates the route data types and the parent dispatch.
-- 'setParameterizedSubroute' forces the NestedDiscovery path so the parent
-- delegates to the split 'SubR' fragment rather than inlining it.
mkYesodOpts (setParameterizedSubroute True defaultOpts) "PApp a" paramFocusResources

instance Yesod (PApp a) where
    messageLoggerSource = mempty

getHomeR :: HandlerFor (PApp a) Text
getHomeR = pure "home"

getItemR :: Int -> HandlerFor (PApp a) Text
getItemR _ = pure "item"

sampleRoutes :: [Route (PApp ())]
sampleRoutes =
    [ HomeR
    , ItemR 7
    , SubR SubHomeR
    , SubR (SubDetailR 9)
    ]

testRequestIO
    :: HasCallStack
    => Int
    -> [Text]
    -> H.Method
    -> Maybe L.ByteString
    -> IO ()
testRequestIO status path method mexpected =
    assertRequestFor (PApp :: PApp ()) method status path mexpected

specs :: Spec
specs = describe "parameterized top-level site, nested routes split with setFocusOnNestedRoute" $ do
    describe "parseRoute . renderRoute round-trips" $
        mapM_
            (\r -> it (show r) $ parseRoute (renderRoute r) `shouldBe` Just r)
            sampleRoutes

    describe "WAI dispatch (parent delegates to the split SubR fragment)" $ do
        it "static leaf (HomeR)" $
            testRequestIO 200 [] "GET" (Just "home")
        it "dynamic leaf (ItemR)" $
            testRequestIO 200 ["item", "7"] "GET" (Just "item")
        it "nested parent home (delegated SubR SubHomeR)" $
            testRequestIO 200 ["sub"] "GET" (Just "subHome")
        it "nested parent dynamic leaf (delegated SubR (SubDetailR _))" $
            testRequestIO 200 ["sub", "detail", "9"] "GET" (Just "subDetail")
        it "404 on unknown nested suffix" $
            testRequestIO 404 ["sub", "detail", "9", "oops"] "GET" Nothing
        it "405 on wrong method" $
            testRequestIO 405 ["sub"] "POST" Nothing