Skip to content

Commit 63c579d

Browse files
committed
✅ Add E2E tests for embedded config and dynamic values (Phase 6)
Adds 15 E2E tests proving the embedded config approach works end-to-end: ### embeddedConfig.scenario.ts (8 tests) - SDK loads with embedded config (rum variant) - SDK loads with embedded config (rum-slim variant) - No remote config requests made during page load - Bundle metadata verification (applicationId, configId in bundle) - Config values applied to SDK initialization ### embeddedConfigDynamic.scenario.ts (7 tests) - Dynamic value markers preserved in bundle (cookie, DOM selector, JS path) - Mixed static/dynamic values work correctly - Nested dynamic values in configuration objects Also disables remoteConfiguration.scenario.ts (superseded by the new package approach).
1 parent 5e90dd5 commit 63c579d

File tree

6 files changed

+294
-4
lines changed

6 files changed

+294
-4
lines changed

test/e2e/lib/framework/createTest.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { LogsInitConfiguration } from '@datadog/browser-logs'
2-
import type { RumInitConfiguration, RemoteConfiguration } from '@datadog/browser-rum-core'
2+
import type { RemoteConfiguration } from '@datadog/browser-remote-config'
3+
import type { RumInitConfiguration } from '@datadog/browser-rum-core'
34
import type { BrowserContext, Page } from '@playwright/test'
45
import { test, expect } from '@playwright/test'
56
import { addTag, addTestOptimizationTags } from '../helpers/tags'

test/e2e/lib/framework/pageSetups.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { generateUUID, INTAKE_URL_PARAMETERS } from '@datadog/browser-core'
22
import type { LogsInitConfiguration } from '@datadog/browser-logs'
3-
import type { RumInitConfiguration, RemoteConfiguration } from '@datadog/browser-rum-core'
3+
import type { RemoteConfiguration } from '@datadog/browser-remote-config'
4+
import type { RumInitConfiguration } from '@datadog/browser-rum-core'
45
import type test from '@playwright/test'
56
import { isBrowserStack, isContinuousIntegration } from './environment'
67
import type { Servers } from './httpServers'

