Testing actors
Because behaviors are deterministic — pure decisions from message + context, with I/O behind tools — they test without mocks of global state. Feed a message, assert the result.
Drive an actor and assert state
Use a local runtime and the actor's command-capable source. ask resolves after the message is processed, so you can assert the next snapshot:
ts
const runtime = await startRuntime(topology);
const counter = runtime.actors.counter.commands();
await counter.ask({ type: 'INCREMENT' });
expect(counter.snapshot().context.count).toBe(1);
await runtime.stop();Assert emitted events
Subscribe a collector actor to the events you care about:
ts
const collector = await system.spawn(createEventCollectorBehavior());
await system.subscribe(actor, { subscriber: collector, events: ['COUNT_CHANGED'] });
await source.ask({ type: 'INCREMENT' });
// the collector's context now holds the COUNT_CHANGED eventDeterminism in tests
- Prefer
askoversendwhen you need to observe the result — it resolves once the handler has run. - Use the system's
flush()to drain mailboxes when coordinating several actors. - Keep time and randomness in tools, so tests inject fixed values instead of fighting real clocks.
Analyze the machine
For machine-based actors, guard the state machine itself with @actor-web/testing:
ts
import { assertNoUnreachableStates } from '@actor-web/testing';
it('compare machine has no dead states', () => {
assertNoUnreachableStates(compareMachine, 'compare');
});