Quickstart

  1. Install xstate and @xstate/test:
bash
yarn add xstate @xstate/test@alpha
bash
yarn add xstate @xstate/test@alpha
  1. Create your test machine using createTestMachine:
ts
import { createTestMachine } from "@xstate/test";
const machine = createTestMachine({
initial: "onHomePage",
states: {
onHomePage: {
on: {
SEARCH_FOR_MODEL_BASED_TESTING:
"searchResultsVisible",
},
},
searchResultsVisible: {
on: {
CLICK_MODEL_BASED_TESTING_RESULT:
"onModelBasedTestingPage",
PRESS_ESCAPE: "searchBoxClosed",
},
},
searchBoxClosed: {},
onModelBasedTestingPage: {},
},
});
ts
import { createTestMachine } from "@xstate/test";
const machine = createTestMachine({
initial: "onHomePage",
states: {
onHomePage: {
on: {
SEARCH_FOR_MODEL_BASED_TESTING:
"searchResultsVisible",
},
},
searchResultsVisible: {
on: {
CLICK_MODEL_BASED_TESTING_RESULT:
"onModelBasedTestingPage",
PRESS_ESCAPE: "searchBoxClosed",
},
},
searchBoxClosed: {},
onModelBasedTestingPage: {},
},
});
  1. Turn the machine into a test model using createTestModel
ts
import { createTestModel } from "@xstate/test";
const model = createTestModel(machine);
ts
import { createTestModel } from "@xstate/test";
const model = createTestModel(machine);
  1. Run the model in a test, passing in instructions on what to do on different states and events. For example, using Cypress:
ts
describe("Toggle component", () => {
/**
* For each path generated by XState,
* run a new test via `it`
*/
model.getPaths().forEach((path) => {
it(path.description, () => {
// Run any setup before each test here
/**
* In environments, like Cypress,
* that don’t support async, run plan.testSync();
*
* Otherwise, you can run await plan.test();
*/
path.testSync({
states: {
onHomePage: () => {
cy.visit("/");
},
searchResultsVisible: () => {
cy.findByText("Model-based testing").should(
"be.visible",
);
},
searchBoxClosed: () => {
cy.findByText("Model-based testing").should(
"not.be.visible",
);
},
onModelBasedTestingPage: () => {
cy.url().should(
"include",
"/model-based-testing/intro",
);
},
},
events: {
CLICK_MODEL_BASED_TESTING_RESULT: () => {
cy.findByText("Model-based testing").click();
},
SEARCH_FOR_MODEL_BASED_TESTING: () => {
cy.findByPlaceholderText("Search").type(
"Model-based testing",
);
},
},
});
// Run any cleanup after each test here
});
});
});
ts
describe("Toggle component", () => {
/**
* For each path generated by XState,
* run a new test via `it`
*/
model.getPaths().forEach((path) => {
it(path.description, () => {
// Run any setup before each test here
/**
* In environments, like Cypress,
* that don’t support async, run plan.testSync();
*
* Otherwise, you can run await plan.test();
*/
path.testSync({
states: {
onHomePage: () => {
cy.visit("/");
},
searchResultsVisible: () => {
cy.findByText("Model-based testing").should(
"be.visible",
);
},
searchBoxClosed: () => {
cy.findByText("Model-based testing").should(
"not.be.visible",
);
},
onModelBasedTestingPage: () => {
cy.url().should(
"include",
"/model-based-testing/intro",
);
},
},
events: {
CLICK_MODEL_BASED_TESTING_RESULT: () => {
cy.findByText("Model-based testing").click();
},
SEARCH_FOR_MODEL_BASED_TESTING: () => {
cy.findByPlaceholderText("Search").type(
"Model-based testing",
);
},
},
});
// Run any cleanup after each test here
});
});
});