19 KiB
xstate-audition Core Functions API Reference
Complete API reference for all xstate-audition testing functions.
Function Naming Conventions
All functions follow consistent naming patterns:
runUntil*(): Starts actor, waits for condition, stops actorwaitFor*(): Starts actor, waits for condition, keeps actor running*With(): AcceptsAuditionOptionsas second parameter- Without
With(): Uses default options (noAuditionOptionsparameter)
runUntilDone / waitForDone
Run a Promise Actor or State Machine Actor to completion.
Signatures
function runUntilDone<TLogic extends AnyActorLogic>(
actor: Actor<TLogic>,
): Promise<OutputFrom<TLogic>>;
function runUntilDoneWith<TLogic extends AnyActorLogic>(
actor: Actor<TLogic>,
options: AuditionOptions,
): Promise<OutputFrom<TLogic>>;
Parameters
actor: Actor to run (Promise Actor or State Machine Actor)options(With variant only):AuditionOptionsobject
Returns
Promise<Output> - Resolves with actor output when reaching final state
Behavior
- Starts the actor if not already started
- Waits for actor to reach final state (
type: 'final') - Immediately stops the actor upon completion
- Rejects if timeout expires before completion
Example
const promiseLogic = fromPromise<string>(async () => 'result');
const actor = createActor(promiseLogic);
const output = await runUntilDone(actor);
// output === 'result'
// With timeout
await runUntilDoneWith(actor, { timeout: 100 });
Notes
- Similar to XState's
toPromise()but with options support - No
waitForDone()variant (would be identical torunUntilDone())
runUntilEmitted / waitForEmitted
Run a State Machine until it emits specified events.
Signatures
function runUntilEmitted<TActor extends AnyStateMachineActor>(
actor: TActor,
emittedTypes: Array<EmittedFrom<TActor>['type']>,
): Promise<Array<EmittedFrom<TActor>>>;
function runUntilEmittedWith<TActor extends AnyStateMachineActor>(
actor: TActor,
options: AuditionOptions,
emittedTypes: Array<EmittedFrom<TActor>['type']>,
): Promise<Array<EmittedFrom<TActor>>>;
function waitForEmitted<TActor extends AnyStateMachineActor>(
actor: TActor,
emittedTypes: Array<EmittedFrom<TActor>['type']>,
): Promise<Array<EmittedFrom<TActor>>>;
function waitForEmittedWith<TActor extends AnyStateMachineActor>(
actor: TActor,
options: AuditionOptions,
emittedTypes: Array<EmittedFrom<TActor>['type']>,
): Promise<Array<EmittedFrom<TActor>>>;
Parameters
actor: State Machine Actoroptions(With variant only):AuditionOptionsobjectemittedTypes: Array of event type strings to wait for
Returns
Promise<Event[]> - Resolves with array of emitted events (in order emitted)
Behavior
- Starts the actor if not already started
- Waits for all specified event types to be emitted (via
emit()action) runUntil*stops actor after all events emittedwaitFor*keeps actor running after events emitted- Order of events in array matches emission order
Example
const machine = setup({
types: {
emitted: {} as { type: 'READY' } | { type: 'DONE'; value: string },
},
}).createMachine({
entry: [emit({ type: 'READY' }), emit({ type: 'DONE', value: 'success' })],
});
const actor = createActor(machine);
const [readyEvent, doneEvent] = await runUntilEmitted(actor, ['READY', 'DONE']);
// readyEvent.type === 'READY'
// doneEvent.type === 'DONE', doneEvent.value === 'success'
Notes
- Only applies to events emitted via XState's event emitter API (
emit()) - Does NOT track events sent between actors (use
runUntilEventSent/Received) - Events must be emitted in any order, not necessarily the specified order
Currying
// Curry with actor
const runUntilEmit = runUntilEmitted(actor);
const events = await runUntilEmit(['READY', 'DONE']);
runUntilTransition / waitForTransition
Run a State Machine until it transitions from one state to another.
Signatures
function runUntilTransition<TActor extends AnyStateMachineActor>(
actor: TActor,
fromStateId: string,
toStateId: string,
): Promise<void>;
function runUntilTransitionWith<TActor extends AnyStateMachineActor>(
actor: TActor,
options: AuditionOptions,
fromStateId: string,
toStateId: string,
): Promise<void>;
function waitForTransition<TActor extends AnyStateMachineActor>(
actor: TActor,
fromStateId: string,
toStateId: string,
): Promise<void>;
function waitForTransitionWith<TActor extends AnyStateMachineActor>(
actor: TActor,
options: AuditionOptions,
fromStateId: string,
toStateId: string,
): Promise<void>;
Parameters
actor: State Machine Actoroptions(With variant only):AuditionOptionsobjectfromStateId: Full state ID (including machine ID prefix)toStateId: Full state ID (including machine ID prefix)
Returns
Promise<void> - Resolves when transition occurs
Behavior
- Starts the actor if not already started
- Waits for actor to be in state
fromStateId - Then waits for transition to state
toStateId runUntil*stops actor after transitionwaitFor*keeps actor running after transition- Rejects if transition doesn't occur within timeout
Example
const machine = createMachine({
id: 'fetch',
initial: 'idle',
states: {
idle: {
on: { FETCH: 'loading' },
},
loading: {
on: { SUCCESS: 'success' },
},
success: {},
},
});
const actor = createActor(machine);
// Setup promise
const promise = runUntilTransition(actor, 'fetch.idle', 'fetch.loading');
// Send event
actor.send({ type: 'FETCH' });
// Wait for transition
await promise;
Important Notes
- State IDs must include machine ID prefix:
'machineId.stateId' - If no machine ID provided in
createMachine(), default is'(machine)' - Transition must be direct (from → to), not via intermediate states
- Useful for testing explicit transition paths
Currying
// Curry with actor and fromState
const runFromIdle = runUntilTransition(actor, 'fetch.idle');
await runFromIdle('fetch.loading');
runUntilSnapshot / waitForSnapshot
Run an Actor until its snapshot satisfies a predicate.
Signatures
function runUntilSnapshot<TActor extends AnyActor>(
actor: TActor,
predicate: (snapshot: SnapshotFrom<TActor>) => boolean,
): Promise<SnapshotFrom<TActor>>;
function runUntilSnapshotWith<TActor extends AnyActor>(
actor: TActor,
options: AuditionOptions,
predicate: (snapshot: SnapshotFrom<TActor>) => boolean,
): Promise<SnapshotFrom<TActor>>;
function waitForSnapshot<TActor extends AnyActor>(
actor: TActor,
predicate: (snapshot: SnapshotFrom<TActor>) => boolean,
): Promise<SnapshotFrom<TActor>>;
function waitForSnapshotWith<TActor extends AnyActor>(
actor: TActor,
options: AuditionOptions,
predicate: (snapshot: SnapshotFrom<TActor>) => boolean,
): Promise<SnapshotFrom<TActor>>;
Parameters
actor: Any Actor typeoptions(With variant only):AuditionOptionsobjectpredicate: Function that tests snapshot conditions
Returns
Promise<Snapshot> - Resolves with snapshot that satisfied predicate
Behavior
- Starts the actor if not already started
- Evaluates predicate on each snapshot change
- Resolves when predicate returns
true runUntil*stops actor after predicate satisfiedwaitFor*keeps actor running after predicate satisfied
Example
const machine = setup({
types: {
context: {} as { count: number; status: string },
},
}).createMachine({
context: { count: 0, status: 'idle' },
on: {
INCREMENT: {
actions: assign({ count: ({ context }) => context.count + 1 }),
},
},
});
const actor = createActor(machine);
const promise = runUntilSnapshot(
actor,
(snapshot) => snapshot.context.count >= 3,
);
actor.send({ type: 'INCREMENT' });
actor.send({ type: 'INCREMENT' });
actor.send({ type: 'INCREMENT' });
const snapshot = await promise;
// snapshot.context.count === 3
Use Cases
- Testing complex context conditions
- Waiting for computed values
- Combining multiple state/context checks
- Testing conditions not tied to specific states
Notes
- Similar to XState's
waitFor()but with stop behavior - Predicate called on every snapshot change
- Keep predicates performant (called frequently)
runUntilSpawn / waitForSpawn
Run a State Machine until it spawns a child actor.
Signatures
function runUntilSpawn<TLogic extends AnyActorLogic = AnyActorLogic>(
actor: AnyStateMachineActor,
childId: string | RegExp,
): Promise<ActorRefFrom<TLogic>>;
function runUntilSpawnWith<TLogic extends AnyActorLogic = AnyActorLogic>(
actor: AnyStateMachineActor,
options: AuditionOptions,
childId: string | RegExp,
): Promise<ActorRefFrom<TLogic>>;
function waitForSpawn<TLogic extends AnyActorLogic = AnyActorLogic>(
actor: AnyStateMachineActor,
childId: string | RegExp,
): Promise<ActorRefFrom<TLogic>>;
function waitForSpawnWith<TLogic extends AnyActorLogic = AnyActorLogic>(
actor: AnyStateMachineActor,
options: AuditionOptions,
childId: string | RegExp,
): Promise<ActorRefFrom<TLogic>>;
Parameters
actor: State Machine Actor (parent)options(With variant only):AuditionOptionsobjectchildId: String or RegExp to match spawned child ID
Type Parameters
TLogic: Type of the spawned child's logic (for type safety)
Returns
Promise<ActorRef> - Resolves with reference to spawned child actor
Behavior
- Starts the actor if not already started
- Waits for any actor in the system to spawn child with matching ID
runUntil*stops parent actor after spawn detectedwaitFor*keeps parent actor running after spawn detected- Can match child spawned by parent or any descendant
Example
const childLogic = fromPromise<string>(async () => 'child result');
const parentMachine = setup({
actors: { child: childLogic },
}).createMachine({
on: {
SPAWN: {
actions: spawnChild('child', { id: 'myChild' }),
},
},
});
const actor = createActor(parentMachine);
// Provide explicit type for child
const promise = waitForSpawn<typeof childLogic>(actor, 'myChild');
actor.send({ type: 'SPAWN' });
const childRef = await promise;
// childRef.id === 'myChild'
// childRef has correct typing based on childLogic
Important Notes
- Always provide type parameter for proper TypeScript typing
- Without type parameter, returns
AnyActorRef(not useful) - Cannot specify which parent should spawn the child
- Useful for testing actor hierarchies and dynamic spawning
Currying
const waitForChild = waitForSpawn<typeof childLogic>(actor);
const childRef = await waitForChild('myChild');
runUntilEventReceived / waitForEventReceived
Run an Actor until it receives specified events.
Signatures
function runUntilEventReceived<TActor extends EventReceivingActor>(
actor: TActor,
eventTypes: Array<EventReceivedFrom<TActor>['type']>,
): Promise<Array<EventReceivedFrom<TActor>>>;
function runUntilEventReceivedWith<TActor extends EventReceivingActor>(
actor: TActor,
options: AuditionOptions & { otherActorId?: string | RegExp },
eventTypes: Array<EventReceivedFrom<TActor>['type']>,
): Promise<Array<EventReceivedFrom<TActor>>>;
function waitForEventReceived<TActor extends EventReceivingActor>(
actor: TActor,
eventTypes: Array<EventReceivedFrom<TActor>['type']>,
): Promise<Array<EventReceivedFrom<TActor>>>;
function waitForEventReceivedWith<TActor extends EventReceivingActor>(
actor: TActor,
options: AuditionOptions & { otherActorId?: string | RegExp },
eventTypes: Array<EventReceivedFrom<TActor>['type']>,
): Promise<Array<EventReceivedFrom<TActor>>>;
Parameters
actor: State Machine, Callback, or Transition Actoroptions(With variant only):AuditionOptionswith optionalotherActorIdeventTypes: Array of event type strings to wait for
Options Extension
otherActorId: Filter events to only those received FROM actor with this ID
Returns
Promise<Event[]> - Resolves with array of received events
Behavior
- Starts the actor if not already started
- Waits for all specified event types to be received
runUntil*stops actor after all events receivedwaitFor*keeps actor running after events received- If
otherActorIdprovided, only counts events from that sender
Example
const machine = setup({
types: {
events: {} as { type: 'PING' } | { type: 'PONG' },
},
}).createMachine({
on: {
PING: { actions: /* respond */ },
PONG: { actions: /* respond */ },
},
});
const actor = createActor(machine);
const promise = runUntilEventReceived(actor, ['PING', 'PONG']);
actor.send({ type: 'PING' });
actor.send({ type: 'PONG' });
const [pingEvent, pongEvent] = await promise;
Use Cases
- Testing event handling
- Verifying inter-actor communication
- Testing event sources and filters
runUntilEventSent / waitForEventSent
Run an Actor until it sends specified events to other actors.
Signatures
function runUntilEventSent<TActor extends AnyActor>(
actor: TActor,
eventTypes: string[],
): Promise<Array<EventObject>>;
function runUntilEventSentWith<TActor extends AnyActor>(
actor: TActor,
options: AuditionOptions & { otherActorId?: string | RegExp },
eventTypes: string[],
): Promise<Array<EventObject>>;
function waitForEventSent<TActor extends AnyActor>(
actor: TActor,
eventTypes: string[],
): Promise<Array<EventObject>>;
function waitForEventSentWith<TActor extends AnyActor>(
actor: TActor,
options: AuditionOptions & { otherActorId?: string | RegExp },
eventTypes: string[],
): Promise<Array<EventObject>>;
Parameters
actor: Any Actor typeoptions(With variant only):AuditionOptionswith optionalotherActorIdeventTypes: Array of event type strings to wait for
Options Extension
otherActorId: Filter events to only those sent TO actor with this ID
Returns
Promise<Event[]> - Resolves with array of sent events
Behavior
- Starts the actor if not already started
- Waits for actor to send all specified event types
runUntil*stops actor after all events sentwaitFor*keeps actor running after events sent- If
otherActorIdprovided, only counts events to that recipient
Example
const childLogic = fromPromise<string>(async () => 'done');
const parentMachine = setup({
actors: { child: childLogic },
}).createMachine({
invoke: {
id: 'child',
src: 'child',
onDone: {
actions: sendTo('child', { type: 'COMPLETE' }),
},
},
});
const actor = createActor(parentMachine);
const [sentEvent] = await runUntilEventSent(actor, ['COMPLETE']);
// sentEvent.type === 'COMPLETE'
createActorFromLogic
Curried function to create actors from logic.
Signature
function createActorFromLogic<TLogic extends AnyActorLogic>(
logic: TLogic,
options?: ActorOptions<TLogic>,
): Actor<TLogic>;
// Curried
const createActor = createActorFromLogic(logic);
const actor = createActor(options);
Parameters
logic: Actor logic (machine, promise logic, etc.)options: XState actor options (input, inspect, logger, etc.)
Returns
Curried function or Actor
Use Case
Reduce boilerplate when testing same logic with different inputs:
const createActor = createActorFromLogic(myLogic);
it('should work with input A', async () => {
const actor = createActor({ input: 'A' });
await runUntilDone(actor);
});
it('should work with input B', async () => {
const actor = createActor({ input: 'B' });
await runUntilDone(actor);
});
createActorWith
Curried function to create actors with options.
Signature
function createActorWith<TLogic extends AnyActorLogic>(
options: ActorOptions<TLogic>,
logic: TLogic,
): Actor<TLogic>;
// Curried
const createActor = createActorWith(options);
const actor = createActor(logic);
Parameters
options: XState actor options (input, inspect, logger, etc.)logic: Actor logic (machine, promise logic, etc.)
Returns
Curried function or Actor
Use Case
Reduce boilerplate when testing different logic with same input:
const createActor = createActorWith({ input: 'testInput' });
it('should work with machineA', async () => {
const actor = createActor(machineA);
await runUntilDone(actor);
});
it('should work with machineB', async () => {
const actor = createActor(machineB);
await runUntilDone(actor);
});
patchActor
Modify an Actor for use with xstate-audition.
Signature
function patchActor<TActor extends AnyActor>(
actor: TActor,
options?: AuditionOptions,
): TActor;
Parameters
actor: Actor to modifyoptions: OptionalAuditionOptions
Returns
Modified actor (same reference)
Notes
- Used internally by all other functions
- Mutates the actor (adds internal tracking)
- Generally not needed in user code
- All other xstate-audition functions call this automatically
unpatchActor
Revert modifications made by xstate-audition.
Signature
function unpatchActor<TActor extends AnyActor>(actor: TActor): TActor;
Parameters
actor: Actor to revert
Returns
Reverted actor (same reference)
Notes
- Experimental - may be removed in future
- Undoes internal mutations from
patchActor() - No-op if actor was never patched
- Rarely needed in practice
Quick Reference Table
| Function | Condition | Stops Actor | Keeps Running | Options Support |
|---|---|---|---|---|
runUntilDone |
Final state | Yes | No | With variant |
runUntilEmitted |
Events emitted | Yes | No | With variant |
waitForEmitted |
Events emitted | No | Yes | With variant |
runUntilTransition |
State transition | Yes | No | With variant |
waitForTransition |
State transition | No | Yes | With variant |
runUntilSnapshot |
Snapshot predicate | Yes | No | With variant |
waitForSnapshot |
Snapshot predicate | No | Yes | With variant |
runUntilSpawn |
Child spawned | Yes | No | With variant |
waitForSpawn |
Child spawned | No | Yes | With variant |
runUntilEventReceived |
Events received | Yes | No | With variant |
waitForEventReceived |
Events received | No | Yes | With variant |
runUntilEventSent |
Events sent | Yes | No | With variant |
waitForEventSent |
Events sent | No | Yes | With variant |
createActorFromLogic |
N/A (utility) | N/A | N/A | No |
createActorWith |
N/A (utility) | N/A | N/A | No |
patchActor |
N/A (internal) | N/A | N/A | Yes |
unpatchActor |
N/A (internal) | N/A | N/A | No |