Skip to content

Commit

Permalink
Fix unhandled promise rejection in abortable
Browse files Browse the repository at this point in the history
  • Loading branch information
aikoven committed Apr 13, 2021
1 parent 7bf7e2f commit a7b9cc0
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
75 changes: 75 additions & 0 deletions src/abortable.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import AbortController from 'node-abort-controller';
import {abortable} from './abortable';
import {nextTick} from './utils/nextTick';

test('abortable endless promise', async () => {
const abortController = new AbortController();
const signal = abortController.signal;
signal.addEventListener = jest.fn(signal.addEventListener);
signal.removeEventListener = jest.fn(signal.removeEventListener);

let result: PromiseSettledResult<void> | undefined;

abortable(
signal,
new Promise<void>(() => {}),
).then(
value => {
result = {status: 'fulfilled', value};
},
reason => {
result = {status: 'rejected', reason};
},
);

await nextTick();

expect(result).toBeUndefined();

abortController.abort();

await nextTick();

expect(result).toMatchObject({
status: 'rejected',
reason: {name: 'AbortError'},
});

expect(signal.addEventListener).toHaveBeenCalledTimes(1);
expect(signal.removeEventListener).toHaveBeenCalledTimes(1);
});

test('abort before reject', async () => {
const abortController = new AbortController();
const signal = abortController.signal;
signal.addEventListener = jest.fn(signal.addEventListener);
signal.removeEventListener = jest.fn(signal.removeEventListener);

abortController.abort();

let result: PromiseSettledResult<void> | undefined;

abortable(
signal,
new Promise<void>((resolve, reject) => {
reject('test');
}),
).then(
value => {
result = {status: 'fulfilled', value};
},
reason => {
result = {status: 'rejected', reason};
},
);

await nextTick();

expect(result).toMatchObject({
status: 'rejected',
reason: {name: 'AbortError'},
});

expect(signal.addEventListener).toHaveBeenCalledTimes(0);
expect(signal.removeEventListener).toHaveBeenCalledTimes(0);
});
6 changes: 6 additions & 0 deletions src/abortable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ export function abortable<T>(
signal: AbortSignal,
promise: PromiseLike<T>,
): Promise<T> {
if (signal.aborted) {
// prevent unhandled rejection
const noop = () => {};
promise.then(noop, noop);
}

return execute<T>(signal, (resolve, reject) => {
promise.then(resolve, reject);

Expand Down

0 comments on commit a7b9cc0

Please sign in to comment.