Skip to content

Commit 2be99a2

Browse files
committed
add distributed test case to all nuxt tests
1 parent 56c916f commit 2be99a2

File tree

12 files changed

+440
-0
lines changed

12 files changed

+440
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script setup lang="ts">
2+
import { useFetch, useRoute } from '#imports';
3+
4+
const route = useRoute();
5+
const userId = route.params.userId as string;
6+
7+
const { data } = await useFetch(`/api/user/${userId}`, {
8+
server: false, // Don't fetch during SSR, only client-side
9+
});
10+
</script>
11+
12+
<template>
13+
<div>
14+
<p v-if="data">User ID: {{ data }}</p>
15+
</div>
16+
</template>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { defineEventHandler, getRouterParam } from '#imports';
2+
3+
export default defineEventHandler(event => {
4+
const userId = getRouterParam(event, 'userId');
5+
6+
return `UserId Param: ${userId}!`;
7+
});

dev-packages/e2e-tests/test-applications/nuxt-3-dynamic-import/tests/tracing.test.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,91 @@ test.describe('distributed tracing', () => {
6666
expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id);
6767
expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId);
6868
});
69+
70+
test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => {
71+
const clientTxnEventPromise = waitForTransaction('nuxt-3-dynamic-import', txnEvent => {
72+
return txnEvent.transaction === '/test-param/user/:userId()';
73+
});
74+
const ssrTxnEventPromise = waitForTransaction('nuxt-3-dynamic-import', txnEvent => {
75+
return txnEvent.transaction?.includes('GET /test-param/user') ?? false;
76+
});
77+
const serverReqTxnEventPromise = waitForTransaction('nuxt-3-dynamic-import', txnEvent => {
78+
return txnEvent.transaction?.includes('GET /api/user/') ?? false;
79+
});
80+
81+
// Navigate to the page which will trigger an API call from the client-side
82+
await page.goto(`/test-param/user/${PARAM}`);
83+
84+
const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([
85+
clientTxnEventPromise,
86+
ssrTxnEventPromise,
87+
serverReqTxnEventPromise,
88+
]);
89+
90+
const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/user/${PARAM}`);
91+
92+
expect(clientTxnEvent).toEqual(
93+
expect.objectContaining({
94+
type: 'transaction',
95+
transaction: '/test-param/user/:userId()', // parametrized route
96+
transaction_info: { source: 'route' },
97+
contexts: expect.objectContaining({
98+
trace: expect.objectContaining({
99+
op: 'pageload',
100+
origin: 'auto.pageload.vue',
101+
}),
102+
}),
103+
}),
104+
);
105+
106+
expect(httpClientSpan).toBeDefined();
107+
expect(httpClientSpan).toEqual(
108+
expect.objectContaining({
109+
description: `GET /api/user/${PARAM}`, // fixme: parametrize
110+
parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent
111+
data: expect.objectContaining({
112+
url: `/api/user/${PARAM}`,
113+
type: 'fetch',
114+
'sentry.op': 'http.client',
115+
'sentry.origin': 'auto.http.browser',
116+
'http.method': 'GET',
117+
}),
118+
}),
119+
);
120+
121+
expect(ssrTxnEvent).toEqual(
122+
expect.objectContaining({
123+
type: 'transaction',
124+
transaction: `GET /test-param/user/${PARAM}`, // fixme: parametrize (nitro)
125+
transaction_info: { source: 'url' },
126+
contexts: expect.objectContaining({
127+
trace: expect.objectContaining({
128+
op: 'http.server',
129+
origin: 'auto.http.otel.http',
130+
}),
131+
}),
132+
}),
133+
);
134+
135+
expect(serverReqTxnEvent).toEqual(
136+
expect.objectContaining({
137+
type: 'transaction',
138+
transaction: `GET /api/user/${PARAM}`,
139+
transaction_info: { source: 'url' },
140+
contexts: expect.objectContaining({
141+
trace: expect.objectContaining({
142+
op: 'http.server',
143+
origin: 'auto.http.otel.http',
144+
parent_span_id: httpClientSpan?.span_id, // http.client span is parent
145+
}),
146+
}),
147+
}),
148+
);
149+
150+
// All 3 transactions and the http.client span should share the same trace_id
151+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined();
152+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id);
153+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id);
154+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverReqTxnEvent.contexts?.trace?.trace_id);
155+
});
69156
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script setup lang="ts">
2+
import { useFetch, useRoute } from '#imports';
3+
4+
const route = useRoute();
5+
const userId = route.params.userId as string;
6+
7+
const { data } = await useFetch(`/api/user/${userId}`, {
8+
server: false, // Don't fetch during SSR, only client-side
9+
});
10+
</script>
11+
12+
<template>
13+
<div>
14+
<p v-if="data">User ID: {{ data }}</p>
15+
</div>
16+
</template>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { defineEventHandler, getRouterParam } from '#imports';
2+
3+
export default defineEventHandler(event => {
4+
const userId = getRouterParam(event, 'userId');
5+
6+
return `UserId Param: ${userId}!`;
7+
});

dev-packages/e2e-tests/test-applications/nuxt-3-min/tests/tracing.test.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,91 @@ test.describe('distributed tracing', () => {
6666
expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id);
6767
expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId);
6868
});
69+
70+
test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => {
71+
const clientTxnEventPromise = waitForTransaction('nuxt-3-min', txnEvent => {
72+
return txnEvent.transaction === '/test-param/user/:userId()';
73+
});
74+
const ssrTxnEventPromise = waitForTransaction('nuxt-3-min', txnEvent => {
75+
return txnEvent.transaction?.includes('GET /test-param/user') ?? false;
76+
});
77+
const serverReqTxnEventPromise = waitForTransaction('nuxt-3-min', txnEvent => {
78+
return txnEvent.transaction?.includes('GET /api/user/') ?? false;
79+
});
80+
81+
// Navigate to the page which will trigger an API call from the client-side
82+
await page.goto(`/test-param/user/${PARAM}`);
83+
84+
const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([
85+
clientTxnEventPromise,
86+
ssrTxnEventPromise,
87+
serverReqTxnEventPromise,
88+
]);
89+
90+
const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/user/${PARAM}`);
91+
92+
expect(clientTxnEvent).toEqual(
93+
expect.objectContaining({
94+
type: 'transaction',
95+
transaction: '/test-param/user/:userId()', // parametrized route
96+
transaction_info: { source: 'route' },
97+
contexts: expect.objectContaining({
98+
trace: expect.objectContaining({
99+
op: 'pageload',
100+
origin: 'auto.pageload.vue',
101+
}),
102+
}),
103+
}),
104+
);
105+
106+
expect(httpClientSpan).toBeDefined();
107+
expect(httpClientSpan).toEqual(
108+
expect.objectContaining({
109+
description: `GET /api/user/${PARAM}`, // fixme: parametrize
110+
parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent
111+
data: expect.objectContaining({
112+
url: `/api/user/${PARAM}`,
113+
type: 'fetch',
114+
'sentry.op': 'http.client',
115+
'sentry.origin': 'auto.http.browser',
116+
'http.method': 'GET',
117+
}),
118+
}),
119+
);
120+
121+
expect(ssrTxnEvent).toEqual(
122+
expect.objectContaining({
123+
type: 'transaction',
124+
transaction: `GET /test-param/user/${PARAM}`, // fixme: parametrize (nitro)
125+
transaction_info: { source: 'url' },
126+
contexts: expect.objectContaining({
127+
trace: expect.objectContaining({
128+
op: 'http.server',
129+
origin: 'auto.http.otel.http',
130+
}),
131+
}),
132+
}),
133+
);
134+
135+
expect(serverReqTxnEvent).toEqual(
136+
expect.objectContaining({
137+
type: 'transaction',
138+
transaction: `GET /api/user/${PARAM}`,
139+
transaction_info: { source: 'url' },
140+
contexts: expect.objectContaining({
141+
trace: expect.objectContaining({
142+
op: 'http.server',
143+
origin: 'auto.http.otel.http',
144+
parent_span_id: httpClientSpan?.span_id, // http.client span is parent
145+
}),
146+
}),
147+
}),
148+
);
149+
150+
// All 3 transactions and the http.client span should share the same trace_id
151+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined();
152+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id);
153+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id);
154+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverReqTxnEvent.contexts?.trace?.trace_id);
155+
});
69156
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script setup lang="ts">
2+
import { useFetch, useRoute } from '#imports';
3+
4+
const route = useRoute();
5+
const userId = route.params.userId as string;
6+
7+
const { data } = await useFetch(`/api/user/${userId}`, {
8+
server: false, // Don't fetch during SSR, only client-side
9+
});
10+
</script>
11+
12+
<template>
13+
<div>
14+
<p v-if="data">User ID: {{ data }}</p>
15+
</div>
16+
</template>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { defineEventHandler, getRouterParam } from '#imports';
2+
3+
export default defineEventHandler(event => {
4+
const userId = getRouterParam(event, 'userId');
5+
6+
return `UserId Param: ${userId}!`;
7+
});

