@xstate/test
The @xstate/test package contains utilities for facilitating model-based testing for any software.
Watch the talk: Write Fewer Tests! From Automation to Autogeneration at React Rally 2019 (π₯ Video)
Quick startβ
- Install
xstateand@xstate/test:
npm install xstate @xstate/test
- Create the machine that will be used to model the system under test (SUT):
import { createMachine } from 'xstate';
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: {
on: {
TOGGLE: 'active',
},
},
active: {
on: {
TOGGLE: 'inactive',
},
},
},
});
- Add assertions for each state in the machine (in this example, using Puppeteer):
// ...
const toggleMachine = createMachine({
id: 'toggle',
initial: 'inactive',
states: {
inactive: {
on: {
/* ... */
},
meta: {
test: async (page) => {
await page.waitFor('input:checked');
},
},
},
active: {
on: {
/* ... */
},
meta: {
test: async (page) => {
await page.waitFor('input:not(:checked)');
},
},
},
},
});
- Create the model:
import { createMachine } from 'xstate';
import { createModel } from '@xstate/test';
const toggleMachine = createMachine(/* ... */);
const toggleModel = createModel(toggleMachine).withEvents({
TOGGLE: {
exec: async (page) => {
await page.click('input');
},
},
});
- Create test plans and run the tests with coverage:
// ...
describe('toggle', () => {
const testPlans = toggleModel.getShortestPathPlans();
testPlans.forEach((plan) => {
describe(plan.description, () => {
plan.paths.forEach((path) => {
it(path.description, async () => {
// do any setup, then...
await path.test(page);
});
});
});
});
it('should have full coverage', () => {
return toggleModel.testCoverage();
});
});
APIβ
createModel(machine, options?)β
Creates an abstract testing model based on the machine passed in.
| Argument | Type | Description |
|---|---|---|
machine | StateMachine | The machine used to create the abstract model. |
options? | TestModelOptions | Options to customize the abstract model |
Returnsβ
A TestModel instance.
Methodsβ
model.withEvents(eventsMap)β
Provides testing details for each event. Each key in eventsMap is an object whose keys are event types and properties describe the execution and test cases for each event:
exec(function): Function that executes the events. It is given two arguments:testContext(any): any contextual testing dataevent(EventObject): the event sent by the testing model
cases?(EventObject[]): the sample event objects for this event type that can be sent by the testing model.
Example:
const toggleModel = createModel(toggleMachine).withEvents({
TOGGLE: {
exec: async (page) => {
await page.click('input');
},
},
});