Skip to content

Commit d66de2d

Browse files
feature: [#1540] Adds support for sending AbortSignal as option to EventTarget.addEventListener (#1739)
Co-authored-by: David Ortner <[email protected]>
1 parent 33f1beb commit d66de2d

File tree

3 files changed

+28
-2
lines changed

3 files changed

+28
-2
lines changed

packages/happy-dom/src/event/EventTarget.ts

+7
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export default class EventTarget {
4545
* @param listener Listener.
4646
* @param options An object that specifies characteristics about the event listener.(currently only once)
4747
* @param options.once
48+
* @param options.signal An AbortSignal. The listener will be removed when the given AbortSignal object's abort() method is called.
4849
*/
4950
public addEventListener(
5051
type: string,
@@ -71,6 +72,12 @@ export default class EventTarget {
7172

7273
listeners.push(listener);
7374
listenerOptions.push(options);
75+
76+
if (options.signal && !options.signal.aborted) {
77+
options.signal.addEventListener('abort', () => {
78+
this.removeEventListener(type, listener);
79+
});
80+
}
7481
}
7582

7683
/**
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import AbortSignal from 'src/fetch/AbortSignal.js';
2+
13
export default interface IEventListenerOptions {
24
once?: boolean;
35

46
// TODO: Not implemented yet.
57
capture?: boolean;
68
passive?: boolean;
7-
signal?: unknown;
9+
signal?: AbortSignal;
810
}

packages/happy-dom/test/fetch/AbortController.test.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Event from '../../src/event/Event.js';
22
import AbortController from '../../src/fetch/AbortController.js';
3-
import { describe, it, expect, beforeEach } from 'vitest';
3+
import { describe, it, expect, beforeEach, vi } from 'vitest';
44
import BrowserWindow from '../../src/window/BrowserWindow.js';
55
import Window from '../../src/window/Window.js';
66

@@ -26,5 +26,22 @@ describe('AbortController', () => {
2626
expect(signal.reason).toBe(reason);
2727
expect((<Event>(<unknown>triggeredEvent)).type).toBe('abort');
2828
});
29+
30+
it('Does not trigger abort event listener if the listener signal is aborted', () => {
31+
const controller = new window.AbortController();
32+
const callbackCtrl = new window.AbortController();
33+
const signal = controller.signal;
34+
const callbackMock = vi.fn();
35+
36+
signal.addEventListener('abort', (event: Event) => callbackMock(), {
37+
signal: callbackCtrl.signal
38+
});
39+
40+
callbackCtrl.abort();
41+
controller.abort();
42+
43+
expect(signal.aborted).toBe(true);
44+
expect(callbackMock).toBeCalledTimes(0);
45+
});
2946
});
3047
});

0 commit comments

Comments
 (0)