This is a guide for a chart author outside this repository - someone who
depends on statifier and wants to test the SCXML documents their own
application drives. It does not re-explain the interpreter's architecture;
see docs/architecture.md for that. It shows you how to write a declarative
chart test the same way this engine tests itself.
Statifier.Testing.Case is the test case template that drives every SCION and
W3C conformance test in this repository: an expected initial configuration,
then a list of {event, expected configuration} steps. Statifier.Testing.FeatureDetector is
what keeps a document that uses an SCXML feature the engine does not support
from silently passing. Both are public API, versioned with the engine
(ADR-0053), so you get the same runner without copying any file out of this
repository.
{:statifier, "~> 2.0"}No only: :test companion dependency is needed. Statifier.Testing.Case and
Statifier.Testing.FeatureDetector ship in lib/, the same shape as
Plug.Test and Phoenix.ConnTest in their own ecosystems, and ExUnit ships
with Elixir itself. The two modules compile in every environment, including
:prod - they simply go unused there.
defmodule MyApp.CheckoutChartTest do
use Statifier.Testing.Case, async: true
test "the cart advances to payment" do
test_scxml(
"""
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="cart">
<state id="cart"><transition event="checkout" target="payment"/></state>
<state id="payment"/>
</scxml>
""",
"cart advances on checkout",
["cart"],
[{%{"name" => "checkout"}, ["payment"]}]
)
end
enduse Statifier.Testing.Case, async: true gives the test module test_scxml/4.
Run it with mix test exactly like any other ExUnit case.
The four arguments are the XML document, a description string (used only in
failure messages), the expected initial configuration, and the list of
{event_map, expected_configuration} steps.
test_scxml/4 asserts the active leaf-state configuration - by state id -
after initialize, then again after each event is sent. A chart that
terminates asserts against the configuration it held at exit, not the empty
configuration a terminated chart has by construction: the runner restores the
terminal position from the interpreter's own :done effect before comparing.
A document that uses an SCXML feature the engine does not yet support flunks
the test, naming the feature - it never skips. An unimplemented feature can
never look like a passing test this way. For the authoritative, up-to-date
list of what is detected and its support status, see
Statifier.Testing.FeatureDetector.feature_registry/0.
As of this writing, every feature the detector recognizes is :supported or
:partial, so this path is a guarantee for the future rather than something
you are likely to hit today.
A document whose semantics depend on wall-clock timers, delivery to an
external queue, or child sessions needs a running Statifier.Session rather
than the synchronous driving path - test_scxml/4 detects this
(session_required?/1) and routes automatically; no action is needed at the
call site for the common case.
Two options tune the session path's timing for a chart whose load-bearing delays exceed what this repository's own conformance corpus needed:
:settle_window_ms(default100) - how long to wait for pending timers to drain before sending the next event.:configuration_deadline_ms(default4_000) - the upper bound on waiting for a session to reach an expected configuration.
Pass them as a keyword list after the events:
test_scxml(xml, "slow chart", ["idle"], steps,
configuration_deadline_ms: 15_000,
settle_window_ms: 400
)The shape test_scxml/4 takes - a document, an expected initial
configuration, and a list of {event, expected configuration} steps - is the
same shape ADR-0006 defines for this repository's own conformance corpus. A
fixture already written in that shape is executable against your own chart
with no translation.