A Lamdera package. It is not on package.elm-lang.org: the Lamdera compiler provides it, from static.lamdera.com, so lamdera install works and elm install does not.
Configure the end to end test before starting it
import Backend
import Effect.Test
import Frontend
import Test exposing (Test)
import Url
config =
{ frontendApp = Frontend.appFunctions
, backendApp = Backend.appFunctions
, handleHttpRequest = always Effect.Test.UnhandledHttpRequest
, handlePortToJs = always Nothing
, handleFileUpload = always Effect.Test.UnhandledFileUpload
, handleMultipleFilesUpload = always Effect.Test.UnhandledMultiFileUpload
, domain = unsafeUrl "https://my-app.lamdera.app"
}
test : Test
test =
Effect.Test.start "myButton is clickable"
|> Effect.Test.connectFrontend
sessionId0
myDomain
{ width = 1920, height = 1080 }
(\( state, frontendActions ) ->
state
|> frontendActions.clickButton { htmlId = "myButton" }
)
|> Effect.Test.toTest
unsafeUrl : String -> Url
unsafeUrl urlText =
case Url.fromString urlText of
Just url ->
url
Nothing ->
unsafeUrl urlTextAdd a frontend client to the end to end test
import Effect.Test
import Test exposing (Test)
import Url
testApp =
Effect.Test.testApp
Frontend.appFunctions
Backend.appFunctions
(always NetworkError_)
(always Nothing)
(always Nothing)
(unsafeUrl "https://my-app.lamdera.app")
test : Test
test =
testApp "myButton is clickable"
|> Effect.Test.connectFrontend
sessionId0
myDomain
{ width = 1920, height = 1080 }
(\( state, frontendActions ) ->
state
|> frontendActions.clickButton { htmlId = "myButton" }
)
|> Effect.Test.toTest
unsafeUrl : String -> Url
unsafeUrl urlText =
case Url.fromString urlText of
Just url ->
url
Nothing ->
unsafeUrl urlTextThe response for an http request.
Note that if the http request was expecting one form of data (for example json) and the response contains a different type of data (for example a String) then the data will automatically be converted.
The exception to this is Texture. If the request is expecting a Texture (this will only happen with Effect.WebGL.Texture.load and Effect.WebGL.Texture.loadWith) then the response has to contain a Texture if you want the request to succeed.
In other words, sending the Bytes that represent that texture won't work.
Who made this http request?
File data for when simulating a user uploading a file via Effect.File.Select.file or Effect.File.Select.files
Possible simulated user actions for when Effect.File.Select.file is triggered.
Possible simulated user actions for when Effect.File.Select.files is triggered.
Create a file upload containing binary data
Create a file upload containing text data
FrontendActions contains the possible functions we can call on the client we just connected.
import Effect.Test
import Test exposing (Test)
import Url
config =
{ frontendApp = Frontend.appFunctions
, backendApp = Backend.appFunctions
, handleHttpRequest = always Effect.Test.UnhandledHttpRequest
, handlePortToJs = always Nothing
, handleFileUpload = always Effect.Test.UnhandledFileUpload
, handleMultipleFilesUpload = always Effect.Test.UnhandledMultiFileUpload
, domain = unsafeUrl "https://my-app.lamdera.app"
}
test : Test
test =
Effect.Test.start "myButton is clickable"
|> Effect.Test.connectFrontend
sessionId0
myDomain
{ width = 1920, height = 1080 }
(\( state, frontendActions ) ->
-- frontendActions is a record we can use on this specific frontend we just connected
state
|> frontendActions.clickButton { htmlId = "myButton" }
)
|> Effect.Test.toTest
unsafeUrl : String -> Url
unsafeUrl urlText =
case Url.fromString urlText of
Just url ->
url
Nothing ->
unsafeUrl urlTextNormally you won't send data directly to the backend and instead use connectFrontend followed by things like clickButton or inputText to cause the frontend to send data to the backend.
If you do need to send data directly, then you can use this though.
Directly trigger an update on the backend. Normally you shouldn't need to do this as things like Time.every and completed tasks will generate updates automatically.
Simulate the passage of time.
This will trigger any subscriptions like Browser.onAnimationFrame or Time.every along the way.
If you need to simulate a large passage of time and are finding that it's taking too long to run, try fastForward instead.
Similar to simulateTime but this will not trigger any Browser.onAnimationFrame or Time.every subscriptions.
This is useful if you need to move the clock forward a week and it would take too long to simulate it perfectly.
Sometimes you need to decide what should happen next based on some current state. In order to do that you can write something like this:
import Effect.Test
state
|> Effect.Test.andThen
(\state2 ->
case List.filterMap isLoginEmail state2.httpRequests |> List.head of
Just loginEmail ->
Effect.Test.continueWith state2
|> testApp.connectFrontend
sessionIdFromEmail
(loginEmail.loginUrl)
(\( state3, clientIdFromEmail ) ->
...
)
Nothing ->
Effect.Test.continueWith state2 |> Effect.Test.checkState (\_ -> Err "Should have gotten a login email")
)Make the test fail if it doesn't seem some condition.
Make the test fail if the backend model doesn't seem some condition.
Get all snapshots from a test. This can be used with Effect.Snapshot.uploadSnapshots to perform visual regression testing.
Sometimes it's hard to tell what's going on in an end to end test. One way to make this easier to use the viewer function. It's like a test runner for your browser that also lets you see the frontend of an app as simulated inputs are being triggered.
View your end-to-end tests in a elm reactor style app.
main =
viewer [{- End to end tests go here -}]View your end-to-end tests in a elm reactor style app.
import Effect.Test
main =
Effect.Test.viewerWith
(\image jsonData ->
[{- End to end tests go here -}]
)
|> Effect.Test.addBytesFile "/test.png"
|> Effect.Test.addBytesFile "/data.json"
|> Effect.Test.startViewerView your end-to-end tests in a elm reactor style app.
import Effect.Test
main =
Effect.Test.viewerWith
(\image jsonData ->
[{- End to end tests go here -}]
)
|> Effect.Test.addBytesFile "/test.png"
|> Effect.Test.addBytesFile "/data.json"
|> Effect.Test.startViewerAdd a file containing text data to your tests.
import Effect.Test
main =
Effect.Test.viewerWith
(\text jsonData ->
[{- End to end tests go here -}]
)
|> Effect.Test.addStringFile "/test.txt"
|> Effect.Test.addStringFile "/data.json"
|> Effect.Test.startViewerAdd a file containing binary data to your tests.
import Effect.Test
main =
Effect.Test.viewerWith
(\image jsonData ->
[{- End to end tests go here -}]
)
|> Effect.Test.addBytesFile "/test.png"
|> Effect.Test.addBytesFile "/data.json"
|> Effect.Test.startViewerAdd a file containing data for a Effect.WebGL.Texture.Texture to your tests. Right now this is performed with HTTP get requests which means you can only access files in /public (or make get requests to other websites though this isn't recommended since this API might change in the future)
import Effect.Test
main =
Effect.Test.viewerWith
(\texture ->
[{- End to end tests go here -}]
)
|> Effect.Test.addTextureFile "/texture.png"
|> Effect.Test.startViewerAdd a file containing data for a Effect.WebGL.Texture.Texture to your tests. Right now this is performed with HTTP get requests which means you can only access files in /public (or make get requests to other websites though this isn't recommended since this API might change in the future)
import Effect.Test
main =
Effect.Test.viewerWith
(\texture ->
[{- End to end tests go here -}]
)
|> Effect.Test.addTextureFileWithOptions
-- WebGL texture options go here
"/texture.png"
|> Effect.Test.startViewerIf you want to just run the end to end tests to make sure they work, or automatically check that they pass in your CI pipeline then you can setup a headless test runner with this function:
Create a headless test runner.
import Effect.Test
main =
Effect.Test.viewerWith
(\image jsonData ->
[{- End to end tests go here -}]
)
|> Effect.Test.addBytesFile "/test.png"
|> Effect.Test.addBytesFile "/data.json"
|> Effect.Test.startHeadlessMsg type for a headless end to end test runner.
Start a end-to-end test