From b4b2e220b0c0e11fa1ccfb09aa47aef44d93f8d3 Mon Sep 17 00:00:00 2001 From: Fiona Date: Fri, 12 Jun 2026 18:31:28 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20CI=20baseline=20follow-up=20?= =?UTF-8?q?=E2=80=94=20replay=20focus=20misfire,=20BUILD=5FMODE=20leak,=20?= =?UTF-8?q?PATH=20precedence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pageActivationObservable: ignore element-level focus/blur captured at window; only window-targeted events indicate page (de)activation. Fixes spurious view_change full snapshots when moving focus between inputs (broke recorder masking e2e). - ci.yml: scope BUILD_MODE=release to the bundle build step so script tests run in dev mode as their specs expect. - scripts/cli: prepend node_modules/.bin to PATH so repo-pinned tsc wins over globally installed versions on CI runners. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 5 +++-- packages/core/src/browser/pageActivationObservable.ts | 5 +++++ scripts/cli | 3 ++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a20cc5b37b..7a2b3a53d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,8 +90,6 @@ jobs: bundle: name: Bundle and script tests runs-on: ubuntu-latest - env: - BUILD_MODE: release steps: - name: Checkout code uses: actions/checkout@v4 @@ -106,6 +104,9 @@ jobs: - name: Build release bundles run: yarn build:bundle + env: + # scoped to this step only: script tests must run with the default (dev) build mode + BUILD_MODE: release - name: Run script tests run: yarn test:script diff --git a/packages/core/src/browser/pageActivationObservable.ts b/packages/core/src/browser/pageActivationObservable.ts index 06c834ae89..e875642a81 100644 --- a/packages/core/src/browser/pageActivationObservable.ts +++ b/packages/core/src/browser/pageActivationObservable.ts @@ -37,6 +37,11 @@ export function createPageActivationObservable(configuration: Configuration): Ob window, [DOM_EVENT.BLUR, DOM_EVENT.FOCUS, DOM_EVENT.VISIBILITY_CHANGE, DOM_EVENT.PAGE_SHOW], (event) => { + // With capture on window, focus/blur of descendant elements are also received (they don't + // bubble but are captured). Only window-level focus/blur indicate page (de)activation. + if ((event.type === DOM_EVENT.BLUR || event.type === DOM_EVENT.FOCUS) && event.target !== window) { + return + } if (event.type === DOM_EVENT.BLUR) { isInactive = true } else if (event.type === DOM_EVENT.VISIBILITY_CHANGE) { diff --git a/scripts/cli b/scripts/cli index 6b9564e447..aa7ef8b0f9 100755 --- a/scripts/cli +++ b/scripts/cli @@ -2,7 +2,8 @@ set -euo pipefail -PATH="$PATH:node_modules/.bin" +# prepend so the repo-pinned binaries (tsc, eslint, ...) win over any globally installed ones +PATH="node_modules/.bin:$PATH" main () { if [[ $# -lt 1 ]]; then From 0f5b88eb48513b26ec618cbd1cdd2e4805888c7b Mon Sep 17 00:00:00 2001 From: Fiona Date: Fri, 12 Jun 2026 18:38:47 +0800 Subject: [PATCH 2/2] test(e2e): use latest view update per view id in init scenario rumViewEvents[1] is order-dependent: a view emits several update events and custom_timings only appear on later updates, which made the assertion flaky on CI. Resolve views by id and assert on the update with the highest document_version, like the manually-tracked scenario. Co-Authored-By: Claude Fable 5 --- test/e2e/scenario/rum/init.scenario.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/e2e/scenario/rum/init.scenario.ts b/test/e2e/scenario/rum/init.scenario.ts index c3aac7e316..516b7e4391 100644 --- a/test/e2e/scenario/rum/init.scenario.ts +++ b/test/e2e/scenario/rum/init.scenario.ts @@ -38,14 +38,22 @@ test.describe('API calls and events around init', () => { .run(async ({ intakeRegistry, flushEvents }) => { await flushEvents() - const initialView = intakeRegistry.rumViewEvents[0] + // a view can emit several update events; pick the latest one per view as it carries the + // cumulative state (e.g. custom_timings added after the first update) + const latestViewUpdate = (viewId: string) => + intakeRegistry.rumViewEvents + .filter((event) => event.view.id === viewId) + .sort((a, b) => a._dd.document_version - b._dd.document_version) + .at(-1)! + + const initialView = latestViewUpdate(intakeRegistry.rumViewEvents[0].view.id) expect(initialView.view.name).toBeUndefined() expect(initialView.view.custom_timings).toEqual({ before_manual_view: expect.any(Number), }) - const manualView = intakeRegistry.rumViewEvents[1] - expect(manualView.view.name).toBe('manual view') + const manualViewId = intakeRegistry.rumViewEvents.find((event) => event.view.name === 'manual view')!.view.id + const manualView = latestViewUpdate(manualViewId) expect(manualView.view.custom_timings).toEqual({ after_manual_view: expect.any(Number), })