Skip to content

Commit

Permalink
improve testing
Browse files Browse the repository at this point in the history
  • Loading branch information
myrho committed Apr 12, 2022
1 parent 1e7d01e commit 8a496b9
Show file tree
Hide file tree
Showing 17 changed files with 261 additions and 83 deletions.
15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
include .env

API_ELM=openapi/src/Api.elm

openapi:
tools/generate-openapi.sh
tools/generate-openapi.sh $(OPENAPI_LOCATION)
#--global-property=debugModels \
#--global-property=debugOperations \

watch:
find . -name \*.elm | entr make dev

dev: $(API_ELM) $(wildcard src/**)
npx elm-test

$(API_ELM): $(wildcard templates/*)
make openapi

.PHONY: openapi
1 change: 1 addition & 0 deletions elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"elm/json": "1.1.3",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"krisajenkins/remotedata": "6.0.1",
"rtfeldman/elm-css": "16.1.1",
"rtfeldman/elm-iso8601-date-strings": "1.1.4"
},
Expand Down
78 changes: 55 additions & 23 deletions openapi/src/Api.elm
Original file line number Diff line number Diff line change
@@ -1,48 +1,57 @@
module Api exposing
( Request
, map
, request
, send
, effect
, sendWithCustomError
, task
, map
, baseUrl
, withBasePath
, withTimeout
, withTracker
, withBearerToken
, withHeader
, withHeaders
, withTimeout
, withTracker
)

import Http
import Json.Decode
import Json.Encode
import ProgramTest
import SimulatedEffect.Http
import Task
import Url.Builder


type Request a
= Request
type Request a =
Request
{ method : String
, headers : List Http.Header
, headers : List ( String, Maybe String )
, basePath : String
, pathParams : List String
, queryParams : List Url.Builder.QueryParameter
, body : Http.Body
, body : Maybe Json.Encode.Value
, decoder : Json.Decode.Decoder a
, timeout : Maybe Float
, tracker : Maybe String
}


request : String -> String -> List ( String, String ) -> List ( String, Maybe String ) -> List ( String, Maybe String ) -> Maybe Json.Encode.Value -> Json.Decode.Decoder a -> Request a
baseUrl : String
baseUrl =
"http://localhost:9000"


request : String -> String -> List ( String, String ) -> List (String, Maybe String) -> List (String, Maybe String) -> Maybe Json.Encode.Value -> Json.Decode.Decoder a -> Request a
request method path pathParams queryParams headerParams body decoder =
Request
{ method = method
, headers = headers headerParams
, basePath = "http://localhost:9000"
, headers = headerParams
, basePath = baseUrl
, pathParams = interpolatePath path pathParams
, queryParams = queries queryParams
, body = Maybe.withDefault Http.emptyBody (Maybe.map Http.jsonBody body)
, body = body
, decoder = decoder
, timeout = Nothing
, tracker = Nothing
Expand All @@ -54,13 +63,26 @@ send toMsg req =
sendWithCustomError identity toMsg req


effect : (Result Http.Error a -> msg) -> Request a -> ProgramTest.SimulatedEffect msg
effect toMsg (Request req) =
SimulatedEffect.Http.request
{ method = req.method
, headers = effectHeaders req.headers
, url = Url.Builder.crossOrigin req.basePath req.pathParams req.queryParams
, body = Maybe.withDefault SimulatedEffect.Http.emptyBody (Maybe.map SimulatedEffect.Http.jsonBody req.body)
, expect = effectExpectJson identity toMsg req.decoder
, timeout = req.timeout
, tracker = req.tracker
}


sendWithCustomError : (Http.Error -> e) -> (Result e a -> msg) -> Request a -> Cmd msg
sendWithCustomError mapError toMsg (Request req) =
Http.request
{ method = req.method
, headers = req.headers
, headers = headers req.headers
, url = Url.Builder.crossOrigin req.basePath req.pathParams req.queryParams
, body = req.body
, body = Maybe.withDefault Http.emptyBody (Maybe.map Http.jsonBody req.body)
, expect = expectJson mapError toMsg req.decoder
, timeout = req.timeout
, tracker = req.tracker
Expand All @@ -71,9 +93,9 @@ task : Request a -> Task.Task Http.Error a
task (Request req) =
Http.task
{ method = req.method
, headers = req.headers
, headers = headers req.headers
, url = Url.Builder.crossOrigin req.basePath req.pathParams req.queryParams
, body = req.body
, body = Maybe.withDefault Http.emptyBody (Maybe.map Http.jsonBody req.body)
, resolver = jsonResolver req.decoder
, timeout = req.timeout
}
Expand Down Expand Up @@ -111,49 +133,59 @@ withTracker tracker (Request req) =

withBearerToken : String -> Request a -> Request a
withBearerToken token (Request req) =
Request { req | headers = Http.header "Authorization" ("Bearer " ++ token) :: req.headers }
Request { req | headers = ( "Authorization", Just ("Bearer " ++ token) ) :: req.headers }


withHeader : String -> String -> Request a -> Request a
withHeader key value (Request req) =
Request { req | headers = req.headers ++ [ Http.header key value ] }
Request { req | headers = req.headers ++ [ ( key, Just value ) ] }


withHeaders : List ( String, String ) -> Request a -> Request a
withHeaders headers_ (Request req) =
Request { req | headers = req.headers ++ headers (List.map (Tuple.mapSecond Just) headers_) }
Request { req | headers = req.headers ++ List.map (Tuple.mapSecond Just) headers_ }



-- HELPER


headers : List ( String, Maybe String ) -> List Http.Header
headers : List (String, Maybe String) -> List Http.Header
headers =
List.filterMap (\( key, value ) -> Maybe.map (Http.header key) value)
List.filterMap (\(key, value) -> Maybe.map (Http.header key) value)


effectHeaders : List ( String, Maybe String ) -> List SimulatedEffect.Http.Header
effectHeaders =
List.filterMap (\( key, value ) -> Maybe.map (SimulatedEffect.Http.header key) value)


interpolatePath : String -> List ( String, String ) -> List String
interpolatePath rawPath pathParams =
let
interpolate =
\( name, value ) path -> String.replace ("{" ++ name ++ "}") value path
(\(name, value) path -> String.replace ("{" ++ name ++ "}") value path)
in
List.foldl interpolate rawPath pathParams
|> String.split "/"
|> List.drop 1


queries : List ( String, Maybe String ) -> List Url.Builder.QueryParameter
queries : List (String, Maybe String) -> List Url.Builder.QueryParameter
queries =
List.filterMap (\( key, value ) -> Maybe.map (Url.Builder.string key) value)
List.filterMap (\(key, value) -> Maybe.map (Url.Builder.string key) value)


expectJson : (Http.Error -> e) -> (Result e a -> msg) -> Json.Decode.Decoder a -> Http.Expect msg
expectJson mapError toMsg decoder =
Http.expectStringResponse toMsg (Result.mapError mapError << decodeResponse decoder)


effectExpectJson : (SimulatedEffect.Http.Error -> e) -> (Result e a -> msg) -> Json.Decode.Decoder a -> SimulatedEffect.Http.Expect msg
effectExpectJson mapError toMsg decoder =
SimulatedEffect.Http.expectStringResponse toMsg (Result.mapError mapError << decodeResponse decoder)


jsonResolver : Json.Decode.Decoder a -> Http.Resolver Http.Error a
jsonResolver decoder =
Http.stringResolver (decodeResponse decoder)
Expand Down
18 changes: 9 additions & 9 deletions openapi/src/Api/Data.elm
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,9 @@ type alias SearchResultLevel6 =


type alias Stats =
{ currencies : Maybe (List (CurrencyStats))
, requestTimestamp : Maybe String
, version : Maybe String
{ currencies : List (CurrencyStats)
, requestTimestamp : String
, version : String
}


Expand Down Expand Up @@ -1221,9 +1221,9 @@ encodeStatsPairs : Stats -> List EncodedField
encodeStatsPairs model =
let
pairs =
[ maybeEncode "currencies" (Json.Encode.list encodeCurrencyStats) model.currencies
, maybeEncode "request_timestamp" Json.Encode.string model.requestTimestamp
, maybeEncode "version" Json.Encode.string model.version
[ encode "currencies" (Json.Encode.list encodeCurrencyStats) model.currencies
, encode "request_timestamp" Json.Encode.string model.requestTimestamp
, encode "version" Json.Encode.string model.version
]
in
pairs
Expand Down Expand Up @@ -1761,9 +1761,9 @@ searchResultLevel6Decoder =
statsDecoder : Json.Decode.Decoder Stats
statsDecoder =
Json.Decode.succeed Stats
|> maybeDecode "currencies" (Json.Decode.list currencyStatsDecoder) Nothing
|> maybeDecode "request_timestamp" Json.Decode.string Nothing
|> maybeDecode "version" Json.Decode.string Nothing
|> decode "currencies" (Json.Decode.list currencyStatsDecoder)
|> decode "request_timestamp" Json.Decode.string
|> decode "version" Json.Decode.string


tagDecoder : Json.Decode.Decoder Tag
Expand Down
8 changes: 7 additions & 1 deletion review/elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
"elm/core": "1.0.5",
"jfmengels/elm-review": "2.7.1",
"jfmengels/elm-review-documentation": "2.0.1",
"lue-bird/elm-review-missing-record-field-lens": "1.0.2",
"sparksp/elm-review-ports": "1.3.1",
"stil4m/elm-syntax": "7.2.9"
},
"indirect": {
"Chadtech/elm-bool-extra": "2.4.2",
"elm/html": "1.0.0",
"elm/json": "1.1.3",
"elm/parser": "1.1.0",
Expand All @@ -21,11 +23,15 @@
"elm/regex": "1.0.0",
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.2",
"elm-community/basics-extra": "4.1.0",
"elm-community/list-extra": "8.5.2",
"elm-community/maybe-extra": "5.3.0",
"elm-explorations/test": "1.2.2",
"miniBill/elm-unicode": "1.0.2",
"rtfeldman/elm-hex": "1.0.0",
"stil4m/structured-writer": "1.0.3"
"stil4m/structured-writer": "1.0.3",
"the-sett/elm-pretty-printer": "2.2.3",
"the-sett/elm-syntax-dsl": "5.3.0"
}
},
"test-dependencies": {
Expand Down
13 changes: 10 additions & 3 deletions review/src/ReviewConfig.elm
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ when inside the directory containing this file.

import Docs.NoMissing
import NoDuplicatePorts
import NoMissingRecordFieldLens
import Review.Rule exposing (Rule)


config : List Rule
config =
[ NoDuplicatePorts.rule
, Docs.NoMissing.rule
{ document = Docs.NoMissing.everything
, from = Docs.NoMissing.allModules

{- , Docs.NoMissing.rule
{ document = Docs.NoMissing.everything
, from = Docs.NoMissing.allModules
}
-}
, NoMissingRecordFieldLens.rule
{ generator = NoMissingRecordFieldLens.monocle
, generateIn = ( "Lenses", [] )
}
]
12 changes: 11 additions & 1 deletion src/Effect.elm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module Effect exposing (Effect(..), n, perform)
module Effect exposing (Effect(..), batch, n, perform)

import Api
import Api.Request.General
Expand All @@ -11,13 +11,19 @@ type Effect
| NavLoadEffect String
| NavPushUrlEffect String
| GetStatisticsEffect
| BatchedEffects (List Effect)


n : model -> ( model, Effect )
n model =
( model, NoEffect )


batch : List Effect -> Effect
batch effs =
BatchedEffects effs


perform : Nav.Key -> Effect -> Cmd Msg
perform key effect =
case effect of
Expand All @@ -33,3 +39,7 @@ perform key effect =
GetStatisticsEffect ->
Api.Request.General.getStatistics
|> Api.send BrowserGotStatistics

BatchedEffects effs ->
List.map (perform key) effs
|> Cmd.batch
34 changes: 22 additions & 12 deletions src/Init.elm
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
module Init exposing (init)

import Api.Data
import Browser.Navigation as Nav
import Effect exposing (Effect(..), n)
import Iknaio
import Locale.Init as Locale
import Model exposing (..)
import RemoteData exposing (RemoteData(..))
import Url exposing (Url)


init : Flags -> Url -> key -> ( Model key, Effect )
init _ url key =
( { url = url
, key = key
, locale = Locale.init
, theme = Iknaio.theme
, search = ()
, user = ()
, stats = Api.Data.Stats Nothing Nothing Nothing
}
, GetStatisticsEffect
)
n
{ url = url
, key = key
, locale = Locale.init
, theme = Iknaio.theme
, search = ()
, user = ()
, stats = NotAsked
}
|> getStatistics


getStatistics : ( Model key, Effect ) -> ( Model key, Effect )
getStatistics ( model, eff ) =
if model.stats == NotAsked then
( { model | stats = Loading }
, Effect.batch [ eff, GetStatisticsEffect ]
)

else
( model, eff )
4 changes: 2 additions & 2 deletions src/Model.elm
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module Model exposing (..)

import Api.Data
import Browser.Navigation as Nav
import Locale.Model as Locale
import RemoteData exposing (WebData)
import Themes.Model exposing (Theme)
import Url exposing (Url)

Expand All @@ -23,5 +23,5 @@ type alias Model navigationKey =
, theme : Theme
, search : ()
, user : ()
, stats : Api.Data.Stats
, stats : WebData Api.Data.Stats
}
Loading

0 comments on commit 8a496b9

Please sign in to comment.