From 6ca0061dde7b8b89449e403f852ade75bd227a53 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Mon, 27 Oct 2025 16:50:25 +0100 Subject: [PATCH 1/4] new approach to playwright --- packages/datadog-instrumentations/src/playwright.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/datadog-instrumentations/src/playwright.js b/packages/datadog-instrumentations/src/playwright.js index 1a6a6f4747c..01ca960b2c0 100644 --- a/packages/datadog-instrumentations/src/playwright.js +++ b/packages/datadog-instrumentations/src/playwright.js @@ -1063,13 +1063,10 @@ addHook({ const url = page.url() if (url) { const domain = new URL(url).hostname - await page.context().addCookies([{ + await page.context().clearCookies({ name: 'datadog-ci-visibility-test-execution-id', - value: '', - domain, - expires: 0, - path: '/' - }]) + domain + }) } } } From a512ca438fc166f1904869d17b5b6511697114b8 Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Thu, 30 Oct 2025 14:40:16 +0100 Subject: [PATCH 2/4] wait for flush RUM events --- .../datadog-instrumentations/src/playwright.js | 14 +++++++++++--- packages/datadog-plugin-playwright/src/index.js | 6 +++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/datadog-instrumentations/src/playwright.js b/packages/datadog-instrumentations/src/playwright.js index 01ca960b2c0..58c6da7ed44 100644 --- a/packages/datadog-instrumentations/src/playwright.js +++ b/packages/datadog-instrumentations/src/playwright.js @@ -37,6 +37,8 @@ const testSuiteToTestStatuses = new Map() const testSuiteToErrors = new Map() const testsToTestStatuses = new Map() +const RUM_FLUSH_WAIT_TIME = 1000 + let applyRepeatEachIndex = null let startedSuites = [] @@ -1063,10 +1065,16 @@ addHook({ const url = page.url() if (url) { const domain = new URL(url).hostname - await page.context().clearCookies({ + await page.context().addCookies([{ name: 'datadog-ci-visibility-test-execution-id', - domain - }) + value: '', + domain, + path: '/' + }]) + // Give some time RUM to flush data + await new Promise(resolve => setTimeout(resolve, RUM_FLUSH_WAIT_TIME)) + } else { + log.error('afterEach hook: page.url() is not available') } } } diff --git a/packages/datadog-plugin-playwright/src/index.js b/packages/datadog-plugin-playwright/src/index.js index 27f8a2cc857..7dca0da442d 100644 --- a/packages/datadog-plugin-playwright/src/index.js +++ b/packages/datadog-plugin-playwright/src/index.js @@ -47,6 +47,7 @@ const { TELEMETRY_EVENT_FINISHED } = require('../../dd-trace/src/ci-visibility/telemetry') const { appClosing: appClosingTelemetry } = require('../../dd-trace/src/telemetry') +const log = require('../../dd-trace/src/log') class PlaywrightPlugin extends CiPlugin { static id = 'playwright' @@ -174,7 +175,10 @@ class PlaywrightPlugin extends CiPlugin { }) => { const store = storage('legacy').getStore() const span = store && store.span - if (!span) return + if (!span) { + log.error('ci:playwright:test:page-goto: test span not found') + return + } if (isRumActive) { span.setTag(TEST_IS_RUM_ACTIVE, 'true') From a449f2a48b7ccc90000fd4eeafe2bb18d6c12d6a Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Thu, 30 Oct 2025 14:43:42 +0100 Subject: [PATCH 3/4] better msg and wait before clearing the cookie --- packages/datadog-instrumentations/src/playwright.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/datadog-instrumentations/src/playwright.js b/packages/datadog-instrumentations/src/playwright.js index 58c6da7ed44..27bc0b302ce 100644 --- a/packages/datadog-instrumentations/src/playwright.js +++ b/packages/datadog-instrumentations/src/playwright.js @@ -1062,6 +1062,8 @@ addHook({ }) if (isRumActive) { + // Give some time RUM to flush data, similar to what we do in selenium + await new Promise(resolve => setTimeout(resolve, RUM_FLUSH_WAIT_TIME)) const url = page.url() if (url) { const domain = new URL(url).hostname @@ -1071,10 +1073,8 @@ addHook({ domain, path: '/' }]) - // Give some time RUM to flush data - await new Promise(resolve => setTimeout(resolve, RUM_FLUSH_WAIT_TIME)) } else { - log.error('afterEach hook: page.url() is not available') + log.error('RUM is active but page.url() is not available') } } } From c502521ebe6af38193576c95a9832fff99f48a6b Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Thu, 30 Oct 2025 15:13:35 +0100 Subject: [PATCH 4/4] update tests --- .../rum-multiple-goto-test.js | 19 +++++++++ ...tive-test-span-rum-test.js => rum-test.js} | 0 .../playwright/playwright.spec.js | 42 ++++++++++--------- 3 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 integration-tests/ci-visibility/playwright-tests-rum/rum-multiple-goto-test.js rename integration-tests/ci-visibility/playwright-tests-rum/{active-test-span-rum-test.js => rum-test.js} (100%) diff --git a/integration-tests/ci-visibility/playwright-tests-rum/rum-multiple-goto-test.js b/integration-tests/ci-visibility/playwright-tests-rum/rum-multiple-goto-test.js new file mode 100644 index 00000000000..967f2fbb905 --- /dev/null +++ b/integration-tests/ci-visibility/playwright-tests-rum/rum-multiple-goto-test.js @@ -0,0 +1,19 @@ +'use strict' + +const { test, expect } = require('@playwright/test') + +test.beforeEach(async ({ page }) => { + await page.goto(process.env.PW_BASE_URL) +}) + +test.describe('playwright', () => { + test('should have RUM active', async ({ page }) => { + await expect(page.locator('.hello-world')).toHaveText([ + 'Hello World' + ]) + await page.goto(`${process.env.PW_BASE_URL}/another-page`) + await expect(page.locator('.hello-world')).toHaveText([ + 'Hello World' + ]) + }) +}) diff --git a/integration-tests/ci-visibility/playwright-tests-rum/active-test-span-rum-test.js b/integration-tests/ci-visibility/playwright-tests-rum/rum-test.js similarity index 100% rename from integration-tests/ci-visibility/playwright-tests-rum/active-test-span-rum-test.js rename to integration-tests/ci-visibility/playwright-tests-rum/rum-test.js diff --git a/integration-tests/playwright/playwright.spec.js b/integration-tests/playwright/playwright.spec.js index 1bf67b67bcd..62b6a816541 100644 --- a/integration-tests/playwright/playwright.spec.js +++ b/integration-tests/playwright/playwright.spec.js @@ -1700,25 +1700,26 @@ versions.forEach((version) => { receiver .gatherPayloadsMaxTimeout(({ url }) => url === '/api/v2/citestcycle', (payloads) => { const events = payloads.flatMap(({ payload }) => payload.events) - const playwrightTest = events.find(event => event.type === 'test').content - if (isRedirecting) { - assert.notProperty(playwrightTest.meta, TEST_IS_RUM_ACTIVE) - assert.notProperty(playwrightTest.meta, TEST_BROWSER_VERSION) - } else { - assert.property(playwrightTest.meta, TEST_IS_RUM_ACTIVE, 'true') - assert.property(playwrightTest.meta, TEST_BROWSER_VERSION) - } - assert.include(playwrightTest.meta, { - [TEST_BROWSER_NAME]: 'chromium', - [TEST_TYPE]: 'browser' + const tests = events.filter(event => event.type === 'test').map(event => event.content) + tests.forEach(test => { + if (isRedirecting) { + // can't do assertions because playwright has been redirected + assert.propertyVal(test.meta, TEST_STATUS, 'fail') + assert.notProperty(test.meta, TEST_IS_RUM_ACTIVE) + assert.notProperty(test.meta, TEST_BROWSER_VERSION) + } else { + assert.propertyVal(test.meta, TEST_STATUS, 'pass') + assert.property(test.meta, TEST_IS_RUM_ACTIVE, 'true') + assert.property(test.meta, TEST_BROWSER_VERSION) + } }) }) - const runTest = (done, { isRedirecting }, extraEnvVars) => { + const runRumTest = async ({ isRedirecting }, extraEnvVars) => { const testAssertionsPromise = getTestAssertions({ isRedirecting }) childProcess = exec( - './node_modules/.bin/playwright test -c playwright.config.js active-test-span-rum-test.js', + './node_modules/.bin/playwright test -c playwright.config.js', { cwd, env: { @@ -1731,17 +1732,18 @@ versions.forEach((version) => { } ) - childProcess.on('exit', () => { - testAssertionsPromise.then(() => done()).catch(done) - }) + await Promise.all([ + once(childProcess, 'exit'), + testAssertionsPromise + ]) } - it('can correlate tests and RUM sessions', (done) => { - runTest(done, { isRedirecting: false }) + it('can correlate tests and RUM sessions', async () => { + await runRumTest({ isRedirecting: false }) }) - it('do not crash when redirecting and RUM sessions are not active', (done) => { - runTest(done, { isRedirecting: true }) + it('do not crash when redirecting and RUM sessions are not active', async () => { + await runRumTest({ isRedirecting: true }) }) })