Skip to content

Commit 08fd91a

Browse files
fix(test-optimization): support Jest 24 retry registration (#9699)
1 parent 8b37126 commit 08fd91a

3 files changed

Lines changed: 42 additions & 20 deletions

File tree

.github/workflows/test-optimization.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,13 @@ jobs:
262262
- jest.core
263263
- jest.tia-efd
264264
- jest.test-management
265+
test-pattern:
266+
- ''
267+
include:
268+
- version: oldest
269+
jest-version: 25.5.1
270+
spec: jest.tia-efd
271+
test-pattern: '^jest@25[.]5[.]1 commonJS early flake detection retries new tests$'
265272
name: integration-jest (${{ matrix.jest-version }}, node-${{ matrix.version }}, ${{ matrix.spec }})
266273
runs-on: ubuntu-latest
267274
permissions:
@@ -278,10 +285,14 @@ jobs:
278285
with:
279286
version: ${{ matrix.version }}
280287
- uses: ./.github/actions/install
281-
- run: npm run test:integration:jest:coverage
288+
- name: Simulate the v5 release line for Jest 25 compatibility
289+
if: matrix.jest-version == '25.5.1'
290+
run: npm pkg set version=5.0.0
291+
- run: npm run test:integration:jest:coverage -- --grep "$JEST_TEST_PATTERN"
282292
env:
283293
NODE_OPTIONS: "-r ./ci/init"
284294
JEST_VERSION: ${{ matrix.jest-version }}
295+
JEST_TEST_PATTERN: ${{ matrix.test-pattern }}
285296
SPEC: ${{ matrix.spec }}
286297
DD_API_KEY: ${{ steps.dd-sts.outputs.api_key }}
287298
- uses: ./.github/actions/coverage

integration-tests/jest/jest.tia-efd.spec.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,12 @@ const runTestsCommand = 'node ./ci-visibility/run-jest.js'
7070
const requestedJestVersion = process.env.JEST_VERSION || 'latest'
7171
const oldestJestVersion = DD_MAJOR >= 6 ? '28.0.0' : '24.8.0'
7272
const JEST_VERSION = requestedJestVersion === 'oldest' ? oldestJestVersion : requestedJestVersion
73+
const jestMajor = JEST_VERSION === 'latest' ? Infinity : Number(JEST_VERSION.split('.')[0])
7374
const onlyLatestIt = JEST_VERSION === 'latest' ? it : it.skip
74-
const onlyBeforeJest30It = JEST_VERSION !== 'latest' && Number(JEST_VERSION.split('.')[0]) < 30 ? it : it.skip
75-
const shouldInstallJestEnvironmentJsdom = JEST_VERSION === 'latest' || Number(JEST_VERSION.split('.')[0]) >= 28
76-
const isJestCoverageBackfillSupported = JEST_VERSION === 'latest' || Number(JEST_VERSION.split('.')[0]) >= 28
75+
const onlyJest28Before30It = jestMajor >= 28 && jestMajor < 30 ? it : it.skip
76+
const onlyJest28AndLaterIt = jestMajor >= 28 ? it : it.skip
77+
const shouldInstallJestEnvironmentJsdom = jestMajor >= 28
78+
const isJestCoverageBackfillSupported = jestMajor >= 28
7779

7880
function assertItrSkippingEnabledTags (events, expected) {
7981
const testSuite = events.find(event => event.type === 'test_suite_end').content
@@ -1807,7 +1809,7 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
18071809
assert.strictEqual(exitCode, 0)
18081810
})
18091811