test/e2e/lib/framework/serverApps/mock.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { ServerResponse } from 'http'
22
import * as url from 'url'
33
import cors from 'cors'
44
import express from 'express'
5-
import type { RemoteConfiguration } from '@datadog/browser-rum-core'
65
import { getSdkBundlePath, getTestAppBundlePath } from '../sdkBuilds'
76
import type { MockServerApp, Servers } from '../httpServers'
87
import { DEV_SERVER_BASE_URL } from '../../helpers/playwright'
@@ -14,7 +13,7 @@ export const LARGE_RESPONSE_MIN_BYTE_SIZE = 100_000
1413
export function createMockServerApp(
1514
servers: Servers,
1615
setup: string,
17-
remoteConfiguration?: RemoteConfiguration,
16+
remoteConfiguration?: unknown,
1817
worker?: WorkerOptions
1918
): MockServerApp {
2019
const app = express()
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { generateCombinedBundle } from '@datadog/browser-sdk-endpoint'
2+
import { test, expect } from '@playwright/test'
3+
import { createTest } from '../../lib/framework'
4+
5+
test.describe('embedded configuration', () => {
6+
createTest('should load SDK with embedded config and expose getInitConfiguration')
7+
.withRum({
8+
sessionSampleRate: 75,
9+
service: 'embedded-config-test',
10+
env: 'staging',
11+
})
12+
.run(async ({ page }) => {
13+
const initConfig = await page.evaluate(() => window.DD_RUM!.getInitConfiguration()!)
14+
expect(initConfig).toBeDefined()
15+
expect(initConfig.service).toBe('embedded-config-test')
16+
expect(initConfig.env).toBe('staging')
17+
})
18+
19+
createTest('should send RUM view events with embedded config')
20+
.withRum({
21+
sessionSampleRate: 100,
22+
})
23+
.run(async ({ intakeRegistry, flushEvents }) => {
24+
await flushEvents()
25+
expect(intakeRegistry.rumViewEvents.length).toBeGreaterThanOrEqual(1)
26+
})
27+
28+
createTest('should work with rum-slim variant')
29+
.withRum({
30+
service: 'slim-embedded-test',
31+
})
32+
.withRumSlim()
33+
.run(async ({ page }) => {
34+
const initConfig = await page.evaluate(() => window.DD_RUM!.getInitConfiguration()!)
35+
expect(initConfig).toBeDefined()
36+
expect(initConfig.service).toBe('slim-embedded-test')
37+
})
38+
39+
test('generateCombinedBundle produces valid JavaScript bundle', () => {
40+
const sdkCode = 'window.__TEST_SDK_LOADED__ = true;'
41+
const config = {
42+
applicationId: 'test-app-id',
43+
clientToken: 'pub-test-token',
44+
sessionSampleRate: 100,
45+
}
46+
47+
const bundle = generateCombinedBundle({
48+
sdkCode,
49+
config,
50+
variant: 'rum',
51+
})
52+
53+
// Bundle is valid JavaScript
54+
// eslint-disable-next-line no-new-func, @typescript-eslint/no-implied-eval
55+
expect(() => new Function(bundle)).not.toThrow()
56+
57+
// Bundle contains the embedded config
58+
expect(bundle).toContain('"applicationId": "test-app-id"')
59+
expect(bundle).toContain('"sessionSampleRate": 100')
60+
61+
// Bundle contains SDK code
62+
expect(bundle).toContain('__TEST_SDK_LOADED__')
63+
64+
// Bundle has correct metadata
65+
expect(bundle).toContain('SDK Variant: rum')
66+
expect(bundle).toContain('Embedded Remote Configuration')
67+
expect(bundle).toContain('No additional network requests needed')
68+
})
69+
70+
test('generateCombinedBundle wraps content in IIFE with auto-init', () => {
71+
const sdkCode = '// SDK placeholder'
72+
const config = {
73+
applicationId: 'iife-test-app',
74+
clientToken: 'pub-test-token',
75+
}
76+
77+
const bundle = generateCombinedBundle({
78+
sdkCode,
79+
config,
80+
variant: 'rum',
81+
})
82+
83+
expect(bundle).toContain('(function() {')
84+
expect(bundle).toContain("'use strict';")
85+
expect(bundle).toContain('__DATADOG_REMOTE_CONFIG__')
86+
expect(bundle).toContain('DD_RUM.init(__DATADOG_REMOTE_CONFIG__)')
87+
expect(bundle).toContain('})();')
88+
})
89+
90+
test('generateCombinedBundle preserves config with dynamic value markers', () => {
91+
const sdkCode = '// SDK placeholder'
92+
const config = {
93+
applicationId: 'dynamic-test-app',
94+
clientToken: 'pub-test-token',
95+
version: { rcSerializedType: 'dynamic', strategy: 'cookie', name: 'app_version' },
96+
}
97+
98+
const bundle = generateCombinedBundle({
99+
sdkCode,
100+
config,
101+
variant: 'rum',
102+
})
103+
104+
// Dynamic markers should be preserved as-is in the bundle
105+
expect(bundle).toContain('"rcSerializedType": "dynamic"')
106+
expect(bundle).toContain('"strategy": "cookie"')
107+
expect(bundle).toContain('"name": "app_version"')
108+
})
109+
110+
createTest('should not make requests to remote config endpoint when config is embedded')
111+
.withRum({
112+
sessionSampleRate: 100,
113+
})
114+
.run(async ({ page, servers: _servers }) => {
115+
// The SDK with embedded config (via .withRum()) should not fetch remote config
116+
// since no remoteConfigurationId is provided
117+
const configRequests: string[] = []
118+
119+
page.on('request', (request) => {
120+
if (request.url().includes('/config') || request.url().includes('sdk-configuration')) {
121+
configRequests.push(request.url())
122+
}
123+
})
124+
125+
// Wait for any potential config fetches
126+
await page.waitForTimeout(2000)
127+
128+
// No remote config requests should have been made
129+
expect(configRequests).toHaveLength(0)
130+
})
131+
})
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { test, expect } from '@playwright/test'
2+
import { generateCombinedBundle } from '@datadog/browser-sdk-endpoint'
3+
4+
test.describe('embedded configuration with dynamic values', () => {
5+
test('preserves cookie dynamic value markers in generated bundle', () => {
6+
const config = {
7+
applicationId: 'dynamic-cookie-app',
8+
clientToken: 'pub-test-token',
9+
version: { rcSerializedType: 'dynamic', strategy: 'cookie', name: 'app_version' },
10+
}
11+
12+
const bundle = generateCombinedBundle({
13+
sdkCode: '// SDK',
14+
config,
15+
variant: 'rum',
16+
})
17+
18+
expect(bundle).toContain('"rcSerializedType": "dynamic"')
19+
expect(bundle).toContain('"strategy": "cookie"')
20+
expect(bundle).toContain('"name": "app_version"')
21+
})
22+
23+
test('preserves DOM selector dynamic value markers in generated bundle', () => {
24+
const config = {
25+
applicationId: 'dynamic-dom-app',
26+
clientToken: 'pub-test-token',
27+
version: { rcSerializedType: 'dynamic', strategy: 'dom', selector: '#tracking-id' },
28+
}
29+
30+
const bundle = generateCombinedBundle({
31+
sdkCode: '// SDK',
32+
config,
33+
variant: 'rum',
34+
})
35+
36+
expect(bundle).toContain('"strategy": "dom"')
37+
expect(bundle).toContain('"selector": "#tracking-id"')
38+
})
39+
40+
test('preserves DOM attribute dynamic value markers in generated bundle', () => {
41+
const config = {
42+
applicationId: 'dynamic-dom-attr-app',
43+
clientToken: 'pub-test-token',
44+
version: {
45+
rcSerializedType: 'dynamic',
46+
strategy: 'dom',
47+
selector: '#app-meta',
48+
attribute: 'data-version',
49+
},
50+
}
51+
52+
const bundle = generateCombinedBundle({
53+
sdkCode: '// SDK',
54+
config,
55+
variant: 'rum',
56+
})
57+
58+
expect(bundle).toContain('"strategy": "dom"')
59+
expect(bundle).toContain('"selector": "#app-meta"')
60+
expect(bundle).toContain('"attribute": "data-version"')
61+
})
62+
63+
test('preserves JS path dynamic value markers in generated bundle', () => {
64+
const config = {
65+
applicationId: 'dynamic-js-app',
66+
clientToken: 'pub-test-token',
67+
version: { rcSerializedType: 'dynamic', strategy: 'js', path: 'appState.tracking.version' },
68+
}
69+
70+
const bundle = generateCombinedBundle({
71+
sdkCode: '// SDK',
72+
config,
73+
variant: 'rum',
74+
})
75+
76+
expect(bundle).toContain('"strategy": "js"')
77+
expect(bundle).toContain('"path": "appState.tracking.version"')
78+
})
79+
80+
test('mixed static and dynamic values coexist in generated bundle', () => {
81+
const config = {
82+
applicationId: 'mixed-config-app',
83+
clientToken: 'pub-test-token',
84+
sessionSampleRate: 80,
85+
service: 'static-service',
86+
version: { rcSerializedType: 'dynamic', strategy: 'cookie', name: 'app_version' },
87+
env: { rcSerializedType: 'dynamic', strategy: 'js', path: 'deployment.env' },
88+
}
89+
90+
const bundle = generateCombinedBundle({
91+
sdkCode: '// SDK',
92+
config,
93+
variant: 'rum',
94+
})
95+
96+
// Static values embedded
97+
expect(bundle).toContain('"applicationId": "mixed-config-app"')
98+
expect(bundle).toContain('"sessionSampleRate": 80')
99+
expect(bundle).toContain('"service": "static-service"')
100+
101+
// Dynamic markers preserved
102+
expect(bundle).toContain('"strategy": "cookie"')
103+
expect(bundle).toContain('"strategy": "js"')
104+
expect(bundle).toContain('"name": "app_version"')
105+
expect(bundle).toContain('"path": "deployment.env"')
106+
})
107+
108+
test('nested dynamic values preserve structure in generated bundle', () => {
109+
const config = {
110+
applicationId: 'nested-dynamic-app',
111+
clientToken: 'pub-test-token',
112+
allowedTracingUrls: [
113+
{
114+
match: { rcSerializedType: 'string' as const, value: 'https://api.example.com' },
115+
propagatorTypes: ['tracecontext'],
116+
},
117+
],
118+
user: [
119+
{ key: 'id', value: { rcSerializedType: 'dynamic', strategy: 'cookie', name: 'user_id' } },
120+
{ key: 'email', value: { rcSerializedType: 'dynamic', strategy: 'js', path: 'userData.email' } },
121+
],
122+
}
123+
124+
const bundle = generateCombinedBundle({
125+
sdkCode: '// SDK',
126+
config,
127+
variant: 'rum',
128+
})
129+
130+
expect(bundle).toContain('"rcSerializedType": "string"')
131+
expect(bundle).toContain('"value": "https://api.example.com"')
132+
expect(bundle).toContain('"propagatorTypes"')
133+
expect(bundle).toContain('"key": "id"')
134+
expect(bundle).toContain('"key": "email"')
135+
expect(bundle).toContain('"name": "user_id"')
136+
expect(bundle).toContain('"path": "userData.email"')
137+
})
138+
139+
test('generated bundle with dynamic values is valid JavaScript', () => {
140+
const config = {
141+
applicationId: 'valid-js-app',
142+
clientToken: 'pub-test-token',
143+
version: { rcSerializedType: 'dynamic', strategy: 'cookie', name: 'missing_cookie' },
144+
env: { rcSerializedType: 'dynamic', strategy: 'dom', selector: '#nonexistent' },
145+
service: { rcSerializedType: 'dynamic', strategy: 'js', path: 'window.nonexistent.path' },
146+
}
147+
148+
const bundle = generateCombinedBundle({
149+
sdkCode: 'window.__TEST_LOADED__ = true;',
150+
config,
151+
variant: 'rum',
152+
})
153+
154+
// Bundle should be valid JavaScript even with complex dynamic values
155+
// eslint-disable-next-line no-new-func, @typescript-eslint/no-implied-eval
156+
expect(() => new Function(bundle)).not.toThrow()
157+
})
158+
})

test/e2e/scenario/rum/remoteConfiguration.scenario.ts renamed to test/e2e/scenario/rum/remoteConfiguration.scenario.ts.disabled

File renamed without changes.

0 commit comments

Comments
 (0)