• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2// Flags: --expose-internals --no-warnings --experimental-abortcontroller
3
4const common = require('../common');
5const { once, EventEmitter } = require('events');
6const {
7  strictEqual,
8  deepStrictEqual,
9  fail,
10  rejects,
11} = require('assert');
12const { EventTarget, Event } = require('internal/event_target');
13
14async function onceAnEvent() {
15  const ee = new EventEmitter();
16
17  process.nextTick(() => {
18    ee.emit('myevent', 42);
19  });
20
21  const [value] = await once(ee, 'myevent');
22  strictEqual(value, 42);
23  strictEqual(ee.listenerCount('error'), 0);
24  strictEqual(ee.listenerCount('myevent'), 0);
25}
26
27async function onceAnEventWithTwoArgs() {
28  const ee = new EventEmitter();
29
30  process.nextTick(() => {
31    ee.emit('myevent', 42, 24);
32  });
33
34  const value = await once(ee, 'myevent');
35  deepStrictEqual(value, [42, 24]);
36}
37
38async function catchesErrors() {
39  const ee = new EventEmitter();
40
41  const expected = new Error('kaboom');
42  let err;
43  process.nextTick(() => {
44    ee.emit('error', expected);
45  });
46
47  try {
48    await once(ee, 'myevent');
49  } catch (_e) {
50    err = _e;
51  }
52  strictEqual(err, expected);
53  strictEqual(ee.listenerCount('error'), 0);
54  strictEqual(ee.listenerCount('myevent'), 0);
55}
56
57async function stopListeningAfterCatchingError() {
58  const ee = new EventEmitter();
59
60  const expected = new Error('kaboom');
61  let err;
62  process.nextTick(() => {
63    ee.emit('error', expected);
64    ee.emit('myevent', 42, 24);
65  });
66
67  try {
68    await once(ee, 'myevent');
69  } catch (_e) {
70    err = _e;
71  }
72  process.removeAllListeners('multipleResolves');
73  strictEqual(err, expected);
74  strictEqual(ee.listenerCount('error'), 0);
75  strictEqual(ee.listenerCount('myevent'), 0);
76}
77
78async function onceError() {
79  const ee = new EventEmitter();
80
81  const expected = new Error('kaboom');
82  process.nextTick(() => {
83    ee.emit('error', expected);
84  });
85
86  const promise = once(ee, 'error');
87  strictEqual(ee.listenerCount('error'), 1);
88  const [ err ] = await promise;
89  strictEqual(err, expected);
90  strictEqual(ee.listenerCount('error'), 0);
91  strictEqual(ee.listenerCount('myevent'), 0);
92}
93
94async function onceWithEventTarget() {
95  const et = new EventTarget();
96  const event = new Event('myevent');
97  process.nextTick(() => {
98    et.dispatchEvent(event);
99  });
100  const [ value ] = await once(et, 'myevent');
101  strictEqual(value, event);
102}
103
104async function onceWithEventTargetError() {
105  const et = new EventTarget();
106  const error = new Event('error');
107  process.nextTick(() => {
108    et.dispatchEvent(error);
109  });
110
111  const [ err ] = await once(et, 'error');
112  strictEqual(err, error);
113}
114
115async function prioritizesEventEmitter() {
116  const ee = new EventEmitter();
117  ee.addEventListener = fail;
118  ee.removeAllListeners = fail;
119  process.nextTick(() => ee.emit('foo'));
120  await once(ee, 'foo');
121}
122
123async function abortSignalBefore() {
124  const ee = new EventEmitter();
125  const ac = new AbortController();
126  ee.on('error', common.mustNotCall());
127  ac.abort();
128
129  await Promise.all([1, {}, 'hi', null, false].map((signal) => {
130    return rejects(once(ee, 'foo', { signal }), {
131      code: 'ERR_INVALID_ARG_TYPE'
132    });
133  }));
134
135  return rejects(once(ee, 'foo', { signal: ac.signal }), {
136    name: 'AbortError'
137  });
138}
139
140async function abortSignalAfter() {
141  const ee = new EventEmitter();
142  const ac = new AbortController();
143  ee.on('error', common.mustNotCall());
144  const r = rejects(once(ee, 'foo', { signal: ac.signal }), {
145    name: 'AbortError'
146  });
147  process.nextTick(() => ac.abort());
148  return r;
149}
150
151async function abortSignalAfterEvent() {
152  const ee = new EventEmitter();
153  const ac = new AbortController();
154  process.nextTick(() => {
155    ee.emit('foo');
156    ac.abort();
157  });
158  await once(ee, 'foo', { signal: ac.signal });
159}
160
161async function eventTargetAbortSignalBefore() {
162  const et = new EventTarget();
163  const ac = new AbortController();
164  ac.abort();
165
166  await Promise.all([1, {}, 'hi', null, false].map((signal) => {
167    return rejects(once(et, 'foo', { signal }), {
168      code: 'ERR_INVALID_ARG_TYPE'
169    });
170  }));
171
172  return rejects(once(et, 'foo', { signal: ac.signal }), {
173    name: 'AbortError'
174  });
175}
176
177async function eventTargetAbortSignalAfter() {
178  const et = new EventTarget();
179  const ac = new AbortController();
180  const r = rejects(once(et, 'foo', { signal: ac.signal }), {
181    name: 'AbortError'
182  });
183  process.nextTick(() => ac.abort());
184  return r;
185}
186
187async function eventTargetAbortSignalAfterEvent() {
188  const et = new EventTarget();
189  const ac = new AbortController();
190  process.nextTick(() => {
191    et.dispatchEvent(new Event('foo'));
192    ac.abort();
193  });
194  await once(et, 'foo', { signal: ac.signal });
195}
196
197Promise.all([
198  onceAnEvent(),
199  onceAnEventWithTwoArgs(),
200  catchesErrors(),
201  stopListeningAfterCatchingError(),
202  onceError(),
203  onceWithEventTarget(),
204  onceWithEventTargetError(),
205  prioritizesEventEmitter(),
206  abortSignalBefore(),
207  abortSignalAfter(),
208  abortSignalAfterEvent(),
209  eventTargetAbortSignalBefore(),
210  eventTargetAbortSignalAfter(),
211  eventTargetAbortSignalAfterEvent(),
212]).then(common.mustCall());
213