Adding solver fixtures
Solver behavior is defined by fixtures: a layout, an operation, and the expected outcome including the strategy. When a case behaves unexpectedly, the first step is a fixture that shows it.
Where fixtures live
tests/compatibility/solver.test.tsand its siblings (drag-scenarios,solver-stability,projection-*,nested-layout,presets) hold behavior fixtures. They use small helpers so a test reads like a solver call over bounds.tests/fixtures/holds shared nested trees (dashboard-page.ts,sharing-page.ts) built withnode()andleaf()fromnodes.ts.tests/invariants/holds property tests withfast-checkarbitraries inarbitraries.ts.benchmarks/fixtures.tsholds seeded layouts for timing; each benchmark case asserts the strategy it expects.
A behavior fixture
Conventions:
- Name the intent, not the numbers. The
describesays what the user did; the comment says why the expectation holds. Keep the "why" when you port or move a fixture. - Assert the strategy. Geometry can be right by accident; the strategy pins the path. If a change legitimately reroutes a case, update the strategy and say so in the changeset.
- Use neutral ids.
header,chart,sidebar,stat-1,group-a. No product names, no ticket numbers. - Do not weaken assertions to go green. A failing fixture is a candidate behavior drift; report it with the exact expected and actual values.
A nested fixture
For nested cases, build the tree with the helpers in tests/fixtures/nodes.ts and go through flattenLayout. Solve in container.layout, and assert on projectItemsToRoot when the visible outcome matters.
An invariant
When the property is general ("no accepted result overlaps a solid sibling"), add it to tests/invariants/solver-invariants.test.ts with an arbitrary from arbitraries.ts rather than a single example. Invariants catch what examples miss; examples explain what invariants cannot.
Running
Fixtures run in Bun with import { describe, expect, it } from 'bun:test' and import the library as gridla through a path alias, so they exercise the source, not the build.