In all these years of doing Cypress demos and examples, I used example web applications like this one that stored data on the backend. The front-end and the server communicate via REST api convention: GET /resource
to get all items, GET /resource/:id
to get a single item, DELETE /resource/id:
to remove an item, etc.
Having a separate REST backend to serve the HTML front-end plus the API resources (I typically use json-server) creates challenges:
- you need to start the server in a separate process. I recommend using start-server-and-test that simplifies this step
- resetting the data between the tests requires special API endpoint. For json-server I used the json-server-reset middleware.
Cypress can serve static HTML files using the standard cy.visit command:
1 | cy.visit('index.html') |
But what about REST api backend? Can the cy.intercept command create a useful mock backend for us? Yes - if you use my new plugin cypress-rest-easy. Installation is easy:
1 | npm i -D cypress-rest-easy |
Then import the plugin from your E2E support file
1 | import 'cypress-rest-easy' |
The REST server is created from fixture files, each resource matches a single fixture file. For example, here is our example todos.json
fixture file with 3 items
1 | [ |
Let's define the mock server for a suite of tests. The declaration goes into a describe
or it
configuration object.
1 | describe('Todos', { rest: { todos: 'todos.json' } }, () => { |
Notice how we are visiting a static HTML file using app/index.html
file path, then confirming that 3 items are present on the page. The mock backend is defined using the declaration { rest: { todos: 'todos.json' } }
. If you wanted several resources, just add them to the rest
config object: { rest: { users: 'users.json', posts: 'posts.json' } }
List as data
Instead of a fixture filename, you can provide the data directly
1 | { |
Important: the REST mock uses a copy of the list for each test, thus the changes in one test should not affect the data seen in another test.
Automatic intercepts
You can see the automatic intercept routes created by the plugin by expanding the Routes
section.
The endpoints get automatic alias names, so you can refer to them from the test itself. Let's add new todo items and confirm the web application is making the expected POST /todos
network call to add an item.
1 | describe('Todos', { rest: { todos: 'todos.json' } }, () => { |
Great! What else can we do?
We can point the mock API are a different base URL and let the mock server auto generate id
property for each new posted item:
1 | { |
Finally, we have direct access to the backend data, since it resides in the browser memory. For each resource, the array is automatically stored in the Cypress.env(<name>)
object and is accessible from the test itself.
1 | describe('Todos', { rest: { todos: 'todos.json' } }, () => { |
The reference const todos = Cypress.env('todos')
stays valid through the test.
Finally, all intercepts are reset automatically before each test, so there is no cleanup necessary.
Just write your end-to-end tests, the rest is easy!
See also
- 📝 read the follow up blog post Rest Easy Example
- 🔌 plugin cypress-magic-backend described in my blog post Magic Backed For E2E Testing.
- 🎓 online course Cypress Network Testing Exercises
Watch the video cypress-rest-easy Plugin Introduction below: