Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
variables:
CURRENT_STAGING: staging-20
APP: 'browser-sdk'
CURRENT_CI_IMAGE: 107
CURRENT_CI_IMAGE: 108
BUILD_STABLE_REGISTRY: 'registry.ddbuild.io'
CI_IMAGE: '$BUILD_STABLE_REGISTRY/ci/$APP:$CURRENT_CI_IMAGE'
GIT_REPOSITORY: 'git@github.com:DataDog/browser-sdk.git'
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"devDependencies": {
"@eslint/js": "9.39.4",
"@jsdevtools/coverage-istanbul-loader": "3.0.5",
"@playwright/test": "1.58.2",
"@playwright/test": "1.59.1",
"@swc/core": "1.15.33",
"@types/busboy": "1.5.4",
"@types/chrome": "0.1.40",
Expand Down
15 changes: 11 additions & 4 deletions packages/rum-core/src/domain/resource/resourceCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,19 @@ export function startResourceCollection(lifeCycle: LifeCycle, configuration: Rum
// (notably on Firefox), so the matching REQUEST_COMPLETED isn't in the registry yet.
// Defer the lookup to give the request time to land before we look it up.
//
// Publish synchronously after the delay rather than via the task queue: the queue's
// requestIdleCallback can fire after the click action's PAGE_ACTIVITY_END_DELAY window
// (notably on newer Chromium scheduling), leaving the request uncounted by its parent
// action.
//
// Note: we could clear the timeout on stop(), but this requires a bit of bookkeeping that
// is not necessary right now. We could reevaluate in the future.
setTimeout(
() => handleResource(() => assembleResource(entry, requestRegistry.getMatchingRequest(entry), configuration)),
REQUEST_MATCHING_DELAY
)
setTimeout(() => {
const rawEvent = assembleResource(entry, requestRegistry.getMatchingRequest(entry), configuration)
if (rawEvent) {
lifeCycle.notify(LifeCycleEventType.RAW_RUM_EVENT_COLLECTED, rawEvent)
}
}, REQUEST_MATCHING_DELAY)
} else {
handleResource(() => assembleResource(entry, undefined, configuration))
}
Expand Down
56 changes: 47 additions & 9 deletions test/e2e/scripts/pinnedProxy.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// WebSocket translation proxy that lets a recent @playwright/test client (1.58) drive an
// WebSocket translation proxy that lets a recent @playwright/test client (1.59) drive an
// older `playwright run-server` (1.40). Two layers of translation:
//
// 1) HTTP upgrade — the 1.40 server's User-Agent version check rejects mismatched clients
// with HTTP 428. We rewrite the upgrade request's User-Agent so the check passes.
//
// 2) JSON-RPC — once connected, the 1.58 client validates server messages strictly and
// sends commands using the 1.58 schema. We patch __create__ initializers (server→client)
// 2) JSON-RPC — once connected, the recent client validates server messages strictly and
// sends commands using the recent schema. We patch __create__ initializers (server→client)
// and command parameters (client→server) where the schemas diverge between versions.
//
// Patches were derived from a diff of packages/protocol/src/protocol.yml between v1.40.1
// and v1.58.2 — only the divergences exercised by this repo's e2e tests are translated.
// and v1.59.1 — only the divergences exercised by this repo's e2e tests are translated.
//
// Usage: node pinnedProxy.ts --listen 5400 --upstream 127.0.0.1:5401

Expand Down Expand Up @@ -98,7 +98,9 @@ httpServer.on('upgrade', (req, socket, head) => {
if (rewritten === null) {
return
}
clientWs.send(rewritten)
for (const out of rewritten) {
clientWs.send(out)
}
})

const closeBoth = () => {
Expand Down Expand Up @@ -142,13 +144,27 @@ function forwardHeader(headers: http.IncomingHttpHeaders, name: string): Record<
return typeof value === 'string' ? { [name]: value } : {}
}

// Server (1.40) -> Client (1.58)
function rewriteServerToClient(text: string, guidTypes: Map<string, string>): string | null {
// Server (1.40) -> Client (1.58). Returns one or more messages to forward to the client, or
// null to drop the upstream message. Returning multiple messages allows synthesising channels
// that newer client schemas require but the older server doesn't emit (e.g. Debugger).
function rewriteServerToClient(text: string, guidTypes: Map<string, string>): string[] | null {
let msg: JsonRpcMessage
try {
msg = JSON.parse(text) as JsonRpcMessage
} catch {
return text
return [text]
}
// BrowserContextConsoleEvent requires `timestamp` (tFloat, ms since epoch) in 1.59. The 1.40
// server emits `console` without that field — inject a best-effort wall time.
if (
msg.method === 'console' &&
msg.params &&
msg.params.timestamp === undefined &&
msg.guid !== undefined &&
guidTypes.get(msg.guid) === 'BrowserContext'
) {
msg.params.timestamp = Date.now()
return [JSON.stringify(msg)]
}
if (msg.method === '__create__' && msg.params) {
const type = msg.params.type
Expand All @@ -171,9 +187,31 @@ function rewriteServerToClient(text: string, guidTypes: Map<string, string>): st
if (type === 'Request' && init.hasResponse === undefined) {
init.hasResponse = false
}
// BrowserInitializer requires `browserName` in 1.59. In 1.40 the `name` field already
// held the browser type ("chromium" | "firefox" | "webkit"), so copy it over.
if (type === 'Browser' && init.browserName === undefined && typeof init.name === 'string') {
init.browserName = init.name
}
// BrowserContextInitializer requires a `debugger` Debugger channel in 1.59. The 1.40 server
// has no Debugger channel, so synthesise one (parented to the same Browser as the context)
// and inject the reference. DebuggerInitializer is `{}` in 1.59, so an empty initializer is
// valid. The client only uses BrowserContext.debugger when debug controller features are
// requested, which our tests don't do.
if (type === 'BrowserContext' && init.debugger === undefined && msg.params.guid) {
const debuggerGuid = `debugger@synthetic-${msg.params.guid}`
guidTypes.set(debuggerGuid, 'Debugger')
const debuggerCreate = {
guid: msg.guid,
method: '__create__',
params: { type: 'Debugger', initializer: {}, guid: debuggerGuid },
}
init.debugger = { guid: debuggerGuid }
msg.params.initializer = init
return [JSON.stringify(debuggerCreate), JSON.stringify(msg)]
}
msg.params.initializer = init
}
return JSON.stringify(msg)
return [JSON.stringify(msg)]
}

// Client (1.58) -> Server (1.40)
Expand Down
30 changes: 15 additions & 15 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1697,14 +1697,14 @@ __metadata:
languageName: node
linkType: hard

"@playwright/test@npm:1.58.2":
version: 1.58.2
resolution: "@playwright/test@npm:1.58.2"
"@playwright/test@npm:1.59.1":
version: 1.59.1
resolution: "@playwright/test@npm:1.59.1"
dependencies:
playwright: "npm:1.58.2"
playwright: "npm:1.59.1"
bin:
playwright: cli.js
checksum: 10c0/2164c03ad97c3653ff02e8818a71f3b2bbc344ac07924c9d8e31cd57505d6d37596015a41f51396b3ed8de6840f59143eaa9c21bf65515963da20740119811da
checksum: 10c0/8c2d94a860d3c254a0b114df2f888ad0a0e9310f45b6059bd5d4da196d965cadf6922267cef0881cfa9784d4bef6d78363d2c2d94caa64be67ff644c41162137
languageName: node
linkType: hard

Expand Down Expand Up @@ -3835,7 +3835,7 @@ __metadata:
dependencies:
"@eslint/js": "npm:9.39.4"
"@jsdevtools/coverage-istanbul-loader": "npm:3.0.5"
"@playwright/test": "npm:1.58.2"
"@playwright/test": "npm:1.59.1"
"@swc/core": "npm:1.15.33"
"@types/busboy": "npm:1.5.4"
"@types/chrome": "npm:0.1.40"
Expand Down Expand Up @@ -9497,27 +9497,27 @@ __metadata:
languageName: node
linkType: hard

"playwright-core@npm:1.58.2":
version: 1.58.2
resolution: "playwright-core@npm:1.58.2"
"playwright-core@npm:1.59.1":
version: 1.59.1
resolution: "playwright-core@npm:1.59.1"
bin:
playwright-core: cli.js
checksum: 10c0/5aa15b2b764e6ffe738293a09081a6f7023847a0dbf4cd05fe10eed2e25450d321baf7482f938f2d2eb330291e197fa23e57b29a5b552b89927ceb791266225b
checksum: 10c0/d41a74d9681ce3beb3d5239e9ed577710b4ad099a6ca2476219c6599d51e9cb4b80bd72ed82c528da6a5d929c18ae3b872cf02bb83f78fa1c2cb9199c501abee
languageName: node
linkType: hard

"playwright@npm:1.58.2":
version: 1.58.2
resolution: "playwright@npm:1.58.2"
"playwright@npm:1.59.1":
version: 1.59.1
resolution: "playwright@npm:1.59.1"
dependencies:
fsevents: "npm:2.3.2"
playwright-core: "npm:1.58.2"
playwright-core: "npm:1.59.1"
dependenciesMeta:
fsevents:
optional: true
bin:
playwright: cli.js
checksum: 10c0/d060d9b7cc124bd8b5dffebaab5e84f6b34654a553758fe7b19cc598dfbee93f6ecfbdc1832b40a6380ae04eade86ef3285ba03aa0b136799e83402246dc0727
checksum: 10c0/dfe38396e616e5c4f98825ce90037bb96e477c5a2bd9258a24854f8ce72a8a41427b19098863866f85aa0216e70287dd537c4438d761aca93995e31ae099c533
languageName: node
linkType: hard

Expand Down
Loading