| 1482 | type SpanMatch = Omit<Partial<HierSavedSpan>, 'spans'> & { spans?: SpanMatch[] } |
| 1483 | |
| 1484 | async function expectTrace( |
| 1485 | collector: Collector, |
| 1486 | match: SpanMatch[], |
| 1487 | edgeOnly?: boolean |
| 1488 | ) { |
| 1489 | // Extract expected http.target values from the match to filter out extra spans |
| 1490 | // that may be generated in production mode (e.g., RSC prefetch requests) |
| 1491 | const expectedTargets = new Set( |
| 1492 | match |
| 1493 | .map((m) => m.attributes?.['http.target'] as string | undefined) |
| 1494 | .filter(Boolean) |
| 1495 | ) |
| 1496 | |
| 1497 | await check(async () => { |
| 1498 | const traces = collector.getSpans() |
| 1499 | |
| 1500 | const tree: HierSavedSpan[] = [] |
| 1501 | const spansForTree: HierSavedSpan[] = traces.map((span) => ({ |
| 1502 | ...span, |
| 1503 | spans: [], |
| 1504 | })) |
| 1505 | for (const span of spansForTree) { |
| 1506 | // for edge runtime with `next start` the nodejs runtime spans |
| 1507 | // will not be updated as the sandbox can't update spans across |
| 1508 | // node -> edge boundary, these spans also are not present when |
| 1509 | // deployed as next-server is not invoking edge functions there |
| 1510 | if (span.runtime === 'nodejs' && edgeOnly) { |
| 1511 | continue |
| 1512 | } |
| 1513 | |
| 1514 | const parent = |
| 1515 | !span.parentId || span.parentId === EXTERNAL.spanId |
| 1516 | ? null |
| 1517 | : spansForTree.find((s) => s.id === span.parentId) |
| 1518 | if (parent) { |
| 1519 | parent.spans.push(span) |
| 1520 | } else { |
| 1521 | tree.push(span) |
| 1522 | } |
| 1523 | } |
| 1524 | for (const span of spansForTree) { |
| 1525 | delete span.duration |
| 1526 | delete span.timestamp |
| 1527 | |
| 1528 | span.traceId = |
| 1529 | span.traceId === EXTERNAL.traceId ? span.traceId : '[trace-id]' |
| 1530 | span.parentId = span.parentId || undefined |
| 1531 | |
| 1532 | span.spans.sort((a, b) => { |
| 1533 | const nameDiff = a.name.localeCompare(b.name) |
| 1534 | if (nameDiff !== 0) { |
| 1535 | return nameDiff |
| 1536 | } |
| 1537 | const segmentDiff = |
| 1538 | (a.attributes?.['next.segment'] ?? '').localeCompare( |
| 1539 | b.attributes?.['next.segment'] ?? '' |
| 1540 | ) ?? 0 |
| 1541 | if (segmentDiff !== 0) { |