Skip to content

Commit 1e7d01e

Browse files
committed
setup integration test framework
1 parent 829c5a6 commit 1e7d01e

File tree

11 files changed

+122
-54
lines changed

11 files changed

+122
-54
lines changed

openapi/src/Api.elm

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
module Api exposing
22
( Request
3+
, map
34
, request
45
, send
56
, sendWithCustomError
67
, task
7-
, map
88
, withBasePath
9-
, withTimeout
10-
, withTracker
119
, withBearerToken
1210
, withHeader
1311
, withHeaders
12+
, withTimeout
13+
, withTracker
1414
)
1515

1616
import Http
@@ -20,8 +20,8 @@ import Task
2020
import Url.Builder
2121

2222

23-
type Request a =
24-
Request
23+
type Request a
24+
= Request
2525
{ method : String
2626
, headers : List Http.Header
2727
, basePath : String
@@ -34,12 +34,12 @@ type Request a =
3434
}
3535

3636

37-
request : String -> String -> List ( String, String ) -> List (String, Maybe String) -> List (String, Maybe String) -> Maybe Json.Encode.Value -> Json.Decode.Decoder a -> Request a
37+
request : String -> String -> List ( String, String ) -> List ( String, Maybe String ) -> List ( String, Maybe String ) -> Maybe Json.Encode.Value -> Json.Decode.Decoder a -> Request a
3838
request method path pathParams queryParams headerParams body decoder =
3939
Request
4040
{ method = method
4141
, headers = headers headerParams
42-
, basePath = "https://api.graphsense.info"
42+
, basePath = "http://localhost:9000"
4343
, pathParams = interpolatePath path pathParams
4444
, queryParams = queries queryParams
4545
, body = Maybe.withDefault Http.emptyBody (Maybe.map Http.jsonBody body)
@@ -93,6 +93,7 @@ map fn (Request req) =
9393
, tracker = req.tracker
9494
}
9595

96+
9697
withBasePath : String -> Request a -> Request a
9798
withBasePath basePath (Request req) =
9899
Request { req | basePath = basePath }
@@ -123,28 +124,29 @@ withHeaders headers_ (Request req) =
123124
Request { req | headers = req.headers ++ headers (List.map (Tuple.mapSecond Just) headers_) }
124125

125126

127+
126128
-- HELPER
127129

128130

129-
headers : List (String, Maybe String) -> List Http.Header
131+
headers : List ( String, Maybe String ) -> List Http.Header
130132
headers =
131-
List.filterMap (\(key, value) -> Maybe.map (Http.header key) value)
133+
List.filterMap (\( key, value ) -> Maybe.map (Http.header key) value)
132134

133135

134136
interpolatePath : String -> List ( String, String ) -> List String
135137
interpolatePath rawPath pathParams =
136138
let
137139
interpolate =
138-
(\(name, value) path -> String.replace ("{" ++ name ++ "}") value path)
140+
\( name, value ) path -> String.replace ("{" ++ name ++ "}") value path
139141
in
140142
List.foldl interpolate rawPath pathParams
141143
|> String.split "/"
142144
|> List.drop 1
143145

144146

145-
queries : List (String, Maybe String) -> List Url.Builder.QueryParameter
147+
queries : List ( String, Maybe String ) -> List Url.Builder.QueryParameter
146148
queries =
147-
List.filterMap (\(key, value) -> Maybe.map (Url.Builder.string key) value)
149+
List.filterMap (\( key, value ) -> Maybe.map (Url.Builder.string key) value)
148150

149151

150152
expectJson : (Http.Error -> e) -> (Result e a -> msg) -> Json.Decode.Decoder a -> Http.Expect msg

src/Effect.elm

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
11
module Effect exposing (Effect(..), n, perform)
22

3+
import Api
4+
import Api.Request.General
35
import Browser.Navigation as Nav
4-
import Msg exposing (Msg)
6+
import Msg exposing (Msg(..))
57

68

79
type Effect
810
= NoEffect
911
| NavLoadEffect String
10-
| NavPushUrlEffect Nav.Key String
12+
| NavPushUrlEffect String
13+
| GetStatisticsEffect
1114

1215

1316
n : model -> ( model, Effect )
1417
n model =
1518
( model, NoEffect )
1619

1720

18-
perform : Effect -> Cmd Msg
19-
perform effect =
21+
perform : Nav.Key -> Effect -> Cmd Msg
22+
perform key effect =
2023
case effect of
2124
NoEffect ->
2225
Cmd.none
2326

