diff --git a/src/abortcontroller.js b/src/abortcontroller.js index a28b35f..13f4b6f 100644 --- a/src/abortcontroller.js +++ b/src/abortcontroller.js @@ -60,6 +60,7 @@ export class AbortSignal extends Emitter { // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl Object.defineProperty(this, 'aborted', { value: false, writable: true, configurable: true }); Object.defineProperty(this, 'onabort', { value: null, writable: true, configurable: true }); + Object.defineProperty(this, 'reason', { value: undefined, writable: true, configurable: true }); } toString() { return '[object AbortSignal]'; @@ -82,7 +83,7 @@ export class AbortController { // we want Object.keys(new AbortController()) to be [] for compat with the native impl Object.defineProperty(this, 'signal', { value: new AbortSignal(), writable: true, configurable: true }); } - abort() { + abort(reason) { let event; try { event = new Event('abort'); @@ -106,6 +107,18 @@ export class AbortController { }; } } + + let signalReason = reason; + if (signalReason === undefined) { + if (typeof document === 'undefined') { + signalReason = new Error('This operation was aborted'); + signalReason.name = 'AbortError'; + } else { + signalReason = new DOMException('signal is aborted without reason'); + } + } + this.signal.reason = signalReason; + this.signal.dispatchEvent(event); } toString() { diff --git a/tests/basic.test.js b/tests/basic.test.js index 4ea58fd..b3dc9a5 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -53,7 +53,7 @@ const runBasicTests = (testSuiteTitle, TESTPAGE_URL) => { it('abort during fetch', async () => { const { server, baseUrl } = createFetchTargetServer(); await browser.url(TESTPAGE_URL); - const err = await browser.executeAsync(async (baseUrl, done) => { + const { errorName, signalReason } = await browser.executeAsync(async (baseUrl, done) => { setTimeout(() => { done({ name: 'fail' }); }, 2000); @@ -64,11 +64,12 @@ const runBasicTests = (testSuiteTitle, TESTPAGE_URL) => { }, 500); try { await fetch(`${baseUrl}?sleepMillis=1000`, { signal }); - } catch (err) { - done(err); + } catch (error) { + done({ errorName: error.name, signalReason: signal.reason }); } }, baseUrl); - expect(err.name).toBe('AbortError'); + expect(errorName).toBe('AbortError'); + expect(signalReason.message).toBe('signal is aborted without reason'); server.close(); }); @@ -335,6 +336,17 @@ const runBasicTests = (testSuiteTitle, TESTPAGE_URL) => { }); expect(result).toBe('[object AbortSignal]'); }); + + it('abort(reason)', async () => { + await browser.url(TESTPAGE_URL); + const signalReason = await browser.executeAsync(async (done) => { + const controller = new AbortController(); + controller.abort('My reason'); + + done(controller.signal.reason); + }); + expect(signalReason).toEqual('My reason'); + }); }); };