git.iko.soy/rowtype-yoga/purescript-yoga-fetch-om
on main help sign in
rowtype-yoga/purescript-yoga-fetch-om/test/PlainTextResponse.Spec.purs
122 lines 4.6 kB history raw
1module PlainTextResponse.Spec where
3import Prelude
4import Data.String as String
6import Effect.Aff (Aff, bracket)
7import Effect.Aff.Class (liftAff)
8import Effect.Class (liftEffect)
9import Effect.Ref (Ref)
10import Effect.Exception as Exn
11import Effect.Ref as Ref
12import Foreign (unsafeToForeign)
13import Test.Spec (Spec, around, describe, it)
14import Test.Spec.Assertions (shouldEqual)
15import Yoga.Fastify.Fastify as F
16import Yoga.Fastify.Fastify (Port(..), Host(..), RouteURL(..), StatusCode(..))
17import Yoga.Fastify.Om (createOmFastify, getOm, postOm)
18import Yoga.Fetch.Om (GET, POST, Route, type (/), JSON, PlainText, Streaming, client)
19import Yoga.Fetch.Om.Simple as Simple
20import Yoga.Om (Om, runOm)
21import Yoga.Om.Strom (Strom)
22import Yoga.Om.Strom as Strom
24type Payload = { value :: Int }
25type Result = { doubled :: Int }
27type TestAPI =
28 { double ::
29 Route POST
30 ("plain-text-test" / "double")
31 { body :: JSON Payload }
32 ( ok :: { body :: Result }
33 , badRequest :: { body :: PlainText }
34 )
35 , health :: Route GET ("plain-text-test" / "health") {} (ok :: { body :: PlainText })
36 , stream :: Route GET ("plain-text-test" / "stream") {} (ok :: { body :: Streaming String })
37 }
39api
40 :: forall ctx err
41 . { double :: Payload -> Om (Record ctx) (badRequest :: String | err) Result
42 , health :: Om (Record ctx) err String
43 , stream :: Om (Record ctx) err (Strom {} () String)
44 }
45api = client @TestAPI "http://localhost:44933"
47spec :: Spec Unit
48spec = around withServer $ describe "String body on error responses" do
49 it "200 OK decodes the JSON response body" \_ -> do
50 result <- runOm {}
51 { exception: \_ -> pure { doubled: -1 }
52 , badRequest: \_ -> pure { doubled: -1 }
53 }
54 (api.double { value: 21 })
55 liftAff $ result `shouldEqual` { doubled: 42 }
57 it "400 badRequest delivers the raw text body as a String" \serverMode -> do
58 liftEffect $ Ref.write "badRequest" serverMode
59 captured <- liftEffect $ Ref.new ""
60 runOm {}
61 { exception: \_ -> pure unit
62 , badRequest: \b -> liftEffect $ Ref.write b captured
63 }
64 (void $ api.double { value: 0 })
65 body <- liftEffect $ Ref.read captured
66 liftAff $ body `shouldEqual` "invalid value"
68 it "Simple.get returns plain text for String responses" \_ -> do
69 result <- runOm {}
70 { exception: \e -> pure $ "exception: " <> Exn.message e
71 , fetchError: \e -> pure $ "fetch error: " <> e.body
72 }
73 (Simple.get @String "http://localhost:44933/plain-text-test/health" {})
74 liftAff $ result `shouldEqual` "healthy"
76 it "derived PlainText responses decode to String" \_ -> do
77 result <- runOm {}
78 { exception: \e -> pure $ "exception: " <> Exn.message e }
79 api.health
80 liftAff $ result `shouldEqual` "healthy"
82 it "derived Streaming responses decode to a usable Strom" \_ -> do
83 chunks <- runOm {}
84 { exception: \e -> pure [ "exception: " <> Exn.message e ] }
85 do
86 stream <- api.stream
87 Strom.runCollect stream
88 liftAff $ String.joinWith "" chunks `shouldEqual` "stream €"
90withServer :: forall a. (Ref String -> Aff a) -> Aff a
91withServer test = bracket acquire release (\{ serverMode } -> test serverMode)
92 where
93 acquire = do
94 serverMode <- liftEffect $ Ref.new "ok"
95 fastify <- liftEffect do
96 f <- F.fastify {}
97 omApp <- createOmFastify {} f
98 postOm (RouteURL "/plain-text-test/double") (handler serverMode) omApp
99 getOm (RouteURL "/plain-text-test/health") (plainTextHandler "healthy") omApp
100 getOm (RouteURL "/plain-text-test/stream") (plainTextHandler "stream €") omApp
101 pure f
102 void $ F.listen { port: Port 44933, host: Host "0.0.0.0" } fastify
103 pure { fastify, serverMode }
105 release { fastify } = F.close fastify
107 plainTextHandler text reply = do
108 void $ F.status (StatusCode 200) reply # liftEffect
109 void $ F.header "content-type" "text/plain" reply # liftEffect
110 F.send (unsafeToForeign text) reply # liftAff
112 handler serverMode reply = do
113 mode <- liftEffect $ Ref.read serverMode
114 case mode of
115 "badRequest" -> do
116 void $ F.status (StatusCode 400) reply # liftEffect
117 void $ F.header "content-type" "text/plain" reply # liftEffect
118 F.send (unsafeToForeign "invalid value") reply # liftAff
119 _ -> do
120 void $ F.status (StatusCode 200) reply # liftEffect
121 void $ F.header "content-type" "application/json" reply # liftEffect
122 F.sendJson (unsafeToForeign { doubled: 42 }) reply # liftAff