Skip to content

E2E: restore scope isolation coverage on spans under span streaming #23941

Description

@chargome

Porting the Next.js E2E suites to span streaming (#23802) dropped every isolation-scope assertion that was made against trace data, because span v2 has no equivalent for it. We should decide how to test scope isolation on spans and restore the coverage.

Why the coverage was lost

The suites asserted isolation scope by setting a tag in a request handler and checking it on the transaction:

expect(transaction.tags?.['my-isolated-tag']).toBe(true);
expect(transaction.tags?.['my-global-scope-isolated-tag']).not.toBeDefined();

Nothing maps scope tags (or extra) onto a streamed span. applyScopeToSegmentSpan in packages/core/src/tracing/spans/captureSpan.ts only calls scopeContextsToSpanAttributes, which converts contexts (react.version, culture.locale, response status, cloud resource, profile ids). The processSegmentSpan hooks in packages/browser and packages/aws-serverless likewise map contexts only. So there is no field on SerializedStreamedSpan where a scope tag could land.

Current state after the port

App Isolation coverage now
nextjs-app-dir error-side only (3 specs)
nextjs-pages-dir error-side only (3 specs)
nextjs-14 error-side only (1 spec)
nextjs-16 none
nextjs-16-bun none
nextjs-16-cf-workers none

Where an error event was involved, the error-side assertions still cover isolation and were kept. The three apps with no coverage are the ones whose isolation specs had no error to assert on.

The most valuable single loss is in nextjs-16's middleware spec, which guarded against a tag set in middleware leaking onto the following route's event — the contamination described in vercel/next.js#95306. That guard asserted the absence of a tag, so it has no error-side substitute at all.

nextjs-16-static keeps the transaction-based versions of these specs, so the behaviour is still covered under traceLifecycle: 'static' — but not under streaming, which is the default.

What to decide

Roughly, one of:

  1. Surface scope data on segment spans (e.g. tags as attributes) and assert on that.
  2. Document that scope tags are intentionally not carried on spans, and rebuild the E2E guards around a signal that does survive — attributes set explicitly by the test app, or an error event deliberately raised so the isolation assertion has a carrier.
  3. Accept trace-side isolation as untested under streaming and rely on unit coverage, recording that decision.

Option 2 is the cheapest to implement in the E2E suites and would restore the leak guard, which is the part worth having.

References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions