From cd56c6dfbecc5ca153e1dbcd411f820cb27266cb Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 29 Apr 2026 11:48:40 +0200 Subject: [PATCH 1/5] move to ignore spans --- .../browser/src/integrations/spotlight.ts | 25 +++------ .../test/integrations/spotlight.test.ts | 51 +++++++++++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 packages/browser/test/integrations/spotlight.test.ts diff --git a/packages/browser/src/integrations/spotlight.ts b/packages/browser/src/integrations/spotlight.ts index bea72e029a97..4c04b16ed63b 100644 --- a/packages/browser/src/integrations/spotlight.ts +++ b/packages/browser/src/integrations/spotlight.ts @@ -1,4 +1,4 @@ -import type { Client, Envelope, Event, IntegrationFn } from '@sentry/core'; +import type { Client, Envelope, IntegrationFn } from '@sentry/core'; import { debug, defineIntegration, serializeEnvelope } from '@sentry/core'; import { getNativeImplementation } from '@sentry-internal/browser-utils'; import { DEBUG_BUILD } from '../debug-build'; @@ -14,6 +14,8 @@ export type SpotlightConnectionOptions = { export const INTEGRATION_NAME = 'SpotlightBrowser'; +export const SPOTLIGHT_IGNORE_SPANS = [{ op: 'ui.interaction.click', name: '#sentry-spotlight' }]; + const _spotlightIntegration = ((options: Partial = {}) => { const sidecarUrl = options.sidecarUrl || 'http://localhost:8969/stream'; @@ -22,10 +24,10 @@ const _spotlightIntegration = ((options: Partial = { setup: () => { DEBUG_BUILD && debug.log('Using Sidecar URL', sidecarUrl); }, - // We don't want to send interaction transactions/root spans created from - // clicks within Spotlight to Sentry. Neither do we want them to be sent to - // spotlight. - processEvent: event => (isSpotlightInteraction(event) ? null : event), + beforeSetup(client: Client) { + const opts = client.getOptions(); + opts.ignoreSpans = [...(opts.ignoreSpans || []), ...SPOTLIGHT_IGNORE_SPANS]; + }, afterAllSetup: (client: Client) => { setupSidecarForwarding(client, sidecarUrl); }, @@ -73,16 +75,3 @@ function setupSidecarForwarding(client: Client, sidecarUrl: string): void { * Learn more about spotlight at https://spotlightjs.com */ export const spotlightBrowserIntegration = defineIntegration(_spotlightIntegration); - -/** - * Flags if the event is a transaction created from an interaction with the spotlight UI. - */ -export function isSpotlightInteraction(event: Event): boolean { - return Boolean( - event.type === 'transaction' && - event.spans && - event.contexts?.trace && - event.contexts.trace.op === 'ui.action.click' && - event.spans.some(({ description }) => description?.includes('#sentry-spotlight')), - ); -} diff --git a/packages/browser/test/integrations/spotlight.test.ts b/packages/browser/test/integrations/spotlight.test.ts new file mode 100644 index 000000000000..c49a971e3c28 --- /dev/null +++ b/packages/browser/test/integrations/spotlight.test.ts @@ -0,0 +1,51 @@ +import type { Client, ClientOptions } from '@sentry/core'; +import { shouldIgnoreSpan } from '@sentry/core'; +import { describe, expect, it } from 'vitest'; +import { SPOTLIGHT_IGNORE_SPANS, spotlightBrowserIntegration } from '../../src/integrations/spotlight'; + +function makeMockClient(initial: Partial = {}): Client { + const options = { ...initial } as ClientOptions; + return { getOptions: () => options } as Client; +} + +function setupIntegrationAndGetIgnoreSpans(initial: Partial = {}) { + const integration = spotlightBrowserIntegration(); + const client = makeMockClient(initial); + integration.beforeSetup!(client); + return client.getOptions().ignoreSpans!; +} + +describe('spotlightBrowserIntegration', () => { + it('appends spotlight interaction filters to ignoreSpans', () => { + expect(setupIntegrationAndGetIgnoreSpans()).toEqual(SPOTLIGHT_IGNORE_SPANS); + }); + + it('preserves user-provided ignoreSpans entries', () => { + expect(setupIntegrationAndGetIgnoreSpans({ ignoreSpans: [/keep-me/] })).toEqual([ + /keep-me/, + ...SPOTLIGHT_IGNORE_SPANS, + ]); + }); + + describe('drops spotlight interaction spans', () => { + it.each([ + ['click on spotlight overlay', 'body > div#sentry-spotlight > div.overlay'], + ['click on spotlight button', 'body > div > div#sentry-spotlight > button.close'], + ['click on nested spotlight element', 'html > body > aside#sentry-spotlight'], + ])('%s', (_label, name) => { + const ignoreSpans = setupIntegrationAndGetIgnoreSpans(); + expect(shouldIgnoreSpan({ description: name, op: 'ui.interaction.click' }, ignoreSpans)).toBe(true); + }); + }); + + describe('keeps non-spotlight interaction spans', () => { + it.each([ + ['regular click', 'body > div.main > button.submit', 'ui.interaction.click'], + ['regular ui action', '/dashboard', 'ui.action.click'], + ['non-interaction span', 'GET /api/data', 'http.client'], + ])('%s', (_label, name, op) => { + const ignoreSpans = setupIntegrationAndGetIgnoreSpans(); + expect(shouldIgnoreSpan({ description: name, op }, ignoreSpans)).toBe(false); + }); + }); +}); From 032985806669c785409e85d275a7fbeb75bb9257 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 29 Apr 2026 12:13:18 +0200 Subject: [PATCH 2/5] tests --- .../init.js | 18 ++++++ .../subject.js | 12 ++++ .../template.html | 12 ++++ .../test.ts | 57 +++++++++++++++++++ .../spotlight-interaction-filter/init.js | 17 ++++++ .../spotlight-interaction-filter/subject.js | 12 ++++ .../template.html | 12 ++++ .../spotlight-interaction-filter/test.ts | 49 ++++++++++++++++ 8 files changed, 189 insertions(+) create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/init.js create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/template.html create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/init.js create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/template.html create mode 100644 dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/init.js new file mode 100644 index 000000000000..cf9618aeaf23 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/init.js @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [ + Sentry.browserTracingIntegration({ + enableLongTask: false, + _experiments: { + enableInteractions: true, + }, + }), + Sentry.spanStreamingIntegration(), + Sentry.spotlightBrowserIntegration(), + ], + tracesSampleRate: 1, +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/subject.js new file mode 100644 index 000000000000..cae57f7a9167 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/subject.js @@ -0,0 +1,12 @@ +// Block the main thread for 70ms so the PerformanceObserver registers +// a click event entry, which triggers `ui.interaction.click` child spans. +const simulateSlowClick = e => { + const startTime = Date.now(); + while (Date.now() - startTime < 70) { + // + } + e.target.classList.add('clicked'); +}; + +document.querySelector('[data-test-id=spotlight-button]').addEventListener('click', simulateSlowClick); +document.querySelector('[data-test-id=regular-button]').addEventListener('click', simulateSlowClick); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/template.html b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/template.html new file mode 100644 index 000000000000..9348e00e7db7 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/template.html @@ -0,0 +1,12 @@ + + + + + + +
+ +
+ + + diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/test.ts new file mode 100644 index 000000000000..7b341b01c881 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/test.ts @@ -0,0 +1,57 @@ +import { expect } from '@playwright/test'; +import { sentryTest } from '../../../../utils/fixtures'; +import { shouldSkipTracingTest } from '../../../../utils/helpers'; +import { getSpanOp, observeStreamedSpan, waitForStreamedSpan, waitForStreamedSpans } from '../../../../utils/spanUtils'; + +sentryTest( + 'filters ui.interaction.click spans for spotlight elements via ignoreSpans in streaming mode', + async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestUrl({ testDir: __dirname }); + + // Set up an observer that fails if a spotlight interaction span is ever sent + let sawSpotlightInteractionSpan = false; + await observeStreamedSpan(page, span => { + if (getSpanOp(span) === 'ui.interaction.click' && span.name?.includes('#sentry-spotlight')) { + sawSpotlightInteractionSpan = true; + return true; + } + return false; + }); + + await page.goto(url); + + // Wait for pageload to finish before clicking + await waitForStreamedSpan(page, span => getSpanOp(span) === 'pageload'); + + // Click on the spotlight element — its ui.interaction.click child should be filtered + await page.locator('[data-test-id=spotlight-button]').click(); + await page.locator('.clicked[data-test-id=spotlight-button]').isVisible(); + + // Wait for the spotlight click's segment span to arrive + await waitForStreamedSpans(page, spans => + spans.some(span => span.is_segment && getSpanOp(span) === 'ui.action.click'), + ); + + // Click on the regular button — its ui.interaction.click child should be kept + const regularInteractionSpansPromise = waitForStreamedSpans(page, spans => + spans.some(span => getSpanOp(span) === 'ui.interaction.click' && !span.name?.includes('#sentry-spotlight')), + ); + + await page.locator('[data-test-id=regular-button]').click(); + await page.locator('.clicked[data-test-id=regular-button]').isVisible(); + + const regularSpans = await regularInteractionSpansPromise; + const regularInteractionSpan = regularSpans.find( + span => getSpanOp(span) === 'ui.interaction.click' && !span.name?.includes('#sentry-spotlight'), + ); + expect(regularInteractionSpan).toBeDefined(); + expect(regularInteractionSpan!.name).toContain('button'); + + // Verify no spotlight interaction span was ever sent + expect(sawSpotlightInteractionSpan).toBe(false); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/init.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/init.js new file mode 100644 index 000000000000..1125cb73618b --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/init.js @@ -0,0 +1,17 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [ + Sentry.browserTracingIntegration({ + enableLongTask: false, + _experiments: { + enableInteractions: true, + }, + }), + Sentry.spotlightBrowserIntegration(), + ], + tracesSampleRate: 1, +}); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/subject.js new file mode 100644 index 000000000000..cae57f7a9167 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/subject.js @@ -0,0 +1,12 @@ +// Block the main thread for 70ms so the PerformanceObserver registers +// a click event entry, which triggers `ui.interaction.click` child spans. +const simulateSlowClick = e => { + const startTime = Date.now(); + while (Date.now() - startTime < 70) { + // + } + e.target.classList.add('clicked'); +}; + +document.querySelector('[data-test-id=spotlight-button]').addEventListener('click', simulateSlowClick); +document.querySelector('[data-test-id=regular-button]').addEventListener('click', simulateSlowClick); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/template.html b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/template.html new file mode 100644 index 000000000000..9348e00e7db7 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/template.html @@ -0,0 +1,12 @@ + + + + + + +
+ +
+ + + diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts new file mode 100644 index 000000000000..3214031b1bac --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts @@ -0,0 +1,49 @@ +import { expect } from '@playwright/test'; +import type { Event as SentryEvent } from '@sentry/core'; +import { sentryTest } from '../../../../utils/fixtures'; +import { + getFirstSentryEnvelopeRequest, + getMultipleSentryEnvelopeRequests, + shouldSkipTracingTest, +} from '../../../../utils/helpers'; + +sentryTest( + 'filters ui.interaction.click spans for spotlight elements via ignoreSpans', + async ({ getLocalTestUrl, page }) => { + if (shouldSkipTracingTest()) { + sentryTest.skip(); + } + + const url = await getLocalTestUrl({ testDir: __dirname }); + await page.goto(url); + + // Wait for the pageload transaction to complete + await getFirstSentryEnvelopeRequest(page); + + // Click on the spotlight element — interaction span should be filtered + const spotlightEnvelopePromise = getMultipleSentryEnvelopeRequests(page, 1); + await page.locator('[data-test-id=spotlight-button]').click(); + await page.locator('.clicked[data-test-id=spotlight-button]').isVisible(); + const [spotlightTransaction] = await spotlightEnvelopePromise; + + expect(spotlightTransaction.type).toBe('transaction'); + expect(spotlightTransaction.contexts?.trace?.op).toBe('ui.action.click'); + + const spotlightInteractionSpans = spotlightTransaction.spans?.filter(span => span.op === 'ui.interaction.click'); + expect(spotlightInteractionSpans).toHaveLength(0); + + // Click on the regular button — interaction span should be kept + const regularEnvelopePromise = getMultipleSentryEnvelopeRequests(page, 1); + await page.locator('[data-test-id=regular-button]').click(); + await page.locator('.clicked[data-test-id=regular-button]').isVisible(); + const [regularTransaction] = await regularEnvelopePromise; + + expect(regularTransaction.type).toBe('transaction'); + expect(regularTransaction.contexts?.trace?.op).toBe('ui.action.click'); + + const regularInteractionSpans = regularTransaction.spans?.filter(span => span.op === 'ui.interaction.click'); + expect(regularInteractionSpans?.length).toBeGreaterThanOrEqual(1); + expect(regularInteractionSpans![0]!.description).toContain('button'); + expect(regularInteractionSpans![0]!.description).not.toContain('#sentry-spotlight'); + }, +); From 92ae4ac17da58588f1edd46184e71209a7d4bfe7 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 29 Apr 2026 14:56:00 +0200 Subject: [PATCH 3/5] skip cdn tests --- .../spotlight-interaction-filter-streamed/test.ts | 5 +++-- .../spotlight-interaction-filter/test.ts | 4 +++- dev-packages/browser-integration-tests/utils/helpers.ts | 8 ++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/test.ts index 7b341b01c881..e9c27f682272 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter-streamed/test.ts @@ -1,12 +1,13 @@ import { expect } from '@playwright/test'; import { sentryTest } from '../../../../utils/fixtures'; -import { shouldSkipTracingTest } from '../../../../utils/helpers'; +import { shouldSkipCdnBundleTest, shouldSkipTracingTest } from '../../../../utils/helpers'; import { getSpanOp, observeStreamedSpan, waitForStreamedSpan, waitForStreamedSpans } from '../../../../utils/spanUtils'; sentryTest( 'filters ui.interaction.click spans for spotlight elements via ignoreSpans in streaming mode', async ({ getLocalTestUrl, page }) => { - if (shouldSkipTracingTest()) { + // spotlightBrowserIntegration is not available in CDN bundles + if (shouldSkipTracingTest() || shouldSkipCdnBundleTest()) { sentryTest.skip(); } diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts index 3214031b1bac..45ac7fb930e8 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts @@ -4,13 +4,15 @@ import { sentryTest } from '../../../../utils/fixtures'; import { getFirstSentryEnvelopeRequest, getMultipleSentryEnvelopeRequests, + shouldSkipCdnBundleTest, shouldSkipTracingTest, } from '../../../../utils/helpers'; sentryTest( 'filters ui.interaction.click spans for spotlight elements via ignoreSpans', async ({ getLocalTestUrl, page }) => { - if (shouldSkipTracingTest()) { + // spotlightBrowserIntegration is not available in CDN bundles + if (shouldSkipTracingTest() || shouldSkipCdnBundleTest()) { sentryTest.skip(); } diff --git a/dev-packages/browser-integration-tests/utils/helpers.ts b/dev-packages/browser-integration-tests/utils/helpers.ts index ff0398d6b209..91e5339ff550 100644 --- a/dev-packages/browser-integration-tests/utils/helpers.ts +++ b/dev-packages/browser-integration-tests/utils/helpers.ts @@ -421,6 +421,14 @@ export function shouldSkipFeedbackTest(): boolean { * @returns `true` if we should skip the feature flags test */ export function shouldSkipFeatureFlagsTest(): boolean { + return shouldSkipCdnBundleTest(); +} + +/** + * Returns true if we're running in a CDN bundle environment (not ESM/CJS). + * Use this to skip tests for integrations that are only available via npm, not CDN bundles. + */ +export function shouldSkipCdnBundleTest(): boolean { const bundle = process.env.PW_BUNDLE; return bundle != null && !bundle.includes('esm') && !bundle.includes('cjs'); } From 78c09a4fe0665a8085a8c26234289770ea0863e0 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 29 Apr 2026 15:53:58 +0200 Subject: [PATCH 4/5] use different helper --- .../spotlight-interaction-filter/test.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts index 45ac7fb930e8..0f992d5b27cb 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts @@ -1,11 +1,11 @@ import { expect } from '@playwright/test'; -import type { Event as SentryEvent } from '@sentry/core'; +import type { TransactionEvent } from '@sentry/core'; import { sentryTest } from '../../../../utils/fixtures'; import { - getFirstSentryEnvelopeRequest, - getMultipleSentryEnvelopeRequests, + envelopeRequestParser, shouldSkipCdnBundleTest, shouldSkipTracingTest, + waitForTransactionRequest, } from '../../../../utils/helpers'; sentryTest( @@ -20,27 +20,25 @@ sentryTest( await page.goto(url); // Wait for the pageload transaction to complete - await getFirstSentryEnvelopeRequest(page); + await waitForTransactionRequest(page); // Click on the spotlight element — interaction span should be filtered - const spotlightEnvelopePromise = getMultipleSentryEnvelopeRequests(page, 1); + const spotlightTxnPromise = waitForTransactionRequest(page, txn => txn.contexts?.trace?.op === 'ui.action.click'); await page.locator('[data-test-id=spotlight-button]').click(); await page.locator('.clicked[data-test-id=spotlight-button]').isVisible(); - const [spotlightTransaction] = await spotlightEnvelopePromise; + const spotlightTransaction = envelopeRequestParser(await spotlightTxnPromise); - expect(spotlightTransaction.type).toBe('transaction'); expect(spotlightTransaction.contexts?.trace?.op).toBe('ui.action.click'); const spotlightInteractionSpans = spotlightTransaction.spans?.filter(span => span.op === 'ui.interaction.click'); expect(spotlightInteractionSpans).toHaveLength(0); // Click on the regular button — interaction span should be kept - const regularEnvelopePromise = getMultipleSentryEnvelopeRequests(page, 1); + const regularTxnPromise = waitForTransactionRequest(page, txn => txn.contexts?.trace?.op === 'ui.action.click'); await page.locator('[data-test-id=regular-button]').click(); await page.locator('.clicked[data-test-id=regular-button]').isVisible(); - const [regularTransaction] = await regularEnvelopePromise; + const regularTransaction = envelopeRequestParser(await regularTxnPromise); - expect(regularTransaction.type).toBe('transaction'); expect(regularTransaction.contexts?.trace?.op).toBe('ui.action.click'); const regularInteractionSpans = regularTransaction.spans?.filter(span => span.op === 'ui.interaction.click'); From 8015ae29c052a9c7622014d7bc669d3a8860164a Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 29 Apr 2026 16:49:08 +0200 Subject: [PATCH 5/5] fix --- .../spotlight-interaction-filter/test.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts index 0f992d5b27cb..d0480062c10a 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/spotlight-interaction-filter/test.ts @@ -33,14 +33,22 @@ sentryTest( const spotlightInteractionSpans = spotlightTransaction.spans?.filter(span => span.op === 'ui.interaction.click'); expect(spotlightInteractionSpans).toHaveLength(0); - // Click on the regular button — interaction span should be kept - const regularTxnPromise = waitForTransactionRequest(page, txn => txn.contexts?.trace?.op === 'ui.action.click'); + // Let the first idle span fully settle before clicking again + await page.waitForTimeout(1000); + + // Click on the regular button — wait specifically for a transaction that contains + // a ui.interaction.click child span, since the PerformanceObserver may deliver + // the event entry asynchronously + const regularTxnPromise = waitForTransactionRequest( + page, + txn => + txn.contexts?.trace?.op === 'ui.action.click' && + (txn.spans?.some(span => span.op === 'ui.interaction.click') ?? false), + ); await page.locator('[data-test-id=regular-button]').click(); await page.locator('.clicked[data-test-id=regular-button]').isVisible(); const regularTransaction = envelopeRequestParser(await regularTxnPromise); - expect(regularTransaction.contexts?.trace?.op).toBe('ui.action.click'); - const regularInteractionSpans = regularTransaction.spans?.filter(span => span.op === 'ui.interaction.click'); expect(regularInteractionSpans?.length).toBeGreaterThanOrEqual(1); expect(regularInteractionSpans![0]!.description).toContain('button');