Skip to content

Commit 01acae5

Browse files
Lms24claude
andcommitted
test(nextjs): Expect one http.server segment per request behind the proxy
Requests behind the proxy produce an extra route-less `GET` segment with op `http.server` next to the route segment. This test shows it for an API route and a page. Refs #25370 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent f4a3cba commit 01acae5

3 files changed

Lines changed: 31 additions & 1 deletion

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const dynamic = 'force-dynamic';
2+
3+
export default function Page() {
4+
return <h1>Page behind proxy</h1>;
5+
}

‎dev-packages/e2e-tests/test-applications/nextjs-16/proxy.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ export async function proxy(request: NextRequest) {
3333

3434
// See "Matching Paths" below to learn more
3535
export const config = {
36-
matcher: ['/api/endpoint-behind-middleware', '/api/endpoint-behind-faulty-middleware'],
36+
matcher: ['/api/endpoint-behind-middleware', '/api/endpoint-behind-faulty-middleware', '/page-behind-proxy'],
3737
};

‎dev-packages/e2e-tests/test-applications/nextjs-16/tests/middleware.test.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,31 @@ test('Should create a span for middleware', async ({ request }) => {
4848
expect(routeSpan.attributes['isolation_scope.has_proxy_marker']).toEqual({ value: false, type: 'boolean' });
4949
});
5050

51+
for (const path of ['/api/endpoint-behind-middleware', '/page-behind-proxy']) {
52+
test(`Should create one http.server segment for a request to ${path} behind the proxy`, async ({ request }) => {
53+
test.skip(getRuntime() === 'cloudflare', 'On Workers the middleware span is a child of the request span');
54+
55+
// Next.js runs the proxy in a `BaseServer.handleRequest` span of its own, before the one that renders the route.
56+
// That first span has neither a route nor the middleware span as a child, so it must not become a second
57+
// `http.server` segment.
58+
const spansPromise = collectStreamedSpans(
59+
'nextjs-16',
60+
spans =>
61+
spans.some(span => span.is_segment && span.name === 'middleware GET') &&
62+
spans.some(span => span.is_segment && span.name === `GET ${path}`),
63+
);
64+
65+
const response = await request.get(path);
66+
expect(response.status()).toBe(200);
67+
68+
const segmentSpans = (await spansPromise).filter(span => span.is_segment);
69+
expect(segmentSpans.map(span => span.name).sort()).toEqual([`GET ${path}`, 'middleware GET']);
70+
expect(segmentSpans.filter(span => getSpanOp(span) === 'http.server').map(span => span.name)).toEqual([
71+
`GET ${path}`,
72+
]);
73+
});
74+
}
75+
5176
// `withSentry` from `@sentry/nextjs/cloudflare` wraps the Worker entry, so middleware runs inside the request's
5277
// `http.server` segment and its span is a child of it rather than a segment of its own.
5378
test('Should create a span for middleware inside the request segment of the Worker', async ({ request }) => {

0 commit comments

Comments
 (0)