Skip to content

Commit 748d91b

Browse files
juan-fernandezleoromanovsky
authored andcommitted
fix(cypress): support numeric retries with ATR (#9484)
1 parent fad4883 commit 748d91b

5 files changed

Lines changed: 85 additions & 9 deletions

File tree

integration-tests/cypress-esm-config.mjs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
// Cypress does not call setupNodeEvents from inline config objects.
55
import cypress from 'cypress'
66

7+
const retries = Number(process.env.CYPRESS_RETRIES || 0)
8+
79
async function runCypress () {
810
const results = await cypress.run({
911
config: {
1012
defaultCommandTimeout: 1000,
11-
retries: {
12-
runMode: Number(process.env.CYPRESS_RETRIES || 0),
13-
openMode: 0,
14-
},
13+
retries: process.env.CYPRESS_RETRIES_AS_NUMBER === undefined
14+
? { runMode: retries, openMode: 0 }
15+
: Number(process.env.CYPRESS_RETRIES_AS_NUMBER),
1516
e2e: {
1617
...(process.env.CYPRESS_TEST_ISOLATION === undefined
1718
? {}

integration-tests/cypress.config.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
const { defineConfig } = require('cypress')
44

5+
const retries = Number(process.env.CYPRESS_RETRIES || 0)
6+
57
module.exports = defineConfig({
68
defaultCommandTimeout: 1000,
7-
retries: {
8-
runMode: Number(process.env.CYPRESS_RETRIES || 0),
9-
openMode: 0,
10-
},
9+
retries: process.env.CYPRESS_RETRIES_AS_NUMBER === undefined
10+
? { runMode: retries, openMode: 0 }
11+
: Number(process.env.CYPRESS_RETRIES_AS_NUMBER),
1112
e2e: {
1213
...(process.env.CYPRESS_TEST_ISOLATION === undefined
1314
? {}

integration-tests/cypress/cypress-atr.spec.js

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ moduleTypes.forEach(({
125125
})
126126

127127
context('flaky test retries', () => {
128-
it('retries flaky tests', async () => {
128+
it('retries flaky tests with object Cypress retries', async () => {
129129
receiver.setSettings({
130130
itr_enabled: false,
131131
code_coverage: false,
@@ -232,6 +232,64 @@ moduleTypes.forEach(({
232232
])
233233
})
234234

235+
over12It('retries flaky tests', async () => {
236+
receiver.setSettings({
237+
itr_enabled: false,
238+
code_coverage: false,
239+
tests_skipping: false,
240+
flaky_test_retries_enabled: true,
241+
early_flake_detection: {
242+
enabled: false,
243+
},
244+
})
245+
246+
const envVars = getCiVisEvpProxyConfig(receiver.port)
247+
248+
const specToRun = 'cypress/e2e/numeric-retries.cy.js'
249+
250+
childProcess = exec(
251+
version === 'latest' ? testCommand : `${testCommand} --spec ${specToRun}`,
252+
{
253+
cwd,
254+
env: {
255+
...envVars,
256+
CYPRESS_BASE_URL: webAppBaseUrl,
257+
CYPRESS_RETRIES_AS_NUMBER: '0',
258+
SPEC_PATTERN: specToRun,
259+
},
260+
}
261+
)
262+
263+
const receiverPromise = receiver
264+
.gatherPayloadsUntilChildExit(
265+
childProcess,
266+
({ url }) => url.endsWith('/api/v2/citestcycle'),
267+
payloads => {
268+
const events = payloads.flatMap(({ payload }) => payload.events)
269+
const testSuites = events.filter(event => event.type === 'test_suite_end').map(event => event.content)
270+
assert.strictEqual(testSuites.length, 1)
271+
assert.strictEqual(testSuites[0].meta[TEST_STATUS], 'pass')
272+
273+
const tests = events.filter(event => event.type === 'test').map(event => event.content)
274+
assert.strictEqual(tests.length, 3)
275+
276+
const resource = 'cypress/e2e/numeric-retries.cy.js.numeric Cypress retries eventually passes'
277+
assert.deepStrictEqual(tests.map(test => test.resource), [resource, resource, resource])
278+
assert.strictEqual(tests[0].meta[TEST_STATUS], 'fail')
279+
assert.strictEqual(tests[1].meta[TEST_STATUS], 'fail')
280+
assert.strictEqual(tests[2].meta[TEST_STATUS], 'pass')
281+
assert.strictEqual(tests[1].meta[TEST_IS_RETRY], 'true')
282+
assert.strictEqual(tests[2].meta[TEST_IS_RETRY], 'true')
283+
assert.strictEqual(tests[1].meta[TEST_RETRY_REASON], TEST_RETRY_REASON_TYPES.atr)
284+
assert.strictEqual(tests[2].meta[TEST_RETRY_REASON], TEST_RETRY_REASON_TYPES.atr)
285+
}, { hardTimeout: 30000 })
286+
287+
await Promise.all([
288+
once(childProcess, 'exit'),
289+
receiverPromise,
290+
])
291+
})
292+
235293
it('is disabled if DD_CIVISIBILITY_FLAKY_RETRY_ENABLED is false', async () => {
236294
receiver.setSettings({
237295
itr_enabled: false,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/* eslint-disable */
2+
let attempt = 0
3+
4+
describe('numeric Cypress retries', () => {
5+
it('eventually passes', () => {
6+
cy.then(() => {
7+
expect(attempt++).to.equal(2)
8+
})
9+
})
10+
})

packages/datadog-plugin-cypress/src/cypress-plugin.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,12 @@ class CypressPlugin {
858858
if (isFlakyTestRetriesEnabled && this.isTestIsolationEnabled) {
859859
this.isFlakyTestRetriesEnabled = true
860860
this.flakyTestRetriesCount = flakyTestRetriesCount ?? 0
861+
if (typeof this.cypressConfig.retries === 'number') {
862+
this.cypressConfig.retries = {
863+
openMode: this.cypressConfig.retries,
864+
runMode: this.cypressConfig.retries,
865+
}
866+
}
861867
this.cypressConfig.retries.runMode = this.flakyTestRetriesCount
862868
} else {
863869
this.flakyTestRetriesCount = 0

0 commit comments

Comments
 (0)