Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Throw DomException with name AbortError #482

Merged
Merged
22 changes: 17 additions & 5 deletions source/errors/DOMException.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
const DOMException = globalThis.DOMException ?? Error;
// DomException is supported on most modern browsers, and Node >= 17.
// @see https://developer.mozilla.org/en-US/docs/Web/API/DOMException#browser_compatibility
const domExceptionSupported = Boolean(globalThis.DOMException);
cristobal marked this conversation as resolved.
Show resolved Hide resolved

export default DOMException;

// When targeting Node.js 18, use `signal.throwIfAborted()` (https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted)
// TODO: When targeting Node.js 18, use `signal.throwIfAborted()` (https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted)
export function composeAbortError(signal?: AbortSignal) {
return new DOMException(signal?.reason ?? 'The operation was aborted.');
/*
NOTE: Use DomException with AbortError name as specified in MDN docs (https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort)
> When abort() is called, the fetch() promise rejects with an Error of type DOMException, with name AbortError.
*/
cristobal marked this conversation as resolved.
Show resolved Hide resolved
if (domExceptionSupported) {
return new DOMException(signal?.reason ?? 'The operation was aborted.', 'AbortError');
}

// DomException not supported fallback to use of error and override name
const error = new Error(signal?.reason ?? 'The operation was aborted.');
error.name = 'AbortError';

return error;
}
8 changes: 5 additions & 3 deletions test/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ test('ky.extend()', async t => {
await server.close();
});

test('throws DOMException when aborted by user', async t => {
test('throws DomException/Error with name AbortError when aborted by user', async t => {
cristobal marked this conversation as resolved.
Show resolved Hide resolved
const server = await createHttpTestServer();
// eslint-disable-next-line @typescript-eslint/no-empty-function
server.get('/', () => {});
Expand All @@ -592,8 +592,10 @@ test('throws DOMException when aborted by user', async t => {
const response = ky(server.url, {signal});
abortController.abort();

const {name} = (await t.throwsAsync(response))!;
t.true(['DOMException', 'Error'].includes(name), `Expected DOMException or Error, got ${name}`);
const error = (await t.throwsAsync(response))!;

t.true(['DomException', 'Error'].includes(error.constructor.name), `Expected DOMException or Error, got ${error.constructor.name}`);
cristobal marked this conversation as resolved.
Show resolved Hide resolved
t.true(error.name === 'AbortError', `Expected AbortError, got ${error.name}`);
cristobal marked this conversation as resolved.
Show resolved Hide resolved
});

test('supports Request instance as input', async t => {
Expand Down