2427
NavLoadEffect url ->
2528
Nav.load url
2629

27-
NavPushUrlEffect key url ->
30+
NavPushUrlEffect url ->
2831
Nav.pushUrl key url
32+
33+
GetStatisticsEffect ->
34+
Api.Request.General.getStatistics
35+
|> Api.send BrowserGotStatistics

src/Init.elm

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Init exposing (init)
22

3+
import Api.Data
34
import Browser.Navigation as Nav
45
import Effect exposing (Effect(..), n)
56
import Iknaio
@@ -8,13 +9,15 @@ import Model exposing (..)
89
import Url exposing (Url)
910

1011

11-
init : Flags -> Url -> Nav.Key -> ( Model, Effect )
12+
init : Flags -> Url -> key -> ( Model key, Effect )
1213
init _ url key =
13-
n
14-
{ url = url
15-
, key = key
16-
, locale = Locale.init
17-
, theme = Iknaio.theme
18-
, search = ()
19-
, user = ()
20-
}
14+
( { url = url
15+
, key = key
16+
, locale = Locale.init
17+
, theme = Iknaio.theme
18+
, search = ()
19+
, user = ()
20+
, stats = Api.Data.Stats Nothing Nothing Nothing
21+
}
22+
, GetStatisticsEffect
23+
)

src/Main.elm

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module Main exposing (main)
22

33
import Browser
4+
import Browser.Navigation as Nav
45
import Effect exposing (perform)
56
import Init exposing (init)
67
import Model exposing (Flags, Model)
@@ -11,17 +12,21 @@ import Update exposing (update)
1112
import View exposing (view)
1213

1314

14-
main : Program Flags Model Msg
15+
main : Program Flags (Model Nav.Key) Msg
1516
main =
17+
let
18+
performEffect ( model, effect ) =
19+
( model, perform model.key effect )
20+
in
1621
Browser.application
1722
{ init =
1823
\flags url key ->
1924
init flags url key
20-
|> Tuple.mapSecond perform
25+
|> performEffect
2126
, update =
2227
\msg model ->
2328
update msg model
24-
|> Tuple.mapSecond perform
29+
|> performEffect
2530
, view = view
2631
, subscriptions = subscriptions
2732
, onUrlChange = BrowserChangedUrl

src/Model.elm

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Model exposing (..)
22

3+
import Api.Data
34
import Browser.Navigation as Nav
45
import Locale.Model as Locale
56
import Themes.Model exposing (Theme)
@@ -15,11 +16,12 @@ type alias Config =
1516
}
1617

1718

18-
type alias Model =
19+
type alias Model navigationKey =
1920
{ url : Url
20-
, key : Nav.Key
21+
, key : navigationKey
2122
, locale : Locale.Model
2223
, theme : Theme
2324
, search : ()
2425
, user : ()
26+
, stats : Api.Data.Stats
2527
}

src/Msg.elm

+3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
module Msg exposing (Msg(..))
22

3+
import Api.Data
34
import Browser exposing (UrlRequest)
5+
import Http
46
import Model exposing (..)
57
import Url exposing (Url)
68

79

810
type Msg
911
= UserRequestsUrl UrlRequest
1012
| BrowserChangedUrl Url
13+
| BrowserGotStatistics (Result Http.Error Api.Data.Stats)

src/Sub.elm

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
module Sub exposing (subscriptions)
22

3+
import Browser.Navigation as Nav
34
import Model exposing (Model)
45
import Msg exposing (Msg)
56

67

7-
subscriptions : Model -> Sub Msg
8+
subscriptions : Model Nav.Key -> Sub Msg
89
subscriptions _ =
910
Sub.none

src/Update.elm

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
module Update exposing (update)
22

33
import Browser
4+
import Browser.Navigation as Nav
45
import Effect exposing (Effect(..), n)
56
import Model exposing (Model)
67
import Msg exposing (..)
78
import Url exposing (Url)
89

910

10-
update : Msg -> Model -> ( Model, Effect )
11+
update : Msg -> Model key -> ( Model key, Effect )
1112
update msg model =
1213
case msg of
1314
UserRequestsUrl request ->
1415
case request of
1516
Browser.Internal url ->
1617
( model
1718
, Url.toString url
18-
|> NavPushUrlEffect model.key
19+
|> NavPushUrlEffect
1920
)
2021

