StatifierUI.Fixtures (StatifierUI v0.1.0)

Copy Markdown View Source

Example data a host supplies for a chart: named scenario datamodels and example event payloads (ADR-0003).

A fixture bundle is two maps:

  • scenarios - a scenario name (for example "gold-tier-user") mapped to a complete example of the host-supplied datamodel for that situation.
  • events - an event name (for example "payment.success") mapped to a sample _event.data payload for that event.

Two delivery paths converge on this one struct: a host module implementing StatifierUI.Fixtures.Source (from_source/1), and a JSON sidecar next to a chart (a later phase's loader). Every consumer downstream of either path is indifferent to which one produced the struct.

new/1 validates rather than raises: scenario datamodels must have string keys at every level, so a fixture that would blow up deep inside the engine is instead rejected at load time. Event payloads are preserved verbatim, including the three-way :undefined / nil / map distinction predicator's _event.data semantics require.

Scenario validation is deliberately stricter than the engine's, not a mirror of it. Statifier.MachineState.new/2 rejects only atom keys that are not booleans, so it accepts an integer or boolean key; this rejects every key that is not a string. The reason is convergence: a JSON object key is always a string, so a scenario a behaviour source could supply but a sidecar could never express would break the one-struct guarantee ADR-0003 rests on. Rejecting it in both paths keeps them interchangeable.

Summary

Types

An example datamodel: string keys at every level.

A diagnostic surfaced while loading a fixture bundle. path is the key path inside the bundle; source is the file it came from, or nil for a bundle that never was a file.

The name of a fixture event, matching an SCXML event name.

The name of a fixture scenario.

t()

Functions

Fetches an event's sample payload by name. Returns :error when the event has no fixture, distinct from an event whose fixture value is nil or :undefined.

Event names, sorted (ADR-0005's canonical-order rule).

Builds a validated fixture bundle from a StatifierUI.Fixtures.Source module.

Builds a validated fixture bundle from :scenarios and :events options.

Fetches a scenario's datamodel by name.

Scenario names, sorted (ADR-0005's canonical-order rule).

Types

datamodel()

@type datamodel() :: %{optional(String.t()) => term()}

An example datamodel: string keys at every level.

diagnostic()

@type diagnostic() :: %{
  kind: atom(),
  message: String.t(),
  path: [String.t()],
  source: Path.t() | nil
}

A diagnostic surfaced while loading a fixture bundle. path is the key path inside the bundle; source is the file it came from, or nil for a bundle that never was a file.

event_name()

@type event_name() :: String.t()

The name of a fixture event, matching an SCXML event name.

scenario_name()

@type scenario_name() :: String.t()

The name of a fixture scenario.

t()

@type t() :: %StatifierUI.Fixtures{
  diagnostics: [diagnostic()],
  events: %{optional(event_name()) => term()},
  scenarios: %{optional(scenario_name()) => datamodel()}
}

Functions

event(fixtures, name)

@spec event(t(), event_name()) :: {:ok, term()} | :error

Fetches an event's sample payload by name. Returns :error when the event has no fixture, distinct from an event whose fixture value is nil or :undefined.

event_names(fixtures)

@spec event_names(t()) :: [event_name()]

Event names, sorted (ADR-0005's canonical-order rule).

from_source(module)

@spec from_source(module()) :: {:ok, t()} | {:error, term()}

Builds a validated fixture bundle from a StatifierUI.Fixtures.Source module.

Calls module.scenarios() and module.example_events() and routes both through new/1, so this path and the sidecar loader share exactly one validation implementation. Returns {:error, {:not_a_source, module}} when module does not implement the behaviour.

new(opts \\ [])

@spec new(keyword()) :: {:ok, t()} | {:error, term()}

Builds a validated fixture bundle from :scenarios and :events options.

Both options default to %{}. Returns {:error, reason} rather than raising when a scenario or event key is not a string, when a scenario datamodel is not a map, or when a scenario datamodel contains a non-string key at any depth. A non-string key found inside a datamodel is reported as {:invalid_key, key, path}, where path starts with the scenario name - or, when the offending map is a predicator duration, as {:duration_in_scenario, path}, which says why rather than naming a unit key the author never wrote.

Examples

iex> StatifierUI.Fixtures.new(scenarios: %{"gold-tier-user" => %{"tier" => "gold"}})
{:ok, %StatifierUI.Fixtures{scenarios: %{"gold-tier-user" => %{"tier" => "gold"}}}}

scenario(fixtures, name)

@spec scenario(t(), scenario_name()) :: {:ok, datamodel()} | :error

Fetches a scenario's datamodel by name.

scenario_names(fixtures)

@spec scenario_names(t()) :: [scenario_name()]

Scenario names, sorted (ADR-0005's canonical-order rule).