packages feed

freckle-app-1.15.0.0: tests/Freckle/App/Test/Http/MatchRequestSpec.hs

module Freckle.App.Test.Http.MatchRequestSpec
  ( spec
  ) where

import Freckle.App.Prelude

import Freckle.App.Http
  ( Request
  , addAcceptHeader
  , addRequestHeader
  , parseRequest_
  , setRequestPath
  )
import Freckle.App.Test.Http.MatchRequest
import Network.HTTP.Types.Header (hAccept)
import Test.Hspec

spec :: Spec
spec = do
  describe "matchRequestFromUrl" $ do
    context "matching complete requests" $ do
      let
        url = "https://localhost:3000/hello?world"
        mr = matchRequestFromUrl url

      it "matches the same request" $ do
        mr `shouldMatchRequest` parseRequest_ url

      it "matches on path, even if built relative" $ do
        let req = parseRequest_ "https://localhost:3000/world?world"
        mr `shouldMatchRequest` setRequestPath "hello" req

      it "matches on method" $ do
        mr `shouldNotMatchRequest` parseRequest_ ("POST " <> url)

      it "matches on scheme" $ do
        mr `shouldNotMatchRequest` parseRequest_ "http://localhost:3000/hello?world"

      it "matches on host" $ do
        mr `shouldNotMatchRequest` parseRequest_ "https://localhost2:3000/hello?world"

      it "matches on port" $ do
        mr `shouldNotMatchRequest` parseRequest_ "https://localhost:3001/hello?world"

      it "matches on path" $ do
        mr `shouldNotMatchRequest` parseRequest_ "https://localhost:3000/world?world"

      it "matches on query" $ do
        mr `shouldNotMatchRequest` parseRequest_ "https://localhost:3000/hello?wut"

    it "can match on everything unspecified" $ do
      let mr = matchRequestFromUrl "https://"

      mr `shouldMatchRequest` parseRequest_ "https://example.com"
      mr `shouldMatchRequest` parseRequest_ "https://example.com/"
      mr `shouldMatchRequest` parseRequest_ "https://example.com/foo"
      mr `shouldMatchRequest` parseRequest_ "https://example.com/bar"

    it "can match any path" $ do
      let mr = matchRequestFromUrl "https://example.com"

      mr `shouldMatchRequest` parseRequest_ "https://example.com"
      mr `shouldMatchRequest` parseRequest_ "https://example.com/"
      mr `shouldMatchRequest` parseRequest_ "https://example.com/foo"
      mr `shouldMatchRequest` parseRequest_ "https://example.com/bar"

    it "can match the root path explicitly" $ do
      let mr = matchRequestFromUrl "https://example.com/"

      mr `shouldMatchRequest` parseRequest_ "https://example.com/"
      mr `shouldMatchRequest` parseRequest_ "https://example.com"
      mr `shouldNotMatchRequest` parseRequest_ "https://example.com/foo"
      mr `shouldNotMatchRequest` parseRequest_ "https://example.com/bar"

    context "matching headers" $ do
      let
        url = "https://example.com/"
        accept = "text/plain"
        hasNoHeaders = parseRequest_ url
        hasOnlyTheHeader = addAcceptHeader accept hasNoHeaders
        hasExtraHeaders = addRequestHeader "User-Agent" "me" hasOnlyTheHeader

      it "can match headers exactly" $ do
        let mr = matchRequestFromUrl url <> MatchHeaders [(hAccept, accept)]

        mr `shouldMatchRequest` hasOnlyTheHeader
        mr `shouldNotMatchRequest` hasExtraHeaders
        mr `shouldNotMatchRequest` hasNoHeaders

      it "can match headers-include" $ do
        let mr = matchRequestFromUrl url <> MatchHeader (hAccept, accept)

        mr `shouldMatchRequest` hasOnlyTheHeader
        mr `shouldMatchRequest` hasExtraHeaders
        mr `shouldNotMatchRequest` hasNoHeaders

shouldMatchRequest :: HasCallStack => MatchRequest -> Request -> IO ()
mr `shouldMatchRequest` req = do
  case matchRequest req mr of
    Left err -> do
      let preamble = unlines ["Expected to match request, but did not", "", show req]
      expectationFailure $ preamble <> err
    Right () -> pure ()

infix 1 `shouldMatchRequest`

shouldNotMatchRequest :: HasCallStack => MatchRequest -> Request -> IO ()
mr `shouldNotMatchRequest` req = do
  case matchRequest req mr of
    Left {} -> pure ()
    Right () -> do
      let preamble = unlines ["Expected to NOT match request, but did", "", show req]
      expectationFailure $ preamble <> showMatchRequest mr

infix 1 `shouldNotMatchRequest`