feat: --posix-exit-codes cli flag in run mode (#32609)

* pass posix exit code to server

* return 1 if any tests fail and posix exit codes are enabled

* changelog

* rm .only

* snapshot

* changelog

* update typedef

* changelog

* Update cli/CHANGELOG.md

Co-authored-by: Jennifer Shehane <jennifer@cypress.io>

* lift disabled posix system test to different desc block

* add posix-exit-codes in lib/exec/run.ts#processRunOptions

* Apply suggestion from @jennifer-shehane

Co-authored-by: Jennifer Shehane <jennifer@cypress.io>

---------

Co-authored-by: Jennifer Shehane <jennifer@cypress.io>
This commit is contained in:
Cacie Prins
2025-10-02 09:30:51 -04:00
committed by GitHub
parent 7062573933
commit 14beae32dc
13 changed files with 81 additions and 3 deletions

View File

@@ -1,8 +1,12 @@
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
## 15.3.1
## 15.4.0
_Released 10/07/2025 (PENDING)_
**Features:**
- Added the `--posix-exit-codes` flag for the `run` command. When this flag is passed, Cypress will exit with 1 if any tests fail, rather than the number of failed tests. Addresses [#32605](https://github.com/cypress-io/cypress/issues/32605) and [#24695](https://github.com/cypress-io/cypress/issues/24695). Addressed in [#32609](https://github.com/cypress-io/cypress/pull/32609).
**Bugfixes:**
- Fixed a regression introduced in [`15.0.0`](https://docs.cypress.io/guides/references/changelog#15-0-0) where `dbus` connection error messages appear in docker containers when launching Cypress. Fixes [#32290](https://github.com/cypress-io/cypress/issues/32290).

View File

@@ -127,6 +127,7 @@ const descriptions: any = {
parallel: 'enables concurrent runs and automatic load balancing of specs across multiple machines or processes',
port: 'runs Cypress on a specific port. overrides any value in cypress.config.{js,ts,mjs,cjs}.',
project: 'path to the project',
posixExitCodes: 'use POSIX exit codes for error handling',
quiet: 'run quietly, using only the configured reporter',
record: 'records the run. sends test results, screenshots and videos to Cypress Cloud.',
reporter: 'runs a specific mocha reporter. pass a path to use a custom reporter. defaults to "spec"',
@@ -259,6 +260,7 @@ const addCypressRunCommand = (program: any): any => {
.option('--parallel', text('parallel'))
.option('-p, --port <port>', text('port'))
.option('-P, --project <project-path>', text('project'))
.option('--posix-exit-codes', text('posixExitCodes'))
.option('-q, --quiet', text('quiet'))
.option('--record [bool]', text('record'), coerceFalse)
.option('-r, --reporter <reporter>', text('reporter'))

View File

@@ -110,6 +110,10 @@ const processRunOptions = (options: any = {}): string[] => {
args.push('--parallel')
}
if (options.posixExitCodes) {
args.push('--posix-exit-codes')
}
if (options.port) {
args.push('--port', options.port)
}

View File

@@ -201,6 +201,7 @@ const parseOpts = (opts: any): any => {
'path',
'parallel',
'port',
'posixExitCodes',
'project',
'quiet',
'reporter',
@@ -449,7 +450,7 @@ const util = {
async function _getRealArch (): Promise<string> {
const osPlatform = os.platform()
// eslint-disable-next-line no-restricted-syntax
const osArch = os.arch()
debug('detecting arch %o', { osPlatform, osArch })
@@ -474,7 +475,6 @@ const util = {
if (['aarch64_be', 'aarch64', 'armv8b', 'armv8l'].includes(stdout)) return 'arm64'
}
// eslint-disable-next-line no-restricted-syntax
const pkgArch = arch()
if (pkgArch === 'x86') return 'ia32'

View File

@@ -538,6 +538,7 @@ exports[`cli > unknown option > shows help for run command 1`] = `
--parallel enables concurrent runs and automatic load balancing of specs across multiple machines or processes
-p, --port <port> runs Cypress on a specific port. overrides any value in cypress.config.{js,ts,mjs,cjs}.
-P, --project <project-path> path to the project
--posix-exit-codes use POSIX exit codes for error handling
-q, --quiet run quietly, using only the configured reporter
--record [bool] records the run. sends test results, screenshots and videos to Cypress Cloud.
-r, --reporter <reporter> runs a specific mocha reporter. pass a path to use a custom reporter. defaults to "spec"

View File

@@ -651,6 +651,11 @@ describe('cli', () => {
expect(run.start).toBeCalledWith({ runnerUi: false })
})
it('calls run with --posix-exit-codes', async () => {
await exec('run --posix-exit-codes')
expect(run.start).toBeCalledWith({ posixExitCodes: true })
})
describe('component-testing', () => {
it('passes to run.start the correct args for component-testing', async () => {
await exec('run --component --dev')

View File

@@ -142,6 +142,10 @@ describe('exec run', () => {
it('throws if --config-file is false', () => {
expect(() => run.processRunOptions({ configFile: 'false' })).toThrow()
})
it('adds --posix-exit-codes', () => {
expect(run.processRunOptions({ posixExitCodes: true })).toEqual(expect.arrayContaining(['--posix-exit-codes']))
})
})
describe('.start', () => {

View File

@@ -68,6 +68,10 @@ declare namespace CypressCommandLine {
* Override default port
*/
port: number
/**
* Use POSIX exit codes for error handling
*/
posixExitCodes: boolean
/**
* Run quietly, using only the configured reporter
*/

View File

@@ -266,6 +266,10 @@ export = {
}
}
if (options.posixExitCodes) {
return results.totalFailed ? 1 : 0
}
return results.totalFailed
})
.then(exit)

View File

@@ -37,6 +37,7 @@ const allowList = [
'parallel',
'ping',
'port',
'posixExitCodes',
'project',
'proxySource',
'quiet',
@@ -366,6 +367,7 @@ module.exports = {
'run-project': 'runProject',
'smoke-test': 'smokeTest',
'testing-type': 'testingType',
'posix-exit-codes': 'posixExitCodes',
}
// takes an array of args and converts

View File

@@ -25,6 +25,7 @@ export interface RunModeOptions extends CommonModeOptions {
ciBuildId?: string | null
tag?: (string)[] | null
isBrowserGivenByCli: boolean
posixExitCodes?: boolean | null
}
export type TestingType = 'e2e' | 'component'

View File

@@ -238,6 +238,10 @@ type ExecOptions = {
* Run Cypress with a custom user node version.
*/
userNodeVersion?: string
/**
* Run Cypress with POSIX exit codes.
*/
posixExitCodes?: boolean
}
type Server = {
@@ -764,6 +768,12 @@ const systemTests = {
args.push(`--userNodeVersion=${options.userNodeVersion}`)
}
debug('posixExitCodes', options.posixExitCodes)
if (options.posixExitCodes) {
args.push('--posix-exit-codes')
}
return args
},

View File

@@ -0,0 +1,37 @@
import systemTests from '../lib/system-tests'
describe('posix exit codes', () => {
systemTests.setup()
describe('when posix exit codes are enabled', () => {
const posixExitCodes = true
systemTests.it('returns 1 when there are multiple failing tests', {
spec: 'simple_failing.cy.js',
posixExitCodes,
expectedExitCode: 1,
browser: ['electron'],
project: 'e2e',
})
systemTests.it('returns 0 when there are no failing tests', {
spec: 'simple_passing.cy.js',
posixExitCodes: true,
expectedExitCode: 0,
browser: ['electron'],
project: 'e2e',
})
})
describe('when posix exit codes are disabled', () => {
const posixExitCodes = false
systemTests.it('returns 2 when there are 2 failing tests', {
spec: 'simple_failing.cy.js',
posixExitCodes,
expectedExitCode: 2,
browser: ['electron'],
project: 'e2e',
})
})
})