diff --git a/src/abortable.test.ts b/src/abortable.test.ts new file mode 100644 index 0000000..ac455aa --- /dev/null +++ b/src/abortable.test.ts @@ -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 | undefined; + + abortable( + signal, + new Promise(() => {}), + ).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 | undefined; + + abortable( + signal, + new Promise((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); +}); diff --git a/src/abortable.ts b/src/abortable.ts index faaecb6..11a839e 100644 --- a/src/abortable.ts +++ b/src/abortable.ts @@ -11,6 +11,12 @@ export function abortable( signal: AbortSignal, promise: PromiseLike, ): Promise { + if (signal.aborted) { + // prevent unhandled rejection + const noop = () => {}; + promise.then(noop, noop); + } + return execute(signal, (resolve, reject) => { promise.then(resolve, reject);