1810-
it('keeps concurrent originals and EFD retries concurrent', async () => {
1812+
onlyJest28AndLaterIt('keeps concurrent originals and EFD retries concurrent', async () => {
18111813
receiver.setInfoResponse({ endpoints: ['/evp_proxy/v4'] })
18121814
const testSuite = 'ci-visibility/test-early-flake-detection/concurrent-sibling-test.js'
18131815
const newTestName = 'early flake detection concurrent siblings new test waits for its known sibling'
@@ -1901,7 +1903,7 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
19011903
assert.strictEqual(exitCode, 0)
19021904
})
19031905

1904-
it('retries a concurrent test after its original times out', async () => {
1906+
onlyJest28AndLaterIt('retries a concurrent test after its original times out', async () => {
19051907
receiver.setInfoResponse({ endpoints: ['/evp_proxy/v4'] })
19061908
const testSuite = 'ci-visibility/test-early-flake-detection/concurrent-timeout-test.js'
19071909
receiver.setKnownTests({ jest: {} })
@@ -1955,7 +1957,7 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
19551957
assert.strictEqual(exitCode, 0)
19561958
})
19571959

1958-
onlyBeforeJest30It('applies the Jest timeout to concurrent EFD retry bodies', async () => {
1960+
onlyJest28Before30It('applies the Jest timeout to concurrent EFD retry bodies', async () => {
19591961
receiver.setInfoResponse({ endpoints: ['/evp_proxy/v4'] })
19601962
const testSuite = 'ci-visibility/test-early-flake-detection/concurrent-retry-timeout-test.js'
19611963
receiver.setKnownTests({ jest: {} })
@@ -2059,7 +2061,7 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
20592061
assert.strictEqual(exitCode, 0)
20602062
})
20612063

2062-
it('retries a concurrent test after its original throws synchronously', async () => {
2064+
onlyJest28AndLaterIt('retries a concurrent test after its original throws synchronously', async () => {
20632065
receiver.setInfoResponse({ endpoints: ['/evp_proxy/v4'] })
20642066
const testSuite = 'ci-visibility/test-early-flake-detection/concurrent-throw-test.js'
20652067
receiver.setKnownTests({ jest: {} })
@@ -3987,7 +3989,7 @@ describe(`jest@${JEST_VERSION} commonJS`, () => {
39873989
await Promise.all([once(childProcess, 'exit'), eventsPromise])
39883990
})
39893991

3990-
it('picks the retry budget of a concurrent test from its own execution time', async () => {
3992+
onlyJest28AndLaterIt('picks the retry budget of a concurrent test from its own execution time', async () => {
39913993
receiver.setInfoResponse({ endpoints: ['/evp_proxy/v4'] })
39923994
receiver.setKnownTests({ jest: {} })
39933995
receiver.setSettings({

packages/datadog-instrumentations/src/jest.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,15 @@ function isJestTestSkipped (test, hasFocusedTests, testNamePattern) {
585585

586586
function getWrappedEnvironment (BaseEnvironment, jestVersion) {
587587
const hasConcurrentTestsStartEvent = satisfies(jestVersion, '>=30.0.0')
588+
const hasTestsInChildren = satisfies(jestVersion, '>=26.0.0')
589+
590+
/**
591+
* @param {object} describeBlock
592+
* @returns {object[]|undefined}
593+
*/
594+
function getTestEntries (describeBlock) {
595+
return hasTestsInChildren ? describeBlock?.children : describeBlock?.tests
596+
}
588597

589598
return class DatadogEnvironment extends BaseEnvironment {
590599
#activeDetachedEfdRetries
@@ -1467,16 +1476,16 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
14671476
const concurrentTestState = registeredConcurrentTestState || this.concurrentTestStates.get(fn)
14681477
let originalTest
14691478
if (isEfdRetry && !efdRetryGates) {
1470-
originalTest = state.currentDescribeBlock?.children?.at(-1)
1479+
originalTest = getTestEntries(state.currentDescribeBlock)?.at(-1)
14711480
if (originalTest?.fn !== fn) {
14721481
log.error('%s could not retain its original Jest test', retryType)
14731482
return 0
14741483
}
14751484
}
14761485
let registeredRetryCount = 0
14771486
for (let retryIndex = 1; retryIndex <= retryCount; retryIndex++) {
1478-
const children = state.currentDescribeBlock?.children
1479-
const initialChildCount = children?.length
1487+
const testEntries = getTestEntries(state.currentDescribeBlock)
1488+
const initialTestCount = testEntries?.length
14801489
let retryFn
14811490
if (concurrentTestState) {
14821491
const test = concurrentTestState.concurrentTest ??
@@ -1515,7 +1524,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
15151524
}
15161525

15171526
if (isEfdRetry) {
1518-
const retryTest = children?.length === initialChildCount + 1 ? children.at(-1) : undefined
1527+
const retryTest = testEntries?.length === initialTestCount + 1 ? testEntries.at(-1) : undefined
15191528
if (retryTest?.fn !== retryFn) {
15201529
log.error('%s could not retain its pre-registered Jest retry', retryType)
15211530
continue
@@ -1545,17 +1554,17 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
15451554
return false
15461555
}
15471556

1548-
const children = retryOptions.state.currentDescribeBlock?.children
1549-
const initialChildCount = children?.length
1557+
const testEntries = getTestEntries(retryOptions.state.currentDescribeBlock)
1558+
const initialTestCount = testEntries?.length
15501559
try {
15511560
const registeredRetryCount = this.retryTest(retryOptions)
15521561
if (registeredRetryCount === retryOptions.retryCount) return true
15531562
} catch (error) {
15541563
log.error('%s could not register retries', retryOptions.retryType, error)
15551564
}
15561565

1557-
if (children && initialChildCount !== undefined) {
1558-
const retryTests = children.splice(initialChildCount)
1566+
if (testEntries && initialTestCount !== undefined) {
1567+
const retryTests = testEntries.splice(initialTestCount)
15591568
for (const retryTest of retryTests) {
15601569
removedRetryTests.add(retryTest)
15611570
const retryCtx = this.concurrentTestStates.get(retryTest.fn)?.ctx
@@ -1588,7 +1597,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
15881597
* @returns {number} Retries left to run.
15891598
*/
15901599
discardEfdRetries (testName, executedTest, retryCount = 0) {
1591-
const siblings = executedTest.parent?.children
1600+
const siblings = getTestEntries(executedTest.parent)
15921601
const executedTestIndex = siblings ? siblings.indexOf(executedTest) : -1
15931602
if (executedTestIndex === -1) return 0
15941603

@@ -1732,7 +1741,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
17321741
if (!this.#discardedEfdRetryTests) return
17331742

17341743
for (const retryTest of this.#discardedEfdRetryTests) {
1735-
const siblings = retryTest.parent?.children
1744+
const siblings = getTestEntries(retryTest.parent)
17361745
const retryTestIndex = siblings?.indexOf(retryTest) ?? -1
17371746
if (retryTestIndex !== -1) {
17381747
siblings.splice(retryTestIndex, 1)
@@ -1767,7 +1776,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
17671776
const concurrentTestContexts = this.concurrentTestContexts.get(testFullName)
17681777
const concurrentTestState = this.concurrentTestStates.get(event.fn) ||
17691778
concurrentTestContexts?.at(-1)?.concurrentTestState
1770-
const registeredTest = state.currentDescribeBlock?.children?.at(-1)
1779+
const registeredTest = getTestEntries(state.currentDescribeBlock)?.at(-1)
17711780
if (concurrentTestState && registeredTest?.fn === event.fn) {
17721781
testContexts.set(registeredTest, concurrentTestState.ctx)
17731782
}

0 commit comments

Comments
 (0)