lustre/dev/simulate
Types
A simulated lustre.App
ready
to be started. This module exposes constructor functions that mirrors those
provided by the main lustre
module:
Note: running a simulated app is not the same as running a real app! Any effects that would normally be run after update will be discarded. If you want to simulate messages coming from the outside world, you can use the
message
orevent
functions.
pub opaque type App(args, model, msg)
The simulation keeps a log of events that occur. This includes both simulated
DOM events and messages dispatched using the event
and
message
functions but also entries for failures like an event
target not existing in the current view or an event that was fired but not
handled.
The event log is primarily useful for debugging simulations that don’t produce
the results you expect. You can use the history
function to
introspect a simulation for this event log.
pub type Event(msg) {
Dispatch(message: msg)
Event(target: query.Query, name: String, data: json.Json)
Problem(name: String, message: String)
}
Constructors
-
Dispatch(message: msg)
-
Event(target: query.Query, name: String, data: json.Json)
-
Problem(name: String, message: String)
A running simulation of a Lustre application, produced by calling
start
.This is similar to the Runtime
type and both DOM events and messages dispatched by effects can be simulated
using the event
and message
functions respectively.
Each simulated event returns an updated simulation, making it convenient to pipe multiple events in sequence.
pub opaque type Simulation(model, msg)
Values
pub fn application(
init init: fn(args) -> #(model, effect.Effect(msg)),
update update: fn(model, msg) -> #(model, effect.Effect(msg)),
view view: fn(model) -> @internal Element(msg),
) -> App(args, model, msg)
Construct a simulated Lustre application. The simulation can be started
with the start
function by providing the initial arguments for
your app’s init
function.
DOM events and messages dispatched by effects can be simulated using the
event
and messgae
functions.
Note: simulated apps do not run any effects! You can simulate the result of an effect by using the
message
function, but to test side effects you should test your application in a real environment.
pub fn click(
simulation: Simulation(model, msg),
on query: query.Query,
) -> Simulation(model, msg)
A convenience function that simulates a click event on the first element
matching the given query. This event will have no payload and is only
appropriate for event handlers that use Lustre’s on_click
handler or custom
handlers that do not decode the event payload.
pub fn event(
simulation: Simulation(model, msg),
on query: query.Query,
name event: String,
data payload: List(#(String, json.Json)),
) -> Simulation(model, msg)
Simulate a DOM event on the first element that matches the given query. The payload represents a simulated event object, and should be used to pass data you expect your event handlers to decode.
If no element matches the query, an EventTargetNotFound
event is
logged in the simulation history. If an element is found, but the application
has no handler for the event, the EventHandlerNotFound
event is
logged instead.
Note: this is not a perfect simulation of a real DOM event. There is no capture phase of a simulated event and simulated events will not bubble up to parent elements.
pub fn history(
simulation: Simulation(model, msg),
) -> List(Event(msg))
Receive the current Event
log of a running simulation. You can
use this to produce more detailed snapshots by also rendering the sequence of
events that produced the given view.
In addition to simulated DOM events and message dispatch, the event log will also include entries for when the queried event target could not be found in the view and cases where an event was fired but not handled by your application.
pub fn input(
simulation: Simulation(model, msg),
on query: query.Query,
value value: String,
) -> Simulation(model, msg)
Simulate an input event on the first element matching the given query. This helper has an event payload that looks like this:
{
"target": {
"value": value
}
}
and is appropriate for event handlers that use Lustre’s on_input
handler
or custom handlers that only decode the event target value.
pub fn message(
simulation: Simulation(model, msg),
msg: msg,
) -> Simulation(model, msg)
Simulate a message sent directly to the runtime. This is often used to mimic the result of some effect you would have run in a real environment. For example, you might simulate a click event on a login button and then simulate the successful response from the server by calling this function with the message you would dispatch from the effect:
import birdie
import lustre/dev/simulate
import lustre/dev/query
import lustre/element
pub fn login_test() {
let app = simulate.application(init:, update:, view:)
let login_button = query.element(matching: query.id("login"))
let user = User(name: "Lucy")
simulate.start(app, Nil)
|> simulate.event(on: login_button, name: "click", data: [])
// Simulate a successful response from the server
|> simulate.message(ApiReturnedUser(Ok(user)))
|> simulate.view
|> element.to_readable_string
|> birdie.snap("Successful login")
}
Note: your app’s
view
function will probably be rendering quite a lot of HTML! To make your snapshots more meaningful, you might want to couple this with thequery
module to only snapshot parts of the page that are relevant to the test.
pub fn model(simulation: Simulation(model, msg)) -> model
Introspect the current model
of a running simulation. This can be useful
to debug why a simulation is not producing the view you expect.
pub fn problem(
simulation: Simulation(model, msg),
name name: String,
message message: String,
) -> Simulation(model, msg)
Log a problem that occured during the simulation. This function is useful for
external packages that want to provide functions to simulate certain effects
that may fail in the real world. For example, a routing package may log a
problem if a link has an invalid href
attribute that would cause no message
to be dispatched.
Note: logging a problem will not stop the simulation from running, just like a real application!
pub fn simple(
init init: fn(args) -> model,
update update: fn(model, msg) -> model,
view view: fn(model) -> @internal Element(msg),
) -> App(args, model, msg)
pub fn start(
app: App(args, model, msg),
args: args,
) -> Simulation(model, msg)
pub fn submit(
simulation: Simulation(model, msg),
on query: query.Query,
fields form_data: List(#(String, String)),
) -> Simulation(model, msg)
Simulate a submit event on the first element matching the given query. The simulated event payload looks like this:
{
"detail": {
"formData": [
...
]
}
}
and is appropriate for event handlers that use Lustre’s on_submit
handler
or custom handlers that only decode the non-standard detail.formData
property.
pub fn view(
simulation: Simulation(model, msg),
) -> @internal Element(msg)