From 6812024e8084109d19c87c31abe6ac0dae3692a1 Mon Sep 17 00:00:00 2001 From: Thomas Lebeau Date: Fri, 5 Sep 2025 13:42:27 +0200 Subject: [PATCH 01/12] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20simplify=20browser?= =?UTF-8?q?=20extension=20e2e=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/apps/base-extension/manifest.json | 13 +- test/apps/base-extension/src/background.ts | 2 - test/apps/base-extension/src/contentScript.ts | 25 ++-- test/apps/base-extension/src/form.html | 10 -- test/apps/base-extension/src/popup.html | 8 -- test/apps/base-extension/webpack.config.js | 1 - test/apps/base-extension/yarn.lock | 16 +-- test/apps/react-router-v6-app/yarn.lock | 12 +- test/apps/vanilla/yarn.lock | 16 +-- test/e2e/lib/framework/createTest.ts | 3 +- test/e2e/lib/framework/pageSetups.ts | 36 ++++++ .../browserExtensions.scenario.ts | 112 ++++-------------- 12 files changed, 98 insertions(+), 156 deletions(-) delete mode 100644 test/apps/base-extension/src/background.ts delete mode 100644 test/apps/base-extension/src/form.html delete mode 100644 test/apps/base-extension/src/popup.html diff --git a/test/apps/base-extension/manifest.json b/test/apps/base-extension/manifest.json index a2c31eba57..5294d29b3a 100644 --- a/test/apps/base-extension/manifest.json +++ b/test/apps/base-extension/manifest.json @@ -5,19 +5,12 @@ "description": "Injects Datadog RUM into every page to inspect data being sent.", "permissions": ["scripting", "activeTab"], "host_permissions": [""], - "background": { - "service_worker": "dist/background.js", - "type": "module" - }, "content_scripts": [ { "matches": [""], "js": ["dist/content-script.js"], - "run_at": "document_start" + "run_at": "document_end", + "world": "MAIN" } - ], - "action": { - "default_title": "Datadog RUM Testing Extension", - "default_popup": "src/popup.html" - } + ] } diff --git a/test/apps/base-extension/src/background.ts b/test/apps/base-extension/src/background.ts deleted file mode 100644 index 168831b690..0000000000 --- a/test/apps/base-extension/src/background.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Minimal background service worker to help with extension ID detection -console.log('Background service worker initialized') diff --git a/test/apps/base-extension/src/contentScript.ts b/test/apps/base-extension/src/contentScript.ts index f6782c5f1b..ca4ef6f930 100644 --- a/test/apps/base-extension/src/contentScript.ts +++ b/test/apps/base-extension/src/contentScript.ts @@ -1,17 +1,18 @@ import { datadogRum } from '@datadog/browser-rum' import { datadogLogs } from '@datadog/browser-logs' -// NOTE: RUM and Logs data produced during E2E tests are not sent to the E2E intake, because it's -// not using the E2E init configuration including the `proxy` configuration. -// This could be changed in the future. +if (window.RUM_CONFIGURATION) { + datadogRum.init({ ...window.RUM_CONFIGURATION }) -datadogRum.init({ - applicationId: '1234', - clientToken: 'abcd', - /* EXTENSION_INIT_PARAMETER */ -}) + if (window.RUM_CONTEXT) { + datadogRum.setGlobalContext(window.RUM_CONTEXT) + } +} -datadogLogs.init({ - clientToken: 'abcd', - /* EXTENSION_INIT_PARAMETER */ -}) +if (window.LOGS_CONFIGURATION) { + datadogLogs.init({ ...window.LOGS_CONFIGURATION }) + + if (window.LOGS_CONTEXT) { + datadogLogs.setGlobalContext(window.LOGS_CONTEXT) + } +} diff --git a/test/apps/base-extension/src/form.html b/test/apps/base-extension/src/form.html deleted file mode 100644 index 1db21092a9..0000000000 --- a/test/apps/base-extension/src/form.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Extension Test Page - - - - - diff --git a/test/apps/base-extension/src/popup.html b/test/apps/base-extension/src/popup.html deleted file mode 100644 index 0496063dd3..0000000000 --- a/test/apps/base-extension/src/popup.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - Extension Popup - - - diff --git a/test/apps/base-extension/webpack.config.js b/test/apps/base-extension/webpack.config.js index c8697b443e..37bb9067bc 100644 --- a/test/apps/base-extension/webpack.config.js +++ b/test/apps/base-extension/webpack.config.js @@ -5,7 +5,6 @@ module.exports = { target: ['web', 'es2018'], entry: { 'content-script': './src/contentScript.ts', - background: './src/background.ts', }, output: { filename: '[name].js', diff --git a/test/apps/base-extension/yarn.lock b/test/apps/base-extension/yarn.lock index 0077081d90..6d46027e50 100644 --- a/test/apps/base-extension/yarn.lock +++ b/test/apps/base-extension/yarn.lock @@ -7,14 +7,14 @@ __metadata: "@datadog/browser-core@file:../../../packages/core/package.tgz::locator=rum-testing-extension%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=c8e335&locator=rum-testing-extension%40workspace%3A." - checksum: 10c0/e98c1c4d1dc900848961a233c9cc28fb442219bd45bae226f9a48f6b7282c6ed743a6be9a14477c12affb948184db28a9f9d5c7cd8ce4cf08f6141cbd8bc4679 + resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=3d1932&locator=rum-testing-extension%40workspace%3A." + checksum: 10c0/994366172286b77f3f9fba0e134c87b205a1b8bd55d7f2fa01b71a1151d696f4147d9885c3d10e2dea847adb15e70784115595730cf1126f2fe4c899aabb95db languageName: node linkType: hard "@datadog/browser-logs@file:../../../packages/logs/package.tgz::locator=rum-testing-extension%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-logs@file:../../../packages/logs/package.tgz#../../../packages/logs/package.tgz::hash=471336&locator=rum-testing-extension%40workspace%3A." + resolution: "@datadog/browser-logs@file:../../../packages/logs/package.tgz#../../../packages/logs/package.tgz::hash=5e7803&locator=rum-testing-extension%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.19.0" peerDependencies: @@ -22,22 +22,22 @@ __metadata: peerDependenciesMeta: "@datadog/browser-rum": optional: true - checksum: 10c0/8266d763df3a6fdc22b3dbd2855fea5799d0f27a476ade83850499a8ee2bc890fd09fa1f534c2ad79d8dce75007d908fc4928f77987bb6f74c1c1e4b11115a7e + checksum: 10c0/542438b155eba1f576c00ec24b36f5a191634c2a1912f4723159e934a02f5b485fa549bc8d8b230941ac68b4b3fe07aad38e40a7fc9407c15e2d6d4961a0d2ce languageName: node linkType: hard "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz::locator=rum-testing-extension%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=c25ad6&locator=rum-testing-extension%40workspace%3A." + resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=c95a64&locator=rum-testing-extension%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.19.0" - checksum: 10c0/0b46745d5dd37acb24a715b013622ed35ab01e482a0dfed56aca95cde24cfb907cb1f9deba304f8c7f49885519b2238cdc59bf3a5df0eb90e2d756aea02d346d + checksum: 10c0/272794feb33c274a6517d2bafb1107a77fabd1574f36be3ed9c4735fa8355e286d072355e7d55fafc705fea6b96ce3925a748635b9709771093a013330f3ca6f languageName: node linkType: hard "@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=rum-testing-extension%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=603883&locator=rum-testing-extension%40workspace%3A." + resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=ee0f6e&locator=rum-testing-extension%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.19.0" "@datadog/browser-rum-core": "npm:6.19.0" @@ -46,7 +46,7 @@ __metadata: peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: 10c0/0d05abf96a68f5c709c21e04b6cce6708f1a5e63d146efe4d42276b36d64abdeaccee39858bc0279a5011ab529d4d0d4430b344e34d0a01eed9b913649acb072 + checksum: 10c0/6690b8782df911bfbc4298914ed42bb1b6d1360a5ba43da082423cfa7e083f36e503505e2353ab20df6da1e0d094203257d6a8ae62d5a69cc27c9885fea2e394 languageName: node linkType: hard diff --git a/test/apps/react-router-v6-app/yarn.lock b/test/apps/react-router-v6-app/yarn.lock index cf927c8648..38e0f6cf90 100644 --- a/test/apps/react-router-v6-app/yarn.lock +++ b/test/apps/react-router-v6-app/yarn.lock @@ -7,17 +7,17 @@ __metadata: "@datadog/browser-core@file:../../../packages/core/package.tgz::locator=react-router-v6-app%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=c8e335&locator=react-router-v6-app%40workspace%3A." - checksum: 10c0/e98c1c4d1dc900848961a233c9cc28fb442219bd45bae226f9a48f6b7282c6ed743a6be9a14477c12affb948184db28a9f9d5c7cd8ce4cf08f6141cbd8bc4679 + resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=3d1932&locator=react-router-v6-app%40workspace%3A." + checksum: 10c0/994366172286b77f3f9fba0e134c87b205a1b8bd55d7f2fa01b71a1151d696f4147d9885c3d10e2dea847adb15e70784115595730cf1126f2fe4c899aabb95db languageName: node linkType: hard "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz::locator=react-router-v6-app%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=c25ad6&locator=react-router-v6-app%40workspace%3A." + resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=c95a64&locator=react-router-v6-app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.19.0" - checksum: 10c0/0b46745d5dd37acb24a715b013622ed35ab01e482a0dfed56aca95cde24cfb907cb1f9deba304f8c7f49885519b2238cdc59bf3a5df0eb90e2d756aea02d346d + checksum: 10c0/272794feb33c274a6517d2bafb1107a77fabd1574f36be3ed9c4735fa8355e286d072355e7d55fafc705fea6b96ce3925a748635b9709771093a013330f3ca6f languageName: node linkType: hard @@ -48,7 +48,7 @@ __metadata: "@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=react-router-v6-app%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=603883&locator=react-router-v6-app%40workspace%3A." + resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=ee0f6e&locator=react-router-v6-app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.19.0" "@datadog/browser-rum-core": "npm:6.19.0" @@ -57,7 +57,7 @@ __metadata: peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: 10c0/0d05abf96a68f5c709c21e04b6cce6708f1a5e63d146efe4d42276b36d64abdeaccee39858bc0279a5011ab529d4d0d4430b344e34d0a01eed9b913649acb072 + checksum: 10c0/6690b8782df911bfbc4298914ed42bb1b6d1360a5ba43da082423cfa7e083f36e503505e2353ab20df6da1e0d094203257d6a8ae62d5a69cc27c9885fea2e394 languageName: node linkType: hard diff --git a/test/apps/vanilla/yarn.lock b/test/apps/vanilla/yarn.lock index e590d67bc8..3400902bf5 100644 --- a/test/apps/vanilla/yarn.lock +++ b/test/apps/vanilla/yarn.lock @@ -7,14 +7,14 @@ __metadata: "@datadog/browser-core@file:../../../packages/core/package.tgz::locator=app%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=c8e335&locator=app%40workspace%3A." - checksum: 10c0/e98c1c4d1dc900848961a233c9cc28fb442219bd45bae226f9a48f6b7282c6ed743a6be9a14477c12affb948184db28a9f9d5c7cd8ce4cf08f6141cbd8bc4679 + resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=3d1932&locator=app%40workspace%3A." + checksum: 10c0/994366172286b77f3f9fba0e134c87b205a1b8bd55d7f2fa01b71a1151d696f4147d9885c3d10e2dea847adb15e70784115595730cf1126f2fe4c899aabb95db languageName: node linkType: hard "@datadog/browser-logs@file:../../../packages/logs/package.tgz::locator=app%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-logs@file:../../../packages/logs/package.tgz#../../../packages/logs/package.tgz::hash=471336&locator=app%40workspace%3A." + resolution: "@datadog/browser-logs@file:../../../packages/logs/package.tgz#../../../packages/logs/package.tgz::hash=5e7803&locator=app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.19.0" peerDependencies: @@ -22,22 +22,22 @@ __metadata: peerDependenciesMeta: "@datadog/browser-rum": optional: true - checksum: 10c0/8266d763df3a6fdc22b3dbd2855fea5799d0f27a476ade83850499a8ee2bc890fd09fa1f534c2ad79d8dce75007d908fc4928f77987bb6f74c1c1e4b11115a7e + checksum: 10c0/542438b155eba1f576c00ec24b36f5a191634c2a1912f4723159e934a02f5b485fa549bc8d8b230941ac68b4b3fe07aad38e40a7fc9407c15e2d6d4961a0d2ce languageName: node linkType: hard "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz::locator=app%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=c25ad6&locator=app%40workspace%3A." + resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=c95a64&locator=app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.19.0" - checksum: 10c0/0b46745d5dd37acb24a715b013622ed35ab01e482a0dfed56aca95cde24cfb907cb1f9deba304f8c7f49885519b2238cdc59bf3a5df0eb90e2d756aea02d346d + checksum: 10c0/272794feb33c274a6517d2bafb1107a77fabd1574f36be3ed9c4735fa8355e286d072355e7d55fafc705fea6b96ce3925a748635b9709771093a013330f3ca6f languageName: node linkType: hard "@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=app%40workspace%3A.": version: 6.19.0 - resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=603883&locator=app%40workspace%3A." + resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=ee0f6e&locator=app%40workspace%3A." dependencies: "@datadog/browser-core": "npm:6.19.0" "@datadog/browser-rum-core": "npm:6.19.0" @@ -46,7 +46,7 @@ __metadata: peerDependenciesMeta: "@datadog/browser-logs": optional: true - checksum: 10c0/0d05abf96a68f5c709c21e04b6cce6708f1a5e63d146efe4d42276b36d64abdeaccee39858bc0279a5011ab529d4d0d4430b344e34d0a01eed9b913649acb072 + checksum: 10c0/6690b8782df911bfbc4298914ed42bb1b6d1360a5ba43da082423cfa7e083f36e503505e2353ab20df6da1e0d094203257d6a8ae62d5a69cc27c9885fea2e394 languageName: node linkType: hard diff --git a/test/e2e/lib/framework/createTest.ts b/test/e2e/lib/framework/createTest.ts index 90ac85d03a..52d6bff447 100644 --- a/test/e2e/lib/framework/createTest.ts +++ b/test/e2e/lib/framework/createTest.ts @@ -16,7 +16,7 @@ import { flushEvents } from './flushEvents' import type { Servers } from './httpServers' import { getTestServers, waitForServersIdle } from './httpServers' import type { SetupFactory, SetupOptions } from './pageSetups' -import { DEFAULT_SETUPS, npmSetup, reactSetup } from './pageSetups' +import { DEFAULT_SETUPS, extensionSetup, npmSetup, reactSetup } from './pageSetups' import { createIntakeServerApp } from './serverApps/intake' import { createMockServerApp } from './serverApps/mock' @@ -131,6 +131,7 @@ class TestBuilder { withExtension(extensionPath: string) { this.testFixture = createExtensionTest(extensionPath) + this.setups = [{ factory: (options, servers) => extensionSetup(options, servers) }] return this } diff --git a/test/e2e/lib/framework/pageSetups.ts b/test/e2e/lib/framework/pageSetups.ts index 80c5c187a7..2153675b24 100644 --- a/test/e2e/lib/framework/pageSetups.ts +++ b/test/e2e/lib/framework/pageSetups.ts @@ -184,6 +184,42 @@ export function reactSetup(options: SetupOptions, servers: Servers, appName: str }) } +export function extensionSetup(options: SetupOptions, servers: Servers) { + let header = options.head || '' + const body = options.body || '' + + if (options.eventBridge) { + header += setupEventBridge(servers) + } + + const { rumScriptUrl, logsScriptUrl } = createCrossOriginScriptUrls(servers, options) + + if (options.rum) { + header += html` + + ` + } + + if (options.logs) { + header += html` + + ` + } + + return basePage({ + header, + body, + }) +} + export function basePage({ header, body }: { header?: string; body?: string }) { return html` diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index 59b9b079ae..bb9a743b94 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -1,55 +1,28 @@ import path from 'path' import { test, expect } from '@playwright/test' -import { DEFAULT_LOGS_CONFIGURATION, DEFAULT_RUM_CONFIGURATION, createTest } from '../../lib/framework' +import { createTest } from '../../lib/framework' -// Different extension build paths for different configurations const pathToBaseExtension = path.join(__dirname, '../../../../test/apps/base-extension') -// Contains allowedTrackingOrigins parameter with chrome-extension origin -const pathToAllowedTrackingOriginExtension = path.join(__dirname, '../../../../test/apps/allowed-tracking-origin') -// Contains allowedTrackingOrigins parameter with app.example.com origin -const pathToInvalidTrackingOriginExtension = path.join(__dirname, '../../../../test/apps/invalid-tracking-origin') const warningMessage = 'Datadog Browser SDK: Running the Browser SDK in a Web extension content script is discouraged and will be forbidden in a future major release unless the `allowedTrackingOrigins` option is provided.' const errorMessage = 'Datadog Browser SDK: SDK initialized on a non-allowed domain.' -test.describe('browser extensions', () => { - createTest('popup page should load extension popup and display expected content') - .withExtension(pathToBaseExtension) - .run(async ({ page, getExtensionId }) => { - const extensionId = await getExtensionId() - await page.goto(`chrome-extension://${extensionId}/src/popup.html`) - await expect(page).toHaveTitle(/Extension Popup/) - }) +// TODO: the recorder is lazy loaded and does not works in an browser extension content script +const DISABLE_SESSION_REPLAY_CONFIGURATION = { + sessionReplaySampleRate: 0, +} +test.describe('browser extensions @only', () => { createTest( 'SDK is initialized in an unsupported environment without allowedTrackingOrigins and warns when used in content script' ) .withExtension(pathToBaseExtension) - .withRum() - .withLogs() - .run(async ({ page, baseUrl, getExtensionId, withBrowserLogs }) => { - const extensionId = await getExtensionId() - - await page.goto(`chrome-extension://${extensionId}/src/popup.html`) - - const rumResult = await page.evaluate(() => window.DD_RUM?.getInitConfiguration()) - const logsResult = await page.evaluate(() => window.DD_LOGS?.getInitConfiguration()) - expect(rumResult?.applicationId).toBe('1234') - expect(logsResult?.clientToken).toBe('abcd') - - await page.goto(baseUrl) - - const pageRumResult = await page.evaluate(() => window.DD_RUM?.getInitConfiguration()) - const pageLogsResult = await page.evaluate(() => window.DD_LOGS?.getInitConfiguration()) + .withRum({ ...DISABLE_SESSION_REPLAY_CONFIGURATION }) + .run(async ({ withBrowserLogs, flushEvents }) => { + await flushEvents() - expect(pageRumResult?.applicationId).toBe(DEFAULT_RUM_CONFIGURATION.applicationId) - expect(pageLogsResult?.clientToken).toBe(DEFAULT_LOGS_CONFIGURATION.clientToken) - - // Check for warnings in console messages - should have one from RUM and one from Logs - // But since we also go to the base url, we can have more than 2 logs withBrowserLogs((logs) => { - expect(logs.length).toBeGreaterThanOrEqual(2) expect(logs).toContainEqual( expect.objectContaining({ level: 'warning', @@ -60,68 +33,27 @@ test.describe('browser extensions', () => { }) createTest('SDK with correct allowedTrackingOrigins parameter works correctly for both RUM and Logs') - .withExtension(pathToAllowedTrackingOriginExtension) - .run(async ({ page, getExtensionId, flushBrowserLogs }) => { - const extensionId = await getExtensionId() - const expectedOriginPattern = /^chrome-extension:\/\// - const extensionLogs: any[] = [] - - // Listen for console events and filter for extension page only - // Because the test also goes to the base url, we need to filter for the extension page only - page.on('console', (msg) => { - const url = msg.location().url - if (url && url.startsWith(`chrome-extension://${extensionId}`)) { - extensionLogs.push({ - level: msg.type(), - message: msg.text(), - source: 'console', - url, - }) - } - }) - - await page.goto(`chrome-extension://${extensionId}/src/popup.html`) - - const rumResult = await page.evaluate(() => window.DD_RUM?.getInitConfiguration()) - const logsResult = await page.evaluate(() => window.DD_LOGS?.getInitConfiguration()) - - expect(rumResult?.applicationId).toBe('1234') - expect(rumResult?.allowedTrackingOrigins).toEqual([expectedOriginPattern]) - expect(logsResult?.clientToken).toBe('abcd') - expect(logsResult?.allowedTrackingOrigins).toEqual([expectedOriginPattern]) + .withExtension(pathToBaseExtension) + .withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) + .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { + await flushEvents() - expect(extensionLogs).toEqual([]) + expect(intakeRegistry.rumViewEvents).toHaveLength(1) - flushBrowserLogs() + withBrowserLogs((logs) => { + expect(logs.length).toBe(0) + }) }) createTest('SDK with incorrect allowedTrackingOrigins shows error message for both RUM and Logs') - .withExtension(pathToInvalidTrackingOriginExtension) - .withRum() - .withLogs() - .run(async ({ page, baseUrl, getExtensionId, withBrowserLogs }) => { - const extensionId = await getExtensionId() - - await page.goto(`chrome-extension://${extensionId}/src/popup.html`) - - const rumResult = await page.evaluate(() => window.DD_RUM?.getInitConfiguration()) - const logsResult = await page.evaluate(() => window.DD_LOGS?.getInitConfiguration()) - - expect(rumResult?.applicationId).toBe('1234') - expect(rumResult?.allowedTrackingOrigins).toEqual(['https://app.example.com']) - expect(logsResult?.clientToken).toBe('abcd') - expect(logsResult?.allowedTrackingOrigins).toEqual(['https://app.example.com']) - - await page.goto(baseUrl) - - const pageRumResult = await page.evaluate(() => window.DD_RUM?.getInitConfiguration()) - const pageLogsResult = await page.evaluate(() => window.DD_LOGS?.getInitConfiguration()) + .withExtension(pathToBaseExtension) + .withRum({ allowedTrackingOrigins: ['https://app.example.com'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) + .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { + await flushEvents() - expect(pageRumResult?.applicationId).toBe(DEFAULT_RUM_CONFIGURATION.applicationId) - expect(pageLogsResult?.clientToken).toBe(DEFAULT_LOGS_CONFIGURATION.clientToken) + expect(intakeRegistry.rumViewEvents).toHaveLength(0) withBrowserLogs((logs) => { - expect(logs.length).toBeGreaterThanOrEqual(2) expect(logs).toContainEqual( expect.objectContaining({ level: 'error', From da4204bdca8f339fe9d0d9aa6ad851955164f063 Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Fri, 5 Sep 2025 16:00:29 +0200 Subject: [PATCH 02/12] Add cdn extension for browser extension e2e tests --- scripts/build/build-test-apps.ts | 29 +++----- test/apps/.gitignore | 1 + test/apps/base-extension/manifest.json | 2 +- .../base-extension/src/cdnContentScript.ts | 46 +++++++++++++ .../{contentScript.ts => npmContentScript.ts} | 12 ++++ test/apps/base-extension/webpack.config.js | 12 +++- .../browserExtensions.scenario.ts | 67 +++++++++---------- 7 files changed, 109 insertions(+), 60 deletions(-) create mode 100644 test/apps/base-extension/src/cdnContentScript.ts rename test/apps/base-extension/src/{contentScript.ts => npmContentScript.ts} (54%) diff --git a/scripts/build/build-test-apps.ts b/scripts/build/build-test-apps.ts index 5c672ae25b..9efa5c846a 100644 --- a/scripts/build/build-test-apps.ts +++ b/scripts/build/build-test-apps.ts @@ -5,16 +5,6 @@ import { printLog, runMain } from '../lib/executionUtils.ts' import { command } from '../lib/command.ts' import { modifyFile } from '../lib/filesUtils.ts' -interface ExtensionConfig { - name: string - initParameter: string -} - -const EXTRA_EXTENSIONS: ExtensionConfig[] = [ - { name: 'allowed-tracking-origin', initParameter: 'allowedTrackingOrigins: [/^chrome-extension:\\/\\//],' }, - { name: 'invalid-tracking-origin', initParameter: "allowedTrackingOrigins: ['https://app.example.com']," }, -] - runMain(async () => { printLog('Packing packages...') command`yarn lerna run pack`.run() @@ -66,17 +56,14 @@ async function buildExtensions(): Promise { buildApp(baseExtDir) - for (const { name, initParameter } of EXTRA_EXTENSIONS) { - const targetDir = path.join('test/apps', name) + const cdnExtDir = 'test/apps/cdn-extension' + fs.rmSync(cdnExtDir, { recursive: true, force: true }) + fs.cpSync(baseExtDir, cdnExtDir, { recursive: true }) - fs.rmSync(targetDir, { recursive: true, force: true }) - fs.cpSync(baseExtDir, targetDir, { recursive: true }) - - const contentScriptPath = path.join(targetDir, 'src/contentScript.ts') - await modifyFile(contentScriptPath, (content: string) => - content.replace(/\/\* EXTENSION_INIT_PARAMETER \*\//g, initParameter) - ) + const manifestPath = path.join(cdnExtDir, 'manifest.json') + await modifyFile(manifestPath, (content: string) => + content.replace('dist/npm-content-script.js', 'dist/cdn-content-script.js') + ) - buildApp(targetDir) - } + buildApp(cdnExtDir) } diff --git a/test/apps/.gitignore b/test/apps/.gitignore index 4790c30db0..896309d8d1 100644 --- a/test/apps/.gitignore +++ b/test/apps/.gitignore @@ -1,3 +1,4 @@ allowed-tracking-origin/ invalid-tracking-origin/ react-router-v7-app/ +cdn-extension/ diff --git a/test/apps/base-extension/manifest.json b/test/apps/base-extension/manifest.json index 5294d29b3a..f42fd2ad00 100644 --- a/test/apps/base-extension/manifest.json +++ b/test/apps/base-extension/manifest.json @@ -8,7 +8,7 @@ "content_scripts": [ { "matches": [""], - "js": ["dist/content-script.js"], + "js": ["dist/npm-content-script.js"], "run_at": "document_end", "world": "MAIN" } diff --git a/test/apps/base-extension/src/cdnContentScript.ts b/test/apps/base-extension/src/cdnContentScript.ts new file mode 100644 index 0000000000..5d76fd672c --- /dev/null +++ b/test/apps/base-extension/src/cdnContentScript.ts @@ -0,0 +1,46 @@ +export {} +import type { RumInitConfiguration } from '@datadog/browser-rum-core' +import type { LogsInitConfiguration } from '@datadog/browser-logs' +import type { Context } from '@datadog/browser-core' + +declare global { + interface Window { + RUM_BUNDLE_URL?: string + LOGS_BUNDLE_URL?: string + RUM_CONFIGURATION?: RumInitConfiguration + RUM_CONTEXT?: Context + LOGS_CONFIGURATION?: LogsInitConfiguration + LOGS_CONTEXT?: Context + DD_RUM?: { + init: (config: Record) => void + setGlobalContext: (ctx: Record) => void + } + DD_LOGS?: { + init: (config: Record) => void + setGlobalContext: (ctx: Record) => void + } + } +} + +const scriptUrl = window.RUM_BUNDLE_URL || window.LOGS_BUNDLE_URL +if (scriptUrl) { + const script = document.createElement('script') + script.src = scriptUrl + script.async = true + script.onload = () => { + if (window.RUM_CONFIGURATION && window.DD_RUM) { + window.DD_RUM.init({ ...window.RUM_CONFIGURATION }) + if (window.RUM_CONTEXT) { + window.DD_RUM.setGlobalContext(window.RUM_CONTEXT) + } + } + + if (window.LOGS_CONFIGURATION && window.DD_LOGS) { + window.DD_LOGS.init({ ...window.LOGS_CONFIGURATION }) + if (window.LOGS_CONTEXT) { + window.DD_LOGS.setGlobalContext(window.LOGS_CONTEXT) + } + } + } + document.documentElement.appendChild(script) +} diff --git a/test/apps/base-extension/src/contentScript.ts b/test/apps/base-extension/src/npmContentScript.ts similarity index 54% rename from test/apps/base-extension/src/contentScript.ts rename to test/apps/base-extension/src/npmContentScript.ts index ca4ef6f930..aec65023aa 100644 --- a/test/apps/base-extension/src/contentScript.ts +++ b/test/apps/base-extension/src/npmContentScript.ts @@ -1,5 +1,17 @@ import { datadogRum } from '@datadog/browser-rum' import { datadogLogs } from '@datadog/browser-logs' +import type { RumInitConfiguration } from '@datadog/browser-rum-core' +import type { LogsInitConfiguration } from '@datadog/browser-logs' +import type { Context } from '@datadog/browser-core' + +declare global { + interface Window { + RUM_CONFIGURATION?: RumInitConfiguration + RUM_CONTEXT?: Context + LOGS_CONFIGURATION?: LogsInitConfiguration + LOGS_CONTEXT?: Context + } +} if (window.RUM_CONFIGURATION) { datadogRum.init({ ...window.RUM_CONFIGURATION }) diff --git a/test/apps/base-extension/webpack.config.js b/test/apps/base-extension/webpack.config.js index 37bb9067bc..0bf64dc144 100644 --- a/test/apps/base-extension/webpack.config.js +++ b/test/apps/base-extension/webpack.config.js @@ -4,7 +4,17 @@ module.exports = { mode: 'production', target: ['web', 'es2018'], entry: { - 'content-script': './src/contentScript.ts', + 'npm-content-script': './src/npmContentScript.ts', + 'cdn-content-script': './src/cdnContentScript.ts', + }, + module: { + rules: [ + { + test: /\.ts$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + ], }, output: { filename: '[name].js', diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index bb9a743b94..95a3332583 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -2,64 +2,57 @@ import path from 'path' import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' -const pathToBaseExtension = path.join(__dirname, '../../../../test/apps/base-extension') - -const warningMessage = - 'Datadog Browser SDK: Running the Browser SDK in a Web extension content script is discouraged and will be forbidden in a future major release unless the `allowedTrackingOrigins` option is provided.' -const errorMessage = 'Datadog Browser SDK: SDK initialized on a non-allowed domain.' +const pathToBundleExtension = path.join(__dirname, '../../../../test/apps/base-extension') +const pathToCdnExtension = path.join(__dirname, '../../../../test/apps/cdn-extension') // TODO: the recorder is lazy loaded and does not works in an browser extension content script -const DISABLE_SESSION_REPLAY_CONFIGURATION = { - sessionReplaySampleRate: 0, -} +const DISABLE_SESSION_REPLAY_CONFIGURATION = { sessionReplaySampleRate: 0 } + +interface Ext { name: string; path: string } + +const EXTENSIONS: Ext[] = [ + { name: 'bundle', path: pathToBundleExtension }, + { name: 'cdn', path: pathToCdnExtension }, +] -test.describe('browser extensions @only', () => { - createTest( - 'SDK is initialized in an unsupported environment without allowedTrackingOrigins and warns when used in content script' - ) - .withExtension(pathToBaseExtension) +function declareExtensionTests(ext: Ext) { + const warningMessage = + 'Datadog Browser SDK: Running the Browser SDK in a Web extension content script is discouraged and will be forbidden in a future major release unless the `allowedTrackingOrigins` option is provided.' + const errorMessage = 'Datadog Browser SDK: SDK initialized on a non-allowed domain.' + + createTest(`[${ext.name}] SDK is initialized in an unsupported environment and warns`) + .withExtension(ext.path) .withRum({ ...DISABLE_SESSION_REPLAY_CONFIGURATION }) .run(async ({ withBrowserLogs, flushEvents }) => { await flushEvents() - withBrowserLogs((logs) => { - expect(logs).toContainEqual( - expect.objectContaining({ - level: 'warning', - message: warningMessage, - }) - ) + expect(logs).toContainEqual(expect.objectContaining({ level: 'warning', message: warningMessage })) }) }) - createTest('SDK with correct allowedTrackingOrigins parameter works correctly for both RUM and Logs') - .withExtension(pathToBaseExtension) + createTest(`[${ext.name}] allowedTrackingOrigins accepted`) + .withExtension(ext.path) .withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() - expect(intakeRegistry.rumViewEvents).toHaveLength(1) - - withBrowserLogs((logs) => { - expect(logs.length).toBe(0) - }) + withBrowserLogs((logs) => expect(logs.length).toBe(0)) }) - createTest('SDK with incorrect allowedTrackingOrigins shows error message for both RUM and Logs') - .withExtension(pathToBaseExtension) + createTest(`[${ext.name}] allowedTrackingOrigins rejected`) + .withExtension(ext.path) .withRum({ allowedTrackingOrigins: ['https://app.example.com'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() - expect(intakeRegistry.rumViewEvents).toHaveLength(0) - withBrowserLogs((logs) => { - expect(logs).toContainEqual( - expect.objectContaining({ - level: 'error', - message: errorMessage, - }) - ) + expect(logs).toContainEqual(expect.objectContaining({ level: 'error', message: errorMessage })) }) }) +} + +test.describe('browser extensions', () => { + for (const ext of EXTENSIONS) { + test.describe(ext.name, () => declareExtensionTests(ext)) + } }) From 7b031356c0b7c008c8848d5cd1eee7cfcf208a21 Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Mon, 8 Sep 2025 09:21:29 +0200 Subject: [PATCH 03/12] fix format --- .../browser-extensions/browserExtensions.scenario.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index 95a3332583..302c35a3a6 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -8,7 +8,10 @@ const pathToCdnExtension = path.join(__dirname, '../../../../test/apps/cdn-exten // TODO: the recorder is lazy loaded and does not works in an browser extension content script const DISABLE_SESSION_REPLAY_CONFIGURATION = { sessionReplaySampleRate: 0 } -interface Ext { name: string; path: string } +interface Ext { + name: string + path: string +} const EXTENSIONS: Ext[] = [ { name: 'bundle', path: pathToBundleExtension }, From 391e24fae8a0a4a9671efbf0f849a7490126f83c Mon Sep 17 00:00:00 2001 From: Thomas Lebeau Date: Tue, 9 Sep 2025 09:12:50 +0200 Subject: [PATCH 04/12] =?UTF-8?q?=F0=9F=91=8C=20cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../base-extension/src/cdnContentScript.ts | 50 +++++---- .../base-extension/src/npmContentScript.ts | 4 +- .../browserExtensions.scenario.ts | 105 ++++++++++-------- 3 files changed, 84 insertions(+), 75 deletions(-) diff --git a/test/apps/base-extension/src/cdnContentScript.ts b/test/apps/base-extension/src/cdnContentScript.ts index 5d76fd672c..728fa0fbca 100644 --- a/test/apps/base-extension/src/cdnContentScript.ts +++ b/test/apps/base-extension/src/cdnContentScript.ts @@ -1,6 +1,5 @@ -export {} -import type { RumInitConfiguration } from '@datadog/browser-rum-core' -import type { LogsInitConfiguration } from '@datadog/browser-logs' +import type { RumInitConfiguration, RumPublicApi } from '@datadog/browser-rum-core' +import type { LogsInitConfiguration, LogsGlobal } from '@datadog/browser-logs' import type { Context } from '@datadog/browser-core' declare global { @@ -11,36 +10,39 @@ declare global { RUM_CONTEXT?: Context LOGS_CONFIGURATION?: LogsInitConfiguration LOGS_CONTEXT?: Context - DD_RUM?: { - init: (config: Record) => void - setGlobalContext: (ctx: Record) => void - } - DD_LOGS?: { - init: (config: Record) => void - setGlobalContext: (ctx: Record) => void - } + DD_RUM?: RumPublicApi + DD_LOGS?: LogsGlobal } } -const scriptUrl = window.RUM_BUNDLE_URL || window.LOGS_BUNDLE_URL -if (scriptUrl) { +function load( + sdk: T, + url: string, + initConfig: T extends 'DD_RUM' ? RumInitConfiguration : LogsInitConfiguration, + globalContext?: Context +) { const script = document.createElement('script') - script.src = scriptUrl + script.src = url script.async = true script.onload = () => { - if (window.RUM_CONFIGURATION && window.DD_RUM) { - window.DD_RUM.init({ ...window.RUM_CONFIGURATION }) - if (window.RUM_CONTEXT) { - window.DD_RUM.setGlobalContext(window.RUM_CONTEXT) - } + if (!window[sdk]) { + console.error(`${sdk} is not loaded`) + return } - if (window.LOGS_CONFIGURATION && window.DD_LOGS) { - window.DD_LOGS.init({ ...window.LOGS_CONFIGURATION }) - if (window.LOGS_CONTEXT) { - window.DD_LOGS.setGlobalContext(window.LOGS_CONTEXT) - } + window[sdk].init(initConfig as any) + if (globalContext) { + window[sdk].setGlobalContext(globalContext) } } + document.documentElement.appendChild(script) } + +if (window.RUM_BUNDLE_URL && window.RUM_CONFIGURATION) { + load('DD_RUM', window.RUM_BUNDLE_URL, window.RUM_CONFIGURATION, window.RUM_CONTEXT) +} + +if (window.LOGS_BUNDLE_URL && window.LOGS_CONFIGURATION) { + load('DD_LOGS', window.LOGS_BUNDLE_URL, window.LOGS_CONFIGURATION, window.LOGS_CONTEXT) +} diff --git a/test/apps/base-extension/src/npmContentScript.ts b/test/apps/base-extension/src/npmContentScript.ts index aec65023aa..b868f679d4 100644 --- a/test/apps/base-extension/src/npmContentScript.ts +++ b/test/apps/base-extension/src/npmContentScript.ts @@ -14,7 +14,7 @@ declare global { } if (window.RUM_CONFIGURATION) { - datadogRum.init({ ...window.RUM_CONFIGURATION }) + datadogRum.init(window.RUM_CONFIGURATION) if (window.RUM_CONTEXT) { datadogRum.setGlobalContext(window.RUM_CONTEXT) @@ -22,7 +22,7 @@ if (window.RUM_CONFIGURATION) { } if (window.LOGS_CONFIGURATION) { - datadogLogs.init({ ...window.LOGS_CONFIGURATION }) + datadogLogs.init(window.LOGS_CONFIGURATION) if (window.LOGS_CONTEXT) { datadogLogs.setGlobalContext(window.LOGS_CONTEXT) diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index 302c35a3a6..200ba31865 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -2,60 +2,67 @@ import path from 'path' import { test, expect } from '@playwright/test' import { createTest } from '../../lib/framework' -const pathToBundleExtension = path.join(__dirname, '../../../../test/apps/base-extension') -const pathToCdnExtension = path.join(__dirname, '../../../../test/apps/cdn-extension') - // TODO: the recorder is lazy loaded and does not works in an browser extension content script const DISABLE_SESSION_REPLAY_CONFIGURATION = { sessionReplaySampleRate: 0 } -interface Ext { - name: string - path: string -} - -const EXTENSIONS: Ext[] = [ - { name: 'bundle', path: pathToBundleExtension }, - { name: 'cdn', path: pathToCdnExtension }, -] - -function declareExtensionTests(ext: Ext) { - const warningMessage = - 'Datadog Browser SDK: Running the Browser SDK in a Web extension content script is discouraged and will be forbidden in a future major release unless the `allowedTrackingOrigins` option is provided.' - const errorMessage = 'Datadog Browser SDK: SDK initialized on a non-allowed domain.' - - createTest(`[${ext.name}] SDK is initialized in an unsupported environment and warns`) - .withExtension(ext.path) - .withRum({ ...DISABLE_SESSION_REPLAY_CONFIGURATION }) - .run(async ({ withBrowserLogs, flushEvents }) => { - await flushEvents() - withBrowserLogs((logs) => { - expect(logs).toContainEqual(expect.objectContaining({ level: 'warning', message: warningMessage })) - }) - }) +const EXTENSIONS = [ + [path.join(__dirname, '../../../../test/apps/base-extension'), 'bundle'], + [path.join(__dirname, '../../../../test/apps/cdn-extension'), 'cdn'], +] as const - createTest(`[${ext.name}] allowedTrackingOrigins accepted`) - .withExtension(ext.path) - .withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) - .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { - await flushEvents() - expect(intakeRegistry.rumViewEvents).toHaveLength(1) - withBrowserLogs((logs) => expect(logs.length).toBe(0)) - }) - - createTest(`[${ext.name}] allowedTrackingOrigins rejected`) - .withExtension(ext.path) - .withRum({ allowedTrackingOrigins: ['https://app.example.com'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) - .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { - await flushEvents() - expect(intakeRegistry.rumViewEvents).toHaveLength(0) - withBrowserLogs((logs) => { - expect(logs).toContainEqual(expect.objectContaining({ level: 'error', message: errorMessage })) - }) - }) -} +const WARNING_MESSAGE = + 'Datadog Browser SDK: Running the Browser SDK in a Web extension content script is discouraged and will be forbidden in a future major release unless the `allowedTrackingOrigins` option is provided.' +const ERROR_MESSAGE = 'Datadog Browser SDK: SDK initialized on a non-allowed domain.' test.describe('browser extensions', () => { - for (const ext of EXTENSIONS) { - test.describe(ext.name, () => declareExtensionTests(ext)) + for (const [path, name] of EXTENSIONS) { + test.describe(`with ${name} extension`, () => { + createTest('should warn and start tracking when SDK is initialized in an unsupported environment') + .withExtension(path) + .withRum(DISABLE_SESSION_REPLAY_CONFIGURATION) + .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { + await flushEvents() + + expect(intakeRegistry.rumViewEvents).toHaveLength(1) + + withBrowserLogs((logs) => { + expect(logs).toContainEqual( + expect.objectContaining({ + level: 'warning', + message: WARNING_MESSAGE, + }) + ) + }) + }) + + createTest('should start tracking when allowedTrackingOrigins matches current domain') + .withExtension(path) + .withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) + .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { + await flushEvents() + + expect(intakeRegistry.rumViewEvents).toHaveLength(1) + + withBrowserLogs((logs) => expect(logs.length).toBe(0)) + }) + + createTest('should not start tracking when allowedTrackingOrigins does not match current domain') + .withExtension(path) + .withRum({ allowedTrackingOrigins: ['https://app.example.com'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) + .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { + await flushEvents() + + expect(intakeRegistry.rumViewEvents).toHaveLength(0) + + withBrowserLogs((logs) => { + expect(logs).toContainEqual( + expect.objectContaining({ + level: 'error', + message: ERROR_MESSAGE, + }) + ) + }) + }) + }) } }) From 26fdcd283853aa1620784964d2f242ba376d2b25 Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Tue, 9 Sep 2025 11:39:08 +0200 Subject: [PATCH 05/12] use sync version --- test/apps/base-extension/src/cdnContentScript.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/apps/base-extension/src/cdnContentScript.ts b/test/apps/base-extension/src/cdnContentScript.ts index 728fa0fbca..a9d269dc02 100644 --- a/test/apps/base-extension/src/cdnContentScript.ts +++ b/test/apps/base-extension/src/cdnContentScript.ts @@ -23,7 +23,7 @@ function load( ) { const script = document.createElement('script') script.src = url - script.async = true + script.async = false script.onload = () => { if (!window[sdk]) { console.error(`${sdk} is not loaded`) From 4f4006e6d601f619e859f4d02656654446678495 Mon Sep 17 00:00:00 2001 From: "beltran.bulbarella" Date: Tue, 9 Sep 2025 12:26:28 +0200 Subject: [PATCH 06/12] Remove async attribute --- test/apps/base-extension/src/cdnContentScript.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test/apps/base-extension/src/cdnContentScript.ts b/test/apps/base-extension/src/cdnContentScript.ts index a9d269dc02..909e5ba53d 100644 --- a/test/apps/base-extension/src/cdnContentScript.ts +++ b/test/apps/base-extension/src/cdnContentScript.ts @@ -23,7 +23,6 @@ function load( ) { const script = document.createElement('script') script.src = url - script.async = false script.onload = () => { if (!window[sdk]) { console.error(`${sdk} is not loaded`) From e2afc18d43b16c2759218956889ceb81b2880d18 Mon Sep 17 00:00:00 2001 From: Thomas Lebeau Date: Tue, 9 Sep 2025 17:22:46 +0200 Subject: [PATCH 07/12] =?UTF-8?q?=F0=9F=A7=AA=20add=20e2e=20test=20for=20f?= =?UTF-8?q?alse=20positive=20allowed=20extension?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/build/build-test-apps.ts | 27 ++++-- test/apps/.gitignore | 1 + test/apps/base-extension/manifest.json | 2 +- test/apps/base-extension/src/appendChild.ts | 5 ++ .../src/{npmContentScript.ts => base.ts} | 12 +-- .../src/{cdnContentScript.ts => cdn.ts} | 12 +-- test/apps/base-extension/webpack.config.js | 5 +- test/e2e/lib/framework/createExtension.ts | 45 ++++++++++ test/e2e/lib/framework/createTest.ts | 25 ++++-- test/e2e/lib/framework/index.ts | 3 +- test/e2e/lib/framework/pageSetups.ts | 86 +++++++++++-------- .../browserExtensions.scenario.ts | 50 +++++++---- 12 files changed, 189 insertions(+), 84 deletions(-) create mode 100644 test/apps/base-extension/src/appendChild.ts rename test/apps/base-extension/src/{npmContentScript.ts => base.ts} (67%) rename test/apps/base-extension/src/{cdnContentScript.ts => cdn.ts} (70%) create mode 100644 test/e2e/lib/framework/createExtension.ts diff --git a/scripts/build/build-test-apps.ts b/scripts/build/build-test-apps.ts index 9efa5c846a..575871c37d 100644 --- a/scripts/build/build-test-apps.ts +++ b/scripts/build/build-test-apps.ts @@ -5,6 +5,11 @@ import { printLog, runMain } from '../lib/executionUtils.ts' import { command } from '../lib/command.ts' import { modifyFile } from '../lib/filesUtils.ts' +const OTHER_EXTENSIONS: Array<{ name: string; options?: { runAt?: string } }> = [ + { name: 'cdn' }, + { name: 'appendChild', options: { runAt: 'document_start' } }, +] + runMain(async () => { printLog('Packing packages...') command`yarn lerna run pack`.run() @@ -56,14 +61,20 @@ async function buildExtensions(): Promise { buildApp(baseExtDir) - const cdnExtDir = 'test/apps/cdn-extension' - fs.rmSync(cdnExtDir, { recursive: true, force: true }) - fs.cpSync(baseExtDir, cdnExtDir, { recursive: true }) + for (const { name, options } of OTHER_EXTENSIONS) { + const targetDir = path.join('test/apps', `${name}-extension`) - const manifestPath = path.join(cdnExtDir, 'manifest.json') - await modifyFile(manifestPath, (content: string) => - content.replace('dist/npm-content-script.js', 'dist/cdn-content-script.js') - ) + fs.rmSync(targetDir, { recursive: true, force: true }) + fs.cpSync(baseExtDir, targetDir, { recursive: true }) + + const manifestPath = path.join(targetDir, 'manifest.json') + await modifyFile(manifestPath, (originalContent: string) => { + let content = originalContent.replace('dist/base.js', `dist/${name}.js`) - buildApp(cdnExtDir) + if (options?.runAt) { + content = content.replace('document_end', options.runAt) + } + return content + }) + } } diff --git a/test/apps/.gitignore b/test/apps/.gitignore index 896309d8d1..3c6fddc975 100644 --- a/test/apps/.gitignore +++ b/test/apps/.gitignore @@ -2,3 +2,4 @@ allowed-tracking-origin/ invalid-tracking-origin/ react-router-v7-app/ cdn-extension/ +appendChild-extension/ diff --git a/test/apps/base-extension/manifest.json b/test/apps/base-extension/manifest.json index f42fd2ad00..fd6deac35e 100644 --- a/test/apps/base-extension/manifest.json +++ b/test/apps/base-extension/manifest.json @@ -8,7 +8,7 @@ "content_scripts": [ { "matches": [""], - "js": ["dist/npm-content-script.js"], + "js": ["dist/base.js"], "run_at": "document_end", "world": "MAIN" } diff --git a/test/apps/base-extension/src/appendChild.ts b/test/apps/base-extension/src/appendChild.ts new file mode 100644 index 0000000000..e7ebb609e8 --- /dev/null +++ b/test/apps/base-extension/src/appendChild.ts @@ -0,0 +1,5 @@ +const originalAppendChild = Node.prototype.appendChild // eslint-disable-line @typescript-eslint/unbound-method + +Node.prototype.appendChild = function (node: T): T { + return originalAppendChild.call(this, node) as T +} diff --git a/test/apps/base-extension/src/npmContentScript.ts b/test/apps/base-extension/src/base.ts similarity index 67% rename from test/apps/base-extension/src/npmContentScript.ts rename to test/apps/base-extension/src/base.ts index b868f679d4..be6d6d15d4 100644 --- a/test/apps/base-extension/src/npmContentScript.ts +++ b/test/apps/base-extension/src/base.ts @@ -6,23 +6,23 @@ import type { Context } from '@datadog/browser-core' declare global { interface Window { - RUM_CONFIGURATION?: RumInitConfiguration + EXT_RUM_CONFIGURATION?: RumInitConfiguration RUM_CONTEXT?: Context - LOGS_CONFIGURATION?: LogsInitConfiguration + EXT_LOGS_CONFIGURATION?: LogsInitConfiguration LOGS_CONTEXT?: Context } } -if (window.RUM_CONFIGURATION) { - datadogRum.init(window.RUM_CONFIGURATION) +if (window.EXT_RUM_CONFIGURATION) { + datadogRum.init(window.EXT_RUM_CONFIGURATION) if (window.RUM_CONTEXT) { datadogRum.setGlobalContext(window.RUM_CONTEXT) } } -if (window.LOGS_CONFIGURATION) { - datadogLogs.init(window.LOGS_CONFIGURATION) +if (window.EXT_LOGS_CONFIGURATION) { + datadogLogs.init(window.EXT_LOGS_CONFIGURATION) if (window.LOGS_CONTEXT) { datadogLogs.setGlobalContext(window.LOGS_CONTEXT) diff --git a/test/apps/base-extension/src/cdnContentScript.ts b/test/apps/base-extension/src/cdn.ts similarity index 70% rename from test/apps/base-extension/src/cdnContentScript.ts rename to test/apps/base-extension/src/cdn.ts index 909e5ba53d..b722b1a054 100644 --- a/test/apps/base-extension/src/cdnContentScript.ts +++ b/test/apps/base-extension/src/cdn.ts @@ -6,9 +6,9 @@ declare global { interface Window { RUM_BUNDLE_URL?: string LOGS_BUNDLE_URL?: string - RUM_CONFIGURATION?: RumInitConfiguration + EXT_RUM_CONFIGURATION?: RumInitConfiguration RUM_CONTEXT?: Context - LOGS_CONFIGURATION?: LogsInitConfiguration + EXT_LOGS_CONFIGURATION?: LogsInitConfiguration LOGS_CONTEXT?: Context DD_RUM?: RumPublicApi DD_LOGS?: LogsGlobal @@ -38,10 +38,10 @@ function load( document.documentElement.appendChild(script) } -if (window.RUM_BUNDLE_URL && window.RUM_CONFIGURATION) { - load('DD_RUM', window.RUM_BUNDLE_URL, window.RUM_CONFIGURATION, window.RUM_CONTEXT) +if (window.RUM_BUNDLE_URL && window.EXT_RUM_CONFIGURATION) { + load('DD_RUM', window.RUM_BUNDLE_URL, window.EXT_RUM_CONFIGURATION, window.RUM_CONTEXT) } -if (window.LOGS_BUNDLE_URL && window.LOGS_CONFIGURATION) { - load('DD_LOGS', window.LOGS_BUNDLE_URL, window.LOGS_CONFIGURATION, window.LOGS_CONTEXT) +if (window.LOGS_BUNDLE_URL && window.EXT_LOGS_CONFIGURATION) { + load('DD_LOGS', window.LOGS_BUNDLE_URL, window.EXT_LOGS_CONFIGURATION, window.LOGS_CONTEXT) } diff --git a/test/apps/base-extension/webpack.config.js b/test/apps/base-extension/webpack.config.js index 0bf64dc144..0b6893f665 100644 --- a/test/apps/base-extension/webpack.config.js +++ b/test/apps/base-extension/webpack.config.js @@ -4,8 +4,9 @@ module.exports = { mode: 'production', target: ['web', 'es2018'], entry: { - 'npm-content-script': './src/npmContentScript.ts', - 'cdn-content-script': './src/cdnContentScript.ts', + base: './src/base.ts', + cdn: './src/cdn.ts', + appendChild: './src/appendChild.ts', }, module: { rules: [ diff --git a/test/e2e/lib/framework/createExtension.ts b/test/e2e/lib/framework/createExtension.ts new file mode 100644 index 0000000000..b9ec5bc673 --- /dev/null +++ b/test/e2e/lib/framework/createExtension.ts @@ -0,0 +1,45 @@ +import path from 'path' +import type { RumInitConfiguration } from '@datadog/browser-rum-core' +import type test from '@playwright/test' +import type { LogsInitConfiguration } from '@datadog/browser-logs' +import { createExtensionTest } from '../helpers/extensionFixture' +import { DEFAULT_LOGS_CONFIGURATION, DEFAULT_RUM_CONFIGURATION } from './createTest' + +export function createExtension(name: string) { + return new Extension(name) +} + +// TODO: the recorder is lazy loaded and does not works in an browser extension content script +const DISABLE_SESSION_REPLAY_CONFIGURATION = { sessionReplaySampleRate: 0 } + +export class Extension { + public fixture: typeof test + public rumConfiguration: RumInitConfiguration | undefined + public logsConfiguration: LogsInitConfiguration | undefined + + constructor(name: string) { + this.fixture = createExtensionTest(path.join(__dirname, '../../../../test/apps/', `${name}-extension`)) + + return this + } + + withRum(rumInitConfiguration: Partial = {}) { + this.rumConfiguration = { + ...DEFAULT_RUM_CONFIGURATION, + ...DISABLE_SESSION_REPLAY_CONFIGURATION, + ...rumInitConfiguration, + } + + return this + } + + withLogs(logsInitConfiguration: Partial = {}) { + this.logsConfiguration = { + ...DEFAULT_LOGS_CONFIGURATION, + ...DISABLE_SESSION_REPLAY_CONFIGURATION, + ...logsInitConfiguration, + } + + return this + } +} diff --git a/test/e2e/lib/framework/createTest.ts b/test/e2e/lib/framework/createTest.ts index 52d6bff447..804ebbd6ed 100644 --- a/test/e2e/lib/framework/createTest.ts +++ b/test/e2e/lib/framework/createTest.ts @@ -3,7 +3,6 @@ import type { RumInitConfiguration, RemoteConfiguration } from '@datadog/browser import { DefaultPrivacyLevel } from '@datadog/browser-rum' import type { BrowserContext, Page } from '@playwright/test' import { test, expect } from '@playwright/test' -import { createExtensionTest } from '../helpers/extensionFixture' import { addTag, addTestOptimizationTags } from '../helpers/tags' import { getRunId } from '../../../envUtils' import type { BrowserLog } from '../helpers/browser' @@ -16,9 +15,10 @@ import { flushEvents } from './flushEvents' import type { Servers } from './httpServers' import { getTestServers, waitForServersIdle } from './httpServers' import type { SetupFactory, SetupOptions } from './pageSetups' -import { DEFAULT_SETUPS, extensionSetup, npmSetup, reactSetup } from './pageSetups' +import { asyncSetup, DEFAULT_SETUPS, npmSetup, reactSetup } from './pageSetups' import { createIntakeServerApp } from './serverApps/intake' import { createMockServerApp } from './serverApps/mock' +import type { Extension } from './createExtension' export const DEFAULT_RUM_CONFIGURATION = { applicationId: APPLICATION_ID, @@ -76,6 +76,10 @@ class TestBuilder { private eventBridge = false private setups: Array<{ factory: SetupFactory; name?: string }> = DEFAULT_SETUPS private testFixture: typeof test = test + private extension: { + rumConfiguration?: RumInitConfiguration + logsConfiguration?: LogsInitConfiguration + } = {} constructor(private title: string) {} @@ -129,9 +133,17 @@ class TestBuilder { return this } - withExtension(extensionPath: string) { - this.testFixture = createExtensionTest(extensionPath) - this.setups = [{ factory: (options, servers) => extensionSetup(options, servers) }] + withSetup(setup: SetupFactory) { + this.setups = [{ factory: setup }] + return this + } + + withExtension(extension: Extension) { + this.testFixture = extension.fixture + this.setups = [{ factory: asyncSetup, name: 'async' }] + this.extension.rumConfiguration = extension.rumConfiguration + this.extension.logsConfiguration = extension.logsConfiguration + return this } @@ -157,6 +169,7 @@ class TestBuilder { test_name: '', }, testFixture: this.testFixture, + extension: this.extension, } if (this.alsoRunWithRumSlim) { @@ -203,7 +216,7 @@ function declareTestsForSetups( } function declareTest(title: string, setupOptions: SetupOptions, factory: SetupFactory, runner: TestRunner) { - const testFixture = setupOptions.testFixture + const testFixture = setupOptions.testFixture ?? test testFixture(title, async ({ page, context }) => { const browserName = getBrowserName(test.info().project.name) addTag('test.browserName', browserName) diff --git a/test/e2e/lib/framework/index.ts b/test/e2e/lib/framework/index.ts index dfb8e79529..af62225b15 100644 --- a/test/e2e/lib/framework/index.ts +++ b/test/e2e/lib/framework/index.ts @@ -1,5 +1,6 @@ export { createTest, DEFAULT_RUM_CONFIGURATION, DEFAULT_LOGS_CONFIGURATION } from './createTest' -export { bundleSetup, html, npmSetup, reactSetup } from './pageSetups' +export { createExtension } from './createExtension' +export { bundleSetup, html, npmSetup, reactSetup, formatConfiguration, createCrossOriginScriptUrls } from './pageSetups' export { IntakeRegistry } from './intakeRegistry' export { getTestServers, waitForServersIdle } from './httpServers' export { flushEvents } from './flushEvents' diff --git a/test/e2e/lib/framework/pageSetups.ts b/test/e2e/lib/framework/pageSetups.ts index 2153675b24..fee5b5f6ed 100644 --- a/test/e2e/lib/framework/pageSetups.ts +++ b/test/e2e/lib/framework/pageSetups.ts @@ -20,6 +20,10 @@ export interface SetupOptions { test_name: string } testFixture: typeof test + extension?: { + rumConfiguration?: RumInitConfiguration + logsConfiguration?: LogsInitConfiguration + } } export type SetupFactory = (options: SetupOptions, servers: Servers) => string @@ -46,6 +50,10 @@ export function asyncSetup(options: SetupOptions, servers: Servers) { header += setupEventBridge(servers) } + if (options.extension) { + header += setupExtension(options, servers) + } + function formatSnippet(url: string, globalName: string) { return `(function(h,o,u,n,d) { h=h[d]=h[d]||{q:[],onReady:function(c){h.q.push(c)}} @@ -93,6 +101,10 @@ export function bundleSetup(options: SetupOptions, servers: Servers) { header += setupEventBridge(servers) } + if (options.extension) { + header += setupExtension(options, servers) + } + const { logsScriptUrl, rumScriptUrl } = createCrossOriginScriptUrls(servers, options) if (options.logs) { @@ -129,6 +141,10 @@ export function npmSetup(options: SetupOptions, servers: Servers) { header += setupEventBridge(servers) } + if (options.extension) { + header += setupExtension(options, servers) + } + if (options.logs) { header += html` - ` - } - - body += html` ` - - return basePage({ - header, - body, - }) -} - -export function extensionSetup(options: SetupOptions, servers: Servers) { - let header = options.head || '' - const body = options.body || '' - - if (options.eventBridge) { - header += setupEventBridge(servers) + if (options.extension) { + header += setupExtension(options, servers) } - const { rumScriptUrl, logsScriptUrl } = createCrossOriginScriptUrls(servers, options) - if (options.rum) { header += html` ` } - if (options.logs) { - header += html` - - ` - } + body += html` ` return basePage({ header, @@ -273,7 +257,35 @@ function setupEventBridge(servers: Servers) { ` } -function formatConfiguration(initConfiguration: LogsInitConfiguration | RumInitConfiguration, servers: Servers) { +function setupExtension(options: SetupOptions, servers: Servers) { + let header = '' + + const { rumScriptUrl, logsScriptUrl } = createCrossOriginScriptUrls(servers, { ...options, useRumSlim: false }) + + if (options.extension?.rumConfiguration) { + header += html` + + ` + } + + if (options.extension?.logsConfiguration) { + header += html` + + ` + } + + return header +} + +export function formatConfiguration(initConfiguration: LogsInitConfiguration | RumInitConfiguration, servers: Servers) { const fns = new Map void>() let result = JSON.stringify( @@ -304,7 +316,7 @@ function formatConfiguration(initConfiguration: LogsInitConfiguration | RumInitC return result } -function createCrossOriginScriptUrls(servers: Servers, options: SetupOptions) { +export function createCrossOriginScriptUrls(servers: Servers, options: SetupOptions) { return { logsScriptUrl: `${servers.crossOrigin.url}/datadog-logs.js`, rumScriptUrl: `${servers.crossOrigin.url}/${options.useRumSlim ? 'datadog-rum-slim.js' : 'datadog-rum.js'}`, diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index 200ba31865..35862c7247 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -1,25 +1,15 @@ -import path from 'path' import { test, expect } from '@playwright/test' -import { createTest } from '../../lib/framework' - -// TODO: the recorder is lazy loaded and does not works in an browser extension content script -const DISABLE_SESSION_REPLAY_CONFIGURATION = { sessionReplaySampleRate: 0 } - -const EXTENSIONS = [ - [path.join(__dirname, '../../../../test/apps/base-extension'), 'bundle'], - [path.join(__dirname, '../../../../test/apps/cdn-extension'), 'cdn'], -] as const +import { createTest, createExtension, createCrossOriginScriptUrls, formatConfiguration } from '../../lib/framework' const WARNING_MESSAGE = 'Datadog Browser SDK: Running the Browser SDK in a Web extension content script is discouraged and will be forbidden in a future major release unless the `allowedTrackingOrigins` option is provided.' const ERROR_MESSAGE = 'Datadog Browser SDK: SDK initialized on a non-allowed domain.' test.describe('browser extensions', () => { - for (const [path, name] of EXTENSIONS) { + for (const name of ['base', 'cdn']) { test.describe(`with ${name} extension`, () => { createTest('should warn and start tracking when SDK is initialized in an unsupported environment') - .withExtension(path) - .withRum(DISABLE_SESSION_REPLAY_CONFIGURATION) + .withExtension(createExtension(name).withRum()) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() @@ -36,8 +26,7 @@ test.describe('browser extensions', () => { }) createTest('should start tracking when allowedTrackingOrigins matches current domain') - .withExtension(path) - .withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) + .withExtension(createExtension(name).withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'] })) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() @@ -47,8 +36,7 @@ test.describe('browser extensions', () => { }) createTest('should not start tracking when allowedTrackingOrigins does not match current domain') - .withExtension(path) - .withRum({ allowedTrackingOrigins: ['https://app.example.com'], ...DISABLE_SESSION_REPLAY_CONFIGURATION }) + .withExtension(createExtension(name).withRum({ allowedTrackingOrigins: ['https://app.example.com'] })) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() @@ -65,4 +53,32 @@ test.describe('browser extensions', () => { }) }) } + + /** + * This test is reconstruction of an edge case that happens when using some extension that override `appendChild` and + * the sync installation method using NextJs\'s ` + + ` + }) + .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { + test.fail() // TODO: remove this once the issue is fixed + + await flushEvents() + + expect(intakeRegistry.rumViewEvents).toHaveLength(1) + + withBrowserLogs((logs) => expect(logs.length).toBe(0)) + }) }) From e469c93e73a9218c5265309b988b647d1b7d0086 Mon Sep 17 00:00:00 2001 From: Thomas Lebeau Date: Wed, 10 Sep 2025 08:12:19 +0200 Subject: [PATCH 08/12] =?UTF-8?q?=F0=9F=91=8C=20fix=20dev-extension=20e2e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/e2e/lib/framework/createExtension.ts | 9 ++++----- .../browserExtensions.scenario.ts | 18 +++++++++++++----- .../developerExtension.scenario.ts | 6 ++++-- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/test/e2e/lib/framework/createExtension.ts b/test/e2e/lib/framework/createExtension.ts index b9ec5bc673..fc473bda6e 100644 --- a/test/e2e/lib/framework/createExtension.ts +++ b/test/e2e/lib/framework/createExtension.ts @@ -1,12 +1,11 @@ -import path from 'path' import type { RumInitConfiguration } from '@datadog/browser-rum-core' import type test from '@playwright/test' import type { LogsInitConfiguration } from '@datadog/browser-logs' import { createExtensionTest } from '../helpers/extensionFixture' import { DEFAULT_LOGS_CONFIGURATION, DEFAULT_RUM_CONFIGURATION } from './createTest' -export function createExtension(name: string) { - return new Extension(name) +export function createExtension(path: string) { + return new Extension(path) } // TODO: the recorder is lazy loaded and does not works in an browser extension content script @@ -17,8 +16,8 @@ export class Extension { public rumConfiguration: RumInitConfiguration | undefined public logsConfiguration: LogsInitConfiguration | undefined - constructor(name: string) { - this.fixture = createExtensionTest(path.join(__dirname, '../../../../test/apps/', `${name}-extension`)) + constructor(path: string) { + this.fixture = createExtensionTest(path) return this } diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index 35862c7247..9687724561 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -1,3 +1,4 @@ +import path from 'path' import { test, expect } from '@playwright/test' import { createTest, createExtension, createCrossOriginScriptUrls, formatConfiguration } from '../../lib/framework' @@ -5,11 +6,14 @@ const WARNING_MESSAGE = 'Datadog Browser SDK: Running the Browser SDK in a Web extension content script is discouraged and will be forbidden in a future major release unless the `allowedTrackingOrigins` option is provided.' const ERROR_MESSAGE = 'Datadog Browser SDK: SDK initialized on a non-allowed domain.' +const BASE_PATH = path.join(process.cwd(), 'test/apps') +const EXTENSIONS = ['base-extension', 'cdn-extension'] + test.describe('browser extensions', () => { - for (const name of ['base', 'cdn']) { + for (const name of EXTENSIONS) { test.describe(`with ${name} extension`, () => { createTest('should warn and start tracking when SDK is initialized in an unsupported environment') - .withExtension(createExtension(name).withRum()) + .withExtension(createExtension(path.join(BASE_PATH, name)).withRum()) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() @@ -26,7 +30,9 @@ test.describe('browser extensions', () => { }) createTest('should start tracking when allowedTrackingOrigins matches current domain') - .withExtension(createExtension(name).withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'] })) + .withExtension( + createExtension(path.join(BASE_PATH, name)).withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'] }) + ) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() @@ -36,7 +42,9 @@ test.describe('browser extensions', () => { }) createTest('should not start tracking when allowedTrackingOrigins does not match current domain') - .withExtension(createExtension(name).withRum({ allowedTrackingOrigins: ['https://app.example.com'] })) + .withExtension( + createExtension(path.join(BASE_PATH, name)).withRum({ allowedTrackingOrigins: ['https://app.example.com'] }) + ) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() @@ -59,7 +67,7 @@ test.describe('browser extensions', () => { * the sync installation method using NextJs\'s ` diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index 8a30200073..c4c1ebf488 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -13,25 +13,29 @@ test.describe('browser extensions', () => { for (const name of EXTENSIONS) { test.describe(`with ${name} extension`, () => { createTest('should warn and start tracking when SDK is initialized in an unsupported environment') - .withExtension(createExtension(path.join(BASE_PATH, name)).withRum()) + .withExtension(createExtension(path.join(BASE_PATH, name)).withRum().withLogs()) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() expect(intakeRegistry.rumViewEvents).toHaveLength(1) withBrowserLogs((logs) => { - expect(logs).toContainEqual( - expect.objectContaining({ + // Two warnings, one for RUM and one for LOGS SDK + expect(logs).toHaveLength(2) + logs.forEach((log) => { + expect(log).toMatchObject({ level: 'warning', message: WARNING_MESSAGE, }) - ) + }) }) }) createTest('should start tracking when allowedTrackingOrigins matches current domain') .withExtension( - createExtension(path.join(BASE_PATH, name)).withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'] }) + createExtension(path.join(BASE_PATH, name)) + .withRum({ allowedTrackingOrigins: ['LOCATION_ORIGIN'] }) + .withLogs({ allowedTrackingOrigins: ['LOCATION_ORIGIN'] }) ) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() @@ -53,7 +57,9 @@ test.describe('browser extensions', () => { createTest('should not start tracking when allowedTrackingOrigins does not match current domain') .withExtension( - createExtension(path.join(BASE_PATH, name)).withRum({ allowedTrackingOrigins: ['https://app.example.com'] }) + createExtension(path.join(BASE_PATH, name)) + .withRum({ allowedTrackingOrigins: ['https://app.example.com'] }) + .withLogs({ allowedTrackingOrigins: ['https://app.example.com'] }) ) .run(async ({ withBrowserLogs, flushEvents, intakeRegistry }) => { await flushEvents() @@ -61,12 +67,14 @@ test.describe('browser extensions', () => { expect(intakeRegistry.rumViewEvents).toHaveLength(0) withBrowserLogs((logs) => { - expect(logs).toContainEqual( - expect.objectContaining({ + // Two errors, one for RUM and one for LOGS SDK + expect(logs).toHaveLength(2) + logs.forEach((log) => { + expect(log).toMatchObject({ level: 'error', message: ERROR_MESSAGE, }) - ) + }) }) }) }) @@ -79,13 +87,15 @@ test.describe('browser extensions', () => { createTest('should not warn - edge case simulating NextJs with an extension that override `appendChild`') .withExtension(createExtension(path.join(BASE_PATH, 'appendChild-extension'))) .withRum() + .withLogs() .withSetup((options, servers) => { - const { rumScriptUrl } = createCrossOriginScriptUrls(servers, options) + const { rumScriptUrl, logsScriptUrl } = createCrossOriginScriptUrls(servers, options) return ` + ` From 0395daed155f60de115038b054a5c0cd754cd11d Mon Sep 17 00:00:00 2001 From: Thomas Lebeau Date: Wed, 10 Sep 2025 11:14:40 +0200 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=91=8C=20fix=20npm=20setup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/e2e/lib/framework/index.ts | 1 + .../browserExtensions.scenario.ts | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/test/e2e/lib/framework/index.ts b/test/e2e/lib/framework/index.ts index af62225b15..4b65b4f4bc 100644 --- a/test/e2e/lib/framework/index.ts +++ b/test/e2e/lib/framework/index.ts @@ -7,3 +7,4 @@ export { flushEvents } from './flushEvents' export { waitForRequests } from './waitForRequests' export { LARGE_RESPONSE_MIN_BYTE_SIZE } from './serverApps/mock' export { getSdkBundlePath, getTestAppBundlePath } from './sdkBuilds' +export type { BrowserLog } from '../helpers/browser' diff --git a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts index c4c1ebf488..2ee1a4c33f 100644 --- a/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts +++ b/test/e2e/scenario/browser-extensions/browserExtensions.scenario.ts @@ -1,5 +1,6 @@ import path from 'path' import { test, expect } from '@playwright/test' +import type { BrowserLog } from '../../lib/framework' import { createTest, createExtension, createCrossOriginScriptUrls, formatConfiguration } from '../../lib/framework' const WARNING_MESSAGE = @@ -9,6 +10,11 @@ const ERROR_MESSAGE = 'Datadog Browser SDK: SDK initialized on a non-allowed dom const BASE_PATH = path.join(process.cwd(), 'test/apps') const EXTENSIONS = ['base-extension', 'cdn-extension'] +// NOTE: logs might contain a warning about the SDK being loaded twice when using the npm config +// because the SDK is loaded even though it's not initialized. +// We ignore it here because it's not relevant to the test. +const isNotSdkLoadedMoreThanOnce = (log: BrowserLog) => !log.message.includes('SDK is loaded more than once') + test.describe('browser extensions', () => { for (const name of EXTENSIONS) { test.describe(`with ${name} extension`, () => { @@ -20,9 +26,11 @@ test.describe('browser extensions', () => { expect(intakeRegistry.rumViewEvents).toHaveLength(1) withBrowserLogs((logs) => { + const filteredLogs = logs.filter(isNotSdkLoadedMoreThanOnce) + // Two warnings, one for RUM and one for LOGS SDK - expect(logs).toHaveLength(2) - logs.forEach((log) => { + expect(filteredLogs).toHaveLength(2) + filteredLogs.forEach((log) => { expect(log).toMatchObject({ level: 'warning', message: WARNING_MESSAGE, @@ -43,9 +51,6 @@ test.describe('browser extensions', () => { expect(intakeRegistry.rumViewEvents).toHaveLength(1) withBrowserLogs((logs) => - // NOTE: logs might contain a warning about the SDK being loaded twice when using the npm config - // because the SDK is loaded even though it's not initialized. - // We ignore it here because it's not relevant to the test. expect(logs).not.toContainEqual( expect.objectContaining({ level: 'warning', @@ -67,9 +72,10 @@ test.describe('browser extensions', () => { expect(intakeRegistry.rumViewEvents).toHaveLength(0) withBrowserLogs((logs) => { + const filteredLogs = logs.filter(isNotSdkLoadedMoreThanOnce) // Two errors, one for RUM and one for LOGS SDK - expect(logs).toHaveLength(2) - logs.forEach((log) => { + expect(filteredLogs).toHaveLength(2) + filteredLogs.forEach((log) => { expect(log).toMatchObject({ level: 'error', message: ERROR_MESSAGE,