Skip to content

Commit

Permalink
Merge pull request #1322 from capricorn86/1262-treewalker-with-nodefi…
Browse files Browse the repository at this point in the history
…ltershow_comment-is-not-working

feat: [#1262] Adds support for AbortSignal.throwIfAborted()
  • Loading branch information
capricorn86 committed Mar 17, 2024
2 parents b64c9ac + 97a3937 commit 9d6d1f3
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export default class BrowserFrameNavigator {
let responseText: string;

const timeout = frame.window.setTimeout(
() => abortController.abort('Request timed out.'),
() => abortController.abort(new Error('Request timed out.')),
goToOptions?.timeout ?? 30000
);
const finalize = (): void => {
Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/src/fetch/AbortController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default class AbortController {
*
* @param [reason] Reason.
*/
public abort(reason?: string): void {
public abort(reason?: Error): void {
this.signal[PropertySymbol.abort](reason);
}
}
29 changes: 20 additions & 9 deletions packages/happy-dom/src/fetch/AbortSignal.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import EventTarget from '../event/EventTarget.js';
import * as PropertySymbol from '../PropertySymbol.js';
import Event from '../event/Event.js';
import DOMExceptionNameEnum from '../exception/DOMExceptionNameEnum.js';
import DOMException from '../exception/DOMException.js';

/**
* AbortSignal.
Expand All @@ -9,7 +11,7 @@ import Event from '../event/Event.js';
*/
export default class AbortSignal extends EventTarget {
public readonly aborted: boolean = false;
public readonly reason: string | null = null;
public readonly reason: Error | null = null;
public onabort: ((this: AbortSignal, event: Event) => void) | null = null;

/**
Expand All @@ -24,28 +26,37 @@ export default class AbortSignal extends EventTarget {
*
* @param [reason] Reason.
*/
public [PropertySymbol.abort](reason?: string): void {
public [PropertySymbol.abort](reason?: Error): void {
if (this.aborted) {
return;
}
if (reason) {
(<string>this.reason) = reason;
}
(<Error>this.reason) =
reason ||
new DOMException('signal is aborted without reason', DOMExceptionNameEnum.abortError);
(<boolean>this.aborted) = true;
this.dispatchEvent(new Event('abort'));
}

/**
* Throws an "AbortError" if the signal has been aborted.
*/
public throwIfAborted(): void {
if (this.aborted) {
throw this.reason;
}
}

/**
* Returns an AbortSignal instance that has been set as aborted.
*
* @param [reason] Reason.
* @returns AbortSignal instance.
*/
public static abort(reason?: string): AbortSignal {
public static abort(reason?: Error): AbortSignal {
const signal = new AbortSignal();
if (reason) {
(<string>signal.reason) = reason;
}
(<Error>signal.reason) =
reason ||
new DOMException('signal is aborted without reason', DOMExceptionNameEnum.abortError);
(<boolean>signal.aborted) = true;
return signal;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/happy-dom/src/fetch/Fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -799,9 +799,9 @@ export default class Fetch {
*
* @param reason Reason.
*/
private abort(reason?: string): void {
private abort(reason?: Error): void {
const error = new DOMException(
'The operation was aborted.' + (reason ? ' ' + reason : ''),
'The operation was aborted.' + (reason ? ' ' + reason.toString() : ''),
DOMExceptionNameEnum.abortError
);

Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/test/browser/BrowserFrame.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ describe('BrowserFrame', () => {

expect(error).toEqual(
new DOMException(
'The operation was aborted. Request timed out.',
'The operation was aborted. Error: Request timed out.',
DOMExceptionNameEnum.abortError
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ describe('DetachedBrowserFrame', () => {

expect(error).toEqual(
new DOMException(
'The operation was aborted. Request timed out.',
'The operation was aborted. Error: Request timed out.',
DOMExceptionNameEnum.abortError
)
);
Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/test/fetch/AbortController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('AbortController', () => {
it('Aborts the signal.', () => {
const controller = new AbortController();
const signal = controller.signal;
const reason = 'abort reason';
const reason = new Error('abort reason');
let triggeredEvent: Event | null = null;

signal.addEventListener('abort', (event: Event) => (triggeredEvent = event));
Expand Down
17 changes: 15 additions & 2 deletions packages/happy-dom/test/fetch/AbortSignal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('AbortSignal', () => {
describe('[PropertySymbol.abort]()', () => {
it('Aborts the signal.', () => {
const signal = new AbortSignal();
const reason = 'abort reason';
const reason = new Error('abort reason');
let triggeredEvent: Event | null = null;

signal.addEventListener('abort', (event: Event) => (triggeredEvent = event));
Expand All @@ -20,9 +20,22 @@ describe('AbortSignal', () => {
});
});

describe('throwIfAborted()', () => {
it('Throws an "AbortError" if the signal has been aborted.', () => {
const signal = new AbortSignal();
const reason = new Error('abort reason');

expect(() => signal.throwIfAborted()).not.toThrow(reason);

signal[PropertySymbol.abort](reason);

expect(() => signal.throwIfAborted()).toThrow(reason);
});
});

describe('AbortSignal.abort()', () => {
it('Returns a new instance of AbortSignal.', () => {
const reason = 'abort reason';
const reason = new Error('abort reason');
const signal = AbortSignal.abort(reason);

expect(signal.aborted).toBe(true);
Expand Down
35 changes: 28 additions & 7 deletions packages/happy-dom/test/fetch/Fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2147,7 +2147,10 @@ describe('Fetch', () => {
}

expect(error).toEqual(
new DOMException('The operation was aborted.', DOMExceptionNameEnum.abortError)
new DOMException(
'The operation was aborted. AbortError: signal is aborted without reason',
DOMExceptionNameEnum.abortError
)
);
});

Expand Down Expand Up @@ -2202,7 +2205,10 @@ describe('Fetch', () => {
}

expect(error).toEqual(
new DOMException('The operation was aborted.', DOMExceptionNameEnum.abortError)
new DOMException(
'The operation was aborted. AbortError: signal is aborted without reason',
DOMExceptionNameEnum.abortError
)
);
});
it('Supports aborting multiple ongoing requests using AbortController.', async () => {
Expand Down Expand Up @@ -2249,10 +2255,16 @@ describe('Fetch', () => {
const onFetchCatch = (): void => {
if (error1 && error2) {
expect(error1).toEqual(
new DOMException('The operation was aborted.', DOMExceptionNameEnum.abortError)
new DOMException(
'The operation was aborted. AbortError: signal is aborted without reason',
DOMExceptionNameEnum.abortError
)
);
expect(error2).toEqual(
new DOMException('The operation was aborted.', DOMExceptionNameEnum.abortError)
new DOMException(
'The operation was aborted. AbortError: signal is aborted without reason',
DOMExceptionNameEnum.abortError
)
);
resolve(null);
}
Expand Down Expand Up @@ -2334,7 +2346,10 @@ describe('Fetch', () => {
}

expect(error).toEqual(
new DOMException('The operation was aborted.', DOMExceptionNameEnum.abortError)
new DOMException(
'The operation was aborted. AbortError: signal is aborted without reason',
DOMExceptionNameEnum.abortError
)
);
});

Expand Down Expand Up @@ -2397,7 +2412,10 @@ describe('Fetch', () => {
}

expect(error).toEqual(
new DOMException('The operation was aborted.', DOMExceptionNameEnum.abortError)
new DOMException(
'The operation was aborted. AbortError: signal is aborted without reason',
DOMExceptionNameEnum.abortError
)
);
});

Expand Down Expand Up @@ -2467,7 +2485,10 @@ describe('Fetch', () => {
}

expect(error).toEqual(
new DOMException('The operation was aborted.', DOMExceptionNameEnum.abortError)
new DOMException(
'The operation was aborted. AbortError: signal is aborted without reason',
DOMExceptionNameEnum.abortError
)
);
});

Expand Down
11 changes: 7 additions & 4 deletions packages/happy-dom/test/fetch/Request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Blob from '../../src/file/Blob.js';
import FormData from '../../src/form-data/FormData.js';
import MultipartFormDataParser from '../../src/fetch/multipart/MultipartFormDataParser.js';
import { beforeEach, describe, it, expect, vi, afterEach } from 'vitest';
import Stream from 'stream';
import { ReadableStream } from 'stream/web';
import * as PropertySymbol from '../../src/PropertySymbol.js';

const TEST_URL = 'https://example.com/';
Expand Down Expand Up @@ -115,7 +115,7 @@ describe('Request', () => {
const request = new window.Request(otherRequest);
const chunks: Buffer[] = [];

for await (const chunk of <Stream.Readable>request.body) {
for await (const chunk of <ReadableStream>request.body) {
chunks.push(Buffer.from(chunk));
}

Expand All @@ -126,7 +126,7 @@ describe('Request', () => {
const request = new window.Request(TEST_URL, { method: 'POST', body: 'Hello World' });
const chunks: Buffer[] = [];

for await (const chunk of <Stream.Readable>request.body) {
for await (const chunk of <ReadableStream>request.body) {
chunks.push(Buffer.from(chunk));
}

Expand Down Expand Up @@ -684,7 +684,10 @@ describe('Request', () => {
let isAsyncComplete = false;

vi.spyOn(MultipartFormDataParser, 'streamToFormData').mockImplementation(
(): Promise<FormData> => new Promise((resolve) => setTimeout(() => resolve(formData), 10))
(): Promise<{ formData; buffer: Buffer }> =>
new Promise((resolve) =>
setTimeout(() => resolve({ formData, buffer: Buffer.from([]) }), 10)
)
);

window.happyDOM?.waitUntilComplete().then(() => (isAsyncComplete = true));
Expand Down
4 changes: 1 addition & 3 deletions packages/integration-test/test/tests/Browser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ describe('Browser', () => {
await page.waitUntilComplete();

expect(page.mainFrame.url).toBe('https://github.com/capricorn86/happy-dom');
expect(
page.mainFrame.document.title.startsWith('GitHub - capricorn86/happy-dom: Happy DOM')
).toBe(true);
expect(page.mainFrame.document.title.startsWith('GitHub - capricorn86/happy-dom')).toBe(true);
expect(
page.mainFrame.document.querySelector('a[href="/capricorn86/happy-dom"]').textContent.trim()
).toBe('happy-dom');
Expand Down

0 comments on commit 9d6d1f3

Please sign in to comment.