• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import * as common from '../common/index.mjs';
2import { describe, it } from 'node:test';
3import { once } from 'node:events';
4import assert from 'node:assert';
5
6describe('AbortSignal.any()', { concurrency: true }, () => {
7  it('should throw when not receiving an array', () => {
8    const expectedError = { code: 'ERR_INVALID_ARG_TYPE' };
9    assert.throws(() => AbortSignal.any(), expectedError);
10    assert.throws(() => AbortSignal.any(null), expectedError);
11    assert.throws(() => AbortSignal.any(undefined), expectedError);
12  });
13
14  it('should throw when input contains non-signal values', () => {
15    assert.throws(
16      () => AbortSignal.any([AbortSignal.abort(), undefined]),
17      {
18        code: 'ERR_INVALID_ARG_TYPE',
19        message: 'The "signals[1]" argument must be an instance of AbortSignal. Received undefined'
20      },
21    );
22  });
23
24  it('creates a non-aborted signal for an empty input', () => {
25    const signal = AbortSignal.any([]);
26    assert.strictEqual(signal.aborted, false);
27    signal.addEventListener('abort', common.mustNotCall());
28  });
29
30  it('returns a new signal', () => {
31    const originalSignal = new AbortController().signal;
32    const signalAny = AbortSignal.any([originalSignal]);
33    assert.notStrictEqual(originalSignal, signalAny);
34  });
35
36  it('returns an aborted signal if input has an aborted signal', () => {
37    const signal = AbortSignal.any([AbortSignal.abort('some reason')]);
38    assert.strictEqual(signal.aborted, true);
39    assert.strictEqual(signal.reason, 'some reason');
40    signal.addEventListener('abort', common.mustNotCall());
41  });
42
43  it('returns an aborted signal with the reason of first aborted signal input', () => {
44    const signal = AbortSignal.any([AbortSignal.abort('some reason'), AbortSignal.abort('another reason')]);
45    assert.strictEqual(signal.aborted, true);
46    assert.strictEqual(signal.reason, 'some reason');
47    signal.addEventListener('abort', common.mustNotCall());
48  });
49
50  it('returns the correct signal in the event target', async () => {
51    const signal = AbortSignal.any([AbortSignal.timeout(5)]);
52    const interval = setInterval(() => {}, 100000); // Keep event loop alive
53    const [{ target }] = await once(signal, 'abort');
54    clearInterval(interval);
55    assert.strictEqual(target, signal);
56    assert.ok(signal.aborted);
57    assert.strictEqual(signal.reason.name, 'TimeoutError');
58  });
59
60  it('aborts with reason of first aborted signal', () => {
61    const controllers = Array.from({ length: 3 }, () => new AbortController());
62    const combinedSignal = AbortSignal.any(controllers.map((c) => c.signal));
63    controllers[1].abort(1);
64    controllers[2].abort(2);
65    assert.ok(combinedSignal.aborted);
66    assert.strictEqual(combinedSignal.reason, 1);
67  });
68
69  it('can accept the same signal more than once', () => {
70    const controller = new AbortController();
71    const signal = AbortSignal.any([controller.signal, controller.signal]);
72    assert.strictEqual(signal.aborted, false);
73    controller.abort('reason');
74    assert.ok(signal.aborted);
75    assert.strictEqual(signal.reason, 'reason');
76  });
77
78  it('handles deeply aborted signals', async () => {
79    const controllers = Array.from({ length: 2 }, () => new AbortController());
80    const composedSignal1 = AbortSignal.any([controllers[0].signal]);
81    const composedSignal2 = AbortSignal.any([composedSignal1, controllers[1].signal]);
82
83    composedSignal2.onabort = common.mustCall();
84    controllers[0].abort();
85    assert.ok(composedSignal2.aborted);
86    assert.ok(composedSignal2.reason instanceof DOMException);
87    assert.strictEqual(composedSignal2.reason.name, 'AbortError');
88  });
89
90  it('executes abort handlers in correct order', () => {
91    const controller = new AbortController();
92    const signals = [];
93    signals.push(controller.signal);
94    signals.push(AbortSignal.any([controller.signal]));
95    signals.push(AbortSignal.any([controller.signal]));
96    signals.push(AbortSignal.any([signals[0]]));
97    signals.push(AbortSignal.any([signals[1]]));
98
99    let result = '';
100    signals.forEach((signal, i) => signal.addEventListener('abort', () => result += i));
101    controller.abort();
102    assert.strictEqual(result, '01234');
103  });
104});
105