1'use strict'; 2// Flags: --expose-internals --no-warnings 3 4const common = require('../common'); 5const { once, EventEmitter } = require('events'); 6const { 7 strictEqual, 8 deepStrictEqual, 9 fail, 10 rejects, 11} = require('assert'); 12const { kEvents } = 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 onceAnEventWithNullOptions() { 28 const ee = new EventEmitter(); 29 30 process.nextTick(() => { 31 ee.emit('myevent', 42); 32 }); 33 34 const [value] = await once(ee, 'myevent', null); 35 strictEqual(value, 42); 36} 37 38 39async function onceAnEventWithTwoArgs() { 40 const ee = new EventEmitter(); 41 42 process.nextTick(() => { 43 ee.emit('myevent', 42, 24); 44 }); 45 46 const value = await once(ee, 'myevent'); 47 deepStrictEqual(value, [42, 24]); 48} 49 50async function catchesErrors() { 51 const ee = new EventEmitter(); 52 53 const expected = new Error('kaboom'); 54 let err; 55 process.nextTick(() => { 56 ee.emit('error', expected); 57 }); 58 59 try { 60 await once(ee, 'myevent'); 61 } catch (_e) { 62 err = _e; 63 } 64 strictEqual(err, expected); 65 strictEqual(ee.listenerCount('error'), 0); 66 strictEqual(ee.listenerCount('myevent'), 0); 67} 68 69async function catchesErrorsWithAbortSignal() { 70 const ee = new EventEmitter(); 71 const ac = new AbortController(); 72 const signal = ac.signal; 73 74 const expected = new Error('boom'); 75 let err; 76 process.nextTick(() => { 77 ee.emit('error', expected); 78 }); 79 80 try { 81 const promise = once(ee, 'myevent', { signal }); 82 strictEqual(ee.listenerCount('error'), 1); 83 strictEqual(signal[kEvents].size, 1); 84 85 await promise; 86 } catch (e) { 87 err = e; 88 } 89 strictEqual(err, expected); 90 strictEqual(ee.listenerCount('error'), 0); 91 strictEqual(ee.listenerCount('myevent'), 0); 92 strictEqual(signal[kEvents].size, 0); 93} 94 95async function stopListeningAfterCatchingError() { 96 const ee = new EventEmitter(); 97 98 const expected = new Error('kaboom'); 99 let err; 100 process.nextTick(() => { 101 ee.emit('error', expected); 102 ee.emit('myevent', 42, 24); 103 }); 104 105 try { 106 await once(ee, 'myevent'); 107 } catch (_e) { 108 err = _e; 109 } 110 process.removeAllListeners('multipleResolves'); 111 strictEqual(err, expected); 112 strictEqual(ee.listenerCount('error'), 0); 113 strictEqual(ee.listenerCount('myevent'), 0); 114} 115 116async function onceError() { 117 const ee = new EventEmitter(); 118 119 const expected = new Error('kaboom'); 120 process.nextTick(() => { 121 ee.emit('error', expected); 122 }); 123 124 const promise = once(ee, 'error'); 125 strictEqual(ee.listenerCount('error'), 1); 126 const [ err ] = await promise; 127 strictEqual(err, expected); 128 strictEqual(ee.listenerCount('error'), 0); 129 strictEqual(ee.listenerCount('myevent'), 0); 130} 131 132async function onceWithEventTarget() { 133 const et = new EventTarget(); 134 const event = new Event('myevent'); 135 process.nextTick(() => { 136 et.dispatchEvent(event); 137 }); 138 const [ value ] = await once(et, 'myevent'); 139 strictEqual(value, event); 140} 141 142async function onceWithEventTargetError() { 143 const et = new EventTarget(); 144 const error = new Event('error'); 145 process.nextTick(() => { 146 et.dispatchEvent(error); 147 }); 148 149 const [ err ] = await once(et, 'error'); 150 strictEqual(err, error); 151} 152 153async function onceWithInvalidEventEmmiter() { 154 const ac = new AbortController(); 155 return rejects(once(ac, 'myevent'), { 156 code: 'ERR_INVALID_ARG_TYPE', 157 }); 158} 159 160async function prioritizesEventEmitter() { 161 const ee = new EventEmitter(); 162 ee.addEventListener = fail; 163 ee.removeAllListeners = fail; 164 process.nextTick(() => ee.emit('foo')); 165 await once(ee, 'foo'); 166} 167 168async function abortSignalBefore() { 169 const ee = new EventEmitter(); 170 ee.on('error', common.mustNotCall()); 171 const abortedSignal = AbortSignal.abort(); 172 173 await Promise.all([1, {}, 'hi', null, false].map((signal) => { 174 return rejects(once(ee, 'foo', { signal }), { 175 code: 'ERR_INVALID_ARG_TYPE', 176 }); 177 })); 178 179 return rejects(once(ee, 'foo', { signal: abortedSignal }), { 180 name: 'AbortError', 181 }); 182} 183 184async function abortSignalAfter() { 185 const ee = new EventEmitter(); 186 const ac = new AbortController(); 187 ee.on('error', common.mustNotCall()); 188 const r = rejects(once(ee, 'foo', { signal: ac.signal }), { 189 name: 'AbortError', 190 }); 191 process.nextTick(() => ac.abort()); 192 return r; 193} 194 195async function abortSignalAfterEvent() { 196 const ee = new EventEmitter(); 197 const ac = new AbortController(); 198 process.nextTick(() => { 199 ee.emit('foo'); 200 ac.abort(); 201 }); 202 const promise = once(ee, 'foo', { signal: ac.signal }); 203 strictEqual(ac.signal[kEvents].size, 1); 204 await promise; 205 strictEqual(ac.signal[kEvents].size, 0); 206} 207 208async function abortSignalRemoveListener() { 209 const ee = new EventEmitter(); 210 const ac = new AbortController(); 211 212 try { 213 process.nextTick(() => ac.abort()); 214 await once(ee, 'test', { signal: ac.signal }); 215 } catch { 216 strictEqual(ee.listeners('test').length, 0); 217 strictEqual(ee.listeners('error').length, 0); 218 } 219} 220 221async function eventTargetAbortSignalBefore() { 222 const et = new EventTarget(); 223 const abortedSignal = AbortSignal.abort(); 224 225 await Promise.all([1, {}, 'hi', null, false].map((signal) => { 226 return rejects(once(et, 'foo', { signal }), { 227 code: 'ERR_INVALID_ARG_TYPE', 228 }); 229 })); 230 231 return rejects(once(et, 'foo', { signal: abortedSignal }), { 232 name: 'AbortError', 233 }); 234} 235 236async function eventTargetAbortSignalBeforeEvenWhenSignalPropagationStopped() { 237 const et = new EventTarget(); 238 const ac = new AbortController(); 239 const { signal } = ac; 240 signal.addEventListener('abort', (e) => e.stopImmediatePropagation(), { once: true }); 241 242 process.nextTick(() => ac.abort()); 243 return rejects(once(et, 'foo', { signal }), { 244 name: 'AbortError', 245 }); 246} 247 248async function eventTargetAbortSignalAfter() { 249 const et = new EventTarget(); 250 const ac = new AbortController(); 251 const r = rejects(once(et, 'foo', { signal: ac.signal }), { 252 name: 'AbortError', 253 }); 254 process.nextTick(() => ac.abort()); 255 return r; 256} 257 258async function eventTargetAbortSignalAfterEvent() { 259 const et = new EventTarget(); 260 const ac = new AbortController(); 261 process.nextTick(() => { 262 et.dispatchEvent(new Event('foo')); 263 ac.abort(); 264 }); 265 await once(et, 'foo', { signal: ac.signal }); 266} 267 268Promise.all([ 269 onceAnEvent(), 270 onceAnEventWithNullOptions(), 271 onceAnEventWithTwoArgs(), 272 catchesErrors(), 273 catchesErrorsWithAbortSignal(), 274 stopListeningAfterCatchingError(), 275 onceError(), 276 onceWithEventTarget(), 277 onceWithEventTargetError(), 278 onceWithInvalidEventEmmiter(), 279 prioritizesEventEmitter(), 280 abortSignalBefore(), 281 abortSignalAfter(), 282 abortSignalAfterEvent(), 283 abortSignalRemoveListener(), 284 eventTargetAbortSignalBefore(), 285 eventTargetAbortSignalBeforeEvenWhenSignalPropagationStopped(), 286 eventTargetAbortSignalAfter(), 287 eventTargetAbortSignalAfterEvent(), 288]).then(common.mustCall()); 289