elm-pages-v3-beta/tests/StaticHttpRequestsTests.elm

939 lines
37 KiB
Elm
Raw Normal View History

module StaticHttpRequestsTests exposing (all)
2021-05-06 17:26:21 +03:00
import ApiRoute
2022-02-08 01:50:38 +03:00
import Bytes.Decode
import Bytes.Encode
2019-10-22 08:00:15 +03:00
import Codec
2021-06-04 03:57:57 +03:00
import DataSource exposing (DataSource)
import DataSource.Http
2020-12-07 19:41:10 +03:00
import Dict
2022-12-30 00:03:10 +03:00
import Exception exposing (Throwable)
2019-10-22 06:21:52 +03:00
import Expect
import Html
2022-01-28 07:41:54 +03:00
import Json.Decode as JD exposing (Decoder)
import Json.Encode as Encode
2021-04-03 00:44:40 +03:00
import Pages.Internal.Platform.Cli exposing (..)
2020-06-12 06:57:19 +03:00
import Pages.Internal.Platform.Effect as Effect exposing (Effect)
import Pages.Internal.Platform.ToJsPayload as ToJsPayload
2022-03-25 20:42:00 +03:00
import Pages.ProgramConfig exposing (ProgramConfig)
2021-10-07 22:11:23 +03:00
import Pages.SiteConfig exposing (SiteConfig)
import Pages.StaticHttp.Request as Request
2021-05-23 20:44:39 +03:00
import Path
import ProgramTest exposing (ProgramTest)
2019-11-03 00:46:52 +03:00
import Regex
import RenderRequest
2022-02-27 01:10:31 +03:00
import RequestsAndPending exposing (ResponseBody(..))
2022-01-25 02:43:37 +03:00
import Server.Response as Response
import SimulatedEffect.Cmd
2019-10-22 06:21:52 +03:00
import SimulatedEffect.Ports
2022-03-11 22:52:33 +03:00
import Test exposing (Test, describe, test)
all : Test
all =
describe "Static Http Requests"
[ test "initial requests are sent out" <|
\() ->
startSimple []
2022-12-30 00:03:10 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages" starDecoder |> DataSource.throw)
|> simulateHttp
2022-01-28 07:41:54 +03:00
(get "https://api.github.com/repos/dillonkearns/elm-pages")
2022-02-27 01:10:31 +03:00
(JsonBody
(Encode.object [ ( "stargazer_count", Encode.int 86 ) ])
)
|> expectSuccess []
2021-04-16 18:26:59 +03:00
, test "StaticHttp request for initial are resolved" <|
\() ->
startSimple
[ "post-1" ]
2022-12-30 00:03:10 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages" starDecoder |> DataSource.throw)
|> simulateHttp
2022-01-28 07:41:54 +03:00
(get "https://api.github.com/repos/dillonkearns/elm-pages")
2022-02-27 01:10:31 +03:00
(JsonBody
(Encode.object [ ( "stargazer_count", Encode.int 86 ) ])
)
2022-02-26 04:30:21 +03:00
|> expectSuccess []
, describe "single page renders"
[ test "single pages that are pre-rendered" <|
\() ->
startSimple [ "post-1" ]
2022-12-30 00:03:10 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages" starDecoder |> DataSource.throw)
|> simulateHttp
2022-01-28 07:41:54 +03:00
(get "https://api.github.com/repos/dillonkearns/elm-pages")
2022-02-27 01:10:31 +03:00
(JsonBody
(Encode.object [ ( "stargazer_count", Encode.int 86 ) ])
)
|> ProgramTest.expectOutgoingPortValues
"toJsPort"
(Codec.decoder (ToJsPayload.successCodecNew2 "" ""))
(\actualPorts ->
case actualPorts of
[ ToJsPayload.PageProgress portData ] ->
2022-11-16 03:30:26 +03:00
if portData.is404 then
Expect.fail "Expected page to be found and rendered"
else
Expect.pass
_ ->
Expect.fail <| "Expected exactly 1 port of type PageProgress. Instead, got \n" ++ Debug.toString actualPorts
)
]
, test "the stripped JSON from the same request with different decoders is merged so the decoders succeed" <|
\() ->
startSimple
[ "post-1" ]
(DataSource.map2 Tuple.pair
2022-01-28 07:41:54 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages"
(JD.field "stargazer_count" JD.int)
2022-12-30 00:03:10 +03:00
|> DataSource.throw
)
2022-01-28 07:41:54 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages"
(JD.field "language" JD.string)
2022-12-30 00:03:10 +03:00
|> DataSource.throw
)
)
|> simulateHttp
2022-01-28 07:41:54 +03:00
(get "https://api.github.com/repos/dillonkearns/elm-pages")
2022-02-27 01:10:31 +03:00
(JsonBody
(Encode.object
[ ( "stargazer_count", Encode.int 86 )
, ( "language", Encode.string "Elm" )
]
)
)
2022-02-26 04:30:21 +03:00
|> expectSuccess []
, test "andThen" <|
\() ->
startSimple
[ "elm-pages" ]
2022-01-28 07:41:54 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages" (JD.succeed ())
2022-12-30 00:03:10 +03:00
|> DataSource.throw
|> DataSource.andThen
(\_ ->
2022-01-28 07:41:54 +03:00
DataSource.Http.get "NEXT-REQUEST" (JD.succeed ())
2022-12-30 00:03:10 +03:00
|> DataSource.throw
)
)
|> simulateHttp
2022-01-28 07:41:54 +03:00
(get "https://api.github.com/repos/dillonkearns/elm-pages")
2022-02-27 01:10:31 +03:00
(JsonBody Encode.null)
|> simulateHttp
2022-01-28 07:41:54 +03:00
(get "NEXT-REQUEST")
2022-02-27 01:10:31 +03:00
(JsonBody Encode.null)
2022-02-26 04:30:21 +03:00
|> expectSuccess []
2022-12-23 01:27:00 +03:00
--, test "andThen chain avoids repeat requests" <|
-- TODO is this test case still relevant? Need to think about the new desired functionality with caching HTTP requests given that
-- DataSource's can perform non-deterministic effects now.
-- \() ->
-- let
-- pokemonDetailRequest : DataSource ()
-- pokemonDetailRequest =
-- DataSource.Http.get
-- "https://pokeapi.co/api/v2/pokemon/"
-- (JD.list
-- (JD.field "url" JD.string
-- |> JD.map
-- (\url ->
-- DataSource.Http.get url
-- (JD.field "image" JD.string)
-- )
-- )
-- )
-- |> DataSource.resolve
-- |> DataSource.map (\_ -> ())
-- in
-- startSimple
-- [ "elm-pages" ]
-- pokemonDetailRequest
-- |> simulateMultipleHttp
-- [ ( get "https://pokeapi.co/api/v2/pokemon/"
-- , jsonBody """[
-- {"url": "url1"},
-- {"url": "url2"},
-- {"url": "url3"},
-- {"url": "url4"},
-- {"url": "url5"},
-- {"url": "url6"},
-- {"url": "url7"},
-- {"url": "url8"},
-- {"url": "url9"},
-- {"url": "url10"}
-- ]"""
-- )
-- , ( get "url1"
-- , jsonBody """{"image": "image1.jpg"}"""
-- )
-- , ( get "url2"
-- , jsonBody """{"image": "image2.jpg"}"""
-- )
-- , ( get "url3"
-- , jsonBody """{"image": "image3.jpg"}"""
-- )
-- , ( get "url4"
-- , jsonBody """{"image": "image4.jpg"}"""
-- )
-- , ( get "url5"
-- , jsonBody """{"image": "image5.jpg"}"""
-- )
-- , ( get "url6"
-- , jsonBody """{"image": "image6.jpg"}"""
-- )
-- , ( get "url7"
-- , jsonBody """{"image": "image7.jpg"}"""
-- )
-- , ( get "url8"
-- , jsonBody """{"image": "image8.jpg"}"""
-- )
-- , ( get "url9"
-- , jsonBody """{"image": "image9.jpg"}"""
-- )
-- , ( get "url10"
-- , jsonBody """{"image": "image10.jpg"}"""
-- )
-- ]
-- |> expectSuccess []
--
--, test "port is sent out once all requests are finished" <|
-- \() ->
-- start
-- [ ( [ "elm-pages" ]
-- , DataSource.Http.get (Secrets.succeed "https://api.github.com/repos/dillonkearns/elm-pages") starDecoder
-- )
-- , ( [ "elm-pages-starter" ]
-- , DataSource.Http.get (Secrets.succeed "https://api.github.com/repos/dillonkearns/elm-pages-starter") starDecoder
-- )
-- ]
-- |> ProgramTest.simulateHttpOk
-- "GET"
-- "https://api.github.com/repos/dillonkearns/elm-pages"
-- """{ "stargazer_count": 86 }"""
-- |> ProgramTest.simulateHttpOk
-- "GET"
-- "https://api.github.com/repos/dillonkearns/elm-pages-starter"
-- """{ "stargazer_count": 22 }"""
-- |> expectSuccess
-- [ ( "elm-pages"
-- , [ ( get "https://api.github.com/repos/dillonkearns/elm-pages"
-- , """{"stargazer_count":86}"""
-- )
-- ]
-- )
-- , ( "elm-pages-starter"
-- , [ ( get "https://api.github.com/repos/dillonkearns/elm-pages-starter"
-- , """{"stargazer_count":22}"""
-- )
-- ]
-- )
-- ]
2022-02-26 04:30:21 +03:00
, test "reduced JSON is sent out" <|
\() ->
startSimple []
2022-12-30 00:03:10 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages" (JD.field "stargazer_count" JD.int)
|> DataSource.throw
)
2022-02-26 04:30:21 +03:00
|> simulateHttp
(get "https://api.github.com/repos/dillonkearns/elm-pages")
2022-02-27 01:10:31 +03:00
(jsonBody """{ "stargazer_count": 86, "unused_field": 123 }""")
2022-02-26 04:30:21 +03:00
|> expectSuccess []
, test "you can use elm/json decoders with StaticHttp.unoptimizedRequest" <|
\() ->
startSimple []
(DataSource.Http.request
{ url = "https://api.github.com/repos/dillonkearns/elm-pages"
, method = "GET"
, headers = []
, body = DataSource.Http.emptyBody
}
(DataSource.Http.expectJson
(JD.field "stargazer_count" JD.int)
)
2022-12-30 00:03:10 +03:00
|> DataSource.throw
2022-02-26 04:30:21 +03:00
)
|> simulateHttp
(get "https://api.github.com/repos/dillonkearns/elm-pages")
2022-02-27 01:10:31 +03:00
(jsonBody """{ "stargazer_count": 86, "unused_field": 123 }""")
|> expectSuccess []
, test "plain string" <|
\() ->
startSimple []
(DataSource.Http.request
{ url = "https://example.com/file.txt"
, method = "GET"
, headers = []
, body = DataSource.Http.emptyBody
}
DataSource.Http.expectString
2022-12-30 00:03:10 +03:00
|> DataSource.throw
2022-02-27 01:10:31 +03:00
)
|> simulateHttp
{ method = "GET"
, url = "https://example.com/file.txt"
, headers =
[]
, body = DataSource.Http.emptyBody
2022-07-24 22:03:38 +03:00
, useCache = True
2022-02-27 01:10:31 +03:00
}
(StringBody "This is a raw text file.")
2022-02-26 04:30:21 +03:00
|> expectSuccess []
2022-02-27 01:35:52 +03:00
, test "Err in String to Result function turns into decode error" <|
\() ->
startSimple []
(DataSource.Http.request
{ url = "https://example.com/file.txt"
, method = "GET"
, headers = []
, body = DataSource.Http.emptyBody
}
DataSource.Http.expectString
2022-12-30 00:03:10 +03:00
|> DataSource.throw
|> DataSource.map
2022-02-27 01:35:52 +03:00
(\string ->
if String.toUpper string == string then
Ok string
2022-02-27 01:35:52 +03:00
else
Err "String was not uppercased"
)
2022-12-30 00:03:10 +03:00
|> DataSource.andThen (\result -> result |> Result.mapError Exception.fromString |> DataSource.fromResult)
2022-02-27 01:35:52 +03:00
)
|> simulateHttp
(get "https://example.com/file.txt")
(StringBody "This is a raw text file.")
|> ProgramTest.expectOutgoingPortValues
"toJsPort"
(Codec.decoder (ToJsPayload.successCodecNew2 "" ""))
(expectErrorsPort
2022-12-30 00:14:08 +03:00
"""-- INTERNAL ERROR ----------------------------------------------------- elm-pages
2020-03-11 19:03:47 +03:00
2022-12-30 00:14:08 +03:00
String was not uppercased"""
2022-02-27 01:35:52 +03:00
)
2022-02-27 01:18:37 +03:00
, test "POST method works" <|
\() ->
startSimple []
(DataSource.Http.request
{ method = "POST"
, url = "https://api.github.com/repos/dillonkearns/elm-pages"
, headers = []
, body = DataSource.Http.emptyBody
}
(DataSource.Http.expectJson
(JD.field "stargazer_count" JD.int)
2022-02-26 03:57:50 +03:00
)
2022-12-30 00:03:10 +03:00
|> DataSource.throw
2022-02-27 01:18:37 +03:00
)
|> simulateHttp
(post "https://api.github.com/repos/dillonkearns/elm-pages")
(jsonBody """{ "stargazer_count": 86, "unused_field": 123 }""")
|> expectSuccess []
2022-02-26 04:30:21 +03:00
, test "json is reduced from andThen chains" <|
\() ->
startSimple []
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages" (JD.field "stargazer_count" JD.int)
|> DataSource.andThen
(\_ ->
DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages-starter" (JD.field "stargazer_count" JD.int)
)
2022-12-30 00:03:10 +03:00
|> DataSource.throw
2022-02-26 04:30:21 +03:00
)
|> simulateHttp
(get "https://api.github.com/repos/dillonkearns/elm-pages")
2022-02-27 01:10:31 +03:00
(jsonBody """{ "stargazer_count": 100, "unused_field": 123 }""")
2022-02-26 04:30:21 +03:00
|> simulateHttp
(get "https://api.github.com/repos/dillonkearns/elm-pages-starter")
2022-02-27 01:10:31 +03:00
(jsonBody """{ "stargazer_count": 50, "unused_field": 456 }""")
2022-02-26 04:30:21 +03:00
|> expectSuccess []
2022-02-26 18:44:16 +03:00
, test "reduced json is preserved by StaticHttp.map2" <|
\() ->
startSimple []
(DataSource.map2 (\_ _ -> ())
2022-12-30 00:03:10 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages" (JD.field "stargazer_count" JD.int) |> DataSource.throw)
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages-starter" (JD.field "stargazer_count" JD.int) |> DataSource.throw)
2022-02-26 18:44:16 +03:00
)
|> simulateMultipleHttp
[ ( get "https://api.github.com/repos/dillonkearns/elm-pages"
2022-02-27 01:10:31 +03:00
, jsonBody """{ "stargazer_count": 100, "unused_field": 123 }"""
2022-02-26 18:44:16 +03:00
)
, ( get "https://api.github.com/repos/dillonkearns/elm-pages-starter"
2022-02-27 01:10:31 +03:00
, jsonBody """{ "stargazer_count": 50, "unused_field": 456 }"""
2022-02-26 18:44:16 +03:00
)
]
|> expectSuccess []
2022-02-27 01:10:31 +03:00
, test "the port sends out even if there are no http requests" <|
\() ->
start
[ ( []
, DataSource.succeed ()
)
]
|> expectSuccess []
, test "the port sends out when there are duplicate http requests for the same page" <|
\() ->
startSimple []
(DataSource.map2 (\_ _ -> ())
2022-12-30 00:03:10 +03:00
(DataSource.Http.get "http://example.com" (JD.succeed ()) |> DataSource.throw)
(DataSource.Http.get "http://example.com" (JD.succeed ()) |> DataSource.throw)
2022-02-27 01:10:31 +03:00
)
|> simulateHttp
(get "http://example.com")
(jsonBody """null""")
|> expectSuccess []
2022-02-27 01:42:31 +03:00
, test "an error is sent out for decoder failures" <|
\() ->
startSimple [ "elm-pages" ]
2022-12-30 00:03:10 +03:00
(DataSource.Http.get "https://api.github.com/repos/dillonkearns/elm-pages" (JD.fail "The user should get this message from the CLI.") |> DataSource.throw)
2022-02-27 01:42:31 +03:00
|> simulateHttp
(get "https://api.github.com/repos/dillonkearns/elm-pages")
(jsonBody """{ "stargazer_count": 86 }""")
|> ProgramTest.expectOutgoingPortValues
"toJsPort"
(Codec.decoder (ToJsPayload.successCodecNew2 "" ""))
(expectErrorsPort
2022-12-30 00:14:08 +03:00
"""-- INTERNAL ERROR ----------------------------------------------------- elm-pages
2019-10-30 08:33:47 +03:00
2022-02-27 01:42:31 +03:00
Problem with the given value:
2019-10-27 02:50:09 +03:00
2022-02-27 01:42:31 +03:00
{
"stargazer_count": 86
}
2022-02-27 01:42:31 +03:00
The user should get this message from the CLI."""
)
]
2021-04-16 18:04:15 +03:00
type Route
= Route String
2022-12-30 00:03:10 +03:00
start : List ( List String, DataSource Throwable a ) -> ProgramTest (Model Route) Msg Effect
start pages =
2021-06-04 03:14:25 +03:00
startWithHttpCache [] pages
2020-06-13 22:29:36 +03:00
startWithHttpCache :
2021-06-04 03:14:25 +03:00
List ( Request.Request, String )
2022-12-30 00:03:10 +03:00
-> List ( List String, DataSource Throwable a )
2021-04-16 18:04:15 +03:00
-> ProgramTest (Model Route) Msg Effect
startWithHttpCache =
2021-05-06 17:14:49 +03:00
startLowLevel []
startLowLevel :
2021-07-31 01:35:02 +03:00
List (ApiRoute.ApiRoute ApiRoute.Response)
-> List ( Request.Request, String )
2022-12-30 00:03:10 +03:00
-> List ( List String, DataSource Throwable a )
2021-04-16 18:04:15 +03:00
-> ProgramTest (Model Route) Msg Effect
2021-06-04 03:14:25 +03:00
startLowLevel apiRoutes staticHttpCache pages =
let
2021-07-27 20:41:18 +03:00
pageToLoad : List String
pageToLoad =
case pages |> List.head |> Maybe.map Tuple.first of
Just justPageToLoad ->
justPageToLoad
Nothing ->
Debug.todo "Error - no pages"
2021-06-04 03:57:57 +03:00
encodedFlags : Encode.Value
encodedFlags =
--{"secrets":
-- {"API_KEY": "ABCD1234","BEARER": "XYZ789"}, "mode": "prod", "staticHttpCache": {}
-- }
Encode.object
[ ( "secrets"
, [ ( "API_KEY", "ABCD1234" )
, ( "BEARER", "XYZ789" )
]
|> Dict.fromList
|> Encode.dict identity Encode.string
)
, ( "mode", Encode.string "prod" )
, ( "staticHttpCache", encodedStaticHttpCache )
2022-11-07 09:09:06 +03:00
, ( "compatibilityKey", Encode.int currentCompatibilityKey )
]
2021-06-04 03:57:57 +03:00
encodedStaticHttpCache : Encode.Value
encodedStaticHttpCache =
staticHttpCache
|> List.map
(\( request, httpResponseString ) ->
( Request.hash request, Encode.string httpResponseString )
)
|> Encode.object
in
{-
(Model -> model)
-> ContentCache.ContentCache metadata view
2021-04-10 20:33:26 +03:00
-> Result (List BuildError) (List ( PagePath, metadata ))
-> Config pathKey userMsg userModel metadata view
-> Decode.Value
-> ( model, Effect pathKey )
-}
ProgramTest.createDocument
2021-07-27 20:41:18 +03:00
{ init =
init
2021-09-27 20:48:49 +03:00
site
2021-07-27 20:41:18 +03:00
(RenderRequest.SinglePage
RenderRequest.OnlyJson
(RenderRequest.Page
{ path = Path.fromString (pageToLoad |> String.join "/")
, frontmatter = Route (pageToLoad |> String.join "/")
}
)
(Encode.object [])
)
2022-05-12 01:49:04 +03:00
(config apiRoutes pages)
2022-12-23 02:17:21 +03:00
, update = update
2019-10-25 17:00:04 +03:00
, view = \_ -> { title = "", body = [] }
}
|> ProgramTest.withSimulatedEffects simulateEffects
|> ProgramTest.start (flags (Encode.encode 0 encodedFlags))
2019-10-24 18:26:41 +03:00
2022-02-26 03:57:50 +03:00
site : SiteConfig
2021-09-27 20:48:49 +03:00
site =
2022-02-26 03:57:50 +03:00
{ canonicalUrl = "canonical-site-url"
, head = DataSource.succeed []
2021-09-27 20:48:49 +03:00
}
2022-12-30 00:03:10 +03:00
startSimple : List String -> DataSource Throwable a -> ProgramTest (Model Route) Msg Effect
startSimple route dataSources =
startWithRoutes route [ route ] [] [ ( route, dataSources ) ]
2022-12-30 00:03:10 +03:00
config : List (ApiRoute.ApiRoute ApiRoute.Response) -> List ( List String, DataSource Throwable a ) -> ProgramConfig Msg () Route () () () Effect mappedMsg ()
2022-05-12 01:49:04 +03:00
config apiRoutes pages =
{ toJsPort = toJsPort
, fromJsPort = fromJsPort
2022-09-27 01:37:10 +03:00
, init = \_ _ _ _ _ -> ( (), Effect.NoEffect )
2022-05-12 01:49:04 +03:00
, getStaticRoutes =
--StaticHttp.get (Secrets.succeed "https://my-cms.com/posts")
-- (Decode.field "posts" (Decode.list (Decode.string |> Decode.map Route)))
pages
|> List.map Tuple.first
|> List.map (String.join "/")
|> List.map Route
|> DataSource.succeed
, handleRoute = \_ -> DataSource.succeed Nothing
, urlToRoute = .path >> Route
2022-06-29 00:30:41 +03:00
, update = \_ _ _ _ _ _ _ _ -> ( (), Effect.NoEffect )
2022-05-12 01:49:04 +03:00
, basePath = []
2022-06-29 00:30:41 +03:00
, onActionData = \() -> Nothing
2022-05-12 01:49:04 +03:00
, data =
2022-12-23 01:27:00 +03:00
\_ (Route pageRoute) ->
2022-05-12 01:49:04 +03:00
let
2022-12-30 00:03:10 +03:00
thing : Maybe (DataSource Throwable a)
2022-05-12 01:49:04 +03:00
thing =
pages
|> Dict.fromList
|> Dict.get
(pageRoute
|> String.split "/"
|> List.filter (\pathPart -> pathPart /= "")
)
in
case thing of
Just request ->
request |> DataSource.map (\_ -> Response.render ())
Nothing ->
Debug.todo <| "Couldn't find page: " ++ pageRoute ++ "\npages: " ++ Debug.toString pages
, site = Just site
, view =
2022-06-29 00:30:41 +03:00
\_ _ _ page _ _ _ _ ->
2022-05-12 01:49:04 +03:00
let
2022-12-30 00:03:10 +03:00
thing : Maybe (DataSource Throwable a)
2022-05-12 01:49:04 +03:00
thing =
pages
|> Dict.fromList
|> Dict.get
(page.path |> Path.toSegments)
in
case thing of
Just _ ->
{ view = \_ -> { title = "Title", body = [ Html.text "" ] }, head = [] }
2022-05-12 01:49:04 +03:00
Nothing ->
Debug.todo <| "Couldn't find page: " ++ Debug.toString page ++ "\npages: " ++ Debug.toString pages
, subscriptions = \_ _ _ -> Sub.none
, routeToPath = \(Route route) -> route |> String.split "/"
, sharedData = DataSource.succeed ()
2022-08-25 21:56:03 +03:00
, onPageChange = \_ -> GotDataBatch []
2022-05-12 01:49:04 +03:00
, apiRoutes = \_ -> apiRoutes
, pathPatterns = []
, byteDecodePageData = \_ -> Bytes.Decode.fail
, sendPageData = \_ -> Cmd.none
, encodeResponse = \_ -> Bytes.Encode.signedInt8 0
, hotReloadData = Sub.none
, decodeResponse = Bytes.Decode.fail
, byteEncodePageData = \_ -> Bytes.Encode.signedInt8 0
, gotBatchSub = Sub.none
, globalHeadTags = Nothing
, perform = \_ _ -> Cmd.none
, cmdToEffect = \_ -> Effect.NoEffect
, errorStatusCode = \_ -> 404
, notFoundPage = ()
, notFoundRoute = Route "not-found"
, internalError = \_ -> ()
, errorPageToData = \_ -> ()
2022-12-30 00:03:10 +03:00
, action = \_ _ -> DataSource.fail (Exception.fromString "No action.")
2022-05-12 01:49:04 +03:00
, encodeAction = \_ -> Bytes.Encode.signedInt8 0
}
startWithRoutes :
List String
-> List (List String)
-> List ( Request.Request, String )
2022-12-30 00:03:10 +03:00
-> List ( List String, DataSource Throwable a )
-> ProgramTest (Model Route) Msg Effect
2022-06-30 20:15:33 +03:00
startWithRoutes pageToLoad _ staticHttpCache pages =
let
encodedFlags : Encode.Value
encodedFlags =
--{"secrets":
-- {"API_KEY": "ABCD1234","BEARER": "XYZ789"}, "mode": "prod", "staticHttpCache": {}
-- }
Encode.object
[ ( "secrets"
, [ ( "API_KEY", "ABCD1234" )
, ( "BEARER", "XYZ789" )
]
|> Dict.fromList
|> Encode.dict identity Encode.string
)
, ( "staticHttpCache", encodedStaticHttpCache )
2021-08-10 05:52:56 +03:00
, ( "mode", Encode.string "dev-server" )
2022-11-07 09:09:06 +03:00
, ( "compatibilityKey", Encode.int currentCompatibilityKey )
]
encodedStaticHttpCache : Encode.Value
encodedStaticHttpCache =
staticHttpCache
|> List.map
(\( request, httpResponseString ) ->
( Request.hash request, Encode.string httpResponseString )
)
|> Encode.object
in
{-
(Model -> model)
-> ContentCache.ContentCache metadata view
-> Result (List BuildError) (List ( PagePath, metadata ))
-> Config pathKey userMsg userModel metadata view
-> Decode.Value
-> ( model, Effect pathKey )
-}
ProgramTest.createDocument
{ init =
init
2021-09-27 20:48:49 +03:00
site
(RenderRequest.SinglePage
RenderRequest.OnlyJson
(RenderRequest.Page
{ path = Path.fromString (pageToLoad |> String.join "/")
, frontmatter = Route (pageToLoad |> String.join "/")
}
)
(Encode.object [])
)
2022-05-12 01:49:04 +03:00
(config [] pages)
2022-12-23 02:17:21 +03:00
, update = update
, view = \_ -> { title = "", body = [] }
}
|> ProgramTest.withSimulatedEffects simulateEffects
|> ProgramTest.withSimulatedSubscriptions simulateSubscriptions
|> ProgramTest.start (flags (Encode.encode 0 encodedFlags))
flags : String -> JD.Value
2019-10-24 18:26:41 +03:00
flags jsonString =
case JD.decodeString JD.value jsonString of
2019-10-24 18:26:41 +03:00
Ok value ->
value
Err _ ->
Debug.todo "Invalid JSON value."
2021-07-29 20:03:42 +03:00
sendToJsPort : ToJsPayload.ToJsSuccessPayloadNewCombined -> ProgramTest.SimulatedEffect msg
sendToJsPort value =
SimulatedEffect.Ports.send "toJsPort" (value |> Codec.encoder (ToJsPayload.successCodecNew2 "" ""))
2021-04-16 18:04:15 +03:00
simulateEffects : Effect -> ProgramTest.SimulatedEffect Msg
simulateEffects effect =
2022-02-27 19:50:43 +03:00
case effect of
2020-06-12 06:57:19 +03:00
Effect.NoEffect ->
SimulatedEffect.Cmd.none
-- toJsPort value |> Cmd.map never
2020-06-12 06:57:19 +03:00
Effect.Batch list ->
list
|> List.map simulateEffects
|> SimulatedEffect.Cmd.batch
2022-01-28 07:41:54 +03:00
Effect.FetchHttp unmasked ->
2022-02-26 03:57:50 +03:00
if unmasked.url |> String.startsWith "port://" then
let
portName : String
portName =
String.dropLeft 7 unmasked.url
in
ToJsPayload.Port portName
|> sendToJsPort
|> SimulatedEffect.Cmd.map never
else
2022-02-27 01:10:31 +03:00
ToJsPayload.DoHttp
(unmasked
--|> withInternalHeader
)
2022-07-24 22:03:38 +03:00
True
|> sendToJsPort
|> SimulatedEffect.Cmd.map never
2022-02-26 03:57:50 +03:00
Effect.SendSinglePage info ->
2020-10-14 07:02:12 +03:00
SimulatedEffect.Cmd.batch
2020-10-18 04:58:17 +03:00
[ info
2020-10-20 03:41:27 +03:00
|> Codec.encoder (ToJsPayload.successCodecNew2 "" "")
2020-10-18 04:58:17 +03:00
|> SimulatedEffect.Ports.send "toJsPort"
2022-02-26 03:57:50 +03:00
, SimulatedEffect.Cmd.none
2020-10-14 07:02:12 +03:00
]
2022-02-26 03:57:50 +03:00
Effect.SendSinglePageNew _ toJsSuccessPayloadNewCombined ->
2022-02-08 01:50:38 +03:00
SimulatedEffect.Cmd.batch
[ toJsSuccessPayloadNewCombined
|> Codec.encoder (ToJsPayload.successCodecNew2 "" "")
|> SimulatedEffect.Ports.send "toJsPort"
2022-02-26 03:57:50 +03:00
, SimulatedEffect.Cmd.none
2022-02-08 01:50:38 +03:00
]
expectErrorsPort : String -> List ToJsPayload.ToJsSuccessPayloadNewCombined -> Expect.Expectation
2019-11-03 00:46:52 +03:00
expectErrorsPort expectedPlainString actualPorts =
case actualPorts |> List.reverse |> List.head of
Just (ToJsPayload.Errors actualRichTerminalString) ->
2020-01-28 02:28:42 +03:00
actualRichTerminalString
|> List.map .title
|> String.join "\n"
2020-01-28 02:28:42 +03:00
|> normalizeErrorExpectEqual expectedPlainString
Nothing ->
Expect.fail "Expected single error port. Didn't receive any ports."
2020-01-28 02:28:42 +03:00
_ ->
Expect.fail <| "Expected single error port. Got\n" ++ String.join "\n\n" (List.map Debug.toString actualPorts)
normalizeErrorExpectEqual : String -> String -> Expect.Expectation
normalizeErrorExpectEqual expectedPlainString actualRichTerminalString =
actualRichTerminalString
|> Regex.replace
-- strip out all possible ANSI sequences
(Regex.fromString "(\\x9B|\\x1B\\[)[0-?]*[ -/]*[@-~]"
2020-01-28 02:28:42 +03:00
|> Maybe.withDefault Regex.never
)
(\_ -> "")
|> String.replace "\u{001B}" ""
|> normalizeNewlines
|> Expect.equal
(expectedPlainString |> normalizeNewlines)
normalizeNewlines : String -> String
normalizeNewlines string =
string
|> Regex.replace
(Regex.fromString "(\n)+" |> Maybe.withDefault Regex.never)
(\_ -> "")
|> Regex.replace
(Regex.fromString "( )+" |> Maybe.withDefault Regex.never)
(\_ -> " ")
|> String.replace "\u{000D}" ""
|> Regex.replace
(Regex.fromString "\\s" |> Maybe.withDefault Regex.never)
(\_ -> "")
2019-11-03 00:46:52 +03:00
2021-06-04 03:59:58 +03:00
toJsPort : a -> Cmd msg
2021-04-03 00:49:18 +03:00
toJsPort _ =
Cmd.none
2021-06-04 03:59:58 +03:00
fromJsPort : Sub msg
fromJsPort =
Sub.none
2020-05-12 02:42:54 +03:00
starDecoder : Decoder Int
starDecoder =
2022-01-28 07:41:54 +03:00
JD.field "stargazer_count" JD.int
expectSuccess : List ( Request.Request, String ) -> ProgramTest model msg effect -> Expect.Expectation
expectSuccess expectedRequests previous =
expectSuccessNew expectedRequests [] previous
expectSuccessNew : List ( Request.Request, String ) -> List (ToJsPayload.ToJsSuccessPayloadNew -> Expect.Expectation) -> ProgramTest model msg effect -> Expect.Expectation
expectSuccessNew expectedRequest expectations previous =
previous
|> ProgramTest.expectOutgoingPortValues
"toJsPort"
(Codec.decoder (ToJsPayload.successCodecNew2 "" ""))
(\value ->
case value of
(ToJsPayload.PageProgress portPayload) :: _ ->
let
singleExpectation : ToJsPayload.ToJsSuccessPayloadNew -> Expect.Expectation
singleExpectation =
\subject ->
subject.contentJson
|> Expect.equal
(expectedRequest
|> List.map
(\( request, response ) ->
( Request.hash request, response )
)
|> Dict.fromList
)
in
portPayload
|> Expect.all
(singleExpectation
:: expectations
)
[ errorPort ] ->
Expect.fail <| "Expected success port. Got:\n" ++ Debug.toString errorPort
_ ->
Expect.fail ("Expected ports to be called once, but instead there were " ++ String.fromInt (List.length value) ++ " calls.")
)
simulateSubscriptions : a -> ProgramTest.SimulatedSub Msg
simulateSubscriptions _ =
2022-02-26 03:57:50 +03:00
-- TODO handle build errors or not needed?
SimulatedEffect.Ports.subscribe "gotBatchSub"
2022-02-27 19:50:43 +03:00
(RequestsAndPending.batchDecoder |> JD.map GotDataBatch)
identity
get : String -> Request.Request
get url =
{ method = "GET"
, url = url
2022-02-27 01:36:03 +03:00
, headers = []
, body = DataSource.Http.emptyBody
2022-07-24 22:03:38 +03:00
, useCache = True
}
post : String -> Request.Request
post url =
{ method = "POST"
, url = url
2022-02-27 01:36:03 +03:00
, headers = []
, body = DataSource.Http.emptyBody
2022-07-24 22:03:38 +03:00
, useCache = True
}
2022-02-27 19:50:43 +03:00
simulateHttp : Request.Request -> ResponseBody -> ProgramTest model msg effect -> ProgramTest model msg effect
simulateHttp request response program =
program
|> ProgramTest.ensureOutgoingPortValues
"toJsPort"
(Codec.decoder (ToJsPayload.successCodecNew2 "" ""))
(\actualPorts ->
case actualPorts of
2022-07-24 22:03:38 +03:00
[ ToJsPayload.DoHttp _ _ ] ->
Expect.pass
_ ->
Expect.fail <|
"Expected an HTTP request, got:\n"
++ Debug.toString actualPorts
)
2022-02-26 03:57:50 +03:00
|> ProgramTest.simulateIncomingPort "gotBatchSub"
2022-02-26 18:44:16 +03:00
(Encode.list (\req -> encodeBatchEntry req response)
2022-02-26 03:57:50 +03:00
[ request ]
)
2022-02-27 01:10:31 +03:00
simulateMultipleHttp : List ( Request.Request, ResponseBody ) -> ProgramTest model msg effect -> ProgramTest model msg effect
simulateMultipleHttp requests program =
program
|> ProgramTest.ensureOutgoingPortValues
"toJsPort"
(Codec.decoder (ToJsPayload.successCodecNew2 "" ""))
(\actualPorts ->
case actualPorts of
2022-07-24 22:03:38 +03:00
(ToJsPayload.DoHttp _ _) :: _ ->
-- TODO check count of HTTP requests, and check the URLs
Expect.pass
_ ->
Expect.fail <|
"Expected an HTTP request, got:\n"
++ Debug.toString actualPorts
)
2022-02-26 03:57:50 +03:00
|> ProgramTest.simulateIncomingPort "gotBatchSub"
(requests
|> Encode.list
(\( req, response ) ->
2022-02-26 18:44:16 +03:00
encodeBatchEntry req response
2022-02-26 03:57:50 +03:00
)
)
2022-02-26 18:44:16 +03:00
2022-02-27 01:10:31 +03:00
jsonBody : String -> ResponseBody
jsonBody jsonString =
JsonBody
(jsonString
|> JD.decodeString JD.value
|> Result.withDefault Encode.null
)
encodeBatchEntry : Request.Request -> ResponseBody -> Encode.Value
2022-02-26 18:44:16 +03:00
encodeBatchEntry req response =
Encode.object
[ ( "request"
2022-02-27 01:10:31 +03:00
, Codec.encodeToValue Request.codec
(withInternalHeader response req)
2022-02-26 18:44:16 +03:00
)
, ( "response"
2022-02-27 01:10:31 +03:00
, RequestsAndPending.bodyEncoder response
2022-02-26 18:44:16 +03:00
)
]
2022-02-27 01:10:31 +03:00
2022-02-27 19:50:43 +03:00
withInternalHeader : ResponseBody -> { a | headers : List ( String, String ) } -> { a | headers : List ( String, String ) }
2022-02-27 01:10:31 +03:00
withInternalHeader res req =
{ req
| headers =
( "elm-pages-internal"
, case res of
JsonBody _ ->
"ExpectJson"
BytesBody _ ->
"ExpectBytes"
StringBody _ ->
"ExpectString"
WhateverBody ->
"ExpectWhatever"
)
:: req.headers
}