Skip to content

Commit c9aaf8b

Browse files
author
Luca Forstner
authored
test(e2e): Add E2E test for sourcemap processing pipeline with debug IDs (#9243)
1 parent 3f4d823 commit c9aaf8b

File tree

8 files changed

+130
-0
lines changed

8 files changed

+130
-0
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,7 @@ jobs:
848848
'create-next-app',
849849
'create-remix-app',
850850
'create-remix-app-v2',
851+
'debug-id-sourcemaps',
851852
'nextjs-app-dir',
852853
'react-create-hash-router',
853854
'react-router-6-use-routes',
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://localhost:4873
2+
@sentry-internal:registry=http://localhost:4873
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "debug-id-sourcemaps",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"build": "rollup --config rollup.config.mjs",
7+
"test": "vitest run",
8+
"clean": "npx rimraf node_modules,pnpm-lock.yaml",
9+
"test:build": "pnpm install && pnpm build",
10+
"test:assert": "pnpm test"
11+
},
12+
"dependencies": {
13+
"@sentry/node": "latest || *"
14+
},
15+
"devDependencies": {
16+
"rollup": "^4.0.2",
17+
"vitest": "^0.34.6",
18+
"@sentry/rollup-plugin": "2.8.0"
19+
},
20+
"volta": {
21+
"extends": "../../package.json"
22+
}
23+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { defineConfig } from 'rollup';
2+
import { sentryRollupPlugin } from '@sentry/rollup-plugin';
3+
4+
export default defineConfig({
5+
input: './src/app.js',
6+
external: ['@sentry/node'],
7+
plugins: [
8+
sentryRollupPlugin({
9+
org: process.env.E2E_TEST_SENTRY_ORG_SLUG,
10+
project: process.env.E2E_TEST_SENTRY_TEST_PROJECT,
11+
authToken: process.env.E2E_TEST_AUTH_TOKEN,
12+
}),
13+
],
14+
output: {
15+
file: './dist/app.js',
16+
compact: true,
17+
format: 'cjs',
18+
sourcemap: 'hidden',
19+
},
20+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as Sentry from '@sentry/node';
2+
3+
Sentry.init({
4+
environment: 'qa', // dynamic sampling bias to keep transactions
5+
dsn: process.env.E2E_TEST_DSN,
6+
});
7+
8+
const eventId = Sentry.captureException(new Error('Sentry Debug ID E2E Test Error'));
9+
10+
process.stdout.write(eventId);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`Find symbolicated event on sentry 1`] = `
4+
{
5+
"colno": 41,
6+
"contextLine": "const eventId = Sentry.captureException(new Error('Sentry Debug ID E2E Test Error'));",
7+
"lineno": 8,
8+
"postContext": [
9+
"",
10+
"process.stdout.write(eventId);",
11+
],
12+
"preContext": [
13+
"Sentry.init({",
14+
" environment: 'qa', // dynamic sampling bias to keep transactions",
15+
" dsn: process.env.E2E_TEST_DSN,",
16+
"});",
17+
"",
18+
],
19+
}
20+
`;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { test } from 'vitest';
2+
import childProcess from 'child_process';
3+
import path from 'path';
4+
5+
const authToken = process.env.E2E_TEST_AUTH_TOKEN;
6+
const sentryTestOrgSlug = process.env.E2E_TEST_SENTRY_ORG_SLUG;
7+
const sentryTestProject = process.env.E2E_TEST_SENTRY_TEST_PROJECT;
8+
const EVENT_POLLING_TIMEOUT = 30_000;
9+
10+
test(
11+
'Find symbolicated event on sentry',
12+
async ({ expect }) => {
13+
const eventId = childProcess.execSync(`node ${path.join(__dirname, '..', 'dist', 'app.js')}`, {
14+
encoding: 'utf-8',
15+
});
16+
17+
console.log(`Polling for error eventId: ${eventId}`);
18+
19+
let timedOut = false;
20+
setTimeout(() => {
21+
timedOut = true;
22+
}, EVENT_POLLING_TIMEOUT);
23+
24+
while (!timedOut) {
25+
await new Promise(resolve => setTimeout(resolve, 2000)); // poll every two seconds
26+
const response = await fetch(
27+
`https://sentry.io/api/0/projects/${sentryTestOrgSlug}/${sentryTestProject}/events/${eventId}/json/`,
28+
{ headers: { Authorization: `Bearer ${authToken}` } },
29+
);
30+
31+
// Only allow ok responses or 404
32+
if (!response.ok) {
33+
expect(response.status).toBe(404);
34+
continue;
35+
}
36+
37+
const eventPayload = await response.json();
38+
const frames = eventPayload.exception?.values?.[0]?.stacktrace?.frames;
39+
const topFrame = frames[frames.length - 1];
40+
expect({
41+
preContext: topFrame?.pre_context,
42+
contextLine: topFrame?.context_line,
43+
postContext: topFrame?.post_context,
44+
lineno: topFrame?.lineno,
45+
colno: topFrame?.colno,
46+
}).toMatchSnapshot();
47+
return;
48+
}
49+
50+
throw new Error('Test timed out');
51+
},
52+
{ timeout: EVENT_POLLING_TIMEOUT },
53+
);

0 commit comments

Comments
 (0)