1.19.0 â€ĸ Published 5 months ago

cypress-magic-backend v1.19.0

Weekly downloads
-
License
SEE LICENSE IN LI...
Repository
github
Last release
5 months ago

cypress-magic-backend

It is like a real backend but magically faster and better

Magic backend

Learn

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, since cypress-magic-backend is applied last. Thus your cy.intercepts work first
  • check the current mode using the env variable const mode = Cypress.env('magic_backend_mode'), possible values are undefined, playback, playback-only, and inspect

Assumptions

  1. 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.
  2. 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
})

API call has changed its duration

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 responses
  • playback 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 backend
  • playback-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 immediately
  • inspect 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.

Lock mode checkboxes

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:

  1. Pass an entire config object using any Cypress config way
$ CYPRESS_magicBackend='{ "mode":"recording", "store":"remote", "apiCallsToIntercept":"..." }' npx cypress run
  1. Use the configuration from the cypress.config.js file and pass any additional options in the magicBackendAdd 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"

1.15.0

5 months ago

1.14.0

5 months ago

1.13.0

5 months ago

1.19.0

5 months ago

1.18.0

5 months ago

1.17.0

5 months ago

1.16.0

5 months ago

1.12.0

5 months ago

1.11.0

5 months ago

1.9.1

5 months ago

1.9.0

5 months ago

1.8.0

5 months ago

1.10.0

5 months ago

1.7.0

6 months ago

1.6.0

6 months ago

1.5.0

6 months ago

1.4.0

6 months ago

1.3.0

6 months ago

1.2.0

6 months ago

1.1.0

6 months ago

1.0.4

6 months ago

1.0.3

6 months ago

1.0.2

6 months ago

1.0.1

6 months ago

1.0.0

6 months ago