Skip to content

breaking: update execa from 1.0.0 to 4.1.0 #32238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/cache-version.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Bump this version to force CI to re-create the cache from scratch.
8-7-2025
8-13-2025
10 changes: 5 additions & 5 deletions .circleci/workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ mainBuildFilters: &mainBuildFilters
- /^release\/\d+\.\d+\.\d+$/
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- 'update-v8-snapshot-cache-on-develop'
- 'mabel/issue-10425-studio-redesign'
- 'breaking/update_execa'

# usually we don't build Mac app - it takes a long time
# but sometimes we want to really confirm we are doing the right thing
Expand All @@ -49,7 +49,7 @@ macWorkflowFilters: &darwin-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'feat/support_vite_7', << pipeline.git.branch >> ]
- equal: [ 'breaking/update_execa', << pipeline.git.branch >> ]
- equal: [ 'chore/test_cypress_recipes_15', << pipeline.git.branch >> ]
- equal: [ 'mabel/issue-31677-reporter-redesign', << pipeline.git.branch >> ]
- matches:
Expand All @@ -62,7 +62,7 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'feat/support_vite_7', << pipeline.git.branch >> ]
- equal: [ 'breaking/update_execa', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand All @@ -85,7 +85,7 @@ windowsWorkflowFilters: &windows-workflow-filters
- equal: [ develop, << pipeline.git.branch >> ]
# use the following branch as well to ensure that v8 snapshot cache updates are fully tested
- equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ]
- equal: [ 'feat/support_vite_7', << pipeline.git.branch >> ]
- equal: [ 'breaking/update_execa', << pipeline.git.branch >> ]
- matches:
pattern: /^release\/\d+\.\d+\.\d+$/
value: << pipeline.git.branch >>
Expand Down Expand Up @@ -159,7 +159,7 @@ commands:
name: Set environment variable to determine whether or not to persist artifacts
command: |
echo "Setting SHOULD_PERSIST_ARTIFACTS variable"
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "mabel/issue-10425-studio-redesign" ]]; then
echo 'if ! [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "breaking/update_execa" ]]; then
export SHOULD_PERSIST_ARTIFACTS=true
fi' >> "$BASH_ENV"
# You must run `setup_should_persist_artifacts` command and be using bash before running this command
Expand Down
1 change: 1 addition & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ _Released 08/12/2025 (PENDING)_
- The application under test's `pagehide` event in Chromium browsers will no longer trigger Cypress's `window:unload` event. Addressed in [#31853](https://github.com/cypress-io/cypress/pull/31853).
- The `Cypress.SelectorPlayground` API has been renamed to `Cypress.ElementSelector`. This API was renamed to accommodate its use for defining `selectorPriority` in Cypress Studio and our future [`cy.prompt` release](https://on.cypress.io/cy-prompt-early-access?utm_source=docs&utm_medium=app-changelog&utm_content=cy-prompt-release). Additionally, the `getSelector` method and the `onElement` option of `defaults` were removed from this API. Addresses [#31801](https://github.com/cypress-io/cypress/issues/31801). Addressed in [#31889](https://github.com/cypress-io/cypress/pull/31889) and [#32098](https://github.com/cypress-io/cypress/pull/32098).
- The direct download option for installing Cypress is no longer supported. Users should install via a package manager. Addressed in [#32249](https://github.com/cypress-io/cypress/pull/32249).
- Updated `execa` from `1.0.0` to `4.1.0`. This changes the `code` property returned by [`cy.exec()`](https://docs.cypress.io/api/commands/exec) to `exitCode`. Addressed in [#32238](https://github.com/cypress-io/cypress/pull/32238).
- **Component Testing breaking changes:**
- Removed support for Angular 17. The minimum supported version is now `18.0.0`. Addresses [#31303](https://github.com/cypress-io/cypress/issues/31303).
- `@cypress/angular` now requires a minimum of `zone.js` `0.14.0`. Addresses [#31582](https://github.com/cypress-io/cypress/issues/31582).
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
"eslint-plugin-react": "7.22.0",
"eslint-plugin-react-hooks": "4.2.0",
"eslint-plugin-vue": "7.18.0",
"execa": "4.0.0",
"execa": "4.1.0",
"fast-xml-parser": "^4.5.1",
"filesize": "10.1.1",
"fs-extra": "9.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/data-context/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"dedent": "^0.7.0",
"ejs": "^3.1.10",
"endent": "2.0.1",
"execa": "1.0.0",
"execa": "4.1.0",
"front-matter": "^4.0.2",
"fs-extra": "8.1.0",
"get-tsconfig": "4.10.0",
Expand Down
16 changes: 8 additions & 8 deletions packages/driver/cypress/e2e/commands/exec.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const { assertLogLength } = require('../../support/utils')
const { _, Promise } = Cypress

describe('src/cy/commands/exec', () => {
const okResponse = { code: 0 }
const okResponse = { exitCode: 0 }

context('#exec', {
execTimeout: 2500,
Expand Down Expand Up @@ -302,7 +302,7 @@ describe('src/cy/commands/exec', () => {

describe('when error code is non-zero', () => {
it('throws error that includes useful information and exit code', (done) => {
Cypress.backend.resolves({ code: 1 })
Cypress.backend.resolves({ exitCode: 1 })

cy.on('fail', (err) => {
expect(err.message).to.contain('`cy.exec(\'ls\')` failed because the command exited with a non-zero code.\n\nPass `{failOnNonZeroExit: false}` to ignore exit code failures.')
Expand All @@ -316,7 +316,7 @@ describe('src/cy/commands/exec', () => {
})

it('throws error that includes stderr if it exists and is non-empty', (done) => {
Cypress.backend.resolves({ code: 1, stderr: 'error output', stdout: '' })
Cypress.backend.resolves({ exitCode: 1, stderr: 'error output', stdout: '' })

cy.on('fail', (err) => {
expect(err.message).to.contain('Stderr:\nerror output')
Expand All @@ -329,7 +329,7 @@ describe('src/cy/commands/exec', () => {
})

it('throws error that includes stdout if it exists and is non-empty', (done) => {
Cypress.backend.resolves({ code: 1, stderr: '', stdout: 'regular output' })
Cypress.backend.resolves({ exitCode: 1, stderr: '', stdout: 'regular output' })

cy.on('fail', (err) => {
expect(err.message).to.contain('\nStdout:\nregular output')
Expand All @@ -342,7 +342,7 @@ describe('src/cy/commands/exec', () => {
})

it('throws error that includes stdout and stderr if they exists and are non-empty', (done) => {
Cypress.backend.resolves({ code: 1, stderr: 'error output', stdout: 'regular output' })
Cypress.backend.resolves({ exitCode: 1, stderr: 'error output', stdout: 'regular output' })

cy.on('fail', (err) => {
expect(err.message).to.contain('\nStdout:\nregular output\nStderr:\nerror output')
Expand All @@ -355,7 +355,7 @@ describe('src/cy/commands/exec', () => {

it('truncates the stdout and stderr in the error message', (done) => {
Cypress.backend.resolves({
code: 1,
exitCode: 1,
stderr: `${_.range(200).join()}stderr should be truncated`,
stdout: `${_.range(200).join()}stdout should be truncated`,
})
Expand All @@ -381,7 +381,7 @@ describe('src/cy/commands/exec', () => {
expect(Yielded).to.deep.eq({
stdout: 'foo',
stderr: '',
code: 1,
exitCode: 1,
})

done()
Expand All @@ -392,7 +392,7 @@ describe('src/cy/commands/exec', () => {

describe('and failOnNonZeroExit is false', () => {
it('does not error', () => {
const response = { code: 1, stderr: 'error output', stdout: 'regular output' }
const response = { exitCode: 1, stderr: 'error output', stdout: 'regular output' }

Cypress.backend.resolves(response)

Expand Down
2 changes: 1 addition & 1 deletion packages/driver/cypress/e2e/e2e/origin/commands/misc.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ context('cy.origin misc', { browser: '!webkit' }, () => {
expect(consoleProps.name).to.equal('exec')
expect(consoleProps.type).to.equal('command')
expect(consoleProps.props['Shell Used']).to.be.undefined
expect(consoleProps.props.Yielded).to.have.property('code').that.equals(0)
expect(consoleProps.props.Yielded).to.have.property('exitCode').that.equals(0)
expect(consoleProps.props.Yielded).to.have.property('stderr').that.equals('')
expect(consoleProps.props.Yielded).to.have.property('stdout').that.equals('foobar')
})
Expand Down
4 changes: 2 additions & 2 deletions packages/driver/src/cy/commands/exec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default (Commands, Cypress, cy) => {
consoleOutput['Shell Used'] = result.shell
}

if ((result.code === 0) || !options.failOnNonZeroExit) {
if ((result.exitCode === 0) || !options.failOnNonZeroExit) {
return result
}

Expand All @@ -79,7 +79,7 @@ export default (Commands, Cypress, cy) => {

return $errUtils.throwErrByPath('exec.non_zero_exit', {
onFail: options._log,
args: { cmd, output, code: result.code },
args: { cmd, output, code: result.exitCode },
})
})
.catch(Promise.TimeoutError, { timedOut: true }, () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"test-unit": "echo 'no unit tests'"
},
"devDependencies": {
"cypress-example-kitchensink": "5.0.0",
"cypress-example-kitchensink": "5.1.0",
"gh-pages": "5.0.0",
"gulp": "4.0.2",
"gulp-clean": "0.4.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend-shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"cypress-real-events": "1.14.0",
"dayjs": "^1.9.3",
"dedent": "^0.7.0",
"execa": "4.0.0",
"execa": "4.1.0",
"fake-uuid": "^1.0.0",
"floating-vue": "2.0.0-beta.17",
"fs-extra": "9.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/launcher/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"dependencies": {
"bluebird": "3.5.3",
"debug": "^4.3.4",
"execa": "4.0.0",
"execa": "4.1.0",
"fs-extra": "9.1.0",
"lodash": "^4.17.21",
"plist": "3.1.0",
Expand Down
6 changes: 4 additions & 2 deletions packages/launchpad/cypress/e2e/open-mode.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,14 @@ describe('Launchpad: Open Mode', () => {
// so just adding one here
{
id: 'well-known-editor',
binary: '/usr/bin/well-known',
binary: o.platform === 'win32' ? 'cmd.exe' : '/bin/bash',
name: 'Well known editor',
},
]

ctx.coreData.app.projects = [{ projectRoot: '/some/project', savedState: () => Promise.resolve({}) }]
}, {
platform: Cypress.platform,
})

cy.visitLaunchpad()
Expand All @@ -315,7 +317,7 @@ describe('Launchpad: Open Mode', () => {
cy.get('@modal').contains('Choose your editor...').click()
cy.get('@modal').contains('Well known editor').click()
cy.get('@modal').contains('Save changes').click()
cy.wait('@SetPreferred').its('request.body.variables.value').should('include', '/usr/bin/well-known')
cy.wait('@SetPreferred').its('request.body.variables.value').should('include', Cypress.platform === 'win32' ? 'cmd.exe' : '/bin/bash')
})

it('opens using finder', () => {
Expand Down
6 changes: 3 additions & 3 deletions packages/server/lib/exec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ const Promise = require('bluebird')
const execa = require('execa')
const shellEnv = require('shell-env')
const _ = require('lodash')
const log = require('./log')
const log = require('debug')('cypress:server:exec')
const utils = require('./util/shell')

const pickMainProps = (val) => _.pick(val, ['stdout', 'stderr', 'code'])
const pickMainProps = (val) => _.pick(val, ['stdout', 'stderr', 'exitCode'])

const trimStdio = (val) => {
const result = { ...val }
Expand All @@ -32,7 +32,7 @@ module.exports = {
log('and is running command:', options.cmd)
log('in folder:', projectRoot)

return execa.shell(cmd, { cwd, env, shell })
return execa(cmd, { cwd, env, shell: shell || true })
.then((result) => {
// do we want to return all fields returned by execa?
result.shell = shell
Expand Down
4 changes: 2 additions & 2 deletions packages/server/lib/util/shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const Promise = require('bluebird')
const execa = require('execa')
const os = require('os')
const commandExistsModule = require('command-exists')
const log = require('../log')
const log = require('debug')('cypress:server:util:shell')

const isWindows = () => {
return os.platform() === 'win32'
Expand Down Expand Up @@ -69,7 +69,7 @@ const sourceShellCommand = function (cmd, shell) {
}

const findBash = () => {
return execa.shell('which bash')
return execa('which bash', { shell: true })
.then((val) => val.stdout)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"electron-context-menu": "3.6.1",
"errorhandler": "1.5.1",
"evil-dns": "0.2.0",
"execa": "1.0.0",
"execa": "4.1.0",
"express": "4.21.0",
"fetch-retry-ts": "^1.3.1",
"find-process": "1.4.7",
Expand Down
6 changes: 3 additions & 3 deletions packages/server/test/scripts/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,12 @@ console.log('specfiles:', run)
console.log('test command:')
console.log(cmd)

const child = execa.shell(cmd, { env, stdio: 'inherit' })
const child = execa(cmd, { env, stdio: 'inherit', shell: true })

child.on('exit', (code, signal) => {
child.on('exit', (exitCode, signal) => {
if (signal) {
console.error(`tests exited with signal ${signal}`)
}

process.exit(code === null ? 1 : code)
process.exit(exitCode === null ? 1 : exitCode)
})
22 changes: 11 additions & 11 deletions packages/server/test/unit/exec_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ describe('lib/exec', function () {
this.timeout(10000)

describe('basic tests', () => {
it('returns only stdout, stderr, and code', () => {
it('returns only stdout, stderr, and exitCode', () => {
return runCommand('echo foo')
.then((result) => {
const props = Object.keys(result)

expect(props).to.deep.eq(['stdout', 'stderr', 'code'])
expect(props).to.deep.eq(['stdout', 'stderr', 'exitCode'])
})
})

Expand All @@ -42,7 +42,7 @@ describe('lib/exec', function () {
const expected = {
stdout: 'foo',
stderr: '',
code: 0,
exitCode: 0,
}

expect(result).to.deep.eq(expected)
Expand All @@ -64,7 +64,7 @@ describe('lib/exec', function () {
const expected = {
stdout: '\'foo\'',
stderr: '',
code: 0,
exitCode: 0,
}

expect(result).to.deep.eq(expected)
Expand All @@ -77,7 +77,7 @@ describe('lib/exec', function () {
const expected = {
stdout: '\'foo bar\'',
stderr: '',
code: 0,
exitCode: 0,
}

expect(result).to.deep.eq(expected)
Expand Down Expand Up @@ -119,7 +119,7 @@ describe('lib/exec', function () {
it('reports the stderr', () => {
return runCommand('>&2 echo \'some error\'')
.then((result) => {
expect(result.code).to.eq(0)
expect(result.exitCode).to.eq(0)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Test Fails Due to API Change

One of the exec module tests still expects result.code for the command's exit status. The underlying execa dependency, however, now provides this as result.exitCode, causing the test to fail.

Fix in Cursor Fix in Web


expect(result.stderr).to.equal('\'some error\'')
})
Expand All @@ -131,7 +131,7 @@ describe('lib/exec', function () {
.then((result) => {
expect(result.stdout).to.equal('')
expect(result.stderr).to.equal('The system cannot find the file specified.')
expect(result.code).to.equal(1)
expect(result.exitCode).to.equal(1)

// stderr should be trimmed already
expect(result.stderr.trim()).to.equal(result.stderr)
Expand Down Expand Up @@ -165,7 +165,7 @@ describe('lib/exec', function () {
const expected = {
stdout: 'foo',
stderr: '',
code: 0,
exitCode: 0,
}

expect(result).to.deep.eq(expected)
Expand All @@ -178,7 +178,7 @@ describe('lib/exec', function () {
const expected = {
stdout: 'foo bar',
stderr: '',
code: 0,
exitCode: 0,
}

expect(result).to.deep.eq(expected)
Expand Down Expand Up @@ -218,7 +218,7 @@ describe('lib/exec', function () {
it('reports the stderr', () => {
return runCommand('>&2 echo \'some error\'')
.then((result) => {
expect(result.code).to.eq(0)
expect(result.exitCode).to.eq(0)

expect(result.stderr).to.equal('some error')
})
Expand All @@ -230,7 +230,7 @@ describe('lib/exec', function () {
.then((result) => {
expect(result.stdout).to.equal('')
expect(result.stderr).to.equal('cat: nooope: No such file or directory')
expect(result.code).to.equal(1)
expect(result.exitCode).to.equal(1)

// stderr should be trimmed already
expect(result.stderr.trim()).to.equal(result.stderr)
Expand Down
Loading
Loading