cypress-magic-backend v1.19.0
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 /graphql
calls. - works with your own
cy.intercept
spying and stubbing, sincecypress-magic-backend
is applied last. Thus yourcy.intercepts
work 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: true
Types
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
recording
spies on all API calls and saves a JSON file with recorded requests and responsesplayback
stubs 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-only
stubs 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 immediatelyinspect
spies 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 run
Here 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: playback
If 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.js
file and pass any additional options in themagicBackendAdd
object
$ CYPRESS_magicBackendAdd='{ "mode":"recording" }' npx cypress run
# Cypress will combine the `magicBackend` with the above object
magic-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 open
If 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 run
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"
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago