From 7befd42a2b195295c9f90e6789f0773ebb022454 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 21 Oct 2026 13:06:52 +0200 Subject: [PATCH] test(react-router): Match error and segment span by trace in instrumentation API e2e test Streamed spans flush after errors, so the segment span listener could pick up a late span from an earlier test that hit the same route, making the trace id assertion flaky (mostly in dev mode). Co-Authored-By: Claude Opus 5.5 --- .../tests/errors/errors.server.test.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/tests/errors/errors.server.test.ts b/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/tests/errors/errors.server.test.ts index 10cf2e5be8e0..f3a52a0b8e46 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/tests/errors/errors.server.test.ts +++ b/dev-packages/e2e-tests/test-applications/react-router-7-framework-instrumentation/tests/errors/errors.server.test.ts @@ -1,4 +1,5 @@ import { expect, test } from '@playwright/test'; +import type { SerializedStreamedSpan } from '@sentry-internal/test-utils'; import { collectStreamedSpansUntilSegment, getSpanOp, @@ -72,18 +73,25 @@ test.describe('server - instrumentation API error capture', () => { return errorEvent.exception?.values?.[0]?.value === 'Loader error for testing'; }); - const spanPromise = waitForStreamedSpan(APP_NAME, span => { - return span.name === 'GET /performance/error-loader' && span.is_segment; + // Streamed spans flush later than errors, so a segment span from an earlier test hitting the same + // route can still be arriving here. Collect them and look for the one in the error's trace. + const segmentSpans: SerializedStreamedSpan[] = []; + void waitForStreamedSpan(APP_NAME, span => { + if (span.name === 'GET /performance/error-loader' && span.is_segment) { + segmentSpans.push(span); + } + return false; }); await page.goto(`/performance/error-loader`).catch(() => { // Expected to fail due to loader error }); - const [error, span] = await Promise.all([errorPromise, spanPromise]); + const error = await errorPromise; + const traceId = error.contexts?.trace?.trace_id; + expect(traceId).toMatch(/^[a-f0-9]{32}$/); - // Error and segment span should have the same trace_id - expect(error.contexts?.trace?.trace_id).toBe(span.trace_id); + await expect.poll(() => segmentSpans.some(span => span.trace_id === traceId)).toBe(true); }); // Skipped in dev: the action error is sometimes captured via the client instrumentation path