If you never used cy.intercept
command, you should. If you are using it a lot, maybe take a look at the new plugin cypress-rest-easy
The example application
Imagine a TodoMVC web application with a REST data backend. Let's say we want to confirm that the app shows "No todos" component if there are no items to show.
1 | <div class="no-todos" v-show="!loading && !todos.length"> |
How would we write a Cypress test for this? It depends on how we handle the data. Our initial test could look like this
1 | describe('Todo app', () => { |
But of course this test would fail if we had even a single todo item.
We need to control the data the application receives from the server.
Regular server
Let's start with the real server that we cannot control during testing. So we need to use the user interface to clear the data for example. Let's say we want to test how the app looks without any items. Since there might be data left by the previous users and tests, we need to write a conditional test.
1 | describe('Todo app', () => { |
Ughh, we need to start the server and use UI to delete the items, and the test is more complex than it needs to be. Tip: you can write conditional tests using my plugin cypress-if
Mocking the individual calls
If you are a fan of cy.intercept command and know how to use it well, you can rewrite the above test to be deterministic by mocking the GET /todos
network call the web app uses to load the data from the server.
1 | describe('Todo app', () => { |
Great, the test is much simpler and is deterministic. But if our test had to add an item, it would need to mock more network calls to avoid sending data to the real backend. Here is a test that loads zero items, adds a todo, then reloads the page. We have to set up separate GET /todos
intercepts just to return different data sets for the first call (zero items) and the second call (1 item). And to avoid storing the created test item on the server, we need to mock the POST /todos
call too.
1 | describe('Todo app', () => { |
The test passes, but it was complicated and not necessarily correct; the item might have a different id
property! To fully recreate the REST api, we would need to keep and store the real item sent by the web application on the POST /todos
call.
cypress-rest-easy plugin
If you need a REST backend API created using cy.intercept
mocks, use the plugin cypress-rest-easy and add the test config object with the "rest" object.
1 | import 'cypress-rest-easy' |
The empty REST resource list is created using the config object { rest: { todos: [] } }
. It starts with an empty list (you could start with real items or pass a JSON fixture name to load data). Each call to POST /todos
updates the list. The second GET /todos
call returns the real list of items. We can even access the list from the test, since the mock server is "running" in the browser memory. Let's confirm the data-todo-id
attribute of the created list element, it should have the id
value.
1 | it( |
Even the most complicated tests are easy to write when you use cypress-rest-easy. And you don't even need the real API backend, since all resource calls are mocked.
🎁 You can find the source code for this blog post in the repo bahmutov/todo-ai-example in the branch rest-easy-example.