Skip to content

Commit 87cd836

Browse files
authored
test(astro-5): Add test for current parametrized routes (#17054)
Adds a test case with a client, server and server API request which checks: - that everything is correctly connected - that everything has parametrized routes (the current state of it - some are not yet parametrized) This is a visual representation of the test case (with a different param): <img width="502" height="197" alt="image" src="https://github.com/user-attachments/assets/e1a14c2b-2547-427b-964b-5c8fb6db49a2" /> Part of #16686
1 parent f538ef0 commit 87cd836

File tree

4 files changed

+170
-0
lines changed

4 files changed

+170
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function GET({ params }) {
2+
return new Response(
3+
JSON.stringify({
4+
greeting: `Hello ${params.userId}`,
5+
userId: params.userId,
6+
}),
7+
);
8+
}

dev-packages/e2e-tests/test-applications/astro-5/src/pages/index.astro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Layout from '../layouts/Layout.astro';
1616
<a href="/test-ssr">SSR page</a>
1717
<a href="/test-static" title="static page">Static Page</a>
1818
<a href="/server-island">Server Island</a>
19+
<a href="/user-page/myUsername123">Test Parametrized Routes</a>
1920
</ul>
2021
</main>
2122
</Layout>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
import Layout from '../../layouts/Layout.astro';
3+
4+
export const prerender = false;
5+
6+
const { userId } = Astro.params;
7+
8+
const response = await fetch(Astro.url.origin + `/api/user/${userId}.json`)
9+
const data = await response.json();
10+
11+
---
12+
13+
<Layout title="Dynamic SSR page">
14+
<h1>{data.greeting}</h1>
15+
16+
<p>data: {JSON.stringify(data)}</p>
17+
</Layout>

dev-packages/e2e-tests/test-applications/astro-5/tests/tracing.dynamic.test.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,147 @@ test.describe('tracing in dynamically rendered (ssr) routes', () => {
119119
});
120120
});
121121
});
122+
123+
test.describe('nested SSR routes (client, server, server request)', () => {
124+
/** The user-page route fetches from an endpoint and creates a deeply nested span structure:
125+
* pageload — /user-page/myUsername123
126+
* ├── browser.** — multiple browser spans
127+
* └── browser.request — /user-page/myUsername123
128+
* └── http.server — GET /user-page/[userId] (SSR page request)
129+
* └── http.client — GET /api/user/myUsername123.json (executing fetch call from SSR page - span)
130+
* └── http.server — GET /api/user/myUsername123.json (server request)
131+
*/
132+
test('sends connected server and client pageload and request spans with the same trace id', async ({ page }) => {
133+
const clientPageloadTxnPromise = waitForTransaction('astro-5', txnEvent => {
134+
return txnEvent?.transaction?.startsWith('/user-page/') ?? false;
135+
});
136+
137+
const serverPageRequestTxnPromise = waitForTransaction('astro-5', txnEvent => {
138+
return txnEvent?.transaction?.startsWith('GET /user-page/') ?? false;
139+
});
140+
141+
const serverHTTPServerRequestTxnPromise = waitForTransaction('astro-5', txnEvent => {
142+
return txnEvent?.transaction?.startsWith('GET /api/user/') ?? false;
143+
});
144+
145+
await page.goto('/user-page/myUsername123');
146+
147+
const clientPageloadTxn = await clientPageloadTxnPromise;
148+
const serverPageRequestTxn = await serverPageRequestTxnPromise;
149+
const serverHTTPServerRequestTxn = await serverHTTPServerRequestTxnPromise;
150+
const serverRequestHTTPClientSpan = serverPageRequestTxn.spans?.find(
151+
span => span.op === 'http.client' && span.description?.includes('/api/user/'),
152+
);
153+
154+
const clientPageloadTraceId = clientPageloadTxn.contexts?.trace?.trace_id;
155+
156+
// Verify all spans have the same trace ID
157+
expect(clientPageloadTraceId).toEqual(serverPageRequestTxn.contexts?.trace?.trace_id);
158+
expect(clientPageloadTraceId).toEqual(serverHTTPServerRequestTxn.contexts?.trace?.trace_id);
159+
expect(clientPageloadTraceId).toEqual(serverRequestHTTPClientSpan?.trace_id);
160+
161+
// serverPageRequest has no parent (root span)
162+
expect(serverPageRequestTxn.contexts?.trace?.parent_span_id).toBeUndefined();
163+
164+
// clientPageload's parent and serverRequestHTTPClient's parent is serverPageRequest
165+
const serverPageRequestSpanId = serverPageRequestTxn.contexts?.trace?.span_id;
166+
expect(clientPageloadTxn.contexts?.trace?.parent_span_id).toEqual(serverPageRequestSpanId);
167+
expect(serverRequestHTTPClientSpan?.parent_span_id).toEqual(serverPageRequestSpanId);
168+
169+
// serverHTTPServerRequest's parent is serverRequestHTTPClient
170+
expect(serverHTTPServerRequestTxn.contexts?.trace?.parent_span_id).toEqual(serverRequestHTTPClientSpan?.span_id);
171+
});
172+
173+
test('sends parametrized pageload, server and API request transaction names', async ({ page }) => {
174+
const clientPageloadTxnPromise = waitForTransaction('astro-5', txnEvent => {
175+
return txnEvent?.transaction?.startsWith('/user-page/') ?? false;
176+
});
177+
178+
const serverPageRequestTxnPromise = waitForTransaction('astro-5', txnEvent => {
179+
return txnEvent?.transaction?.startsWith('GET /user-page/') ?? false;
180+
});
181+
182+
const serverHTTPServerRequestTxnPromise = waitForTransaction('astro-5', txnEvent => {
183+
return txnEvent?.transaction?.startsWith('GET /api/user/') ?? false;
184+
});
185+
186+
await page.goto('/user-page/myUsername123');
187+
188+
const clientPageloadTxn = await clientPageloadTxnPromise;
189+
const serverPageRequestTxn = await serverPageRequestTxnPromise;
190+
const serverHTTPServerRequestTxn = await serverHTTPServerRequestTxnPromise;
191+
192+
const serverRequestHTTPClientSpan = serverPageRequestTxn.spans?.find(
193+
span => span.op === 'http.client' && span.description?.includes('/api/user/'),
194+
);
195+
196+
// Client pageload transaction - actual URL with pageload operation
197+
expect(clientPageloadTxn).toMatchObject({
198+
transaction: '/user-page/myUsername123', // todo: parametrize to '/user-page/[userId]'
199+
transaction_info: { source: 'url' },
200+
contexts: {
201+
trace: {
202+
op: 'pageload',
203+
origin: 'auto.pageload.browser',
204+
data: {
205+
'sentry.op': 'pageload',
206+
'sentry.origin': 'auto.pageload.browser',
207+
'sentry.source': 'url',
208+
},
209+
},
210+
},
211+
});
212+
213+
// Server page request transaction - parametrized transaction name with actual URL in data
214+
expect(serverPageRequestTxn).toMatchObject({
215+
transaction: 'GET /user-page/[userId]',
216+
transaction_info: { source: 'route' },
217+
contexts: {
218+
trace: {
219+
op: 'http.server',
220+
origin: 'auto.http.astro',
221+
data: {
222+
'sentry.op': 'http.server',
223+
'sentry.origin': 'auto.http.astro',
224+
'sentry.source': 'route',
225+
url: expect.stringContaining('/user-page/myUsername123'),
226+
},
227+
},
228+
},
229+
request: { url: expect.stringContaining('/user-page/myUsername123') },
230+
});
231+
232+
// HTTP client span - actual API URL with client operation
233+
expect(serverRequestHTTPClientSpan).toMatchObject({
234+
op: 'http.client',
235+
origin: 'auto.http.otel.node_fetch',
236+
description: 'GET http://localhost:3030/api/user/myUsername123.json', // todo: parametrize (this is just a span though - no transaction)
237+
data: {
238+
'sentry.op': 'http.client',
239+
'sentry.origin': 'auto.http.otel.node_fetch',
240+
'url.full': expect.stringContaining('/api/user/myUsername123.json'),
241+
'url.path': '/api/user/myUsername123.json',
242+
url: expect.stringContaining('/api/user/myUsername123.json'),
243+
},
244+
});
245+
246+
// Server HTTP request transaction - should be parametrized (todo: currently not parametrized)
247+
expect(serverHTTPServerRequestTxn).toMatchObject({
248+
transaction: 'GET /api/user/myUsername123.json', // todo: should be parametrized to 'GET /api/user/[userId].json'
249+
transaction_info: { source: 'route' },
250+
contexts: {
251+
trace: {
252+
op: 'http.server',
253+
origin: 'auto.http.astro',
254+
data: {
255+
'sentry.op': 'http.server',
256+
'sentry.origin': 'auto.http.astro',
257+
'sentry.source': 'route',
258+
url: expect.stringContaining('/api/user/myUsername123.json'),
259+
},
260+
},
261+
},
262+
request: { url: expect.stringContaining('/api/user/myUsername123.json') },
263+
});
264+
});
265+
});

0 commit comments

Comments
 (0)