dev-packages/e2e-tests/test-applications/nuxt-3-top-level-import/tests/tracing.test.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,91 @@ test.describe('distributed tracing', () => {
6666
expect(clientTxnEvent.contexts?.trace?.parent_span_id).toBe(serverTxnEvent.contexts?.trace?.span_id);
6767
expect(serverTxnEvent.contexts?.trace?.trace_id).toBe(metaTraceId);
6868
});
69+
70+
test('capture a distributed trace from a client-side API request with parametrized routes', async ({ page }) => {
71+
const clientTxnEventPromise = waitForTransaction('nuxt-3-top-level-import', txnEvent => {
72+
return txnEvent.transaction === '/test-param/user/:userId()';
73+
});
74+
const ssrTxnEventPromise = waitForTransaction('nuxt-3-top-level-import', txnEvent => {
75+
return txnEvent.transaction?.includes('GET /test-param/user') ?? false;
76+
});
77+
const serverReqTxnEventPromise = waitForTransaction('nuxt-3-top-level-import', txnEvent => {
78+
return txnEvent.transaction?.includes('GET /api/user/') ?? false;
79+
});
80+
81+
// Navigate to the page which will trigger an API call from the client-side
82+
await page.goto(`/test-param/user/${PARAM}`);
83+
84+
const [clientTxnEvent, ssrTxnEvent, serverReqTxnEvent] = await Promise.all([
85+
clientTxnEventPromise,
86+
ssrTxnEventPromise,
87+
serverReqTxnEventPromise,
88+
]);
89+
90+
const httpClientSpan = clientTxnEvent?.spans?.find(span => span.description === `GET /api/user/${PARAM}`);
91+
92+
expect(clientTxnEvent).toEqual(
93+
expect.objectContaining({
94+
type: 'transaction',
95+
transaction: '/test-param/user/:userId()', // parametrized route
96+
transaction_info: { source: 'route' },
97+
contexts: expect.objectContaining({
98+
trace: expect.objectContaining({
99+
op: 'pageload',
100+
origin: 'auto.pageload.vue',
101+
}),
102+
}),
103+
}),
104+
);
105+
106+
expect(httpClientSpan).toBeDefined();
107+
expect(httpClientSpan).toEqual(
108+
expect.objectContaining({
109+
description: `GET /api/user/${PARAM}`, // fixme: parametrize
110+
parent_span_id: clientTxnEvent.contexts?.trace?.span_id, // pageload span is parent
111+
data: expect.objectContaining({
112+
url: `/api/user/${PARAM}`,
113+
type: 'fetch',
114+
'sentry.op': 'http.client',
115+
'sentry.origin': 'auto.http.browser',
116+
'http.method': 'GET',
117+
}),
118+
}),
119+
);
120+
121+
expect(ssrTxnEvent).toEqual(
122+
expect.objectContaining({
123+
type: 'transaction',
124+
transaction: `GET /test-param/user/${PARAM}`, // fixme: parametrize (nitro)
125+
transaction_info: { source: 'url' },
126+
contexts: expect.objectContaining({
127+
trace: expect.objectContaining({
128+
op: 'http.server',
129+
origin: 'auto.http.otel.http',
130+
}),
131+
}),
132+
}),
133+
);
134+
135+
expect(serverReqTxnEvent).toEqual(
136+
expect.objectContaining({
137+
type: 'transaction',
138+
transaction: `GET /api/user/${PARAM}`,
139+
transaction_info: { source: 'url' },
140+
contexts: expect.objectContaining({
141+
trace: expect.objectContaining({
142+
op: 'http.server',
143+
origin: 'auto.http.otel.http',
144+
parent_span_id: httpClientSpan?.span_id, // http.client span is parent
145+
}),
146+
}),
147+
}),
148+
);
149+
150+
// All 3 transactions and the http.client span should share the same trace_id
151+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBeDefined();
152+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(httpClientSpan?.trace_id);
153+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(ssrTxnEvent.contexts?.trace?.trace_id);
154+
expect(clientTxnEvent.contexts?.trace?.trace_id).toBe(serverReqTxnEvent.contexts?.trace?.trace_id);
155+
});
69156
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script setup lang="ts">
2+
import { useFetch, useRoute } from '#imports';
3+
4+
const route = useRoute();
5+
const userId = route.params.userId as string;
6+
7+
const { data } = await useFetch(`/api/user/${userId}`, {
8+
server: false, // Don't fetch during SSR, only client-side
9+
});
10+
</script>
11+
12+
<template>
13+
<div>
14+
<p v-if="data">User ID: {{ data }}</p>
15+
</div>
16+
</template>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { defineEventHandler, getRouterParam } from '#imports';
2+
3+
export default defineEventHandler(event => {
4+
const userId = getRouterParam(event, 'userId');
5+
6+
return `UserId Param: ${userId}!`;
7+
});

0 commit comments

Comments
 (0)