@@ -637,6 +637,58 @@ export function collectStreamedSpans(
637637 } ) . then ( ( ) => collected ) ;
638638}
639639
640+ /**
641+ * Accumulate streamed spans until a segment span matches `isSegment`, then resolve with only the
642+ * spans that share that segment's trace.
643+ *
644+ * Spans are buffered per trace before they flush, so spans from an earlier page load can still be
645+ * arriving when a test starts collecting. Scoping to a single trace is what keeps those leftovers
646+ * from ending the wait early or from failing an assertion about the trace under test. Prefer this
647+ * over {@link collectStreamedSpans} whenever a test asserts on the children of one specific request.
648+ *
649+ * `isDone` receives the spans collected so far for that trace and defaults to "the segment span has
650+ * arrived". Pass it when a test needs particular children, since a child can flush before or after
651+ * its segment.
652+ *
653+ * @example
654+ * ```ts
655+ * const spans = await collectStreamedTrace(PROXY_SERVER_NAME, span => span.name === 'GET /redis');
656+ * expect(spans.map(span => span.name)).toContainEqual('redis-set');
657+ * ```
658+ *
659+ * @example
660+ * ```ts
661+ * // Wait for the segment and at least two of its db spans
662+ * const spans = await collectStreamedTrace(
663+ * PROXY_SERVER_NAME,
664+ * span => span.name === 'GET /redis',
665+ * spansOfTrace => spansOfTrace.filter(span => getSpanOp(span) === 'db.query').length >= 2,
666+ * );
667+ * ```
668+ */
669+ export function collectStreamedTrace (
670+ proxyServerName : string ,
671+ isSegment : ( span : SerializedStreamedSpan ) => boolean ,
672+ isDone ?: ( spansOfTrace : SerializedStreamedSpan [ ] ) => boolean ,
673+ ) : Promise < SerializedStreamedSpan [ ] > {
674+ const collected : SerializedStreamedSpan [ ] = [ ] ;
675+ let traceId : string | undefined ;
676+
677+ return waitForStreamedSpans ( proxyServerName , spans => {
678+ collected . push ( ...spans ) ;
679+
680+ // Only the first matching segment counts, so a later page load on the same route cannot move
681+ // the collection to a different trace halfway through.
682+ traceId ??= collected . find ( span => span . is_segment && isSegment ( span ) ) ?. trace_id ;
683+
684+ if ( traceId === undefined ) {
685+ return false ;
686+ }
687+
688+ return isDone ? isDone ( collected . filter ( span => span . trace_id === traceId ) ) : true ;
689+ } ) . then ( ( ) => collected . filter ( span => span . trace_id === traceId ) ) ;
690+ }
691+
640692/**
641693 * Helper to get the span operation from a Span V2 JSON object.
642694 *
0 commit comments