2122
Browser.External url ->
@@ -26,7 +27,15 @@ update msg model =
2627
BrowserChangedUrl url ->
2728
updateByUrl url model
2829

30+
BrowserGotStatistics result ->
31+
case result of
32+
Ok stats ->
33+
n { model | stats = stats }
2934

30-
updateByUrl : Url -> Model -> ( Model, Effect )
35+
Err _ ->
36+
n model
37+
38+
39+
updateByUrl : Url -> Model key -> ( Model key, Effect )
3140
updateByUrl _ model =
3241
n model

src/View.elm

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Msg exposing (..)
1010
import View.Header as Header
1111

1212

13-
view : Model -> Document Msg
13+
view : Model key -> Document Msg
1414
view model =
1515
{ title = model.locale.getString "Iknaio Dashboard"
1616
, body =
@@ -20,7 +20,7 @@ view model =
2020
}
2121

2222

23-
body : Model -> Html Msg
23+
body : Model key -> Html Msg
2424
body model =
2525
div
2626
[ css
@@ -62,7 +62,7 @@ body model =
6262
[ flexGrow (num 1)
6363
]
6464
]
65-
[ text "MAIN"
65+
[ text <| Maybe.withDefault "no_version" <| model.stats.version
6666
]
6767
]
6868
]

tests/Stats.elm

+47-12
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,67 @@
11
module Stats exposing (exampleProgramTest, start)
22

3+
import Api.Data
4+
import Effect exposing (Effect(..))
5+
import Expect
6+
import Init exposing (init)
7+
import Json.Decode as Dec
8+
import Json.Encode as Enc
9+
import Model exposing (Flags, Model)
10+
import Msg exposing (Msg(..))
311
import ProgramTest exposing (ProgramTest, clickButton, expectViewHas)
12+
import SimulatedEffect.Cmd
13+
import SimulatedEffect.Http
414
import Test exposing (..)
515
import Test.Html.Selector exposing (class, text)
616
import Update exposing (update)
17+
import View exposing (view)
718

819

9-
start : String -> Flags -> ProgramTest Model Msg (Cmd Msg)
20+
start : String -> Flags -> ProgramTest (Model ()) Msg Effect
1021
start initialUrl flags =
1122
ProgramTest.createApplication
12-
{ onUrlChange = MyProgram.OnRouteChange
13-
, init =
14-
-- NOTE: the type of MyProgram.init is:
15-
-- MyProgram.Flags -> Navigation.Location -> (MyProgram.Model, Cmd MyProgram.Msg)
16-
MyProgram.init
17-
, update = MyProgram.update
18-
, view = MyProgram.view
23+
{ onUrlChange = BrowserChangedUrl
24+
, onUrlRequest = UserRequestsUrl
25+
, init = init
26+
, update = update
27+
, view = view
1928
}
2029
|> ProgramTest.withBaseUrl initialUrl
30+
|> ProgramTest.withSimulatedEffects simulateEffects
2131
|> ProgramTest.start flags
2232

2333

2434
exampleProgramTest : Test
2535
exampleProgramTest =
26-
test "pages show social media link at the end" <|
36+
test "fetch stats on start up" <|
2737
\() ->
28-
start "https://app" MyProgram.defaultFlags
38+
start "https://app" {}
39+
|> ProgramTest.simulateHttpOk
40+
"GET"
41+
"http://localhost:9000/stats"
42+
(Api.Data.encodeStats (Api.Data.Stats Nothing Nothing <| Just "the_version")
43+
|> Enc.encode 0
44+
)
2945
|> expectViewHas
30-
[ class "super-social-link"
31-
, attribute (href "https://super.social.example.com/avh4")
46+
[ text "the_version"
3247
]
48+
49+
50+
simulateEffects : Effect -> ProgramTest.SimulatedEffect Msg
51+
simulateEffects effect =
52+
case effect of
53+
NoEffect ->
54+
SimulatedEffect.Cmd.none
55+
56+
NavLoadEffect _ ->
57+
SimulatedEffect.Cmd.none
58+
59+
NavPushUrlEffect _ ->
60+
SimulatedEffect.Cmd.none
61+
62+
GetStatisticsEffect ->
63+
SimulatedEffect.Http.get
64+
{ url = "http://localhost:9000/stats"
65+
, expect =
66+
SimulatedEffect.Http.expectJson BrowserGotStatistics Api.Data.statsDecoder
67+
}

0 commit comments

Comments
 (0)