Skill 127 · Cypress Flake Fixer
Subchapter 127.2
references/removed-apis.mdMarkdown7 KBView on GitHub
The scanner reports these as CY007. An entry is graded error when the installed major already rejects it. Always confirm against the official migration guide for the exact target version.
Requires Node.js 22, 24, or 26+.
| Removed or changed | Replacement |
|---|---|
Cypress.env() | cy.env([...]) for secrets, Cypress.expose() for public values |
env in a test or suite config object | expose |
allowCypressEnv config option | delete |
cy.exec(), execTimeout | cy.task() in setupNodeEvents, taskTimeout |
.end() | delete the call |
cy.getCookie(), cy.getCookies(), cy.getAllCookies(), cy.getAllLocalStorage(), cy.getAllSessionStorage() | now queries: chain .should(); override with Cypress.Commands.overwriteQuery() |
Cypress.config('viewportWidth' / 'viewportHeight' / 'blockHosts', v) during a test | cy.viewport(w, h); { blockHosts: '...' } in the test config object |
experimentalMemoryManagement: true | delete (on by default as manageBrowserMemory) |
experimentalMemoryManagement: false | manageBrowserMemory: false |
experimentalFastVisibility | delete; visibilityStrategy defaults to 'modern' |
experimentalSourceRewriting | delete; removeSRIAttributes if it was used for SRI errors |
keystrokeDelay default 10 | default is 0; pass { delay: 10 } to a single .type() only where the app needs it |
| CoffeeScript specs, support files, fixtures | convert to JavaScript or TypeScript |
cypress/angular-zoneless | cypress/angular |
| Electron as the test browser | deprecated: set defaultBrowser: 'chrome' or pass --browser chrome |
Component testing minimums in 16: Angular 21, Vite 8, Next.js 15.0.4.
Decide per key whether the value is sensitive.
Public values (feature flags, API version, public URLs) are a mechanical change, because Cypress.expose() is synchronous like the API it replaces:
// cypress.config.js
module.exports = defineConfig({
expose: { apiVersion: 'v2', featureNewCheckout: true }, // moved out of env
env: { apiKey: process.env.API_KEY }, // secrets stay in env
})
// Before
const version = Cypress.env('apiVersion')
// After
const version = Cypress.expose('apiVersion')--env apiVersion=v2 becomes --expose apiVersion=v2 (short form -x).it('...', { env: { flag: true } }, ...) becomes { expose: { flag: true } }.CYPRESS_* environment variables populate env, not expose. A public value that CI injects as CYPRESS_apiVersion must be either read with cy.env() or copied into expose in the config file (expose: { apiVersion: process.env.API_VERSION }).Sensitive values require restructuring, because cy.env() is an asynchronous command:
// Before: read at module scope, used anywhere
const apiKey = Cypress.env('apiKey')
it('lists users', () => {
cy.request({ url: '/api/users', headers: { Authorization: `Bearer ${apiKey}` } })
})
// After: read inside the test, used inside the callback
it('lists users', () => {
cy.env(['apiKey']).then(({ apiKey }) => {
cy.request({ url: '/api/users', headers: { Authorization: `Bearer ${apiKey}` } })
})
})cy.env() takes an array of keys and yields an object. An undefined key yields undefined.Cypress.env('token', value) to pass state between steps should use an alias within a test, or a set/get pair of tasks across tests..its().cy.origin(), call cy.env() within the callback.Plugins that call Cypress.env() throw on Cypress 16. Upgrade them in the same change. Known minimums: @cypress/grep 6.0.0, @cypress/code-coverage 4.0.0, cypress-mailpit 2.0.0. Search node_modules of other Cypress plugins for Cypress.env( before upgrading.
On Cypress 15.10 through 15.x, set allowCypressEnv: false after migrating to make any remaining Cypress.env() call fail early. Remove the option when moving to 16.
// cypress.config.js
const { execFileSync } = require('node:child_process')
module.exports = defineConfig({
e2e: {
setupNodeEvents(on) {
on('task', {
seedDatabase(fixture) {
execFileSync('node', ['scripts/seed.js', fixture], { stdio: 'inherit' })
return null
},
})
},
},
})
// Before
cy.exec('node scripts/seed.js users')
// After
cy.task('seedDatabase', 'users')null. Returning undefined fails the task.execFileSync with an argument array so test input never reaches a shell.taskTimeout for longer work.Requires Node.js 20, 22, or 24+ (18 and 23 dropped).
| Removed or changed | Replacement |
|---|---|
cy.stub(obj, 'method', fn) | cy.stub(obj, 'method').callsFake(fn) |
cy.exec(...).its('code') | exitCode |
Cypress.SelectorPlayground | Cypress.ElementSelector |
| Webpack 4 | Webpack 5 |
| Firefox automation over CDP | WebDriver BiDi only; Firefox 135+ (140+ from 15.19) |
CommonJS config with @cypress/vite-dev-server | ESM config (.mjs, "type": "module", or cypress.config.ts) |
| Removed or changed | Replacement |
|---|---|
Commands on a different subdomain worked without cy.origin() | wrap them in cy.origin(); injectDocumentDomain is a deprecated escape hatch |
experimentalSkipDomainInjection | removed |
experimentalJustInTimeCompile | justInTimeCompile |
| Removed or changed | Replacement |
|---|---|
video default true | default false; enable explicitly if CI relies on videos |
videoUploadOnPasses | removed |
| Removed or changed | Replacement |
|---|---|
cy.server(), cy.route() | cy.intercept() |
Cypress.Cookies.preserveOnce(), Cypress.Cookies.defaults() | cy.session() |
experimentalSessionAndOrigin | delete; cy.session() and cy.origin() are stable |
| Tests shared page and storage state | testIsolation is on: each test starts on a blank page with cleared cookies and storage |
cy.route() to cy.intercept() is not a rename. Differences that change test behavior:
cy.intercept() glob-matches the full URL including the query string. cy.intercept('/api/users') never matches /api/users?page=2; use '/api/users*' or { pathname: '/api/users' }.cy.intercept() matches every HTTP method when none is given. cy.route() defaulted to GET.beforeEach and overrides inside the test.cy.wait('@alias') times out. Disable cache headers on the test server.cy.intercept() also sees fetch requests and static resources, which cy.route() did not.