Skip to content

Commit 3b214d2

Browse files
SkyZeroZxatscott
authored andcommitted
feat(service-worker): Logs unhandled promise rejections in service worker (#63059)
Adds handling and logging for unhandled promise rejections to improve debugging and prevent silent failures. Updates tests and test harness to verify logging of rejection reasons PR Close #63059
1 parent efb2726 commit 3b214d2

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

packages/service-worker/worker/src/driver.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ export class Driver implements Debuggable, UpdateSource {
204204
});
205205

206206
// Handle the fetch, message, push, notificationclick,
207-
// notificationclose, pushsubscriptionchange, and messageerror events.
207+
// notificationclose, pushsubscriptionchange, messageerror, rejectionhandled,
208+
// and unhandledrejection events.
208209
this.scope.addEventListener('fetch', (event) => this.onFetch(event!));
209210
this.scope.addEventListener('message', (event) => this.onMessage(event!));
210211
this.scope.addEventListener('push', (event) => this.onPush(event!));
@@ -216,6 +217,7 @@ export class Driver implements Debuggable, UpdateSource {
216217
this.onPushSubscriptionChange(event as PushSubscriptionChangeEvent),
217218
);
218219
this.scope.addEventListener('messageerror', (event) => this.onMessageError(event));
220+
this.scope.addEventListener('unhandledrejection', (event) => this.onUnhandledRejection(event));
219221

220222
// The debugger generates debug pages in response to debugging requests.
221223
this.debugger = new DebugHandler(this, this.adapter);
@@ -362,6 +364,15 @@ export class Driver implements Debuggable, UpdateSource {
362364
);
363365
}
364366

367+
private onUnhandledRejection(event: PromiseRejectionEvent): void {
368+
// Handle unhandled promise rejections in the service worker.
369+
// This is for debugging and preventing silent failures.
370+
this.debugger.log(
371+
`Unhandled promise rejection occurred`,
372+
`Driver.onUnhandledRejection(reason: ${event.reason})`,
373+
);
374+
}
375+
365376
private async ensureInitialized(event: ExtendableEvent): Promise<void> {
366377
// Since the SW may have just been started, it may or may not have been initialized already.
367378
// `this.initialized` will be `null` if initialization has not yet been attempted, or will be a

packages/service-worker/worker/test/happy_spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,21 @@ import {envIsSupported} from '../testing/utils';
12081208
});
12091209
});
12101210

1211+
describe('unhandledrejection events', () => {
1212+
it('logs unhandled promise rejection errors', async () => {
1213+
await driver.initialized;
1214+
1215+
const debuggerLogSpy = spyOn(driver.debugger, 'log');
1216+
1217+
scope.handleUnhandledRejection('Test rejection reason');
1218+
1219+
expect(debuggerLogSpy).toHaveBeenCalledWith(
1220+
'Unhandled promise rejection occurred',
1221+
'Driver.onUnhandledRejection(reason: Test rejection reason)',
1222+
);
1223+
});
1224+
});
1225+
12111226
describe('notification close events', () => {
12121227
it('broadcasts notification close events', async () => {
12131228
expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo');

packages/service-worker/worker/testing/scope.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,17 @@ export class SwTestHarnessImpl
281281
return event.ready;
282282
}
283283

284+
handleUnhandledRejection(reason: any): void {
285+
if (!this.eventHandlers.has('unhandledrejection')) {
286+
throw new Error('No unhandledrejection handler registered');
287+
}
288+
const event = {
289+
reason,
290+
promise: Promise.reject(reason),
291+
} as PromiseRejectionEvent;
292+
this.eventHandlers.get('unhandledrejection')!.call(this, event);
293+
}
294+
284295
override timeout(ms: number): Promise<void> {
285296
const promise = new Promise<void>((resolve) => {
286297
this.timers.push({

0 commit comments

Comments
 (0)