-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathroute-handler.test.ts
More file actions
148 lines (116 loc) · 6.59 KB
/
route-handler.test.ts
File metadata and controls
148 lines (116 loc) · 6.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import test, { expect } from '@playwright/test';
import { waitForError, waitForTransaction } from '@sentry-internal/test-utils';
test('Should create a transaction for node route handlers', async ({ request }) => {
const routehandlerTransactionPromise = waitForTransaction('nextjs-16', async transactionEvent => {
return transactionEvent?.transaction === 'GET /route-handler/[xoxo]/node';
});
const response = await request.get('/route-handler/123/node', { headers: { 'x-charly': 'gomez' } });
expect(await response.json()).toStrictEqual({ message: 'Hello Node Route Handler' });
const routehandlerTransaction = await routehandlerTransactionPromise;
expect(routehandlerTransaction.contexts?.trace?.status).toBe('ok');
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
// This is flaking on dev mode
if (process.env.TEST_ENV !== 'development' && process.env.TEST_ENV !== 'dev-turbopack') {
expect(routehandlerTransaction.contexts?.trace?.data?.['http.request.header.x_charly']).toBe('gomez');
}
});
test('Should create a transaction for edge route handlers', async ({ request }) => {
// This test only works for webpack builds on non-async param extraction
// todo: check if we can set request headers for edge on sdkProcessingMetadata
test.skip();
const routehandlerTransactionPromise = waitForTransaction('nextjs-16', async transactionEvent => {
return transactionEvent?.transaction === 'GET /route-handler/[xoxo]/edge';
});
const response = await request.get('/route-handler/123/edge', { headers: { 'x-charly': 'gomez' } });
expect(await response.json()).toStrictEqual({ message: 'Hello Edge Route Handler' });
const routehandlerTransaction = await routehandlerTransactionPromise;
expect(routehandlerTransaction.contexts?.trace?.status).toBe('ok');
expect(routehandlerTransaction.contexts?.trace?.op).toBe('http.server');
expect(routehandlerTransaction.contexts?.trace?.data?.['http.request.header.x_charly']).toBe('gomez');
});
test('Should report an error with a parameterized transaction name for a throwing route handler', async ({
request,
}) => {
const errorEventPromise = waitForError('nextjs-16', errorEvent => {
return errorEvent?.exception?.values?.some(value => value.value === 'route-handler-error') ?? false;
});
const transactionEventPromise = waitForTransaction('nextjs-16', transactionEvent => {
return (
transactionEvent?.transaction === 'GET /route-handler/[xoxo]/error' &&
transactionEvent?.contexts?.trace?.op === 'http.server'
);
});
request.get('/route-handler/456/error').catch(() => {});
const errorEvent = await errorEventPromise;
const transactionEvent = await transactionEventPromise;
// Error event should be part of the same trace as the transaction
expect(errorEvent.contexts?.trace?.trace_id).toBe(transactionEvent.contexts?.trace?.trace_id);
// Error should carry the parameterized transaction name
expect(errorEvent.transaction).toBe('GET /route-handler/[xoxo]/error');
// On turbopack (no wrapping loader), the error goes through onRequestError which sets nextjs context.
// On webpack, the wrapping loader's error handler fires first and captures without nextjs context.
// The SDK deduplicates by error identity, so only the first capture survives.
if (process.env.TEST_ENV === 'development') {
expect(errorEvent.contexts?.nextjs).toEqual({
route_type: 'route',
router_kind: 'App Router',
router_path: '/route-handler/[xoxo]/error',
request_path: '/route-handler/456/error',
});
expect(errorEvent.exception?.values?.[0]?.mechanism).toEqual({
handled: false,
type: 'auto.function.nextjs.on_request_error',
});
}
// Transaction should have parameterized name and internal_error status
expect(transactionEvent.transaction).toBe('GET /route-handler/[xoxo]/error');
expect(transactionEvent.contexts?.trace?.status).toBe('internal_error');
});
test('Should set a parameterized transaction name on a captureMessage event in a route handler', async ({
request,
}) => {
const messageEventPromise = waitForError('nextjs-16', event => {
return event?.message === 'route-handler-message';
});
const transactionEventPromise = waitForTransaction('nextjs-16', transactionEvent => {
return (
transactionEvent?.transaction === 'GET /route-handler/[xoxo]/capture-message' &&
transactionEvent?.contexts?.trace?.op === 'http.server'
);
});
const response = await request.get('/route-handler/789/capture-message');
expect(await response.json()).toStrictEqual({ message: 'Message captured' });
const messageEvent = await messageEventPromise;
const transactionEvent = await transactionEventPromise;
// Message event should be part of the same trace as the transaction
expect(messageEvent.contexts?.trace?.trace_id).toBe(transactionEvent.contexts?.trace?.trace_id);
// Message should carry the parameterized transaction name
expect(messageEvent.transaction).toBe('GET /route-handler/[xoxo]/capture-message');
// Transaction should have parameterized name and ok status
expect(transactionEvent.transaction).toBe('GET /route-handler/[xoxo]/capture-message');
expect(transactionEvent.contexts?.trace?.status).toBe('ok');
});
test('Should set a parameterized transaction name on a captureException event in a route handler', async ({
request,
}) => {
const errorEventPromise = waitForError('nextjs-16', errorEvent => {
return errorEvent?.exception?.values?.some(value => value.value === 'route-handler-capture-exception') ?? false;
});
const transactionEventPromise = waitForTransaction('nextjs-16', transactionEvent => {
return (
transactionEvent?.transaction === 'GET /route-handler/[xoxo]/capture-exception' &&
transactionEvent?.contexts?.trace?.op === 'http.server'
);
});
const response = await request.get('/route-handler/321/capture-exception');
expect(await response.json()).toStrictEqual({ message: 'Exception captured' });
const errorEvent = await errorEventPromise;
const transactionEvent = await transactionEventPromise;
// Error event should be part of the same trace as the transaction
expect(errorEvent.contexts?.trace?.trace_id).toBe(transactionEvent.contexts?.trace?.trace_id);
// Manually captured exception should carry the parameterized transaction name
expect(errorEvent.transaction).toBe('GET /route-handler/[xoxo]/capture-exception');
// Transaction should have parameterized name and ok status (error was caught, not thrown)
expect(transactionEvent.transaction).toBe('GET /route-handler/[xoxo]/capture-exception');
expect(transactionEvent.contexts?.trace?.status).toBe('ok');
});