Watch Mock And Reload

Speed up your front-end test-driven development by rerunning frontend tests with the magic mocked backend.

How can you develop your frontend website faster? By removing the slow parts during the "code - test" development cycle where the fast feedback is the most important thing. This is why every modern framework offers "hot module replacement" mode for faster bundling; it makes your app changes instantly reflect in the browser.

I want to do a similar thing for your end-to-end tests. As soon as your code editor saves the modified file, we want to re-run the tests to signal to the developer if the new code works. Cypress already watches your spec file and any imported file bundled into the spec. It re-runs the test(s) on the spec file save as shown below:

In the video, I added the following code assertion to the spec file

cypress/e2e/add-todo.cy.js
1
2
// confirm there are two items
cy.get('li.todo').should('have.length', 2)

As soon as the file is saved, Cypress re-runs the spec. The test passes because our backend saves the two items and the application loads them on page reload. Great.

🎓 You might notice in the video that I am not typing the assertion cy.get... code line. Instead, GitHub Copilot guesses this line based on the surrounding code and the comment above. I am successfully using Copilot to speed up coding my end-to-end tests, and if you want to do the same, check out my online course Write Cypress Tests Using GitHub Copilot.

On the other hand, if I modify the application's front-end code, I need to manually re-run the tests. For example, I can change the HTML markup in the index.html, but I will need to click the "Run All Tests (R)" button to see if my change has broken the existing tests.

Replacing the class name "todo" with "item" does break the tests, but it is easy to make such mistakes if you are not continuously and quickly re-running the relevant tests. Our tests a little sluggish since the backend API calls are delayed by one second for this demo. Let's make sure we run the E2E tests on front-end code changes (not just spec file changes) and let's run these tests even quicker than the backend allows.

Watch the front-end code files

The first step I will take is installing the plugin cypress-watch-and-reload. We can configure this plugin to watch additional local files by listing them in the Cypress config file (glob wildcards are supported)

cypress.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const { defineConfig } = require('cypress')

module.exports = defineConfig({
defaultBrowser: 'electron',
e2e: {
// baseUrl, etc
baseUrl: 'http://127.0.0.1:3000',
fixturesFolder: false,
env: {
// list the files and file patterns to watch
// https://github.com/bahmutov/cypress-watch-and-reload
'cypress-watch-and-reload': {
watch: ['index.html', 'app.js'],
},
},
setupNodeEvents(on, config) {
require('cypress-watch-and-reload/plugins')(on, config)

// IMPORTANT: return the config object
// because it might be modified by the plugin function
return config
},
},
})

We also need to include the plugin's front-end code in the E2E support file

cypress/support/e2e.js
1
2
// https://github.com/bahmutov/cypress-watch-and-reload
import 'cypress-watch-and-reload/support'

Let's try modifying the index.html again to see if the tests catch the problem

The plugin restarts the tests as soon as I click "Command+S" key shortcut and the file is saved. Keep Cypress open on one screen and keep coding on the other monitor, saving the file to see if the changes are correct. The feedback is fast, yet we can make it even faster!

Instant backend response

We are modifying the frontend code. The backend should stay the same, yet our tests are slow because of waiting for the API to reset the data at the start of the test, then the initial data load, plus adding each item takes a second. Our full test takes 6 seconds because the backend API is slow. Luckily, I have written plugin cypress-magic-backend that can help us. Read the blog post Magic Backed For E2E Testing for the introduction to the plugin's features. In this blog post, we will use pre-recorded test network call already saved for this spec as local JSON files. I will "lock" the Replay mode via UI button 🪄 🎞️ and every test restart will simply use mock backend API responses for very fast feedback.

In the video below, I try to replace the class name "todo" with just "item". I quickly see that it would break the test, since it is looking for the .todo elements. I then modify the class list to have both todo and item class names. The watch and reload restarts the tests, and the tests are using magic backend "Replay" mode where all API requests are mocked. The final passing test is 10x faster than before; it finishes in 600ms instead of 6 seconds!

When working on front-end code, the combination of watching the application code and rerunning the tests quickly in isolation from the backend is unbeatable in my opinion.

Replay mode with mocked backend API calls

Happy fast testing!