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