Check out a free preview of the full State Machines in JavaScript with XState, v2 course

The "Testing" Lesson is part of the full, State Machines in JavaScript with XState, v2 course featured in this preview video. Here's what you'd learn in this lesson:

David discusses strategies for testing state machines and using state machines for model based testing. An article regarding model based testing in react with state machines is also discussed in this segment.


Transcript from the "Testing" Lesson

>> The final lesson is more open ended. We're gonna be talking about strategies for testing the state machines that we built. We're also gonna be talking about the flip side of that in using state machines for what's known as model based testing, in which we could test any application whether they're using state machines or not.

And then the floor is open to other topics and questions that you may have. So the machines that we created are pretty amenable to testing, and there is a guide in the documentation for how exactly to test these machines. So remember that the machines have a transition function and this transition function is a pure function.

So probably the simplest way to test this is to have an expected value. So for example, let's say we have a traffic light and the expected value is yellow. So if we transition, if we have a state of green and a timer event happens, then we expect that this state should be yellow.

So we could do actual state.matches yellow and check if it's truthy. And so basically the same way that you would unit test functions, you can unit test state machines by unit testing the transition function. And you don't need to just verify that the state is correct you could also verify that the actions that the state is going to execute is correct, you can verify that it receives the right event and other things too.

Now, in testing services is where it gets a little bit more intersting. So when you test services these should really be treated as async tests, so you could use a promise, or what I'd like to do is in Jest or Mocha you could use done. And so basically for example, in this machine, what we're saying is that we want to test that the machine eventually reaches a certain state.

And so that's what we're doing in here, we have this on transition callback that is called whenever the state transitions. And so we could check that if the machine eventually ends up in this success state, then we're done. And so then the test succeeds. What we could also do is we could have an expect call over here and make additional assertions on that state.

And then Jest has this feature where you could say expect.assertions and see the number of assertions that you expect to happen. So again, testing services is more of an acing thing and testing the actual machine logic can be done in your normal unit testing fashion. Now, because machines are configurable all of the implementation details can really be mocked.

So in the machine basically has a built in way of doing this. So just using the same width config callback that we've been using in previous exercises, you can provide alternatives for actions, services, guards, delays and other things, especially in the future. And so that way you can mock responses for example if we have a fetch from API service that's invoked.

We could provide a mock response instead of actually trying to mock that call. So things become a lot easier when it's all contained in the same machine. So those are the general strategies for testing the application logic. Another strategy is using the state machine to test applications that might not use state machines at all.

In this article I wrote we're testing a feedback flow where we have three steps, how was your experience? You could answer good or bad. If you click bad, it asks you why? And then you could submit it. If you answer good, it says thanks for your feedback and then we could close it from this button, or this button, or that button.

So this app may or may not be implemented with XState or state machines, we might just be implementing it with the old ways that we know. But we could still use state machines to test the application. So in here there's a bunch of tests and especially end to end tests that result from this.

We have as a user if I'm on the how was your experience screen, and I click good, I should be on the things for your feedback screen. Similarly, as a user if I'm on the form screen and I press submit, then I should be on the things for your feedback screen.

Or if I'm on the form screen and I press escape, or press this little x over here then I should be in the closed state. And so, instead of specifying all of these end to end tests one by one which is really hard to do exhaustively and takes an enormous amount of time and effort.

It's better to represent it as a model instead or a test model. So this test model is a state machine, and the state machine represents all of your given when then statements in a single state machine. So now we could see each of our specifications are represented completely in this machine.

For example, if we're on the question state and we click bad, now we're on the form state and so on and so forth. So this could be represented using XState, and then using a library called X dates test. We could take that machine, provide test data, and asserts that we are in each state for that test data.

So it also provides a way to execute events. And so what this is going to do, and I'll just scroll down here, it's going to generate all the possible paths through the machine depending on the configuration parameters you set. Like how exhaustive you want these tests to be, and it's going to try to traverse the entire state machine and test all of these paths.

And make sure that your app which again might or might not use XState matches the specification that you modeled in that test state machine. And so, while the learning curve here is pretty much the same as learning state machines and hopefully in this workshop you surmounted that learning curve.

It really shows how state machines can be useful in other areas rather than just application, implementation. So for example, this is a video showing puppeteer running and going through all of those test cases, and manually, or automatically entering that information for you, and making sure that every state is what we expect.

So I encourage you to research model based testing and see how you can use state machine and XState tests to test your existing applications.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now