Skip to content

Commit f370fb3

Browse files
[test optimization] Improve cypress - RUM integration (#7600)
1 parent c639f33 commit f370fb3

2 files changed

Lines changed: 52 additions & 8 deletions

File tree

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ class CypressPlugin {
306306

307307
this.isTestIsolationEnabled = getIsTestIsolationEnabled(cypressConfig)
308308

309+
const envFlushWait = Number(getValueFromEnvSources('DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS'))
310+
this.rumFlushWaitMillis = Number.isFinite(envFlushWait) ? envFlushWait : undefined
311+
309312
if (!this.isTestIsolationEnabled) {
310313
log.warn('Test isolation is disabled, retries will not be enabled')
311314
}
@@ -823,6 +826,7 @@ class CypressPlugin {
823826
isModifiedTest: this.getIsTestModified(testSuiteAbsolutePath),
824827
repositoryRoot: this.repositoryRoot,
825828
isTestIsolationEnabled: this.isTestIsolationEnabled,
829+
rumFlushWaitMillis: this.rumFlushWaitMillis,
826830
}
827831

828832
if (this.testSuiteSpan) {

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

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
'use strict'
22

3+
const DD_CIVISIBILITY_TEST_EXECUTION_ID_COOKIE_NAME = 'datadog-ci-visibility-test-execution-id'
4+
let rumFlushWaitMillis = 500
5+
36
let isEarlyFlakeDetectionEnabled = false
47
let isKnownTestsEnabled = false
58
let knownTestsForSuite = []
@@ -15,9 +18,10 @@ const retryReasonsByTestName = new Map()
1518
// Track quarantined test errors - we catch them in Cypress.on('fail') but need to report to Datadog
1619
const quarantinedTestErrors = new Map()
1720

18-
// We need to grab the original window as soon as possible,
19-
// in case the test changes the origin. If the test does change the origin,
20-
// any call to `cy.window()` will result in a cross origin error.
21+
// Track the most recently loaded window in the AUT. Updated via the 'window:load'
22+
// event so we always get the real app window (after cy.visit()), not the
23+
// about:blank window that exists when beforeEach runs. If the test later navigates
24+
// to a cross-origin URL, safeGetRum() handles the access error.
2125
let originalWindow
2226

2327
// If the test is using multi domain with cy.origin, trying to access
@@ -165,18 +169,45 @@ beforeEach(function () {
165169
retryReasonsByTestName.delete(testName)
166170
}
167171

172+
cy.on('window:load', (win) => {
173+
originalWindow = win
174+
})
175+
168176
cy.task('dd:beforeEach', {
169177
testName,
170178
testSuite: Cypress.mocha.getRootSuite().file,
171179
}).then(({ traceId, shouldSkip }) => {
172-
Cypress.env('traceId', traceId)
180+
if (traceId) {
181+
cy.setCookie(DD_CIVISIBILITY_TEST_EXECUTION_ID_COOKIE_NAME, traceId).then(() => {
182+
// When testIsolation:false, the page is not reset between tests, so the RUM session
183+
// stopped in afterEach must be explicitly restarted so events in this test are
184+
// associated with the new testExecutionId.
185+
//
186+
// After stopSession(), the RUM SDK creates a new session upon a user interaction
187+
// (click, scroll, keydown, or touchstart). We dispatch a synthetic click on the window
188+
// to trigger session renewal, then call startView() to establish a view boundary.
189+
if (!isTestIsolationEnabled && originalWindow) {
190+
const rum = safeGetRum(originalWindow)
191+
if (rum) {
192+
try {
193+
const evt = new originalWindow.MouseEvent('click', { bubbles: true, cancelable: true })
194+
// The browser-sdk addEventListener wrapper filters out untrusted synthetic events
195+
// unless __ddIsTrusted is set. Set it so the click triggers expandOrRenewSession().
196+
// See: https://github.com/DataDog/browser-sdk/blob/v6.27.1/packages/core/src/browser/addEventListener.ts#L119
197+
Object.defineProperty(evt, '__ddIsTrusted', { value: true })
198+
originalWindow.dispatchEvent(evt)
199+
} catch {}
200+
if (rum.startView) {
201+
rum.startView()
202+
}
203+
}
204+
}
205+
})
206+
}
173207
if (shouldSkip) {
174208
this.skip()
175209
}
176210
})
177-
cy.window().then(win => {
178-
originalWindow = win
179-
})
180211
})
181212

182213
before(function () {
@@ -195,6 +226,9 @@ before(function () {
195226
isImpactedTestsEnabled = suiteConfig.isImpactedTestsEnabled
196227
isModifiedTest = suiteConfig.isModifiedTest
197228
isTestIsolationEnabled = suiteConfig.isTestIsolationEnabled
229+
if (Number.isFinite(suiteConfig.rumFlushWaitMillis)) {
230+
rumFlushWaitMillis = suiteConfig.rumFlushWaitMillis
231+
}
198232
}
199233
})
200234
})
@@ -241,8 +275,14 @@ afterEach(function () {
241275
testInfo.testSourceLine = Cypress.mocha.getRunner().currentRunnable.invocationDetails.line
242276
} catch {}
243277

244-
if (safeGetRum(originalWindow)) {
278+
const rum = safeGetRum(originalWindow)
279+
if (rum) {
245280
testInfo.isRUMActive = true
281+
if (rum.stopSession) {
282+
rum.stopSession()
283+
// eslint-disable-next-line cypress/no-unnecessary-waiting
284+
cy.wait(rumFlushWaitMillis)
285+
}
246286
}
247287
let coverage
248288
try {

0 commit comments

Comments
 (0)