From ec311440b0c5d25b978aa49a9622e52a1dcfafe8 Mon Sep 17 00:00:00 2001 From: Ivan Motiienko <1161259+katsanva@users.noreply.github.com> Date: Sat, 2 Nov 2024 14:02:16 +0100 Subject: [PATCH] fix: correct support for AbortSignal:timeout() --- source/core/index.ts | 7 +++++- test/abort.ts | 51 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/source/core/index.ts b/source/core/index.ts index 842bc4def..12c98d213 100644 --- a/source/core/index.ts +++ b/source/core/index.ts @@ -264,7 +264,12 @@ export default class Request extends Duplex implements RequestEvents { if (this.options.signal) { const abort = () => { - this.destroy(new AbortError(this)); + // See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static#return_value + if (this.options.signal?.reason?.name === 'TimeoutError') { + this.destroy(new TimeoutError(this.options.signal.reason, this.timings!, this)); + } else { + this.destroy(new AbortError(this)); + } }; if (this.options.signal.aborted) { diff --git a/test/abort.ts b/test/abort.ts index e9d151400..53738c3a9 100644 --- a/test/abort.ts +++ b/test/abort.ts @@ -324,3 +324,54 @@ test('support setting the signal as a default option', async t => { t.true(signalHandlersRemoved(), 'Abort signal event handlers not removed'); }); + +// See https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout_static +test('support AbortSignal.timeout()', async t => { + const signal = AbortSignal.timeout(1); + + const p = got('http://example.com', {signal}); + + await t.throwsAsync(p, { + code: 23, + message: 'The operation was aborted due to timeout', + }); +}); + +test('support AbortSignal.timeout() without user abort', async t => { + const {controller, signalHandlersRemoved} = createAbortController(); + const timeoutSignal = AbortSignal.timeout(1); + const signal = AbortSignal.any([ + controller.signal, + timeoutSignal, + ]); + const p = got('http://example.com', {signal}); + + await t.throwsAsync(p, { + code: 23, + message: 'The operation was aborted due to timeout', + }); + + t.true(signalHandlersRemoved(), 'Abort signal event handlers not removed'); +}); + +test('support AbortSignal.timeout() with user abort', async t => { + const {controller, signalHandlersRemoved} = createAbortController(); + const timeoutSignal = AbortSignal.timeout(1000); + const signal = AbortSignal.any([ + controller.signal, + timeoutSignal, + ]); + + setTimeout(() => { + controller.abort(); + }, 10); + + const p = got('http://example.com', {signal}); + + await t.throwsAsync(p, { + code: 'ERR_ABORTED', + message: 'This operation was aborted.', + }); + + t.true(signalHandlersRemoved(), 'Abort signal event handlers not removed'); +});