cypress-magic-backend
v1.20.5
Published
It is like a real backend but magically faster and better
Maintainers
Readme
cypress-magic-backend
It is like a real backend but magically faster and better

Learn
- 📝 blog post Magic Backed For E2E Testing
- 📝 blog post Magic Backed Inspection Mode
- 📝 blog post Watch Mock And Reload
- 📝 blog post Mock But Verify
- 🎁 repo cypress-magic-backend-example
- 📺 videos in the playlist Cypress Magic Backend
Features and capabilities
- recording and replaying GraphQL calls would work too, since you just need to record all
POST /graphqlcalls. - works with your own
cy.interceptspying and stubbing, sincecypress-magic-backendis applied last. Thus yourcy.interceptswork first - check the current mode using the env variable
const mode = Cypress.env('magic_backend_mode'), possible values areundefined,playback,playback-only, andinspect
Assumptions
- All API calls in a particular test happen in the same order and can be stubbed in that order. In the future, I will provide a way to do flexible stubbing according to your own matching rules.
- We are using Chromium-based browser that works with cypress-cdp plugin.
Installation
This plugin requires both Node and browser registration. To register the plugin Node code, please call its registration function from your cypress config file
// cypress.config.js
const { defineConfig } = require('cypress')
// https://github.com/bahmutov/cypress-magic-backend
const registerMagicBackend = require('cypress-magic-backend/src/plugin')
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
registerMagicBackend(on, config)
// IMPORTANT: return the config object
// because it might be modified by the plugin function
return config
},
},
})To register the plugin's browser code, include the plugin from your E2E support file
// cypress/support/e2e.js
// https://github.com/bahmutov/cypress-magic-backend
import 'cypress-magic-backend'Done!
Configuration
You should define which API routes the plugin should record / replay. For example, to intercept all calls to /api endpoint you could use the pathname parameter (similar to how cy.intercept defined intercepts)
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
env: {
magicBackend: {
apiCallsToIntercept: { method: '*', pathname: '/api' },
},
},
},
// the rest of the config
})Important: make sure the config object is stored inside the env object of the e2e object, otherwise Cypress would not "combine" env blocks correctly. Read the blog post Cypress v10 Environment Variables for more details.
// 🚨 DO NOT DO THIS!
module.exports = defineConfig({
env: {
...
}
})
// ✅ CORRECT WAY
module.exports = defineConfig({
e2e: {
env: {
...
}
}
})Sometimes the API endpoints are complicated to code using a single intercept definition. You can define an array of separate interceptors. For example, TodoMVC app might allow the following API calls only:
// cypress.config.js
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
env: {
magicBackend: {
// API endpoints to intercept using an array definition
apiCallsToIntercept: [
{ method: 'GET', pathname: '/todos' },
{ method: 'POST', pathname: '/todos' },
{ method: 'DELETE', pathname: '/todos/*' },
],
},
},
},
// the rest of the config
})See cypress-array.config.js. Each intercept will show a number next to its alias, like 🪄 🎞️ 1, 🪄 🎞️ 2, etc.
apiCallDurationDifferenceThreshold
In the inspect mode, the duration of each call is compared to the recorded duration. If the duration changes by more than apiCallDurationDifferenceThreshold limit, the test gives a warning.
module.exports = defineConfig({
e2e: {
env: {
magicBackend: {
apiCallDurationDifferenceThreshold: 1000, // ms, 500 is the default
},
},
},
// the rest of the config
})
collectVisitedUrls
Following the approach outlined in the blog post Collect urls visited during each test, you can grab all URLs each test visits. The list is shown in the Command Log after the test. The baseUrl is automatically removed.
// the magicBackend property
collectVisitedUrls: trueTypes
Tip: if you want code editor IntelliSense help you configure this plugin, specify the type for the magicBackend object using a JSDoc comment
module.exports = defineConfig({
e2e: {
env: {
/** @type {Partial<MagicBackend.UserConfig>} */
magicBackend: {
...
},
},
},IntelliSense should "understand" the right properties available inside the magicBackend and suggest the only valid values.
Modes
recordingspies on all API calls and saves a JSON file with recorded requests and responsesplaybackstubs all API calls using the recorded JSON file. If a test does not have a recorded JSON file, the test runs normally without a magic backendplayback-onlystubs all API calls using the recorded JSON file. If a test does not have a recorded JSON file and the test tries to make an API call, then the test fails immediatelyinspectspies on all API calls in the test, comparing types of the request and response objects
You can control the mode by launching the test runner with the CYPRESS_magic_backend_mode variable or by clicking the Magic Backend buttons in the UI.
Lock modes
You can control the current mode by clicking on the mode buttons. Each click sets the mode and restarts the tests.
- button
🪄 🎥runs the current spec and saves the recorded calls - button
🪄 🎞️runs the current spec using previously recorded network stubs. Warns about any request objects changing shape. - button
🪄 🧐compares the network calls against previously recorded list, warns about any request or response objects changing shape.
The selected mode resets after running the current spec. If you want to keep the mode, click on the "lock mode" checkbox next to the mode button.

Then the mode will stay on, even if you restart the tests using the "Restart" button or by pressing the "R" key.
Using on CI
Assumption: you have probably recorded backend calls using the local cypress open mode. Once you are happy with the recorded JSON files, you can use them on CI during cypress run mode. Just set the plugin to the playback mode via an environment variable:
$ CYPRESS_magic_backend_mode=playback npx cypress runHere is a GitHub Actions example
- name: Cypress against static backend
uses: cypress-io/github-action@v6
with:
start: npm run start:static
env:
# assume that all backend calls are pre-recorded
# in the cypress/magic-backend folder
# and on CI the API backend should be in playback mode
# and completely stubbed
CYPRESS_magic_backend_mode: playbackIf a test does NOT have a recording, it will execute normally without any magic stubbing. If you want the test without a recording to fail on an API call attempt, use CYPRESS_magic_backend_mode: playback-only mode.
Passing additional options
Since the plugin's config is a complex object, we cannot selectively overwrite some fields. Thus you have two choices:
- Pass an entire config object using any Cypress config way
$ CYPRESS_magicBackend='{ "mode":"recording", "store":"remote", "apiCallsToIntercept":"..." }' npx cypress run- Use the configuration from the
cypress.config.jsfile and pass any additional options in themagicBackendAddobject
$ CYPRESS_magicBackendAdd='{ "mode":"recording" }' npx cypress run
# Cypress will combine the `magicBackend` with the above objectmagic-backend as a service
[!WARNING] The remote storage is currently in the experimental development stage.
This plugin supports the remote storing of recorded API network calls. By default, all recorded information is stored in the local JSON files. You can point at the remote service using the config:
module.exports = defineConfig({
e2e: {
env: {
/** @type {Partial<MagicBackend.UserConfig>} */
magicBackend: {
// where to store recorded API calls?
// local: store all API calls locally in JSON files
// remote: send API calls to a remote server at cypress.tips
store: 'remote',
},
},
},
})To authenticate, you need to provide the API key via an environment variable
$ MAGIC_BACKEND_API_KEY=mb.... npx cypress openIf you are using collectVisitedUrls: true, all URLs visited for each passing test are sent to the cloud for saving.
If you are interested in this service, please provide your email to get notified when it becomes generally available or is beta preview.
Debug
This package uses debug to write verbose logs. To see them during runtime, run with the environment variable DEBUG=cypress-magic-backend
$ DEBUG=cypress-magic-backend npx cypress runSee also
- plugin cypress-rest-easy
Copyright
Copyright ©️ 2025 Gleb Bahmutov
License
This package is double licensed. It is free to use for all non-profits, individual developers, and even small commercial organization according to the PolyForm Small Business License 1.0.0 license. No distribution or modification allowed.
Any commercial organization above 100 employees and individual contractors wishing to use this software (even internally for testing) is required to buy its own license. The license is strictly for non-distribution purposes, without any liability, as-is usage. You can purchase a 3-year license here.
Misc
Color scheme used "Holiday Vibes"
