@@ -75,44 +75,42 @@ test('Sends a loader span to Sentry', async ({ page }) => {
7575} ) ;
7676
7777test ( 'Propagates the trace when the ErrorBoundary is triggered' , async ( { page } ) => {
78- // Streamed spans are buffered before they flush, so spans from an earlier page load can still be
79- // arriving here.
80- const streamedSpans : SerializedStreamedSpan [ ] = [ ] ;
81- void waitForStreamedSpans ( APP_NAME , spans => {
82- streamedSpans . push ( ...spans ) ;
83- return false ;
84- } ) ;
85-
8678 // The ErrorBoundary replaces the document, so there is no `sentry-trace` meta tag to read this
87- // page load's trace off. A unique path identifies its server segment instead.
88- const id = crypto . randomUUID ( ) ;
89- await page . goto ( `/error-boundary-capture/${ id } ` ) ;
79+ // page load's trace off. A unique path identifies all three of its spans instead, which lets each
80+ // one be awaited on its own rather than selected out of an accumulated trace.
81+ const path = `/error-boundary-capture/${ crypto . randomUUID ( ) } ` ;
82+ const hasPath = ( span : SerializedStreamedSpan ) : boolean => span . attributes [ 'url.path' ] ?. value === path ;
83+
84+ const serverSegmentSpanPromise = waitForStreamedSpan (
85+ APP_NAME ,
86+ span => getSpanOp ( span ) === 'http.server' && span . is_segment && hasPath ( span ) ,
87+ ) ;
88+ // Remix renders the document from inside the root loader, so that is the span the client
89+ // continues the trace from.
90+ const loaderSpanPromise = waitForStreamedSpan (
91+ APP_NAME ,
92+ span => isDataFunction ( 'loader' , 'root' ) ( span ) && hasPath ( span ) ,
93+ ) ;
94+ const pageloadSpanPromise = waitForStreamedSpan (
95+ APP_NAME ,
96+ span => getSpanOp ( span ) === 'pageload' && span . is_segment && hasPath ( span ) ,
97+ ) ;
98+
99+ await page . goto ( path ) ;
90100 await expect ( page . locator ( '#event-id' ) ) . not . toBeEmpty ( ) ;
91101
92- const findServerSegmentSpan = ( ) =>
93- streamedSpans . find (
94- span =>
95- getSpanOp ( span ) === 'http.server' &&
96- span . is_segment &&
97- span . attributes [ 'url.path' ] ?. value === `/error-boundary-capture/${ id } ` ,
98- ) ;
99- await expect . poll ( findServerSegmentSpan ) . toBeDefined ( ) ;
100- const serverSegmentSpan = findServerSegmentSpan ( ) ! ;
102+ const serverSegmentSpan = await serverSegmentSpanPromise ;
103+ const loaderSpan = await loaderSpanPromise ;
104+ const pageloadSpan = await pageloadSpanPromise ;
105+
101106 expect ( serverSegmentSpan . name ) . toBe ( 'GET error-boundary-capture/:id' ) ;
107+ expect ( pageloadSpan . name ) . toBe ( '/error-boundary-capture/:id' ) ;
102108
103109 // The client continues the server trace, so its pageload span hangs off the root loader span.
104- const findPageloadSpan = ( ) =>
105- streamedSpans . find (
106- span => getSpanOp ( span ) === 'pageload' && span . is_segment && span . trace_id === serverSegmentSpan . trace_id ,
107- ) ;
108- await expect . poll ( findPageloadSpan ) . toBeDefined ( ) ;
109- const pageloadSpan = findPageloadSpan ( ) ! ;
110- expect ( pageloadSpan . name ) . toBe ( '/error-boundary-capture/:id' ) ;
110+ expect ( loaderSpan . parent_span_id ) . toBe ( serverSegmentSpan . span_id ) ;
111+ expect ( pageloadSpan . parent_span_id ) . toBe ( loaderSpan . span_id ) ;
112+ expect ( pageloadSpan . trace_id ) . toBe ( serverSegmentSpan . trace_id ) ;
111113 expect ( pageloadSpan . span_id ) . not . toBe ( serverSegmentSpan . span_id ) ;
112-
113- const findLoaderSpan = ( ) => streamedSpans . find ( span => span . span_id === pageloadSpan . parent_span_id ) ;
114- await expect . poll ( findLoaderSpan ) . toBeDefined ( ) ;
115- expect ( findLoaderSpan ( ) ! . attributes [ 'code.function.name' ] ?. value ) . toBe ( 'loader' ) ;
116114} ) ;
117115
118116test ( 'Parameterizes a 2-level nested route on the server' , async ( { page } ) => {
0 commit comments