A ProgramTest
simulates the execution of an Elm program
enabling you write high-level tests for your program.
(Testing your programs at this level
provides test coverage that is resilient even to drastic refactorings of your application architecture,
and encourages tests that make it clear how end-users and external services will interact with your program.)
This module allows you to interact with your program by simulating user interactions and external events (like HTTP responses and ports), and making assertions about the HTML it renders and the external requests it makes.
The list below is an index into the API documentation for the assertion and simulation functions relevant to each topic:
For a more detailed explanation of how to get started, see the elm-program-test guidebooks (the best one to start with is “Testing programs with interactive views”):
Http.get
and Http.post
A ProgramTest
represents an Elm program,
a current state for that program,
information about external effects that have been produced by the program (such as pending HTTP requests, values sent to outgoing ports, etc),
and a log of any errors that have occurred while simulating interaction with the program.
ProgramTest
, see the create*
functions below.ProgramTest
, see Simulating user input, or the many simulate functions in this module.ProgramTest
, see the many expect*
functions in this module.start : flags -> ProgramDefinition flags model msg effect -> ProgramTest model msg effect
Starts the given test program by initializing it with the given flags.
If your program uses Json.Encode.Value
as its flags type,
you may find withJsonStringFlags
useful.
A ProgramDefinition
(required to create a ProgramTest
with start
)
can be created with one of the following functions that parallel
the functions in elm/browser
for creating programs.
createSandbox : { init : model, view : model -> Html msg, update : msg -> model -> model } -> ProgramDefinition () model msg ()
Creates a ProgramDefinition
from the parts of a Browser.sandbox
program.
See other create*
functions below if the program you want to test does not use Browser.sandbox
.
createElement : { init : flags -> ( model, effect ), view : model -> Html msg, update : msg -> model -> ( model, effect ) } -> ProgramDefinition flags model msg effect
Creates a ProgramTest
from the parts of a Browser.element
program.
See other create*
functions below if the program you want to test does not use Browser.element
.
If your program has subscriptions that you want to simulate, see withSimulatedSubscriptions
.
createDocument : { init : flags -> ( model, effect ), view : model -> Browser.Document msg, update : msg -> model -> ( model, effect ) } -> ProgramDefinition flags model msg effect
Creates a ProgramTest
from the parts of a Browser.document
program.
See other create*
functions if the program you want to test does not use Browser.document
.
If your program has subscriptions that you want to simulate, see withSimulatedSubscriptions
.
createApplication : { init : flags -> Url -> () -> ( model, effect ), view : model -> Browser.Document msg, update : msg -> model -> ( model, effect ), onUrlRequest : Browser.UrlRequest -> msg, onUrlChange : Url -> msg } -> ProgramDefinition flags model msg effect
Creates a ProgramTest
from the parts of a Browser.application
program.
See other create*
functions if the program you want to test does not use Browser.application
.
If your program has subscriptions that you want to simulate, see withSimulatedSubscriptions
.
Note that Elm currently does not provide any way to create a Browser.Navigation.Key
in tests, so this function uses ()
as the key type instead.
For an example of how to test such a program, see
NavigationKeyExample.elm
and NavigationKeyExampleTest.elm.
createWorker : { init : flags -> ( model, effect ), update : msg -> model -> ( model, effect ) } -> ProgramDefinition flags model msg effect
Creates a ProgramTest
from the parts of a Platform.worker
program.
See other create*
functions if the program you want to test does not use Platform.worker
.
If your program has subscriptions that you want to simulate, see withSimulatedSubscriptions
.
Represents an unstarted program test.
Use start
to start the program being tested.
The following functions allow you to configure your
ProgramDefinition
before starting it with start
.
withBaseUrl : String -> ProgramDefinition flags model msg effect -> ProgramDefinition flags model msg effect
Sets the initial browser URL
You must set this when using createApplication
,
or when using clickLink
and expectPageChange
to simulate a user clicking a link with relative URL.
withJsonStringFlags : Json.Decode.Decoder flags -> ProgramDefinition flags model msg effect -> ProgramDefinition String model msg effect
Provides a convenient way to provide flags for a program that decodes flags from JSON.
By providing the JSON decoder, you can then provide the flags as a JSON string when calling
start
.
withSimulatedEffects : (effect -> SimulatedEffect msg) -> ProgramDefinition flags model msg effect -> ProgramDefinition flags model msg effect
This allows you to provide a function that lets ProgramTest
simulate effects that would become Cmd
s and Task
s
when your app runs in production
(this enables you to use simulateHttpResponse
, advanceTime
, etc.).
For a detailed explanation and example of how to set up tests that use simulated effects,
see the “Testing programs with Cmds” guidebook.
You only need to use this if you need to simulate HTTP requests, outgoing ports, or the passing of time.
See the SimulatedEffect.*
modules in this package for functions that you can use to implement
the required effect -> SimulatedEffect msg
function for your effect
type.
SimulatedEffect msg
This represents an effect that elm-program-test is able to simulate.
When using withSimulatedEffects
you will provide a function that can translate
your program's effects into SimulatedEffect
s.
(If you do not use withSimulatedEffects
,
then ProgramTest
will not simulate any effects for you.)
You can create SimulatedEffect
s using the following modules,
which parallel the modules your real program would use to create Cmd
s and Task
s:
SimulatedEffect.Http
(parallels Http
from elm/http
)SimulatedEffect.Cmd
(parallels Platform.Cmd
from elm/core
)SimulatedEffect.Navigation
(parallels Browser.Navigation
from elm/browser
)SimulatedEffect.Ports
(parallels the port
keyword)SimulatedEffect.Task
(parallels Task
from elm/core
)SimulatedEffect.Process
(parallels Process
from elm/core
)SimulatedEffect.Time
(parallels Time
from elm/time
)SimulatedEffect.SimulatedTask x a
Similar to SimulatedEffect
, but represents a Task
instead of a Cmd
.
withSimulatedSubscriptions : (model -> SimulatedSub msg) -> ProgramDefinition flags model msg effect -> ProgramDefinition flags model msg effect
This allows you to provide a function that lets ProgramTest
simulate subscriptions that would be Sub
s
when your app runs in production
(this enables you to use simulateIncomingPort
, etc.).
You only need to use this if you need to simulate subscriptions in your test.
For a detailed explanation and example of how to set up tests that use simulated subscriptions,
see the “Testing programs with ports” guidebook.
The function you provide should be similar to your program's subscriptions
function
but return SimulatedSub
s instead of Sub
s.
See the SimulatedEffect.*
modules in this package for functions that you can use to implement
the required model -> SimulatedSub msg
function.
SimulatedEffect.SimulatedSub msg
This represents a subscription that elm-program-test is able to simulate.
When using withSimulatedSubscriptions
you will provide
a function that is similar to your program's subscriptions
function but that
returns SimulatedSub
s instead Sub
s.
(If you do not use withSimulatedSubscriptions
,
then ProgramTest
will not simulate any subscriptions for you.)
You can create SimulatedSub
s using the following modules:
SimulatedEffect.Ports
(parallels the port
keyword)done : ProgramTest model msg effect -> Expectation
Ends a ProgramTest
, reporting any errors that occurred.
You can also end a ProgramTest
using any of the functions starting with expect*
.
In fact, you should prefer using one of the expect*
functions when possible,
as doing so will make the intent of your test more clear.
expectViewHas : List Test.Html.Selector.Selector -> ProgramTest model msg effect -> Expectation
A simpler way to assert that a ProgramTest
's view matches a given selector.
expectViewHas [...selector...]
is the same as expectView (Test.Html.Query.has [...selector...])
.
If you want to interact with the program more after this assertion, see ensureViewHas
.
expectViewHasNot : List Test.Html.Selector.Selector -> ProgramTest model msg effect -> Expectation
A simpler way to assert that a ProgramTest
's view does not match a given selector.
expectViewHasNot [...selector...]
is the same as expectView (Test.Html.Query.hasNot [...selector...])
.
If you want to interact with the program more after this assertion, see ensureViewHasNot
.
expectView : (Test.Html.Query.Single msg -> Expectation) -> ProgramTest model msg effect -> Expectation
Makes an assertion about the current state of a ProgramTest
's view.
If you want to interact with the program more after this assertion, see ensureView
.
ensureViewHas : List Test.Html.Selector.Selector -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectViewHas
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectViewHas
when possible,
as having a single assertion per test can make the intent of your tests more clear.
ensureViewHasNot : List Test.Html.Selector.Selector -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectViewHasNot
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectViewHasNot
when possible,
as having a single assertion per test can make the intent of your tests more clear.
ensureView : (Test.Html.Query.Single msg -> Expectation) -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectView
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectView
when possible,
as having a single assertion per test can make the intent of your tests more clear.
clickButton : String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates clicking a button.
This function will find and click a <button>
HTML node containing the given buttonText
.
It will also try to find and click elements with the accessibility label role="button"
.
If the button is disabled the test will fail.
clickLink : String -> String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates clicking a <a href="...">
link.
The parameters are:
The text of the <a>
tag (which is the link text visible to the user).
The href
of the <a>
tag.
NOTE: After eeue56/elm-html-test#52 is resolved,
a future release of this package will remove the href
parameter.
Note for testing single-page apps:
if the target <a>
tag has an onClick
handler,
then the message produced by the handler will be processed
and the href
will not be followed.
NOTE: Currently this function cannot verify that the onClick handler
sets preventDefault
, but this will be done in the future after
https://github.com/eeue56/elm-html-test/issues/63 is resolved.
fillIn : String -> String -> String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates replacing the text in an input field labeled with the given label.
The id of the input field
(which must match both the id
attribute of the target input
element,
and the for
attribute of the label
element),
or ""
if the <input>
is a descendant of the <label>
.
NOTE: After eeue56/elm-html-test#52 is resolved, a future release of this package will remove this parameter.
The label text of the input field.
The text that will be entered into the input field.
There are a few different ways to accessibly label your input fields so that fillIn
will find them:
You can place the <input>
element inside a <label>
element that also contains the label text.
html
<label>
Favorite fruit
<input>
</label>
You can place the <input>
and a <label>
element anywhere on the page and link them with a unique id.
html
<label for="fruit">Favorite fruit</label>
<input id="fruit"></input>
You can use the aria-label
attribute.
html
<input aria-label="Favorite fruit"></input>
If you need to target a <textarea>
that does not have a label,
see fillInTextarea
.
If you need more control over finding the target element or creating the simulated event,
see simulateDomEvent
.
fillInTextarea : String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates replacing the text in a <textarea>
.
This function expects that there is only one <textarea>
in the view.
If your view has more than one <textarea>
,
prefer adding associated <label>
elements and use fillIn
.
If you cannot add <label>
elements see within
.
If you need more control over finding the target element or creating the simulated event,
see simulateDomEvent
.
check : String -> String -> Basics.Bool -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates setting the value of a checkbox labeled with the given label.
The parameters are:
The id of the input field
(which must match both the id
attribute of the target input
element,
and the for
attribute of the label
element),
or ""
if the <input>
is a descendant of the <label>
.
NOTE: After eeue56/elm-html-test#52 is resolved, a future release of this package will remove this parameter.
The label text of the input field
A Bool
indicating whether to check (True
) or uncheck (False
) the checkbox.
NOTE: In the future, this will be generalized to work with aria accessibility attributes in addition to working with standard HTML label elements.
If you need more control over finding the target element or creating the simulated event,
see simulateDomEvent
.
selectOption : String -> String -> String -> String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates choosing an option with the given text in a select with a given label
The parameters are:
The id of the <select>
(which must match both the id
attribute of the target select
element,
and the for
attribute of the label
element),
or ""
if the <select>
is a descendant of the <label>
.
NOTE: After eeue56/elm-html-test#52 is resolved, a future release of this package will remove this parameter.
The label text of the select.
The value
of the <option>
that will be chosen.
NOTE: After eeue56/elm-html-test#51 is resolved, a future release of this package will remove this parameter.
The user-visible text of the <option>
that will be chosen.
Example: If you have a view like the following,
import Html
import Html.Attributes exposing (for, id, value)
import Html.Events exposing (on, targetValue)
Html.div []
[ Html.label [ for "pet-select" ] [ Html.text "Choose a pet" ]
, Html.select
[ id "pet-select", on "change" targetValue ]
[ Html.option [ value "dog" ] [ Html.text "Dog" ]
, Html.option [ value "hamster" ] [ Html.text "Hamster" ]
]
]
you can simulate selecting an option like this:
ProgramTest.selectOption "pet-select" "Choose a pet" "dog" "Dog"
If you need more control over finding the target element or creating the simulated event,
see simulateDomEvent
.
simulateDomEvent : (Test.Html.Query.Single msg -> Test.Html.Query.Single msg) -> ( String, Json.Encode.Value ) -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates a custom DOM event.
NOTE: If there is another, more specific function (see “Simulating user input”) that does what you want, prefer that instead, as you will get the benefit of better error messages.
The parameters are:
Test.Html.Query.find [ ...some selector... ]
)within : (Test.Html.Query.Single msg -> Test.Html.Query.Single msg) -> (ProgramTest model msg effect -> ProgramTest model msg effect) -> ProgramTest model msg effect -> ProgramTest model msg effect
Focus on a part of the view for a particular operation.
For example, if your view produces the following HTML:
<div>
<div id="sidebar">
<button>Submit</button>
</div>
<div id="content">
<button>Submit</button>
</div>
</div>
then the following will allow you to simulate clicking the "Submit" button in the sidebar
(simply using clickButton "Submit"
would fail because there are two buttons matching that text):
import Test.Html.Query as Query
import Test.Html.Selector exposing (id)
programTest
|> ProgramTest.within
(Query.find [ id "sidebar" ])
(ProgramTest.clickButton "Submit")
|> ...
expectHttpRequestWasMade : String -> String -> ProgramTest model msg effect -> Expectation
Asserts that an HTTP request to the specific url and method has been made.
The parameters are:
"GET"
or "POST"
)For example:
...
|> expectHttpRequestWasMade "GET" "https://example.com/api/data"
If you want to check the headers or request body, see expectHttpRequest
.
If you expect multiple requests to have been made to the same endpoint, see expectHttpRequests
.
NOTE: You must use withSimulatedEffects
before you call start
to be able to use this function.
If you want to interact with the program more after this assertion, see ensureHttpRequestWasMade
.
expectHttpRequest : String -> String -> (Test.Http.HttpRequest msg msg -> Expectation) -> ProgramTest model msg effect -> Expectation
Allows you to check the details of a pending HTTP request.
See the “Expectations” section of Test.Http
for functions that might be helpful
in create an expectation on the request.
If you only care about whether the a request was made to the correct URL, see expectHttpRequestWasMade
.
...
|> expectHttpRequest "POST"
"https://example.com/save"
(.body >> Expect.equal """{"content":"updated!"}""")
If you expect multiple requests to have been made to the same endpoint, see expectHttpRequests
.
NOTE: You must use withSimulatedEffects
before you call start
to be able to use this function.
If you want to interact with the program more after this assertion, see ensureHttpRequest
.
expectHttpRequests : String -> String -> (List (Test.Http.HttpRequest msg msg) -> Expectation) -> ProgramTest model msg effect -> Expectation
Allows you to check the details of pending HTTP requests.
See the “Expectations” section of Test.Http
for functions that might be helpful
in create an expectation on the request.
If your program will only have a single pending request to any particular URL, you can use the simpler expectHttpRequest
(singular) or expectHttpRequestWasMade
instead.
...
|> expectHttpRequests "POST"
"https://example.com/save"
(List.map .body >> Expect.equal ["""body1""", """body2"""])
NOTE: You must use withSimulatedEffects
before you call start
to be able to use this function.
If you want to interact with the program more after this assertion, see ensureHttpRequests
.
ensureHttpRequestWasMade : String -> String -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectHttpRequestWasMade
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectHttpRequestWasMade
when possible,
as having a single assertion per test can make the intent of your tests more clear.
ensureHttpRequest : String -> String -> (Test.Http.HttpRequest msg msg -> Expectation) -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectHttpRequest
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectHttpRequest
when possible,
as having a single assertion per test can make the intent of your tests more clear.
ensureHttpRequests : String -> String -> (List (Test.Http.HttpRequest msg msg) -> Expectation) -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectHttpRequests
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectHttpRequests
when possible,
as having a single assertion per test can make the intent of your tests more clear.
simulateHttpOk : String -> String -> String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates an HTTP 200 response to a pending request with the given method and url.
The parameters are:
"GET"
or "POST"
)For example:
...
|> simulateHttpOk "GET"
"https://example.com/time.json"
"""{"currentTime":1559013158}"""
|> ...
If you need to simulate an error, a response with a different status code,
or a response with response headers,
see simulateHttpResponse
.
If you want to check the request headers or request body, use ensureHttpRequest
immediately before using simulateHttpOk
.
NOTE: You must use withSimulatedEffects
before you call start
to be able to use this function.
simulateHttpResponse : String -> String -> Http.Response String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates a response to a pending HTTP request. The test will fail if there is no pending request matching the given method and url.
The parameters are:
"GET"
or "POST"
)Http.Response
value for the simulated response. You may find it helpful to see the “Responses” section in Test.Http
for convenient ways to create Http.Response
values.For example:
...
|> simulateHttpResponse "GET"
"https://example.com/time.json"
Test.Http.networkError
|> ...
|> simulateHttpResponse "POST"
"https://example.com/api/v1/process_data"
(Test.Http.httpResponse
{ statusCode : 204
, headers : [ ( "X-Procesing-Time", "1506ms") ]
, body : ""
}
)
If you are simulating a 200 OK response and don't need to provide response headers,
you can use the simpler simulateHttpOk
.
If you want to check the request headers or request body, use ensureHttpRequest
immediately before using simulateHttpResponse
.
If your program will make multiple pending requests to the same URL, see simulateHttpResponseAdvanced
.
NOTE: You must use withSimulatedEffects
before you call start
to be able to use this function.
simulateHttpResponseAdvanced : String -> String -> Basics.Int -> Http.Response String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates a response to one of several pending HTTP requests made to a given endpoint.
This is the same as simulateHttpResponse
,
except that the additional Int
parameter specificies which request to resolve if multiple requests to the same method/URL are pending.
advanceTime : Basics.Int -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates the passing of time.
The Int
parameter is the number of milliseconds to simulate.
This will cause any pending Task.sleep
s to trigger if their delay has elapsed.
NOTE: You must use withSimulatedEffects
before you call start
to be able to use this function.
expectOutgoingPortValues : String -> Json.Decode.Decoder a -> (List a -> Expectation) -> ProgramTest model msg effect -> Expectation
Lets you assert on the values that the program being tested has sent to an outgoing port.
The parameters are:
ensureOutgoingPortValues
)
and return an Expectation
For example:
...
|> expectOutgoingPortValues
"saveApiTokenToLocalStorage"
Json.Decode.string
(Expect.equal [ "975774a26612", "920facb1bac0" ])
For a more detailed explanation and example, see the “Testing programs with ports” guidebook.
NOTE: You must use withSimulatedEffects
before you call start
to be able to use this function.
If you want to interact with the program more after this assertion, see ensureOutgoingPortValues
.
ensureOutgoingPortValues : String -> Json.Decode.Decoder a -> (List a -> Expectation) -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectOutgoingPortValues
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectOutgoingPortValues
when possible,
as having a single assertion per test can make the intent of your tests more clear.
simulateIncomingPort : String -> Json.Encode.Value -> ProgramTest model msg effect -> ProgramTest model msg effect
Lets you simulate a value being sent to the program being tested via an incoming port.
The parameters are:
For example, here we are simulating the program receiving a list of strings on the incoming port
port resultsFromJavascript : (List String -> msg) -> Sub msg
:
...
|> ProgramTest.simulateIncomingPort
"resultsFromJavascript"
(Json.Encode.list Json.Encode.string
[ "Garden-path sentences can confuse the reader." ]
)
For a more detailed explanation and example, see the “Testing programs with ports” guidebook.
NOTE: You must use withSimulatedSubscriptions
before you call start
to be able to use this function.
expectPageChange : String -> ProgramTest model msg effect -> Expectation
Asserts that the program ended by navigating away to another URL.
The parameter is:
If your program is an application that manages URL changes
(created with createApplication
),
then you probably want expectBrowserUrl
instead.
expectBrowserUrl : (String -> Expectation) -> ProgramTest model msg effect -> Expectation
Asserts on the current value of the browser URL bar in the simulated test environment.
The parameter is:
Expect.equal
with the exact URL you expect.If your program is not an application that manages URL changes
and you want to assert that the user clicked a link that goes to an external web page,
then you probably want expectPageChange
instead.
expectBrowserHistory : (List String -> Expectation) -> ProgramTest model msg effect -> Expectation
Asserts on the current browser history in the simulated test environment.
This only makes sense if you are using withSimulatedEffects
and the function you provide to it produces
SimulatedEffect.Navigation.replaceUrl
or
SimulatedEffect.Navigation.pushUrl
for one or more of your effects.
The previous URL is added to the simulated browser history whenever a pushUrl
effect is simulated.
The parameter is:
Example: If there's only one expected item in the history or if you want check the complete history since the start of the test, use this with Expect.equal
createApplication { ... }
|> withBaseUrl "https://example.com/resource/123"
|> start ()
|> clickButton "Details"
|> expectBrowserHistory (Expect.equal [ "https://example.com/resource/123/details" ])
Example: If there might be multiple items in the history and you only want to check the most recent item:
createApplication { ... }
|> withBaseUrl "https://example.com/resource/123"
|> start ()
|> clickButton "Details"
|> clickButton "Calendar"
|> expectBrowserHistory (List.head >> Expect.equal (Just "https://example.com/resource/123/calendar"))
If you need to assert on the current URL, see expectBrowserUrl
.
ensureBrowserUrl : (String -> Expectation) -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectBrowserUrl
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectBrowserUrl
when possible,
as having a single assertion per test can make the intent of your tests more clear.
ensureBrowserHistory : (List String -> Expectation) -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectBrowserHistory
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectBrowserHistory
when possible,
as having a single assertion per test can make the intent of your tests more clear.
routeChange : String -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulates a route change event (which would happen when your program is
a Browser.application
and the user manually changes the URL in the browser's URL bar).
The parameter may be an absolute URL or relative URL.
You should avoid the functions below when possible, but you may find them useful to test things that are not yet directly supported by elm-program-test.
update : msg -> ProgramTest model msg effect -> ProgramTest model msg effect
Advances the state of the ProgramTest
by applying the given msg
to your program's update function
(provided when you created the ProgramTest
).
This can be used to simulate events that can only be triggered by commands (Cmd
) and subscriptions (Sub
)
(i.e., that cannot be triggered by user interaction with the view).
NOTE: When possible, you should prefer Simulating user input,
Simulating HTTP responses,
or (if neither of those support what you need) simulateLastEffect
,
as doing so will make your tests more resilient to changes in your program's implementation details.
expectModel : (model -> Expectation) -> ProgramTest model msg effect -> Expectation
Make an assertion about the current state of a ProgramTest
's model.
When possible, you should prefer making assertions about the rendered view (see expectView
)
or external requests made by your program (see expectHttpRequest
, expectOutgoingPortValues
),
as testing at the level that users and external services interact with your program
will make your tests more resilient to changes in the private implementation of your program.
expectLastEffect : (effect -> Expectation) -> ProgramTest model msg effect -> Expectation
Makes an assertion about the last effect produced by a ProgramTest
's program.
NOTE: If you are asserting about HTTP requests or outgoing ports, you should prefer more specific functions designed for that purpose. You can find links to the relevant documentation in the documentation index.
If you want to interact with the program more after this assertion, see ensureLastEffect
.
ensureLastEffect : (effect -> Expectation) -> ProgramTest model msg effect -> ProgramTest model msg effect
See the documentation for expectLastEffect
.
This is the same except that it returns a ProgramTest
instead of an Expectation
so that you can interact with the program further after this assertion.
You should prefer expectLastEffect
when possible,
as having a single assertion per test can make the intent of your tests more clear.
simulateLastEffect : (effect -> Result String (List msg)) -> ProgramTest model msg effect -> ProgramTest model msg effect
Simulate the outcome of the last effect produced by the program being tested
by providing a function that can convert the last effect into msg
s.
The function you provide will be called with the effect that was returned by the most recent call to update
or init
in the ProgramTest
.
Err
, then the ProgramTest
will enter a failure state with the provided error message.Ok
, then the list of msg
s will be applied in order via ProgramTest.update
.NOTE: If you are simulating HTTP responses, you should prefer more specific functions designed for that purpose. You can find links to the relevant documentation in the documentation index.
These functions may be useful if you are writing your own custom assertion functions.
fail : String -> String -> ProgramTest model msg effect -> ProgramTest model msg effect
fail
can be used to report custom errors if you are writing your own convenience functions to deal with program tests.
For example, this function checks for a particular structure in the program's view,
but will also fail the ProgramTest if the expectedCount
parameter is invalid:
expectNotificationCount : Int -> ProgramTest model msg effect -> Expectation
expectNotificationCount expectedCount programTest =
if expectedCount <= 0 then
programTest
|> ProgramTest.fail "expectNotificationCount"
("expectedCount must be positive, but was: " ++ String.fromInt expectedCount)
else
programTest
|> expectViewHas
[ Test.Html.Selector.class "notifications"
, Test.Html.Selector.text (toString expectedCount)
]
If you are writing a convenience function that is creating a program test, see createFailed
.
createFailed : String -> String -> ProgramTest model msg effect
createFailed
can be used to report custom errors if you are writing your own convenience functions to create program tests.
NOTE: if you are writing a convenience function that takes a ProgramTest
as input, you should use fail
instead,
as it provides more context in the test failure message.
The parameters are:
For example:
-- JsonSchema and MyProgram are imaginary modules for this example
import JsonSchema exposing (Schema, validateJsonSchema)
import MyProgram exposing (Model, Msg)
import ProgramTest exposing (ProgramTest)
createWithValidatedJson : Schema -> String -> ProgramTest Model Msg (Cmd Msg)
createWithValidatedJson schema json =
case validateJsonSchema schema json of
Err message ->
ProgramTest.createFailed
"createWithValidatedJson"
("JSON schema validation failed:\n" ++ message)
Ok () ->
ProgramTest.createElement
{ init = MyProgram.init
, update = MyProgram.update
, view = MyProgram.view
}
|> ProgramTest.start json
getOutgoingPortValues : String -> ProgramTest model msg effect -> Result (ProgramTest model msg effect) (List Json.Encode.Value)
This can be used for advanced helper functions where you want to continue a test but need the data sent out through ports later in your test.
NOTE: If you do not need this advanced functionality,
prefer expectOutgoingPortValues
instead.
Unused. This is a workaround for issues with publishing this package.
Until Allow package authors to request major versions if API is the same, but behavior is not · Issue #2099 · elm/compiler, Inaccuracy: Elm does not enforce semantic versioning · Issue #868 · elm/elm-lang.org, and elm diff / publish is unaware of breaking visual changes · Issue #2145 · elm/compiler are addressed, this is required to allow the major version of this package to be updated.