A Witness
can be used to record information about the arguments passed to
a Cmd
-generating function.
If you use dependency inversion to decouple part of your program from the
Cmd
-generating functions it depends upon, you can use a Witness
to prove that this
part of your program works with the Cmd
-generating function in the right way.
Let's say I have a Cmd
-generating function that takes a score (an Int
) and saves
it to the server via some HTTP request. Let's further suppose I want to describe the behavior
of my user interface, without worrying about the details of how a score is saved. In this
case, I'll 'inject' the Cmd
-generating function instead of calling it directly from my update
function. This allows me to substitute a fake function during my spec.
Here's the update function:
update : (Int -> Cmd Msg) -> Msg -> Model -> (Model, Cmd Msg)
update scoreSaver msg model =
case msg of
SaveScore score ->
( model, scoreSaver score )
...
To use a Witness, you must reference the elmSpecOut
port defined when configuring
Spec.program
or Spec.browserProgram
. I suggest creating a file called
Spec.Witness.Extra
like so:
module Spec.Witness.Extra exposing (record)
import Runner -- your own setup module
import Spec.Witness
record =
Runner.elmSpecOut
|> Spec.Witness.connect
|> Spec.Witness.record
Now, I can write a spec that uses a witness to record the score passed to the injected
scoreSaver
function like so:
Spec.describe "saving the score"
[ Spec.scenario "successful save" (
Spec.given (
Spec.Setup.init (App.init testFlags)
|> Spec.Setup.withView App.view
|> Spec.Setup.withUpdate (
App.update (\score ->
Json.Encode.int score
|> Spec.Witness.Extra.record "saved-score"
)
)
)
|> Spec.when "the score is saved"
[ Spec.Markup.target << by [ id "game-over-button" ]
, Spec.Markup.Event.click
]
|> it "saves the proper score" (
Witness.observe "saved-score" (Json.Decode.int)
|> Spec.expect (Spec.Claim.isListWhere
[ Spec.Claim.isEqual Debug.toString 28
]
)
)
)
]
Use a Witness
to record information from inside a Cmd
-generating function.
connect : (Spec.Message.Message -> Platform.Cmd.Cmd msg) -> Witness msg
Create a Witness by connecting it with the elmSpecOut
port.
When you configure Spec.program
or Spec.browserProgram
you must
provide a reference to a port called elmSpecOut
. Pass that same port to this
function to create a Witness.
For example, you might create a file called Spec.Witness.Extra
that sets up
a record
function for you to use in your specs:
module Spec.Witness.Extra exposing (record)
import Runner -- your own setup module
import Spec.Witness
record =
Runner.elmSpecOut
|> Spec.Witness.connect
|> Spec.Witness.record
See Spec.Config and the README for more information on the elmSpecOut
port.
record : Witness msg -> String -> Json.Encode.Value -> Platform.Cmd.Cmd msg
Create a Cmd
that records some information.
Provide the name of this witness and a JSON value with any information to be recorded.
Use Spec.Witness.observe
to make a claim about the recorded value.
observe : String -> Json.Decode.Decoder a -> Spec.Observer.Observer model (List a)
Observe the values recorded by a witness.
Provide the name of the witness and a JSON decoder that can decode whatever value you need to observe.