MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 333 lines 10 kB view raw
1import { test, testDeep, summary } from './helpers.js'; 2import { EventEmitter } from 'ant:events'; 3import { once as nodeOnce, addAbortListener, getMaxListeners, setMaxListeners } from 'node:events'; 4 5console.log('EventEmitter Tests\n'); 6 7const ee = new EventEmitter(); 8 9let received = null; 10ee.on('test', data => { 11 received = data; 12}); 13ee.emit('test', 'hello'); 14test('on and emit', received, 'hello'); 15 16let count = 0; 17ee.on('count', () => count++); 18ee.on('count', () => count++); 19ee.emit('count'); 20test('multiple listeners', count, 2); 21 22let onceValue = 0; 23ee.once('once', val => { 24 onceValue = val; 25}); 26ee.emit('once', 42); 27ee.emit('once', 100); 28test('once only fires once', onceValue, 42); 29 30let removed = false; 31const handler = () => { 32 removed = true; 33}; 34ee.on('remove', handler); 35ee.off('remove', handler); 36ee.emit('remove'); 37test('off removes listener', removed, false); 38 39let allRemoved = 0; 40ee.on('all', () => allRemoved++); 41ee.on('all', () => allRemoved++); 42ee.removeAllListeners('all'); 43ee.emit('all'); 44test('removeAllListeners', allRemoved, 0); 45 46test('listenerCount', ee.listenerCount('count'), 2); 47 48const names = ee.eventNames(); 49test('eventNames includes count', names.includes('count'), true); 50 51const ee2 = new EventEmitter(); 52let args = []; 53ee2.on('multi', (a, b, c) => { 54 args = [a, b, c]; 55}); 56ee2.emit('multi', 1, 2, 3); 57test('multiple emit args', args.join(','), '1,2,3'); 58 59const ee3 = new EventEmitter(); 60test('emit returns false with no listeners', ee3.emit('none'), false); 61ee3.on('exists', () => {}); 62test('emit returns true with listeners', ee3.emit('exists'), true); 63 64const ee4 = new EventEmitter(); 65const chain = ee4 66 .on('a', () => {}) 67 .once('b', () => {}) 68 .off('b', () => {}); 69test('methods return this for chaining', chain, ee4); 70 71const ee5 = new EventEmitter(); 72let aliasCount = 0; 73ee5.addListener('alias', () => aliasCount++); 74ee5.emit('alias'); 75test('addListener alias works', aliasCount, 1); 76 77const ee6 = new EventEmitter(); 78let removeAliasVal = 0; 79const removeAliasHandler = () => { 80 removeAliasVal = 1; 81}; 82ee6.on('rem', removeAliasHandler); 83ee6.removeListener('rem', removeAliasHandler); 84ee6.emit('rem'); 85test('removeListener alias works', removeAliasVal, 0); 86 87const ee7 = new EventEmitter(); 88let onceCount = 0; 89ee7.once('multi-once', () => onceCount++); 90ee7.once('multi-once', () => onceCount++); 91ee7.emit('multi-once'); 92test('multiple once listeners fire', onceCount, 2); 93ee7.emit('multi-once'); 94test('multiple once listeners only fire once', onceCount, 2); 95 96const ee8 = new EventEmitter(); 97test('listenerCount for non-existent event', ee8.listenerCount('nope'), 0); 98 99const ee9 = new EventEmitter(); 100const h = () => {}; 101ee9.on('temp', h); 102ee9.off('temp', h); 103test('eventNames excludes removed events', ee9.eventNames().includes('temp'), false); 104 105const eeA = new EventEmitter(); 106const eeB = new EventEmitter(); 107let aVal = 0, 108 bVal = 0; 109eeA.on('x', () => aVal++); 110eeB.on('x', () => bVal++); 111eeA.emit('x'); 112test('separate instances are isolated (A)', aVal, 1); 113test('separate instances are isolated (B)', bVal, 0); 114 115const eeC = new EventEmitter(); 116eeC.on('a', () => {}); 117eeC.on('b', () => {}); 118eeC.removeAllListeners(); 119test('removeAllListeners without event clears all listeners', eeC.listenerCount('a') + eeC.listenerCount('b'), 0); 120 121const eeD = new EventEmitter(); 122let listenerThis = null; 123eeD.on('ctx', function () { 124 listenerThis = this; 125}); 126eeD.emit('ctx'); 127test('EventEmitter listeners receive emitter as this', listenerThis, eeD); 128 129function LegacyEmitter() { 130 EventEmitter.call(this); 131} 132LegacyEmitter.prototype = {}; 133LegacyEmitter.prototype.__proto__ = EventEmitter.prototype; 134LegacyEmitter.prototype.constructor = LegacyEmitter; 135 136const legacy = new LegacyEmitter(); 137let legacyCount = 0; 138legacy.on('legacy', () => legacyCount++); 139legacy.emit('legacy'); 140test('EventEmitter.call(this) initializes classic inherited receivers', legacyCount, 1); 141 142console.log('\nEventTarget Tests\n'); 143 144const et = new EventTarget(); 145let etReceived = null; 146et.addEventListener('click', e => { 147 etReceived = e.type; 148}); 149et.dispatchEvent(new Event('click')); 150test('EventTarget addEventListener and dispatchEvent', etReceived, 'click'); 151 152let etEvent = null; 153const et2 = new EventTarget(); 154et2.addEventListener('custom', e => { 155 etEvent = e; 156}); 157et2.dispatchEvent(new CustomEvent('custom', { detail: { foo: 'bar' } })); 158test('event.type', etEvent.type, 'custom'); 159test('event.target is EventTarget', etEvent.target, et2); 160test('event.detail', etEvent.detail.foo, 'bar'); 161 162const et3 = new EventTarget(); 163let et3Val = 0; 164const et3Handler = () => { 165 et3Val++; 166}; 167et3.addEventListener('rem', et3Handler); 168et3.removeEventListener('rem', et3Handler); 169et3.dispatchEvent(new Event('rem')); 170test('EventTarget removeEventListener', et3Val, 0); 171 172const et4 = new EventTarget(); 173let et4Count = 0; 174et4.addEventListener('once', () => et4Count++, { once: true }); 175et4.dispatchEvent(new Event('once')); 176et4.dispatchEvent(new Event('once')); 177test('EventTarget once option', et4Count, 1); 178 179console.log('\nGlobal Event Tests\n'); 180 181let globalReceived = null; 182addEventListener('global-test', e => { 183 globalReceived = e.type; 184}); 185dispatchEvent(new Event('global-test')); 186test('global addEventListener and dispatchEvent', globalReceived, 'global-test'); 187 188let globalRemoved = 0; 189const globalHandler = () => { 190 globalRemoved++; 191}; 192addEventListener('global-rem', globalHandler); 193removeEventListener('global-rem', globalHandler); 194dispatchEvent(new Event('global-rem')); 195test('global removeEventListener', globalRemoved, 0); 196 197console.log('\nCustomEvent Tests\n'); 198 199const ce1 = new CustomEvent('ping'); 200test('CustomEvent type', ce1.type, 'ping'); 201test('CustomEvent detail defaults to null', ce1.detail, null); 202 203const ce2 = new CustomEvent('animalfound', { detail: { name: 'cat' } }); 204test('CustomEvent detail', ce2.detail.name, 'cat'); 205 206let ceReceived = null; 207const et5 = new EventTarget(); 208et5.addEventListener('animalfound', e => { 209 ceReceived = e.detail.name; 210}); 211et5.dispatchEvent(ce2); 212test('EventTarget dispatchEvent with CustomEvent', ceReceived, 'cat'); 213 214let ceGlobal = null; 215addEventListener('custom-global', e => { 216 ceGlobal = e.detail.value; 217}); 218dispatchEvent(new CustomEvent('custom-global', { detail: { value: 42 } })); 219test('global dispatchEvent with CustomEvent', ceGlobal, 42); 220 221const ce3 = new CustomEvent('tagged'); 222test('CustomEvent Symbol.toStringTag', Object.prototype.toString.call(ce3), '[object CustomEvent]'); 223 224console.log('\nnode:events Helper Tests\n'); 225 226const eeNodeOnce = new EventEmitter(); 227const eeNodeOncePromise = nodeOnce(eeNodeOnce, 'ready'); 228eeNodeOnce.emit('ready', 'ok', 7); 229testDeep('events.once resolves emitted args', await eeNodeOncePromise, ['ok', 7]); 230 231const eeRaw = new EventEmitter(); 232function rawOnce() {} 233function rawOn() {} 234eeRaw.once('raw', rawOnce); 235eeRaw.on('raw', rawOn); 236const rawListeners = eeRaw.rawListeners('raw'); 237test('rawListeners returns wrapper for once listeners', rawListeners[0] !== rawOnce, true); 238test('rawListeners wrapper exposes original listener', rawListeners[0].listener, rawOnce); 239test('rawListeners keeps non-once listeners unchanged', rawListeners[1], rawOn); 240 241const etNodeOnce = new EventTarget(); 242const etNodeOncePromise = nodeOnce(etNodeOnce, 'ping'); 243etNodeOnce.dispatchEvent(new Event('ping')); 244const etNodeOnceArgs = await etNodeOncePromise; 245test('events.once supports EventTarget', etNodeOnceArgs[0].type, 'ping'); 246 247const abortController = new AbortController(); 248const abortPromise = nodeOnce(abortController.signal, 'abort'); 249abortController.abort('stop'); 250const abortArgs = await abortPromise; 251test('events.once supports AbortSignal', abortArgs[0].type, 'abort'); 252 253let duckOnceRejected = false; 254try { 255 await nodeOnce( 256 { 257 once(_name, listener) { 258 listener('bad'); 259 } 260 }, 261 'ready' 262 ); 263} catch { 264 duckOnceRejected = true; 265} 266test('events.once rejects once-shaped plain objects', duckOnceRejected, true); 267 268let protoEmitterRejected = false; 269try { 270 await nodeOnce(Object.create(EventEmitter.prototype), 'ready'); 271} catch { 272 protoEmitterRejected = true; 273} 274test('events.once rejects EventEmitter prototype spoofing', protoEmitterRejected, true); 275 276let duckTargetRejected = false; 277try { 278 await nodeOnce( 279 { 280 addEventListener(_name, listener) { 281 listener(new Event('bad')); 282 } 283 }, 284 'ready' 285 ); 286} catch { 287 duckTargetRejected = true; 288} 289test('events.once rejects EventTarget-shaped plain objects', duckTargetRejected, true); 290 291let protoTargetRejected = false; 292try { 293 await nodeOnce(Object.create(EventTarget.prototype), 'ready'); 294} catch { 295 protoTargetRejected = true; 296} 297test('events.once rejects EventTarget prototype spoofing', protoTargetRejected, true); 298 299let addAbortValue = 0; 300const addAbortController = new AbortController(); 301const disposable = addAbortListener(addAbortController.signal, () => { 302 addAbortValue++; 303}); 304addAbortController.abort(); 305test('events.addAbortListener fires on abort', addAbortValue, 1); 306test('events.addAbortListener returns disposable', typeof disposable.dispose, 'function'); 307 308let disposedAbortValue = 0; 309const disposedAbortController = new AbortController(); 310const disposedAbort = addAbortListener(disposedAbortController.signal, () => { 311 disposedAbortValue++; 312}); 313disposedAbort.dispose(); 314disposedAbortController.abort(); 315test('events.addAbortListener dispose removes listener', disposedAbortValue, 0); 316 317let onceAbortCalls = 0; 318const onceAbortController = new AbortController(); 319const onceAbortListener = () => { 320 onceAbortCalls++; 321}; 322addAbortListener(onceAbortController.signal, onceAbortListener); 323const onceAbortEmitter = new EventEmitter(); 324const onceAbortPromise = nodeOnce(onceAbortEmitter, 'done', { signal: onceAbortController.signal }); 325onceAbortEmitter.emit('done', 'ok'); 326await onceAbortPromise; 327onceAbortController.abort(); 328test('events.once removes abort listener after resolve', onceAbortCalls, 1); 329 330test('events.getMaxListeners default', getMaxListeners(eeNodeOnce), 10); 331test('events.setMaxListeners no-op return', setMaxListeners(20, eeNodeOnce), undefined); 332 333summary();