Skip to content

Commit e8f2b2d

Browse files
authored
feat(browser): Add debugId sync APIs between web worker and main thread (#16981)
Add two Browser SDK APIs to let the main thread know about debugIds of worker files: - `webWorkerIntegration({worker})` to be used in the main thread - `registerWebWorker(self)` to be used in the web worker - unit tests for the two APIs - integration test testing the `webWorkerIntegration` - e2e test demonstrating correct usage of both APIs together
1 parent 1b41126 commit e8f2b2d

File tree

22 files changed

+992
-1
lines changed

22 files changed

+992
-1
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
self._sentryDebugIds = {
2+
'Error at http://sentry-test.io/worker.js': 'worker-debug-id-789',
3+
};
4+
5+
self.postMessage({
6+
_sentryMessage: true,
7+
_sentryDebugIds: self._sentryDebugIds,
8+
});
9+
10+
self.addEventListener('message', event => {
11+
if (event.data.type === 'throw-error') {
12+
throw new Error('Worker error for testing');
13+
}
14+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import * as Sentry from '@sentry/browser';
2+
3+
// Initialize Sentry with webWorker integration
4+
Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
});
7+
8+
const worker = new Worker('/worker.js');
9+
10+
Sentry.addIntegration(Sentry.webWorkerIntegration({ worker }));
11+
12+
const btn = document.getElementById('errWorker');
13+
14+
btn.addEventListener('click', () => {
15+
worker.postMessage({
16+
type: 'throw-error',
17+
});
18+
});

dev-packages/browser-integration-tests/suites/integrations/webWorker/subject.js

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<button id="errWorker">Throw error in worker</button>
8+
</body>
9+
</html>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { expect } from '@playwright/test';
2+
import type { Event } from '@sentry/core';
3+
import { sentryTest } from '../../../utils/fixtures';
4+
import { getFirstSentryEnvelopeRequest } from '../../../utils/helpers';
5+
6+
sentryTest('Assigns web worker debug IDs when using webWorkerIntegration', async ({ getLocalTestUrl, page }) => {
7+
const bundle = process.env.PW_BUNDLE as string | undefined;
8+
if (bundle != null && !bundle.includes('esm') && !bundle.includes('cjs')) {
9+
sentryTest.skip();
10+
}
11+
12+
const url = await getLocalTestUrl({ testDir: __dirname });
13+
14+
const errorEventPromise = getFirstSentryEnvelopeRequest<Event>(page, url);
15+
16+
page.route('**/worker.js', route => {
17+
route.fulfill({
18+
path: `${__dirname}/assets/worker.js`,
19+
});
20+
});
21+
22+
const button = page.locator('#errWorker');
23+
await button.click();
24+
25+
const errorEvent = await errorEventPromise;
26+
27+
expect(errorEvent.debug_meta?.images).toBeDefined();
28+
29+
const debugImages = errorEvent.debug_meta?.images || [];
30+
31+
expect(debugImages.length).toBe(1);
32+
33+
debugImages.forEach(image => {
34+
expect(image.type).toBe('sourcemap');
35+
expect(image.debug_id).toEqual('worker-debug-id-789');
36+
expect(image.code_file).toEqual('http://sentry-test.io/worker.js');
37+
});
38+
});

dev-packages/e2e-tests/lib/copyToTemp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function fixPackageJson(cwd: string): void {
2828

2929
// 2. Fix volta extends
3030
if (!packageJson.volta) {
31-
throw new Error('No volta config found, please provide one!');
31+
throw new Error("No volta config found, please add one to the test app's package.json!");
3232
}
3333

3434
if (typeof packageJson.volta.extends === 'string') {
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Vite + TS</title>
7+
</head>
8+
<body>
9+
<div id="app"></div>
10+
<script type="module" src="/src/main.ts"></script>
11+
<button id="trigger-error" type="button" style="background-color: #dc3545; color: white">
12+
Trigger Worker Error
13+
</button>
14+
<button id="trigger-error-2" type="button" style="background-color: #dc3545; color: white">
15+
Trigger Worker 2 Error
16+
</button>
17+
<button id="trigger-error-3" type="button" style="background-color: #dc3545; color: white">
18+
Trigger Worker 3 (lazily added) Error
19+
</button>
20+
</body>
21+
</html>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "browser-webworker-vite",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "rm -rf dist && tsc && vite build",
9+
"preview": "vite preview --port 3030",
10+
"test": "playwright test",
11+
"test:build": "pnpm install && pnpm build",
12+
"test:assert": "pnpm test"
13+
},
14+
"devDependencies": {
15+
"@playwright/test": "~1.53.2",
16+
"@sentry-internal/test-utils": "link:../../../test-utils",
17+
"typescript": "~5.8.3",
18+
"vite": "^7.0.4"
19+
},
20+
"dependencies": {
21+
"@sentry/browser": "latest || *",
22+
"@sentry/vite-plugin": "^3.5.0"
23+
},
24+
"volta": {
25+
"node": "20.19.2",
26+
"yarn": "1.22.22",
27+
"pnpm": "9.15.9"
28+
}
29+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { getPlaywrightConfig } from '@sentry-internal/test-utils';
2+
3+
const config = getPlaywrightConfig({
4+
startCommand: `pnpm preview`,
5+
eventProxyFile: 'start-event-proxy.mjs',
6+
eventProxyPort: 3031,
7+
port: 3030,
8+
});
9+
10+
export default config;

0 commit comments

Comments
 (0)