Tests
Tests are scenarios you author against a specific expression: input state on one side, expected outcome on the other, run on demand. Unlike the always-on checks (validation, the simulator, the path tester), tests only cover what you write for them, but they cover it deterministically.
What an expression test is
An expression test pairs a target expression with a list of scenarios. Each scenario names input state (variable values, current location, inventory, time) and an expected outcome. The runtime evaluates the target against each scenario’s setup and reports pass or fail.
The contrast with the path tester is deliberate. Expression tests are unit tests on one expression. Path tests are integration tests across many random walks.
Adding a test from an inspector
Every expression field with an Add test for … button under it is testable. The named sites are the Node Inspector’s Visible when, the Scene Inspector’s Visible when, the Event editor’s Condition / Value / DC, and the Location Inspector’s connection rows and pinned encounters. Click the button and the new test opens in the Tests tab already bound to that field.
Generating scenarios
Suggest scenarios in the detail-pane header is the fastest way to fill a test with scenarios.
- Variables to vary. The dialog reads the identifiers your target expression references and lists one row per variable.
- Boundary is the default for every supported numeric-ish type.
boolopens on{false, true};intanddecimalopen on{−, equal, +}(or{min, low, high, max}when the variable declares bounds). Twointvariables under boundary expand to nine scenarios covering every combination of low, equal, and high, one click of Generate away. - Generate turns the current grid into concrete scenarios. Each scenario picks up a readable name from its inputs (
gun_true_remaining_low,x_high_y_max), which you can rename inline in the scenario’s editor.
Suggest scenarios is static analysis, not an LLM call. String variables stay on default since there’s no natural boundary; pick fixed, values, or range yourself. Run it right after you author a new test, before writing scenarios by hand.
Generate evaluates every input combination and groups the results by outcome.
- False group. The input combinations that produced
false. Collapsed by default. - True group. The input combinations that produced
true, expanded here so you can read the individual probes. - Lock in on a group appends its scenarios to the test, one scenario per cell. Use it when only one outcome is worth pinning, for example locking in the
falsebucket to guard against regressions where the condition starts firing when it shouldn’t. - Lock in all appends every group’s scenarios in one action.
The bucket sizes are diagnostic. If one group is dramatically larger than the other and that surprises you, the expression probably doesn’t match your intent. Here the buggy || places seven of eight cells in the true group; the writer’s intended && would put only three. The four extras are the same overly-permissive combinations the Tests panel flags as failing scenarios in the next section, seen from a different angle.
Reading the Tests panel
- Selected test row in the tree, marked ✗ because scenarios under it failed.
- Target expression in the detail pane: the actual expression the test is checking.
- Two failing scenario rows: the specific input states that failed against the writer’s expected result.
The tree structure mirrors the project: scenes contain nodes, nodes contain any inline expression tests as well as event-field groups for events that carry their own tests, and a Locations bucket collects location-scoped tests. A filter box and a Show empty toggle at the top of the tree pane narrow the view, and Run All / Run Filtered / Run Selected in the header let you scope the run.
In the shot above, the visibility check uses || where the writer meant &&, so the condition fires whenever either variable alone is set. Two scenarios that expect false return true, and the panel points at both overly-permissive branches. The pattern says either single term shouldn’t be enough, and the writer swaps the operator.
The Playground
- Variable-state editor. Set the vars the expression will read.
- Expression input. Type any expression.
- Evaluate and Save as case. Evaluate runs the expression against the state above; Save as case turns the current state and expression into a scenario on the currently selected test.
- Result, result type, and variables-read: the answer plus the identifiers the runtime touched.
Reset from defaults populates every project variable at its declared default, so you can start from a known baseline and override just the fields you want to probe.
It’s the fastest way to try an expression against a hand-built state before committing to a full test, or to debug a test scenario by stepping the same state through by hand.
See also
- validation: structural and expression-level errors that surface as you author.
- path tester: many random walks against the runtime, complementing unit-testing single expressions here.
- simulator: drive one path by hand; the Debug toggle in the toolbar renders the debug trace inline in the dialogue timeline.
- expressions: the four types, boolean coercion, and the test-harness functions callout.