Skip to content

Commit 7a570db

Browse files
authored
Merge branch 'develop' into fix-streaming
2 parents 0842114 + 33d5898 commit 7a570db

File tree

23 files changed

+551
-67
lines changed

23 files changed

+551
-67
lines changed

.size-limit.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ module.exports = [
3838
path: 'packages/browser/build/npm/esm/index.js',
3939
import: createImport('init', 'browserTracingIntegration'),
4040
gzip: true,
41-
limit: '41 KB',
41+
limit: '41.3 KB',
4242
},
4343
{
4444
name: '@sentry/browser (incl. Tracing, Profiling)',
@@ -127,7 +127,7 @@ module.exports = [
127127
import: createImport('init', 'ErrorBoundary', 'reactRouterV6BrowserTracingIntegration'),
128128
ignore: ['react/jsx-runtime'],
129129
gzip: true,
130-
limit: '43 KB',
130+
limit: '43.3 KB',
131131
},
132132
// Vue SDK (ESM)
133133
{
@@ -142,7 +142,7 @@ module.exports = [
142142
path: 'packages/vue/build/esm/index.js',
143143
import: createImport('init', 'browserTracingIntegration'),
144144
gzip: true,
145-
limit: '43 KB',
145+
limit: '43.1 KB',
146146
},
147147
// Svelte SDK (ESM)
148148
{
@@ -190,7 +190,7 @@ module.exports = [
190190
path: createCDNPath('bundle.tracing.min.js'),
191191
gzip: false,
192192
brotli: false,
193-
limit: '124 KB',
193+
limit: '124.1 KB',
194194
},
195195
{
196196
name: 'CDN Bundle (incl. Tracing, Replay) - uncompressed',
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
1+
// This worker manually replicates what Sentry.registerWebWorker() does
2+
// (In real code with a bundler, you'd import and call Sentry.registerWebWorker({ self }))
3+
14
self._sentryDebugIds = {
25
'Error at http://sentry-test.io/worker.js': 'worker-debug-id-789',
36
};
47

8+
// Send debug IDs
59
self.postMessage({
610
_sentryMessage: true,
711
_sentryDebugIds: self._sentryDebugIds,
812
});
913

14+
// Set up unhandledrejection handler (same as registerWebWorker)
15+
self.addEventListener('unhandledrejection', event => {
16+
self.postMessage({
17+
_sentryMessage: true,
18+
_sentryWorkerError: {
19+
reason: event.reason,
20+
filename: self.location.href,
21+
},
22+
});
23+
});
24+
1025
self.addEventListener('message', event => {
1126
if (event.data.type === 'throw-error') {
1227
throw new Error('Worker error for testing');
1328
}
29+
30+
if (event.data.type === 'throw-rejection') {
31+
// Create an unhandled rejection
32+
Promise.reject(new Error('Worker unhandled rejection'));
33+
}
1434
});

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,17 @@ const worker = new Worker('/worker.js');
99

1010
Sentry.addIntegration(Sentry.webWorkerIntegration({ worker }));
1111

12-
const btn = document.getElementById('errWorker');
12+
const btnError = document.getElementById('errWorker');
13+
const btnRejection = document.getElementById('rejectionWorker');
1314

14-
btn.addEventListener('click', () => {
15+
btnError.addEventListener('click', () => {
1516
worker.postMessage({
1617
type: 'throw-error',
1718
});
1819
});
20+
21+
btnRejection.addEventListener('click', () => {
22+
worker.postMessage({
23+
type: 'throw-rejection',
24+
});
25+
});

dev-packages/browser-integration-tests/suites/integrations/webWorker/template.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
</head>
66
<body>
77
<button id="errWorker">Throw error in worker</button>
8+
<button id="rejectionWorker">Throw unhandled rejection in worker</button>
89
</body>
910
</html>

dev-packages/browser-integration-tests/suites/integrations/webWorker/test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,32 @@ sentryTest('Assigns web worker debug IDs when using webWorkerIntegration', async
3636
expect(image.code_file).toEqual('http://sentry-test.io/worker.js');
3737
});
3838
});
39+
40+
sentryTest('Captures unhandled rejections from web workers', async ({ getLocalTestUrl, page }) => {
41+
const bundle = process.env.PW_BUNDLE;
42+
if (bundle != null && !bundle.includes('esm') && !bundle.includes('cjs')) {
43+
sentryTest.skip();
44+
}
45+
46+
const url = await getLocalTestUrl({ testDir: __dirname });
47+
48+
const errorEventPromise = getFirstSentryEnvelopeRequest<Event>(page, url);
49+
50+
page.route('**/worker.js', route => {
51+
route.fulfill({
52+
path: `${__dirname}/assets/worker.js`,
53+
});
54+
});
55+
56+
const button = page.locator('#rejectionWorker');
57+
await button.click();
58+
59+
const errorEvent = await errorEventPromise;
60+
61+
// Verify the unhandled rejection was captured
62+
expect(errorEvent.exception?.values?.[0]?.value).toContain('Worker unhandled rejection');
63+
expect(errorEvent.exception?.values?.[0]?.mechanism?.type).toBe('auto.browser.web_worker.onunhandledrejection');
64+
expect(errorEvent.exception?.values?.[0]?.mechanism?.handled).toBe(false);
65+
expect(errorEvent.contexts?.worker).toBeDefined();
66+
expect(errorEvent.contexts?.worker?.filename).toContain('worker.js');
67+
});

dev-packages/browser-integration-tests/suites/tracing/metrics/web-vitals-inp-navigate/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ sentryTest(
159159
value: inpValue,
160160
},
161161
},
162-
description: '<unknown>', // FIXME: currently unable to get the target name when element is removed from DOM
162+
description: 'body > nav#navigation > NavigationLink',
163163
exclusive_time: inpValue,
164164
op: 'ui.interaction.click',
165165
origin: 'auto.http.browser.inp',

dev-packages/e2e-tests/run.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,38 @@ const DEFAULT_DSN = 'https://username@domain/123';
1212
const DEFAULT_SENTRY_ORG_SLUG = 'sentry-javascript-sdks';
1313
const DEFAULT_SENTRY_PROJECT = 'sentry-javascript-e2e-tests';
1414

15-
function asyncExec(command: string, options: { env: Record<string, string | undefined>; cwd: string }): Promise<void> {
15+
function asyncExec(
16+
command: string | string[],
17+
options: { env: Record<string, string | undefined>; cwd: string },
18+
): Promise<void> {
1619
return new Promise((resolve, reject) => {
17-
const process = spawn(command, { ...options, shell: true });
20+
// If command is an array, use spawn with separate command and args (safer)
21+
// If command is a string, maintain backward compatibility with shell: true
22+
let process: ReturnType<typeof spawn>;
23+
if (typeof command === 'string') {
24+
process = spawn(command, { ...options, shell: true });
25+
} else {
26+
if (command.length === 0) {
27+
return reject(new Error('Command array cannot be empty'));
28+
}
29+
const cmd = command[0];
30+
if (!cmd) {
31+
return reject(new Error('Command array cannot be empty'));
32+
}
33+
process = spawn(cmd, command.slice(1), { ...options, shell: false });
34+
}
1835

19-
process.stdout.on('data', data => {
20-
console.log(`${data}`);
21-
});
36+
if (process.stdout) {
37+
process.stdout.on('data', data => {
38+
console.log(`${data}`);
39+
});
40+
}
2241

23-
process.stderr.on('data', data => {
24-
console.error(`${data}`);
25-
});
42+
if (process.stderr) {
43+
process.stderr.on('data', data => {
44+
console.error(`${data}`);
45+
});
46+
}
2647

2748
process.on('error', error => {
2849
reject(error);
@@ -43,6 +64,8 @@ async function run(): Promise<void> {
4364

4465
// Allow to run a single app only via `yarn test:run <app-name>`
4566
const appName = process.argv[2] || '';
67+
// Forward any additional flags to the test command
68+
const testFlags = process.argv.slice(3);
4669

4770
const dsn = process.env.E2E_TEST_DSN || DEFAULT_DSN;
4871

@@ -87,7 +110,9 @@ async function run(): Promise<void> {
87110
await asyncExec('volta run pnpm test:build', { env, cwd });
88111

89112
console.log(`Testing ${testAppPath}...`);
90-
await asyncExec('volta run pnpm test:assert', { env, cwd });
113+
// Pass command and arguments as an array to prevent command injection
114+
const testCommand = ['volta', 'run', 'pnpm', 'test:assert', ...testFlags];
115+
await asyncExec(testCommand, { env, cwd });
91116

92117
// clean up (although this is tmp, still nice to do)
93118
await rm(tmpDirPath, { recursive: true });
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

dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"cf-typegen": "wrangler types --env-interface CloudflareBindings",
99
"test:build": "pnpm install && pnpm build",
1010
"//": "Just checking if it builds correctly and types don't break",
11-
"test:assert": "pnpm typecheck"
11+
"test:assert": "pnpm typecheck && vitest run ."
1212
},
1313
"dependencies": {
1414
"@sentry/cloudflare": "latest || *",

dev-packages/e2e-tests/test-applications/nuxt-3-min/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
},
2828
"pnpm": {
2929
"overrides": {
30-
"nitropack": "2.10.0",
3130
"ofetch": "1.4.0",
3231
"@vercel/nft": "0.29.4"
3332
}

0 commit comments

Comments
 (0)