Skip to content

Commit bb0cc94

Browse files
Use test RUM proxy config
1 parent 2e89087 commit bb0cc94

8 files changed

Lines changed: 40 additions & 43 deletions

File tree

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
# BROWSERSTACK CREDENTIALS
22
BS_USERNAME=xxx
33
BS_ACCESS_KEY=xxx
4+
5+
# Salesforce credentials
6+
SF_LWC_CLIENT_ID=xxx
7+
SF_LWC_USERNAME=xxx
8+
SF_LWC_INSTANCE_URL=xxx
9+
SF_LWC_JWT_PRIVATE_KEY_B64=xxx

scripts/lib/secrets.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ export function getSfLwcInstanceUrl(): string {
101101
}
102102

103103
export function getSfLwcJwtPrivateKey(): string {
104-
const key = process.env.SF_LWC_JWT_PRIVATE_KEY_B64 ?? getSecretKey('ci.browser-sdk.sf_lwc_jwt_private_key_b64')
105-
return Buffer.from(key, 'base64').toString('utf8')
104+
return process.env.SF_LWC_JWT_PRIVATE_KEY_B64 ?? getSecretKey('ci.browser-sdk.sf_lwc_jwt_private_key_b64')
106105
}
107106

108107
function getSecretKey(name: string): string {

scripts/salesforce-lwc-app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function authenticate() {
3939
const keyPath = resolve(keyDirectory, 'server.key')
4040

4141
try {
42-
writeFileSync(keyPath, getSfLwcJwtPrivateKey(), { mode: 0o600 })
42+
writeFileSync(keyPath, Buffer.from(getSfLwcJwtPrivateKey(), 'base64').toString('utf8'), { mode: 0o600 })
4343
chmodSync(keyPath, 0o600)
4444

4545
printLog(`Authenticating Salesforce CLI alias ${defaultTargetOrg}...`)
@@ -126,6 +126,7 @@ function assignPermissionSet(targetOrg: string, permSetName: string) {
126126

127127
function buildOpenUrl(): string {
128128
const targetOrg = getTargetOrg()
129+
const proxy = process.env.DD_SALESFORCE_E2E_PROXY
129130
const path = new URL(salesforceHomePath, 'https://salesforce.local')
130131

131132
path.searchParams.set(
@@ -144,6 +145,7 @@ function buildOpenUrl(): string {
144145
telemetryConfigurationSampleRate: 100,
145146
service: 'browser-sdk-salesforce-e2e',
146147
env: 'e2e',
148+
...(proxy ? { proxy } : {}),
147149
})
148150
)
149151

test/e2e/lib/framework/createTest.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import type { Servers } from './httpServers'
2929
import { getTestServers, waitForServersIdle } from './httpServers'
3030
import type { CallerLocation, EventBridgeOptions, SetupFactory, SetupOptions, UrlHook } from './pageSetups'
3131
import { html, DEFAULT_SETUPS, npmSetup, appSetup, formatConfiguration } from './pageSetups'
32-
import { computeIntakeRequestInfos, readIntakeRequest } from './intakeProxyMiddleware'
3332
import { createDatadogHttpApi } from './serverApps/datadogHttpApi'
3433
import type { DatadogHttpApiControl } from './serverApps/datadogHttpApi'
3534
import { createMockServerApp } from './serverApps/mock'
@@ -275,8 +274,8 @@ class TestBuilder {
275274
withSalesforceApp() {
276275
this.salesforceApp = true
277276
this.setups = [{ factory: () => '' }]
278-
this.baseUrlHooks.push((baseUrl) => {
279-
baseUrl.href = buildSalesforceLwcUrl()
277+
this.baseUrlHooks.push((baseUrl, servers) => {
278+
baseUrl.href = buildSalesforceLwcUrl(servers.datadogHttpApi.origin)
280279
})
281280
return this
282281
}
@@ -464,14 +463,6 @@ function declareTest(title: string, setupOptions: SetupOptions, factory: SetupFa
464463
contentType: 'application/javascript',
465464
})
466465
})
467-
// Because of CSP, we need to intercept the intake request and push it to the intake registry
468-
await page.route('*/**/api/v2/rum**', async (route) => {
469-
const request = route.request()
470-
const infos = computeIntakeRequestInfos(request)
471-
const intakeRequest = await readIntakeRequest(request, infos)
472-
intakeRegistry.push(intakeRequest)
473-
await route.fulfill({ status: 202 })
474-
})
475466
}
476467

477468
await setUpTest(browserLogs, setupOptions, testContext)

test/e2e/lib/framework/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ export type { DatadogHttpApiControl } from './serverApps/datadogHttpApi'
2222
export type { DebuggerHttpApiControl, DebuggerProbeResponse } from './serverApps/debuggerHttpApi'
2323
export { flushEvents } from './flushEvents'
2424
export { waitForRequests } from './waitForRequests'
25-
export { computeIntakeRequestInfos, readIntakeRequest } from './intakeProxyMiddleware'
26-
export type { IncomingRequest } from './intakeProxyMiddleware'
2725
export { LARGE_RESPONSE_MIN_BYTE_SIZE } from './serverApps/mock'
2826
export { getSdkBundlePath, getTestAppBundlePath } from './sdkBuilds'
2927
export type { BrowserLog } from '../helpers/browser'

test/e2e/lib/framework/intakeProxyMiddleware.ts

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
import { createInflate, inflateSync } from 'node:zlib'
22
import https from 'node:https'
33
import type express from 'express'
4-
import type { Request as PlaywrightRequest } from '@playwright/test'
54
import createBusboy from 'busboy'
65
import type { BrowserProfileEvent, BrowserProfilerTrace } from '@datadog/browser-rum/src/types/profiling'
76
import type { BrowserSegment, BrowserSegmentMetadata } from '@datadog/browser-rum/src/types/sessionReplay'
87
import type { LogsEvent } from '@datadog/browser-logs/src/logsEvent.types'
98
import type { RumEvent } from '@datadog/browser-rum-core/src/rumEvent.types'
109
import type { TelemetryEvent } from '@datadog/browser-core/src/domain/telemetry/telemetryEvent.types'
1110

12-
export type IncomingRequest = express.Request | PlaywrightRequest
13-
14-
function isPlaywrightRequest(req: IncomingRequest): req is PlaywrightRequest {
15-
return typeof (req as { url: unknown }).url === 'function'
16-
}
17-
1811
interface BaseIntakeRequest {
1912
isBridge: boolean
2013
encoding: string | null
@@ -100,24 +93,19 @@ export function createIntakeProxyMiddleware(options: IntakeProxyOptions): expres
10093
}
10194
}
10295

103-
export function computeIntakeRequestInfos(req: IncomingRequest): IntakeRequestInfos {
104-
let intakeUrl: URL
105-
if (isPlaywrightRequest(req)) {
106-
intakeUrl = new URL(req.url(), 'https://example.org')
107-
} else if (typeof req.query.ddforward === 'string') {
108-
intakeUrl = new URL(req.query.ddforward, 'https://example.org')
109-
} else {
110-
intakeUrl = new URL(req.url, 'https://example.org')
96+
function computeIntakeRequestInfos(req: express.Request): IntakeRequestInfos {
97+
const ddforward = req.query.ddforward as string | undefined
98+
if (!ddforward) {
99+
throw new Error('ddforward is missing')
111100
}
101+
const { pathname, searchParams } = new URL(ddforward, 'https://example.org')
112102

113-
const { pathname, searchParams } = intakeUrl
114-
const headers = isPlaywrightRequest(req) ? req.headers() : req.headers
115-
const encoding = headers['content-encoding'] || searchParams.get('dd-evp-encoding')
103+
const encoding = req.headers['content-encoding'] || searchParams.get('dd-evp-encoding')
116104
const transport = searchParams.get('_dd.api')
117105
const batchTimeRaw = searchParams.get('batch_time')
118106
const batchTime = batchTimeRaw ? Number(batchTimeRaw) : null
119107

120-
if (!isPlaywrightRequest(req) && req.query.bridge === 'true') {
108+
if (req.query.bridge === 'true') {
121109
const eventType = req.query.event_type
122110
return {
123111
isBridge: true,
@@ -152,21 +140,21 @@ export function computeIntakeRequestInfos(req: IncomingRequest): IntakeRequestIn
152140
}
153141
}
154142

155-
export function readIntakeRequest(req: IncomingRequest, infos: IntakeRequestInfos): Promise<IntakeRequest> {
143+
function readIntakeRequest(req: express.Request, infos: IntakeRequestInfos): Promise<IntakeRequest> {
156144
if (infos.intakeType === 'replay') {
157-
return readReplayIntakeRequest(req as express.Request, infos as IntakeRequestInfos & { intakeType: 'replay' })
145+
return readReplayIntakeRequest(req, infos as IntakeRequestInfos & { intakeType: 'replay' })
158146
}
159147
if (infos.intakeType === 'profile') {
160-
return readProfileIntakeRequest(req as express.Request, infos as IntakeRequestInfos & { intakeType: 'profile' })
148+
return readProfileIntakeRequest(req, infos as IntakeRequestInfos & { intakeType: 'profile' })
161149
}
162150
return readEventIntakeRequest(req, infos as IntakeRequestInfos & { intakeType: 'rum' | 'logs' | 'debugger' })
163151
}
164152

165153
async function readEventIntakeRequest(
166-
req: IncomingRequest,
154+
req: express.Request,
167155
infos: IntakeRequestInfos & { intakeType: 'rum' | 'logs' | 'debugger' }
168156
): Promise<RumIntakeRequest | LogsIntakeRequest | DebuggerIntakeRequest> {
169-
const rawBody = isPlaywrightRequest(req) ? req.postDataBuffer()! : await readStream(req)
157+
const rawBody = await readStream(req)
170158
const encodedBody = infos.encoding === 'deflate' ? inflateSync(rawBody) : rawBody
171159

172160
return {

test/e2e/lib/helpers/salesforceApp.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ export function getSalesforceConfig(): { targetOrg: string; isConfigured: boolea
1818
return { targetOrg, isConfigured }
1919
}
2020

21-
export function buildSalesforceLwcUrl(): string {
21+
export function buildSalesforceLwcUrl(proxy: string): string {
2222
const result = spawnSync('node', ['scripts/salesforce-lwc-app.ts', 'open-url'], {
2323
encoding: 'utf8',
2424
cwd: repositoryRoot,
25+
env: { ...process.env, DD_SALESFORCE_E2E_PROXY: proxy },
2526
})
2627

2728
if (result.status !== 0) {

test/e2e/scenario/salesforce/salesforceLwc.scenario.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ import { expect, test } from '@playwright/test'
22
import { createTest } from '../../lib/framework'
33
import { getSalesforceConfig } from '../../lib/helpers/salesforceApp'
44

5+
test.use({
6+
bypassCSP: true,
7+
launchOptions: {
8+
args: ['--disable-web-security'],
9+
},
10+
})
11+
512
const { targetOrg, isConfigured } = getSalesforceConfig()
613
test.skip(
714
!isConfigured,
@@ -10,7 +17,7 @@ test.skip(
1017

1118
createTest('salesforce')
1219
.withSalesforceApp()
13-
.run(async ({ page, intakeRegistry, flushEvents }) => {
20+
.run(async ({ page, intakeRegistry, flushEvents, withBrowserLogs }) => {
1421
await expect(page.getByTestId('home-custom-actions')).toBeVisible()
1522

1623
await page.getByTestId('custom-action-1').click()
@@ -21,7 +28,7 @@ createTest('salesforce')
2128

2229
// Verify that the initial view event is present.
2330
expect(intakeRegistry.rumViewEvents.length).toBeGreaterThanOrEqual(1)
24-
const homeView = intakeRegistry.rumViewEvents.find((e) => e.view.name?.includes('/lightning/page/home') === true)
31+
const homeView = intakeRegistry.rumViewEvents.find((e) => e.view.name?.includes('/page/home') === true)
2532
expect(homeView).toBeDefined()
2633
expect(homeView?.view.loading_type).toBe('initial_load')
2734

@@ -38,4 +45,9 @@ createTest('salesforce')
3845
)
3946
expect(productExplorerView).toBeDefined()
4047
expect(productExplorerView?.view.loading_type).toBe('route_change')
48+
49+
// Salesforce's own app generates console errors we cannot control because of Dev Mode configuration in the application
50+
// Clear them so the generic teardown check doesn't fail on noise unrelated to the SDK.
51+
// eslint-disable-next-line @typescript-eslint/no-empty-function
52+
withBrowserLogs(() => {})
4153
})

0 commit comments

Comments
 (0)