When to use
Use this skill when:
- •Writing tests for Rezi widgets or components
- •Testing app state logic (reducers)
- •Testing keybinding resolvers
- •Need snapshot-style output assertions
Source of truth
- •
packages/core/src/testing/— test utilities (createTestRenderer, etc.) - •
packages/core/src/widgets/__tests__/— existing widget tests (use as examples) - •
packages/core/src/widgets/__tests__/composition.animationHooks.test.ts— animation hook test patterns - •
packages/core/src/app/__tests__/widgetRenderer.transition.test.ts—ui.boxtransition expectations - •
scripts/run-tests.mjs— test runner - •
packages/core/src/testing/snapshot.ts— golden frame snapshot utilities (captureSnapshot,serializeSnapshot,diffSnapshots) - •
scripts/rezi-snap.mjs— CLI for snapshot capture and verification
Steps
- •
Create test file in the appropriate
__tests__/directory - •
Use
createTestRenderer()for widget/render tests:typescriptimport { describe, it } from "node:test"; import * as assert from "node:assert/strict"; import { createTestRenderer, ui } from "@rezi-ui/core"; describe("MyWidget", () => { it("renders correctly", () => { const r = createTestRenderer({ viewport: { cols: 80, rows: 24 } }); const result = r.render(ui.text("hello")); assert.ok(result.findText("hello")); }); }); - •
Test state logic by testing reducer functions directly:
typescriptit("increments count", () => { const state = reducer({ count: 0 }, { type: "increment" }); assert.strictEqual(state.count, 1); }); - •
Use
result.toText()for snapshot-style assertions - •
Use
result.findById()to locate specific nodes in the render tree - •
Use golden frame snapshots for visual regression:
typescriptimport { captureSnapshot, serializeSnapshot, diffSnapshots, parseSnapshot } from "@rezi-ui/core"; const snapshot = captureSnapshot("my-scene", myView(state), { viewport: { cols: 80, rows: 24 }, theme }, "dark"); const text = serializeSnapshot(snapshot); // Compare with stored snapshot using diffSnapshots() - •
Run snapshot CLI for bulk capture/verify:
bashnode scripts/rezi-snap.mjs --update # Capture new snapshots node scripts/rezi-snap.mjs --verify # Verify against stored
- •
For animation features, cover:
- •mount value
- •retarget while running
- •cleanup on unmount (no timer leak)
- •property filtering (
position/size/opacity) forui.boxtransitions
- •
For extended routed actions, verify
UiEventpayloads for widgets that emit non-press actions:- •checkbox emits
action: "toggle"withchecked - •virtualList emits
action: "select"withindex - •table emits
action: "rowPress"withrowIndex - •radio/select flows emit
action: "change"
- •checkbox emits
- •
For animation hook behavior, test:
- •supported easing presets (
linear, quad, cubic) resolve as expected - •retargeted mid-flight runs continue smoothly without jumping
- •looping sequences (
loop: true) remain active and deterministic
Running tests
bash
# Full suite node scripts/run-tests.mjs # Single file node --test path/to/test.ts
Verification
- •All new tests pass
- •No existing tests broken
- •Tests are deterministic (bounded timers/explicit waits, no randomness)
- •Golden snapshots match expected output (if applicable)