@gjsify/events 0.0.4 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/cjs-compat.cjs +6 -0
- package/lib/esm/event-emitter.js +591 -0
- package/lib/esm/index.js +24 -4
- package/lib/types/event-emitter.d.ts +69 -0
- package/lib/types/index.d.ts +13 -0
- package/package.json +14 -22
- package/src/event-emitter.spec.ts +1250 -24
- package/src/event-emitter.ts +726 -0
- package/src/index.ts +20 -11
- package/tsconfig.json +21 -9
- package/tsconfig.tsbuildinfo +1 -0
- package/lib/cjs/index.js +0 -6
- package/test.gjs.js +0 -34942
- package/test.gjs.mjs +0 -34799
- package/test.gjs.mjs.meta.json +0 -1
- package/test.node.js +0 -1410
- package/test.node.mjs +0 -418
- package/tsconfig.types.json +0 -8
|
@@ -1,15 +1,531 @@
|
|
|
1
|
+
// Ported from refs/node-test/parallel/test-events-*.js
|
|
2
|
+
// Original: MIT license, Node.js contributors
|
|
3
|
+
|
|
1
4
|
import { describe, it, expect } from '@gjsify/unit';
|
|
5
|
+
import 'abort-controller'; // Registers AbortController/AbortSignal globals on GJS; no-op on Node.js
|
|
2
6
|
|
|
3
|
-
import { EventEmitter } from 'events';
|
|
7
|
+
import { EventEmitter } from 'node:events';
|
|
4
8
|
|
|
5
9
|
export default async () => {
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
await describe('EventEmitter: constructor', async () => {
|
|
12
|
+
await it('should create an instance', async () => {
|
|
13
|
+
const emitter = new EventEmitter();
|
|
14
|
+
expect(emitter).toBeDefined();
|
|
15
|
+
expect(emitter instanceof EventEmitter).toBeTruthy();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
await it('should have default max listeners of 10', async () => {
|
|
19
|
+
const emitter = new EventEmitter();
|
|
20
|
+
expect(emitter.getMaxListeners()).toBe(10);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
await describe('EventEmitter: emit', async () => {
|
|
25
|
+
await it('should call listeners when event is emitted', async () => {
|
|
26
|
+
const emitter = new EventEmitter();
|
|
27
|
+
let called = false;
|
|
28
|
+
emitter.on('test', () => { called = true; });
|
|
29
|
+
emitter.emit('test');
|
|
30
|
+
expect(called).toBeTruthy();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await it('should call multiple listeners in order', async () => {
|
|
34
|
+
const emitter = new EventEmitter();
|
|
35
|
+
const order: number[] = [];
|
|
36
|
+
emitter.on('test', () => order.push(1));
|
|
37
|
+
emitter.on('test', () => order.push(2));
|
|
38
|
+
emitter.emit('test');
|
|
39
|
+
expect(order.length).toBe(2);
|
|
40
|
+
expect(order[0]).toBe(1);
|
|
41
|
+
expect(order[1]).toBe(2);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
await it('should pass arguments to listeners', async () => {
|
|
45
|
+
const emitter = new EventEmitter();
|
|
46
|
+
let received: any[] = [];
|
|
47
|
+
emitter.on('test', (...args) => { received = args; });
|
|
48
|
+
emitter.emit('test', 'a', 'b', 'c');
|
|
49
|
+
expect(received.length).toBe(3);
|
|
50
|
+
expect(received[0]).toBe('a');
|
|
51
|
+
expect(received[1]).toBe('b');
|
|
52
|
+
expect(received[2]).toBe('c');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await it('should return true when listeners exist', async () => {
|
|
56
|
+
const emitter = new EventEmitter();
|
|
57
|
+
emitter.on('test', () => {});
|
|
58
|
+
expect(emitter.emit('test')).toBeTruthy();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
await it('should return false when no listeners exist', async () => {
|
|
62
|
+
const emitter = new EventEmitter();
|
|
63
|
+
expect(emitter.emit('test')).toBeFalsy();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
await it('should throw on unhandled error event', async () => {
|
|
67
|
+
const emitter = new EventEmitter();
|
|
68
|
+
expect(() => {
|
|
69
|
+
emitter.emit('error', new Error('test error'));
|
|
70
|
+
}).toThrow();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await it('should not throw on error event with listener', async () => {
|
|
74
|
+
const emitter = new EventEmitter();
|
|
75
|
+
let caught = false;
|
|
76
|
+
emitter.on('error', () => { caught = true; });
|
|
77
|
+
emitter.emit('error', new Error('test error'));
|
|
78
|
+
expect(caught).toBeTruthy();
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
await describe('EventEmitter: on / addListener', async () => {
|
|
83
|
+
await it('should add a listener', async () => {
|
|
84
|
+
const emitter = new EventEmitter();
|
|
85
|
+
const fn = () => {};
|
|
86
|
+
emitter.on('test', fn);
|
|
87
|
+
expect(emitter.listenerCount('test')).toBe(1);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await it('should return this for chaining', async () => {
|
|
91
|
+
const emitter = new EventEmitter();
|
|
92
|
+
const result = emitter.on('test', () => {});
|
|
93
|
+
expect(result).toBe(emitter);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await it('addListener should be an alias for on', async () => {
|
|
97
|
+
const emitter = new EventEmitter();
|
|
98
|
+
let count = 0;
|
|
99
|
+
emitter.addListener('test', () => { count++; });
|
|
100
|
+
emitter.emit('test');
|
|
101
|
+
expect(count).toBe(1);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await describe('EventEmitter: once', async () => {
|
|
106
|
+
await it('should fire listener only once', async () => {
|
|
107
|
+
const emitter = new EventEmitter();
|
|
108
|
+
let count = 0;
|
|
109
|
+
emitter.once('test', () => { count++; });
|
|
110
|
+
emitter.emit('test');
|
|
111
|
+
emitter.emit('test');
|
|
112
|
+
expect(count).toBe(1);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
await it('should remove listener after first call', async () => {
|
|
116
|
+
const emitter = new EventEmitter();
|
|
117
|
+
emitter.once('test', () => {});
|
|
118
|
+
expect(emitter.listenerCount('test')).toBe(1);
|
|
119
|
+
emitter.emit('test');
|
|
120
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
await it('should pass arguments correctly', async () => {
|
|
124
|
+
const emitter = new EventEmitter();
|
|
125
|
+
let received: any;
|
|
126
|
+
emitter.once('test', (val) => { received = val; });
|
|
127
|
+
emitter.emit('test', 42);
|
|
128
|
+
expect(received).toBe(42);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await describe('EventEmitter: removeListener / off', async () => {
|
|
133
|
+
await it('should remove a specific listener', async () => {
|
|
134
|
+
const emitter = new EventEmitter();
|
|
135
|
+
const fn = () => {};
|
|
136
|
+
emitter.on('test', fn);
|
|
137
|
+
expect(emitter.listenerCount('test')).toBe(1);
|
|
138
|
+
emitter.removeListener('test', fn);
|
|
139
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await it('off should be an alias for removeListener', async () => {
|
|
143
|
+
const emitter = new EventEmitter();
|
|
144
|
+
const fn = () => {};
|
|
145
|
+
emitter.on('test', fn);
|
|
146
|
+
emitter.off('test', fn);
|
|
147
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
await it('should return this for chaining', async () => {
|
|
151
|
+
const emitter = new EventEmitter();
|
|
152
|
+
const fn = () => {};
|
|
153
|
+
emitter.on('test', fn);
|
|
154
|
+
const result = emitter.removeListener('test', fn);
|
|
155
|
+
expect(result).toBe(emitter);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await it('should not fail when removing non-existent listener', async () => {
|
|
159
|
+
const emitter = new EventEmitter();
|
|
160
|
+
emitter.removeListener('nonexistent', () => {});
|
|
161
|
+
expect(emitter.listenerCount('nonexistent')).toBe(0);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
await it('should only remove the last matching listener', async () => {
|
|
165
|
+
const emitter = new EventEmitter();
|
|
166
|
+
const fn = () => {};
|
|
167
|
+
emitter.on('test', fn);
|
|
168
|
+
emitter.on('test', fn);
|
|
169
|
+
emitter.removeListener('test', fn);
|
|
170
|
+
expect(emitter.listenerCount('test')).toBe(1);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await describe('EventEmitter: removeAllListeners', async () => {
|
|
175
|
+
await it('should remove all listeners for an event', async () => {
|
|
176
|
+
const emitter = new EventEmitter();
|
|
177
|
+
emitter.on('test', () => {});
|
|
178
|
+
emitter.on('test', () => {});
|
|
179
|
+
emitter.removeAllListeners('test');
|
|
180
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
await it('should remove all listeners for all events when no arg', async () => {
|
|
184
|
+
const emitter = new EventEmitter();
|
|
185
|
+
emitter.on('a', () => {});
|
|
186
|
+
emitter.on('b', () => {});
|
|
187
|
+
emitter.removeAllListeners();
|
|
188
|
+
expect(emitter.eventNames().length).toBe(0);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
await describe('EventEmitter: prependListener', async () => {
|
|
193
|
+
await it('should add listener at the beginning', async () => {
|
|
194
|
+
const emitter = new EventEmitter();
|
|
195
|
+
const order: number[] = [];
|
|
196
|
+
emitter.on('test', () => order.push(1));
|
|
197
|
+
emitter.prependListener('test', () => order.push(0));
|
|
198
|
+
emitter.emit('test');
|
|
199
|
+
expect(order[0]).toBe(0);
|
|
200
|
+
expect(order[1]).toBe(1);
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
await describe('EventEmitter: prependOnceListener', async () => {
|
|
205
|
+
await it('should add once listener at the beginning', async () => {
|
|
206
|
+
const emitter = new EventEmitter();
|
|
207
|
+
const order: number[] = [];
|
|
208
|
+
emitter.on('test', () => order.push(1));
|
|
209
|
+
emitter.prependOnceListener('test', () => order.push(0));
|
|
210
|
+
emitter.emit('test');
|
|
211
|
+
emitter.emit('test');
|
|
212
|
+
expect(order.length).toBe(3);
|
|
213
|
+
expect(order[0]).toBe(0);
|
|
214
|
+
expect(order[1]).toBe(1);
|
|
215
|
+
expect(order[2]).toBe(1);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
await describe('EventEmitter: listeners', async () => {
|
|
220
|
+
await it('should return array of listeners', async () => {
|
|
221
|
+
const emitter = new EventEmitter();
|
|
222
|
+
const fn1 = () => {};
|
|
223
|
+
const fn2 = () => {};
|
|
224
|
+
emitter.on('test', fn1);
|
|
225
|
+
emitter.on('test', fn2);
|
|
226
|
+
const listeners = emitter.listeners('test');
|
|
227
|
+
expect(listeners.length).toBe(2);
|
|
228
|
+
expect(listeners[0]).toBe(fn1);
|
|
229
|
+
expect(listeners[1]).toBe(fn2);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
await it('should return empty array for non-existent event', async () => {
|
|
233
|
+
const emitter = new EventEmitter();
|
|
234
|
+
const listeners = emitter.listeners('test');
|
|
235
|
+
expect(listeners.length).toBe(0);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
await it('should unwrap once listeners', async () => {
|
|
239
|
+
const emitter = new EventEmitter();
|
|
240
|
+
const fn = () => {};
|
|
241
|
+
emitter.once('test', fn);
|
|
242
|
+
const listeners = emitter.listeners('test');
|
|
243
|
+
expect(listeners[0]).toBe(fn);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
await describe('EventEmitter: rawListeners', async () => {
|
|
248
|
+
await it('should return wrapped once listeners', async () => {
|
|
249
|
+
const emitter = new EventEmitter();
|
|
250
|
+
const fn = () => {};
|
|
251
|
+
emitter.once('test', fn);
|
|
252
|
+
const raw = emitter.rawListeners('test');
|
|
253
|
+
expect(raw.length).toBe(1);
|
|
254
|
+
// Raw listener should have .listener property pointing to original
|
|
255
|
+
expect((raw[0] as any).listener).toBe(fn);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
await describe('EventEmitter: listenerCount', async () => {
|
|
260
|
+
await it('should return count of listeners', async () => {
|
|
261
|
+
const emitter = new EventEmitter();
|
|
262
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
263
|
+
emitter.on('test', () => {});
|
|
264
|
+
expect(emitter.listenerCount('test')).toBe(1);
|
|
265
|
+
emitter.on('test', () => {});
|
|
266
|
+
expect(emitter.listenerCount('test')).toBe(2);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
await describe('EventEmitter: eventNames', async () => {
|
|
271
|
+
await it('should return array of event names', async () => {
|
|
272
|
+
const emitter = new EventEmitter();
|
|
273
|
+
emitter.on('foo', () => {});
|
|
274
|
+
emitter.on('bar', () => {});
|
|
275
|
+
const names = emitter.eventNames();
|
|
276
|
+
expect(names.length).toBe(2);
|
|
277
|
+
expect(names).toContain('foo');
|
|
278
|
+
expect(names).toContain('bar');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
await it('should return empty array when no listeners', async () => {
|
|
282
|
+
const emitter = new EventEmitter();
|
|
283
|
+
expect(emitter.eventNames().length).toBe(0);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
await it('should support symbol event names', async () => {
|
|
287
|
+
const emitter = new EventEmitter();
|
|
288
|
+
const sym = Symbol('test');
|
|
289
|
+
emitter.on(sym, () => {});
|
|
290
|
+
const names = emitter.eventNames();
|
|
291
|
+
expect(names.length).toBe(1);
|
|
292
|
+
// Use typeof check since toBe cannot compare Symbols
|
|
293
|
+
expect(typeof names[0]).toBe('symbol');
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
await describe('EventEmitter: setMaxListeners / getMaxListeners', async () => {
|
|
298
|
+
await it('should set and get max listeners', async () => {
|
|
299
|
+
const emitter = new EventEmitter();
|
|
300
|
+
emitter.setMaxListeners(20);
|
|
301
|
+
expect(emitter.getMaxListeners()).toBe(20);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
await it('should allow 0 for unlimited', async () => {
|
|
305
|
+
const emitter = new EventEmitter();
|
|
306
|
+
emitter.setMaxListeners(0);
|
|
307
|
+
expect(emitter.getMaxListeners()).toBe(0);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
await it('should throw for negative values', async () => {
|
|
311
|
+
const emitter = new EventEmitter();
|
|
312
|
+
expect(() => emitter.setMaxListeners(-1)).toThrow();
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
await describe('EventEmitter: newListener event', async () => {
|
|
317
|
+
await it('should emit newListener when adding a listener', async () => {
|
|
318
|
+
const emitter = new EventEmitter();
|
|
319
|
+
let eventName: string | undefined;
|
|
320
|
+
emitter.on('newListener', (name: string) => {
|
|
321
|
+
eventName = name;
|
|
322
|
+
});
|
|
323
|
+
emitter.on('test', () => {});
|
|
324
|
+
expect(eventName).toBe('test');
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
await describe('EventEmitter: removeListener event', async () => {
|
|
329
|
+
await it('should emit removeListener when removing a listener', async () => {
|
|
330
|
+
const emitter = new EventEmitter();
|
|
331
|
+
let eventName: string | undefined;
|
|
332
|
+
emitter.on('removeListener', (name: string) => {
|
|
333
|
+
eventName = name;
|
|
334
|
+
});
|
|
335
|
+
const fn = () => {};
|
|
336
|
+
emitter.on('test', fn);
|
|
337
|
+
emitter.removeListener('test', fn);
|
|
338
|
+
expect(eventName).toBe('test');
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
await describe('EventEmitter.once (static)', async () => {
|
|
343
|
+
await it('should return a promise that resolves on event', async () => {
|
|
344
|
+
const emitter = new EventEmitter();
|
|
345
|
+
const promise = EventEmitter.once(emitter, 'test');
|
|
346
|
+
emitter.emit('test', 'value');
|
|
347
|
+
const result = await promise;
|
|
348
|
+
expect(result.length).toBe(1);
|
|
349
|
+
expect(result[0]).toBe('value');
|
|
350
|
+
});
|
|
9
351
|
|
|
10
|
-
|
|
352
|
+
await it('should reject on error event', async () => {
|
|
353
|
+
const emitter = new EventEmitter();
|
|
354
|
+
const promise = EventEmitter.once(emitter, 'test');
|
|
355
|
+
const error = new Error('test error');
|
|
356
|
+
emitter.emit('error', error);
|
|
357
|
+
try {
|
|
358
|
+
await promise;
|
|
359
|
+
// Should not reach here
|
|
360
|
+
expect(false).toBeTruthy();
|
|
361
|
+
} catch (err) {
|
|
362
|
+
expect(err).toBe(error);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
await it('should pass multiple args as array', async () => {
|
|
367
|
+
const emitter = new EventEmitter();
|
|
368
|
+
const promise = EventEmitter.once(emitter, 'test');
|
|
369
|
+
emitter.emit('test', 1, 2, 3);
|
|
370
|
+
const result = await promise;
|
|
371
|
+
expect(result.length).toBe(3);
|
|
372
|
+
expect(result[0]).toBe(1);
|
|
373
|
+
expect(result[1]).toBe(2);
|
|
374
|
+
expect(result[2]).toBe(3);
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
await describe('EventEmitter.on (static)', async () => {
|
|
379
|
+
await it('should return an async iterator', async () => {
|
|
380
|
+
const emitter = new EventEmitter();
|
|
381
|
+
const iterator = EventEmitter.on(emitter, 'data');
|
|
382
|
+
expect(iterator).toBeDefined();
|
|
383
|
+
expect(typeof iterator[Symbol.asyncIterator]).toBe('function');
|
|
384
|
+
|
|
385
|
+
// Emit some data then end iterator
|
|
386
|
+
emitter.emit('data', 1);
|
|
387
|
+
emitter.emit('data', 2);
|
|
388
|
+
|
|
389
|
+
const first = await iterator.next();
|
|
390
|
+
expect(first.done).toBeFalsy();
|
|
391
|
+
expect(first.value[0]).toBe(1);
|
|
392
|
+
|
|
393
|
+
const second = await iterator.next();
|
|
394
|
+
expect(second.done).toBeFalsy();
|
|
395
|
+
expect(second.value[0]).toBe(2);
|
|
396
|
+
|
|
397
|
+
await iterator.return!();
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
await describe('EventEmitter.listenerCount (static)', async () => {
|
|
402
|
+
await it('should return listener count', async () => {
|
|
403
|
+
const emitter = new EventEmitter();
|
|
404
|
+
emitter.on('test', () => {});
|
|
405
|
+
emitter.on('test', () => {});
|
|
406
|
+
expect(EventEmitter.listenerCount(emitter, 'test')).toBe(2);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
await describe('EventEmitter.getEventListeners (static)', async () => {
|
|
411
|
+
await it('should return listeners array', async () => {
|
|
412
|
+
const emitter = new EventEmitter();
|
|
413
|
+
const fn = () => {};
|
|
414
|
+
emitter.on('test', fn);
|
|
415
|
+
const listeners = EventEmitter.getEventListeners(emitter, 'test');
|
|
416
|
+
expect(listeners.length).toBe(1);
|
|
417
|
+
expect(listeners[0]).toBe(fn);
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
await describe('EventEmitter: error handling', async () => {
|
|
422
|
+
await it('should throw generic error when emitting error with no listener and no Error arg', async () => {
|
|
423
|
+
const emitter = new EventEmitter();
|
|
424
|
+
expect(() => {
|
|
425
|
+
emitter.emit('error', 'string error');
|
|
426
|
+
}).toThrow();
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
await it('should throw with context for non-Error arguments', async () => {
|
|
430
|
+
const emitter = new EventEmitter();
|
|
431
|
+
try {
|
|
432
|
+
emitter.emit('error', 'string error');
|
|
433
|
+
expect(false).toBeTruthy();
|
|
434
|
+
} catch (err: any) {
|
|
435
|
+
expect(err.context).toBe('string error');
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// ==================== additional tests ported from refs/node ====================
|
|
441
|
+
|
|
442
|
+
await describe('EventEmitter: defaultMaxListeners static', async () => {
|
|
443
|
+
await it('should have defaultMaxListeners property', async () => {
|
|
444
|
+
expect(typeof EventEmitter.defaultMaxListeners).toBe('number');
|
|
445
|
+
expect(EventEmitter.defaultMaxListeners).toBe(10);
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
await describe('EventEmitter: Symbol event names', async () => {
|
|
450
|
+
await it('should support Symbol as event name', async () => {
|
|
451
|
+
const emitter = new EventEmitter();
|
|
452
|
+
const sym = Symbol('myEvent');
|
|
453
|
+
let called = false;
|
|
454
|
+
emitter.on(sym, () => { called = true; });
|
|
455
|
+
emitter.emit(sym);
|
|
456
|
+
expect(called).toBeTruthy();
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
await it('should support removing Symbol listeners', async () => {
|
|
460
|
+
const emitter = new EventEmitter();
|
|
461
|
+
const sym = Symbol('myEvent');
|
|
462
|
+
const fn = () => {};
|
|
463
|
+
emitter.on(sym, fn);
|
|
464
|
+
expect(emitter.listenerCount(sym)).toBe(1);
|
|
465
|
+
emitter.removeListener(sym, fn);
|
|
466
|
+
expect(emitter.listenerCount(sym)).toBe(0);
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
await describe('EventEmitter: removeAllListeners', async () => {
|
|
471
|
+
await it('should remove all listeners for a specific event', async () => {
|
|
472
|
+
const emitter = new EventEmitter();
|
|
473
|
+
emitter.on('test', () => {});
|
|
474
|
+
emitter.on('test', () => {});
|
|
475
|
+
emitter.on('other', () => {});
|
|
476
|
+
emitter.removeAllListeners('test');
|
|
477
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
478
|
+
expect(emitter.listenerCount('other')).toBe(1);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
await it('should remove all listeners when no event specified', async () => {
|
|
482
|
+
const emitter = new EventEmitter();
|
|
483
|
+
emitter.on('test', () => {});
|
|
484
|
+
emitter.on('other', () => {});
|
|
485
|
+
emitter.removeAllListeners();
|
|
486
|
+
expect(emitter.eventNames().length).toBe(0);
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
await it('should return this for chaining', async () => {
|
|
490
|
+
const emitter = new EventEmitter();
|
|
491
|
+
const result = emitter.removeAllListeners();
|
|
492
|
+
expect(result).toBe(emitter);
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
await describe('EventEmitter: listener removal during emit', async () => {
|
|
497
|
+
await it('should not skip listeners when one removes itself', async () => {
|
|
498
|
+
const emitter = new EventEmitter();
|
|
499
|
+
const calls: number[] = [];
|
|
500
|
+
const fn1 = () => {
|
|
501
|
+
calls.push(1);
|
|
502
|
+
emitter.removeListener('test', fn1);
|
|
503
|
+
};
|
|
504
|
+
const fn2 = () => { calls.push(2); };
|
|
505
|
+
emitter.on('test', fn1);
|
|
506
|
+
emitter.on('test', fn2);
|
|
507
|
+
emitter.emit('test');
|
|
508
|
+
expect(calls.length).toBe(2);
|
|
509
|
+
expect(calls[0]).toBe(1);
|
|
510
|
+
expect(calls[1]).toBe(2);
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
await describe('EventEmitter: off alias', async () => {
|
|
515
|
+
await it('off should be an alias for removeListener', async () => {
|
|
516
|
+
const emitter = new EventEmitter();
|
|
517
|
+
const fn = () => {};
|
|
518
|
+
emitter.on('test', fn);
|
|
519
|
+
expect(emitter.listenerCount('test')).toBe(1);
|
|
520
|
+
emitter.off('test', fn);
|
|
521
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// Keep original tests for backwards compatibility
|
|
526
|
+
await describe('events.EventEmitter: emit (original)', async () => {
|
|
11
527
|
await it('1. Add two listeners on a single event and emit the event', async () => {
|
|
12
|
-
|
|
528
|
+
const emitter = new EventEmitter();
|
|
13
529
|
let count = 0;
|
|
14
530
|
|
|
15
531
|
function functionA() { count++; }
|
|
@@ -24,7 +540,7 @@ export default async () => {
|
|
|
24
540
|
});
|
|
25
541
|
|
|
26
542
|
await it('2. Add two listeners on a single event and emit the event twice', async () => {
|
|
27
|
-
|
|
543
|
+
const emitter = new EventEmitter();
|
|
28
544
|
let count = 0;
|
|
29
545
|
|
|
30
546
|
function functionA() { count++ }
|
|
@@ -40,7 +556,7 @@ export default async () => {
|
|
|
40
556
|
});
|
|
41
557
|
|
|
42
558
|
await it('3. Add two listeners on a single event and emit the event with a parameter', async () => {
|
|
43
|
-
|
|
559
|
+
const emitter = new EventEmitter();
|
|
44
560
|
let count = 0;
|
|
45
561
|
|
|
46
562
|
function functionA(value1: string) {
|
|
@@ -62,7 +578,7 @@ export default async () => {
|
|
|
62
578
|
});
|
|
63
579
|
|
|
64
580
|
await it(`4. Add two listeners on an single event and emit the event twice with a parameter.`, async () => {
|
|
65
|
-
|
|
581
|
+
const emitter = new EventEmitter();
|
|
66
582
|
let count = 0;
|
|
67
583
|
|
|
68
584
|
function functionA(value1: string) {
|
|
@@ -85,13 +601,11 @@ export default async () => {
|
|
|
85
601
|
});
|
|
86
602
|
|
|
87
603
|
await it(`5. Add two listeners on an single event and emit the event twice with multiple parameters.`, async () => {
|
|
88
|
-
|
|
89
|
-
var emitter = new EventEmitter({ verbose: true } as any);
|
|
604
|
+
const emitter = new EventEmitter();
|
|
90
605
|
let count = 0;
|
|
91
606
|
|
|
92
607
|
function functionA(value1: string, value2: string, value3: string) {
|
|
93
608
|
count++;
|
|
94
|
-
expect(true).toBeTruthy(); // 'The event was raised';
|
|
95
609
|
expect(typeof value1).toBe('string');
|
|
96
610
|
expect(typeof value2).toBe('string');
|
|
97
611
|
expect(typeof value3).toBe('string');
|
|
@@ -99,7 +613,6 @@ export default async () => {
|
|
|
99
613
|
|
|
100
614
|
function functionB(value1: string, value2: string, value3: string) {
|
|
101
615
|
count++;
|
|
102
|
-
expect(true).toBeTruthy(); // 'The event was raised';
|
|
103
616
|
expect(typeof value1).toBe('string');
|
|
104
617
|
expect(typeof value2).toBe('string');
|
|
105
618
|
expect(typeof value3).toBe('string');
|
|
@@ -117,31 +630,23 @@ export default async () => {
|
|
|
117
630
|
|
|
118
631
|
await it('6. Check return values of emit.', async () => {
|
|
119
632
|
let count = 0;
|
|
120
|
-
|
|
633
|
+
const emitter = new EventEmitter();
|
|
121
634
|
|
|
122
635
|
function functionA() {
|
|
123
636
|
count++;
|
|
124
|
-
expect(true).toBeTruthy(); // 'The event was raised'
|
|
125
637
|
}
|
|
126
638
|
|
|
127
639
|
emitter.on('test6', functionA);
|
|
128
640
|
|
|
129
|
-
expect(emitter.emit('test6')).toBeTruthy();
|
|
130
|
-
expect(emitter.emit('other')).toBeFalsy();
|
|
131
|
-
|
|
132
|
-
// The original implementation has no onAny method
|
|
133
|
-
expect(() => {
|
|
134
|
-
(emitter as any).onAny(functionA);
|
|
135
|
-
}).toThrow();
|
|
136
|
-
|
|
137
|
-
expect(emitter.emit('other')).toBeFalsy(); // 'emit should return false without the onAny() listener'
|
|
641
|
+
expect(emitter.emit('test6')).toBeTruthy();
|
|
642
|
+
expect(emitter.emit('other')).toBeFalsy();
|
|
138
643
|
|
|
139
644
|
expect(count).toBe(1);
|
|
140
645
|
});
|
|
141
646
|
|
|
142
647
|
await it('7. Emit event with more than 2 arguments', async () => {
|
|
143
648
|
let count = 0;
|
|
144
|
-
|
|
649
|
+
const emitter = new EventEmitter();
|
|
145
650
|
|
|
146
651
|
emitter.on('test', function (x: number, y: number, z: number) {
|
|
147
652
|
count++;
|
|
@@ -155,4 +660,725 @@ export default async () => {
|
|
|
155
660
|
});
|
|
156
661
|
|
|
157
662
|
});
|
|
663
|
+
|
|
664
|
+
// ==================== expanded tests: setMaxListeners / getMaxListeners ====================
|
|
665
|
+
|
|
666
|
+
await describe('EventEmitter: setMaxListeners / getMaxListeners (expanded)', async () => {
|
|
667
|
+
await it('should return this from setMaxListeners for chaining', async () => {
|
|
668
|
+
const emitter = new EventEmitter();
|
|
669
|
+
const result = emitter.setMaxListeners(5);
|
|
670
|
+
expect(result).toBe(emitter);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
await it('should throw for NaN', async () => {
|
|
674
|
+
const emitter = new EventEmitter();
|
|
675
|
+
expect(() => emitter.setMaxListeners(NaN)).toThrow();
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
await it('should accept Infinity', async () => {
|
|
679
|
+
const emitter = new EventEmitter();
|
|
680
|
+
emitter.setMaxListeners(Infinity);
|
|
681
|
+
expect(emitter.getMaxListeners()).toBe(Infinity);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
await it('static setMaxListeners should set on multiple emitters', async () => {
|
|
685
|
+
const ee1 = new EventEmitter();
|
|
686
|
+
const ee2 = new EventEmitter();
|
|
687
|
+
EventEmitter.setMaxListeners(42, ee1, ee2);
|
|
688
|
+
expect(ee1.getMaxListeners()).toBe(42);
|
|
689
|
+
expect(ee2.getMaxListeners()).toBe(42);
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
await it('static getMaxListeners should return max listeners for emitter', async () => {
|
|
693
|
+
const ee = new EventEmitter();
|
|
694
|
+
expect(EventEmitter.getMaxListeners(ee)).toBe(EventEmitter.defaultMaxListeners);
|
|
695
|
+
ee.setMaxListeners(101);
|
|
696
|
+
expect(EventEmitter.getMaxListeners(ee)).toBe(101);
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
await it('static setMaxListeners with no emitters should set defaultMaxListeners', async () => {
|
|
700
|
+
const original = EventEmitter.defaultMaxListeners;
|
|
701
|
+
try {
|
|
702
|
+
EventEmitter.setMaxListeners(99);
|
|
703
|
+
expect(EventEmitter.defaultMaxListeners).toBe(99);
|
|
704
|
+
} finally {
|
|
705
|
+
EventEmitter.defaultMaxListeners = original;
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
// ==================== expanded tests: errorMonitor ====================
|
|
711
|
+
|
|
712
|
+
await describe('EventEmitter: errorMonitor symbol', async () => {
|
|
713
|
+
await it('should emit to errorMonitor before throwing', async () => {
|
|
714
|
+
const emitter = new EventEmitter();
|
|
715
|
+
let monitorCalled = false;
|
|
716
|
+
let monitorError: Error | undefined;
|
|
717
|
+
emitter.on(EventEmitter.errorMonitor, (err: Error) => {
|
|
718
|
+
monitorCalled = true;
|
|
719
|
+
monitorError = err;
|
|
720
|
+
});
|
|
721
|
+
const testErr = new Error('monitored');
|
|
722
|
+
try {
|
|
723
|
+
emitter.emit('error', testErr);
|
|
724
|
+
} catch {
|
|
725
|
+
// expected
|
|
726
|
+
}
|
|
727
|
+
expect(monitorCalled).toBeTruthy();
|
|
728
|
+
expect(monitorError).toBe(testErr);
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
await it('should emit to errorMonitor even when error listener exists', async () => {
|
|
732
|
+
const emitter = new EventEmitter();
|
|
733
|
+
let monitorCalled = false;
|
|
734
|
+
let errorCalled = false;
|
|
735
|
+
emitter.on(EventEmitter.errorMonitor, () => { monitorCalled = true; });
|
|
736
|
+
emitter.on('error', () => { errorCalled = true; });
|
|
737
|
+
emitter.emit('error', new Error('test'));
|
|
738
|
+
expect(monitorCalled).toBeTruthy();
|
|
739
|
+
expect(errorCalled).toBeTruthy();
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
await it('errorMonitor should be a symbol', async () => {
|
|
743
|
+
expect(typeof EventEmitter.errorMonitor).toBe('symbol');
|
|
744
|
+
});
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
// ==================== expanded tests: captureRejections ====================
|
|
748
|
+
|
|
749
|
+
await describe('EventEmitter: captureRejections', async () => {
|
|
750
|
+
await it('should have captureRejectionSymbol static property', async () => {
|
|
751
|
+
expect(EventEmitter.captureRejectionSymbol).toBeDefined();
|
|
752
|
+
expect(typeof EventEmitter.captureRejectionSymbol).toBe('symbol');
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
await it('should default captureRejections to false', async () => {
|
|
756
|
+
expect(EventEmitter.captureRejections).toBe(false);
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
await it('should accept captureRejections in constructor options', async () => {
|
|
760
|
+
const emitter = new EventEmitter({ captureRejections: true });
|
|
761
|
+
// The emitter was created with captureRejections enabled
|
|
762
|
+
// (internal state, no public getter — just ensure no error thrown)
|
|
763
|
+
expect(emitter).toBeDefined();
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
await it('captureRejections should route async errors to error event', async () => {
|
|
767
|
+
const emitter = new EventEmitter({ captureRejections: true });
|
|
768
|
+
let caughtErr: Error | undefined;
|
|
769
|
+
const expectedErr = new Error('async failure');
|
|
770
|
+
emitter.on('error', (err: Error) => { caughtErr = err; });
|
|
771
|
+
emitter.on('test', async () => {
|
|
772
|
+
throw expectedErr;
|
|
773
|
+
});
|
|
774
|
+
emitter.emit('test');
|
|
775
|
+
// Wait for the microtask to propagate
|
|
776
|
+
await new Promise(r => setTimeout(r, 50));
|
|
777
|
+
expect(caughtErr).toBe(expectedErr);
|
|
778
|
+
});
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
// ==================== expanded tests: getEventListeners static ====================
|
|
782
|
+
|
|
783
|
+
await describe('EventEmitter.getEventListeners (expanded)', async () => {
|
|
784
|
+
await it('should return empty array for non-existent event', async () => {
|
|
785
|
+
const emitter = new EventEmitter();
|
|
786
|
+
const listeners = EventEmitter.getEventListeners(emitter, 'nonexistent');
|
|
787
|
+
expect(listeners.length).toBe(0);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
await it('should return correct listeners for multiple events', async () => {
|
|
791
|
+
const emitter = new EventEmitter();
|
|
792
|
+
const fn1 = () => {};
|
|
793
|
+
const fn2 = () => {};
|
|
794
|
+
emitter.on('foo', fn1);
|
|
795
|
+
emitter.on('foo', fn2);
|
|
796
|
+
emitter.on('baz', fn1);
|
|
797
|
+
const fooListeners = EventEmitter.getEventListeners(emitter, 'foo');
|
|
798
|
+
expect(fooListeners.length).toBe(2);
|
|
799
|
+
expect(fooListeners[0]).toBe(fn1);
|
|
800
|
+
expect(fooListeners[1]).toBe(fn2);
|
|
801
|
+
const bazListeners = EventEmitter.getEventListeners(emitter, 'baz');
|
|
802
|
+
expect(bazListeners.length).toBe(1);
|
|
803
|
+
expect(bazListeners[0]).toBe(fn1);
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
await it('should unwrap once listeners', async () => {
|
|
807
|
+
const emitter = new EventEmitter();
|
|
808
|
+
const fn = () => {};
|
|
809
|
+
emitter.once('test', fn);
|
|
810
|
+
const listeners = EventEmitter.getEventListeners(emitter, 'test');
|
|
811
|
+
expect(listeners.length).toBe(1);
|
|
812
|
+
expect(listeners[0]).toBe(fn);
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
// ==================== expanded tests: listenerCount static ====================
|
|
817
|
+
|
|
818
|
+
await describe('EventEmitter.listenerCount static (expanded)', async () => {
|
|
819
|
+
await it('should return 0 for no listeners', async () => {
|
|
820
|
+
const emitter = new EventEmitter();
|
|
821
|
+
expect(EventEmitter.listenerCount(emitter, 'test')).toBe(0);
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
await it('should count once listeners', async () => {
|
|
825
|
+
const emitter = new EventEmitter();
|
|
826
|
+
emitter.once('test', () => {});
|
|
827
|
+
expect(EventEmitter.listenerCount(emitter, 'test')).toBe(1);
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
await it('should count mixed on and once listeners', async () => {
|
|
831
|
+
const emitter = new EventEmitter();
|
|
832
|
+
emitter.on('test', () => {});
|
|
833
|
+
emitter.once('test', () => {});
|
|
834
|
+
emitter.on('test', () => {});
|
|
835
|
+
expect(EventEmitter.listenerCount(emitter, 'test')).toBe(3);
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
// ==================== expanded tests: once static (promise-based) ====================
|
|
840
|
+
|
|
841
|
+
await describe('EventEmitter.once static (expanded)', async () => {
|
|
842
|
+
await it('should resolve with empty array when event has no args', async () => {
|
|
843
|
+
const emitter = new EventEmitter();
|
|
844
|
+
const promise = EventEmitter.once(emitter, 'test');
|
|
845
|
+
emitter.emit('test');
|
|
846
|
+
const result = await promise;
|
|
847
|
+
expect(result.length).toBe(0);
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
await it('should clean up listeners after resolving', async () => {
|
|
851
|
+
const emitter = new EventEmitter();
|
|
852
|
+
const promise = EventEmitter.once(emitter, 'test');
|
|
853
|
+
emitter.emit('test', 'value');
|
|
854
|
+
await promise;
|
|
855
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
856
|
+
expect(emitter.listenerCount('error')).toBe(0);
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
await it('should clean up listeners after error rejection', async () => {
|
|
860
|
+
const emitter = new EventEmitter();
|
|
861
|
+
const promise = EventEmitter.once(emitter, 'test');
|
|
862
|
+
emitter.emit('error', new Error('fail'));
|
|
863
|
+
try {
|
|
864
|
+
await promise;
|
|
865
|
+
} catch {
|
|
866
|
+
// expected
|
|
867
|
+
}
|
|
868
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
869
|
+
expect(emitter.listenerCount('error')).toBe(0);
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
await it('should resolve when listening for error event itself', async () => {
|
|
873
|
+
const emitter = new EventEmitter();
|
|
874
|
+
const expectedErr = new Error('expected');
|
|
875
|
+
const promise = EventEmitter.once(emitter, 'error');
|
|
876
|
+
emitter.emit('error', expectedErr);
|
|
877
|
+
const [err] = await promise;
|
|
878
|
+
expect(err).toBe(expectedErr);
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
await it('should reject with AbortError when signal is already aborted', async () => {
|
|
882
|
+
const emitter = new EventEmitter();
|
|
883
|
+
const abortedSignal = AbortSignal.abort();
|
|
884
|
+
try {
|
|
885
|
+
await EventEmitter.once(emitter, 'test', { signal: abortedSignal });
|
|
886
|
+
expect(false).toBeTruthy();
|
|
887
|
+
} catch (err: any) {
|
|
888
|
+
expect(err.name).toBe('AbortError');
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
await it('should reject when abort signal fires after call', async () => {
|
|
893
|
+
const emitter = new EventEmitter();
|
|
894
|
+
const ac = new AbortController();
|
|
895
|
+
const promise = EventEmitter.once(emitter, 'test', { signal: ac.signal });
|
|
896
|
+
ac.abort();
|
|
897
|
+
try {
|
|
898
|
+
await promise;
|
|
899
|
+
expect(false).toBeTruthy();
|
|
900
|
+
} catch (err: any) {
|
|
901
|
+
expect(err.name).toBe('AbortError');
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
// ==================== expanded tests: prependListener / prependOnceListener ====================
|
|
907
|
+
|
|
908
|
+
await describe('EventEmitter: prependListener (expanded)', async () => {
|
|
909
|
+
await it('should return this for chaining', async () => {
|
|
910
|
+
const emitter = new EventEmitter();
|
|
911
|
+
const result = emitter.prependListener('test', () => {});
|
|
912
|
+
expect(result).toBe(emitter);
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
await it('should prepend multiple listeners in correct order', async () => {
|
|
916
|
+
const emitter = new EventEmitter();
|
|
917
|
+
const order: number[] = [];
|
|
918
|
+
emitter.on('test', () => order.push(1));
|
|
919
|
+
emitter.prependListener('test', () => order.push(2));
|
|
920
|
+
emitter.prependListener('test', () => order.push(3));
|
|
921
|
+
emitter.emit('test');
|
|
922
|
+
// Last prepended is first
|
|
923
|
+
expect(order[0]).toBe(3);
|
|
924
|
+
expect(order[1]).toBe(2);
|
|
925
|
+
expect(order[2]).toBe(1);
|
|
926
|
+
});
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
await describe('EventEmitter: prependOnceListener (expanded)', async () => {
|
|
930
|
+
await it('should return this for chaining', async () => {
|
|
931
|
+
const emitter = new EventEmitter();
|
|
932
|
+
const result = emitter.prependOnceListener('test', () => {});
|
|
933
|
+
expect(result).toBe(emitter);
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
await it('should only fire once and then be removed', async () => {
|
|
937
|
+
const emitter = new EventEmitter();
|
|
938
|
+
let count = 0;
|
|
939
|
+
emitter.prependOnceListener('test', () => { count++; });
|
|
940
|
+
emitter.emit('test');
|
|
941
|
+
emitter.emit('test');
|
|
942
|
+
expect(count).toBe(1);
|
|
943
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
944
|
+
});
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
// ==================== expanded tests: eventNames ====================
|
|
948
|
+
|
|
949
|
+
await describe('EventEmitter: eventNames (expanded)', async () => {
|
|
950
|
+
await it('should reflect removal of events', async () => {
|
|
951
|
+
const emitter = new EventEmitter();
|
|
952
|
+
const fn = () => {};
|
|
953
|
+
emitter.on('foo', () => {});
|
|
954
|
+
emitter.on('bar', fn);
|
|
955
|
+
expect(emitter.eventNames().length).toBe(2);
|
|
956
|
+
emitter.removeListener('bar', fn);
|
|
957
|
+
const names = emitter.eventNames();
|
|
958
|
+
expect(names.length).toBe(1);
|
|
959
|
+
expect(names[0]).toBe('foo');
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
await it('should list symbol event names alongside string names', async () => {
|
|
963
|
+
const emitter = new EventEmitter();
|
|
964
|
+
const sym = Symbol('s');
|
|
965
|
+
emitter.on('foo', () => {});
|
|
966
|
+
emitter.on(sym, () => {});
|
|
967
|
+
const names = emitter.eventNames();
|
|
968
|
+
expect(names.length).toBe(2);
|
|
969
|
+
expect(names[0]).toBe('foo');
|
|
970
|
+
expect(typeof names[1]).toBe('symbol');
|
|
971
|
+
});
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
// ==================== expanded tests: rawListeners ====================
|
|
975
|
+
|
|
976
|
+
await describe('EventEmitter: rawListeners (expanded)', async () => {
|
|
977
|
+
await it('should return unwrapped functions for on listeners', async () => {
|
|
978
|
+
const emitter = new EventEmitter();
|
|
979
|
+
const fn = () => {};
|
|
980
|
+
emitter.on('test', fn);
|
|
981
|
+
const raw = emitter.rawListeners('test');
|
|
982
|
+
expect(raw.length).toBe(1);
|
|
983
|
+
expect(raw[0]).toBe(fn);
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
await it('should return empty array for non-existent event', async () => {
|
|
987
|
+
const emitter = new EventEmitter();
|
|
988
|
+
const raw = emitter.rawListeners('nonexistent');
|
|
989
|
+
expect(raw.length).toBe(0);
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
await it('raw once listeners should be callable and remove themselves', async () => {
|
|
993
|
+
const emitter = new EventEmitter();
|
|
994
|
+
let called = false;
|
|
995
|
+
emitter.once('test', () => { called = true; });
|
|
996
|
+
const raw = emitter.rawListeners('test');
|
|
997
|
+
expect(raw.length).toBe(1);
|
|
998
|
+
// Call the raw (wrapped) listener directly
|
|
999
|
+
raw[0]();
|
|
1000
|
+
expect(called).toBeTruthy();
|
|
1001
|
+
// After calling, the once listener should be removed
|
|
1002
|
+
expect(emitter.listenerCount('test')).toBe(0);
|
|
1003
|
+
});
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
// ==================== expanded tests: removeAllListeners with specific event ====================
|
|
1007
|
+
|
|
1008
|
+
await describe('EventEmitter: removeAllListeners specific (expanded)', async () => {
|
|
1009
|
+
await it('should not affect other events when removing specific event', async () => {
|
|
1010
|
+
const emitter = new EventEmitter();
|
|
1011
|
+
emitter.on('a', () => {});
|
|
1012
|
+
emitter.on('a', () => {});
|
|
1013
|
+
emitter.on('b', () => {});
|
|
1014
|
+
emitter.on('c', () => {});
|
|
1015
|
+
emitter.removeAllListeners('a');
|
|
1016
|
+
expect(emitter.listenerCount('a')).toBe(0);
|
|
1017
|
+
expect(emitter.listenerCount('b')).toBe(1);
|
|
1018
|
+
expect(emitter.listenerCount('c')).toBe(1);
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
await it('should emit removeListener for each removed listener', async () => {
|
|
1022
|
+
const emitter = new EventEmitter();
|
|
1023
|
+
const removed: string[] = [];
|
|
1024
|
+
emitter.on('removeListener', (name: string) => { removed.push(name); });
|
|
1025
|
+
emitter.on('data', () => {});
|
|
1026
|
+
emitter.on('data', () => {});
|
|
1027
|
+
emitter.removeAllListeners('data');
|
|
1028
|
+
expect(removed.length).toBe(2);
|
|
1029
|
+
expect(removed[0]).toBe('data');
|
|
1030
|
+
expect(removed[1]).toBe('data');
|
|
1031
|
+
});
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
// ==================== expanded tests: error handling ====================
|
|
1035
|
+
|
|
1036
|
+
await describe('EventEmitter: error handling (expanded)', async () => {
|
|
1037
|
+
await it('should throw the Error object directly when emitting error', async () => {
|
|
1038
|
+
const emitter = new EventEmitter();
|
|
1039
|
+
const err = new Error('direct throw');
|
|
1040
|
+
try {
|
|
1041
|
+
emitter.emit('error', err);
|
|
1042
|
+
expect(false).toBeTruthy();
|
|
1043
|
+
} catch (caught) {
|
|
1044
|
+
expect(caught).toBe(err);
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
await it('should throw generic error when emitting error with no args', async () => {
|
|
1049
|
+
const emitter = new EventEmitter();
|
|
1050
|
+
try {
|
|
1051
|
+
emitter.emit('error');
|
|
1052
|
+
expect(false).toBeTruthy();
|
|
1053
|
+
} catch (err: any) {
|
|
1054
|
+
expect(err instanceof Error).toBeTruthy();
|
|
1055
|
+
expect(err.message).toMatch('Unhandled error');
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
await it('should throw wrapped error when emitting non-Error error arg', async () => {
|
|
1060
|
+
const emitter = new EventEmitter();
|
|
1061
|
+
try {
|
|
1062
|
+
emitter.emit('error', 42);
|
|
1063
|
+
expect(false).toBeTruthy();
|
|
1064
|
+
} catch (err: any) {
|
|
1065
|
+
expect(err.context).toBe(42);
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
// ==================== expanded tests: emit returns boolean ====================
|
|
1071
|
+
|
|
1072
|
+
await describe('EventEmitter: emit return value (expanded)', async () => {
|
|
1073
|
+
await it('should return true when once listener exists', async () => {
|
|
1074
|
+
const emitter = new EventEmitter();
|
|
1075
|
+
emitter.once('test', () => {});
|
|
1076
|
+
expect(emitter.emit('test')).toBeTruthy();
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
await it('should return false after once listener consumed', async () => {
|
|
1080
|
+
const emitter = new EventEmitter();
|
|
1081
|
+
emitter.once('test', () => {});
|
|
1082
|
+
emitter.emit('test');
|
|
1083
|
+
expect(emitter.emit('test')).toBeFalsy();
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
await it('should return true for each emit when persistent listener exists', async () => {
|
|
1087
|
+
const emitter = new EventEmitter();
|
|
1088
|
+
emitter.on('test', () => {});
|
|
1089
|
+
expect(emitter.emit('test')).toBeTruthy();
|
|
1090
|
+
expect(emitter.emit('test')).toBeTruthy();
|
|
1091
|
+
});
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
// ==================== expanded tests: Symbol events ====================
|
|
1095
|
+
|
|
1096
|
+
await describe('EventEmitter: Symbol events (expanded)', async () => {
|
|
1097
|
+
await it('should pass arguments with Symbol events', async () => {
|
|
1098
|
+
const emitter = new EventEmitter();
|
|
1099
|
+
const sym = Symbol('data');
|
|
1100
|
+
let received: unknown;
|
|
1101
|
+
emitter.on(sym, (val: unknown) => { received = val; });
|
|
1102
|
+
emitter.emit(sym, 'hello');
|
|
1103
|
+
expect(received).toBe('hello');
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
await it('should support once with Symbol events', async () => {
|
|
1107
|
+
const emitter = new EventEmitter();
|
|
1108
|
+
const sym = Symbol('once');
|
|
1109
|
+
let count = 0;
|
|
1110
|
+
emitter.once(sym, () => { count++; });
|
|
1111
|
+
emitter.emit(sym);
|
|
1112
|
+
emitter.emit(sym);
|
|
1113
|
+
expect(count).toBe(1);
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
await it('should support removeAllListeners with Symbol events', async () => {
|
|
1117
|
+
const emitter = new EventEmitter();
|
|
1118
|
+
const sym = Symbol('rem');
|
|
1119
|
+
emitter.on(sym, () => {});
|
|
1120
|
+
emitter.on(sym, () => {});
|
|
1121
|
+
emitter.removeAllListeners(sym);
|
|
1122
|
+
expect(emitter.listenerCount(sym)).toBe(0);
|
|
1123
|
+
});
|
|
1124
|
+
|
|
1125
|
+
await it('should support prependListener with Symbol events', async () => {
|
|
1126
|
+
const emitter = new EventEmitter();
|
|
1127
|
+
const sym = Symbol('prepend');
|
|
1128
|
+
const order: number[] = [];
|
|
1129
|
+
emitter.on(sym, () => order.push(1));
|
|
1130
|
+
emitter.prependListener(sym, () => order.push(0));
|
|
1131
|
+
emitter.emit(sym);
|
|
1132
|
+
expect(order[0]).toBe(0);
|
|
1133
|
+
expect(order[1]).toBe(1);
|
|
1134
|
+
});
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
// ==================== expanded tests: multiple listeners ordering ====================
|
|
1138
|
+
|
|
1139
|
+
await describe('EventEmitter: multiple listeners ordering (expanded)', async () => {
|
|
1140
|
+
await it('should call listeners in registration order', async () => {
|
|
1141
|
+
const emitter = new EventEmitter();
|
|
1142
|
+
const order: number[] = [];
|
|
1143
|
+
for (let i = 0; i < 5; i++) {
|
|
1144
|
+
const val = i;
|
|
1145
|
+
emitter.on('test', () => order.push(val));
|
|
1146
|
+
}
|
|
1147
|
+
emitter.emit('test');
|
|
1148
|
+
expect(order.length).toBe(5);
|
|
1149
|
+
for (let i = 0; i < 5; i++) {
|
|
1150
|
+
expect(order[i]).toBe(i);
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
await it('should maintain order with mixed on and once', async () => {
|
|
1155
|
+
const emitter = new EventEmitter();
|
|
1156
|
+
const order: number[] = [];
|
|
1157
|
+
emitter.on('test', () => order.push(1));
|
|
1158
|
+
emitter.once('test', () => order.push(2));
|
|
1159
|
+
emitter.on('test', () => order.push(3));
|
|
1160
|
+
emitter.emit('test');
|
|
1161
|
+
expect(order.length).toBe(3);
|
|
1162
|
+
expect(order[0]).toBe(1);
|
|
1163
|
+
expect(order[1]).toBe(2);
|
|
1164
|
+
expect(order[2]).toBe(3);
|
|
1165
|
+
});
|
|
1166
|
+
|
|
1167
|
+
await it('should maintain order with prepend mixed in', async () => {
|
|
1168
|
+
const emitter = new EventEmitter();
|
|
1169
|
+
const order: number[] = [];
|
|
1170
|
+
emitter.on('test', () => order.push(1));
|
|
1171
|
+
emitter.on('test', () => order.push(2));
|
|
1172
|
+
emitter.prependListener('test', () => order.push(0));
|
|
1173
|
+
emitter.prependOnceListener('test', () => order.push(-1));
|
|
1174
|
+
emitter.emit('test');
|
|
1175
|
+
expect(order.length).toBe(4);
|
|
1176
|
+
expect(order[0]).toBe(-1);
|
|
1177
|
+
expect(order[1]).toBe(0);
|
|
1178
|
+
expect(order[2]).toBe(1);
|
|
1179
|
+
expect(order[3]).toBe(2);
|
|
1180
|
+
});
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
// ==================== expanded tests: on async iterator ====================
|
|
1184
|
+
|
|
1185
|
+
await describe('EventEmitter.on async iterator (expanded)', async () => {
|
|
1186
|
+
await it('should be an async iterable', async () => {
|
|
1187
|
+
const emitter = new EventEmitter();
|
|
1188
|
+
const iterator = EventEmitter.on(emitter, 'data');
|
|
1189
|
+
expect(typeof iterator[Symbol.asyncIterator]).toBe('function');
|
|
1190
|
+
expect(iterator[Symbol.asyncIterator]()).toBe(iterator);
|
|
1191
|
+
await iterator.return!();
|
|
1192
|
+
});
|
|
1193
|
+
|
|
1194
|
+
await it('should buffer events emitted before consumption', async () => {
|
|
1195
|
+
const emitter = new EventEmitter();
|
|
1196
|
+
const iterator = EventEmitter.on(emitter, 'data');
|
|
1197
|
+
emitter.emit('data', 'a');
|
|
1198
|
+
emitter.emit('data', 'b');
|
|
1199
|
+
emitter.emit('data', 'c');
|
|
1200
|
+
|
|
1201
|
+
const r1 = await iterator.next();
|
|
1202
|
+
expect(r1.done).toBeFalsy();
|
|
1203
|
+
expect(r1.value[0]).toBe('a');
|
|
1204
|
+
|
|
1205
|
+
const r2 = await iterator.next();
|
|
1206
|
+
expect(r2.done).toBeFalsy();
|
|
1207
|
+
expect(r2.value[0]).toBe('b');
|
|
1208
|
+
|
|
1209
|
+
const r3 = await iterator.next();
|
|
1210
|
+
expect(r3.done).toBeFalsy();
|
|
1211
|
+
expect(r3.value[0]).toBe('c');
|
|
1212
|
+
|
|
1213
|
+
await iterator.return!();
|
|
1214
|
+
});
|
|
1215
|
+
|
|
1216
|
+
await it('should clean up listeners after return', async () => {
|
|
1217
|
+
const emitter = new EventEmitter();
|
|
1218
|
+
const iterator = EventEmitter.on(emitter, 'data');
|
|
1219
|
+
expect(emitter.listenerCount('data')).toBe(1);
|
|
1220
|
+
await iterator.return!();
|
|
1221
|
+
expect(emitter.listenerCount('data')).toBe(0);
|
|
1222
|
+
});
|
|
1223
|
+
|
|
1224
|
+
await it('should yield multiple arguments as array', async () => {
|
|
1225
|
+
const emitter = new EventEmitter();
|
|
1226
|
+
const iterator = EventEmitter.on(emitter, 'data');
|
|
1227
|
+
emitter.emit('data', 1, 2, 3);
|
|
1228
|
+
const result = await iterator.next();
|
|
1229
|
+
expect(result.value.length).toBe(3);
|
|
1230
|
+
expect(result.value[0]).toBe(1);
|
|
1231
|
+
expect(result.value[1]).toBe(2);
|
|
1232
|
+
expect(result.value[2]).toBe(3);
|
|
1233
|
+
await iterator.return!();
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
await it('return should signal done', async () => {
|
|
1237
|
+
const emitter = new EventEmitter();
|
|
1238
|
+
const iterator = EventEmitter.on(emitter, 'data');
|
|
1239
|
+
const result = await iterator.return!();
|
|
1240
|
+
expect(result.done).toBeTruthy();
|
|
1241
|
+
});
|
|
1242
|
+
});
|
|
1243
|
+
|
|
1244
|
+
// ==================== expanded tests: newListener and removeListener events ====================
|
|
1245
|
+
|
|
1246
|
+
await describe('EventEmitter: newListener event (expanded)', async () => {
|
|
1247
|
+
await it('should receive the listener function as second arg', async () => {
|
|
1248
|
+
const emitter = new EventEmitter();
|
|
1249
|
+
let receivedFn: unknown;
|
|
1250
|
+
const fn = () => {};
|
|
1251
|
+
emitter.on('newListener', (_name: string, listener: unknown) => {
|
|
1252
|
+
receivedFn = listener;
|
|
1253
|
+
});
|
|
1254
|
+
emitter.on('test', fn);
|
|
1255
|
+
expect(receivedFn).toBe(fn);
|
|
1256
|
+
});
|
|
1257
|
+
|
|
1258
|
+
await it('should fire for once listeners with original function', async () => {
|
|
1259
|
+
const emitter = new EventEmitter();
|
|
1260
|
+
let receivedFn: unknown;
|
|
1261
|
+
const fn = () => {};
|
|
1262
|
+
emitter.on('newListener', (_name: string, listener: unknown) => {
|
|
1263
|
+
if (_name === 'test') receivedFn = listener;
|
|
1264
|
+
});
|
|
1265
|
+
emitter.once('test', fn);
|
|
1266
|
+
expect(receivedFn).toBe(fn);
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
await it('should not emit newListener for newListener itself', async () => {
|
|
1270
|
+
const emitter = new EventEmitter();
|
|
1271
|
+
const names: string[] = [];
|
|
1272
|
+
emitter.on('newListener', (name: string) => { names.push(name); });
|
|
1273
|
+
emitter.on('foo', () => {});
|
|
1274
|
+
emitter.on('bar', () => {});
|
|
1275
|
+
expect(names.length).toBe(2);
|
|
1276
|
+
expect(names[0]).toBe('foo');
|
|
1277
|
+
expect(names[1]).toBe('bar');
|
|
1278
|
+
});
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
await describe('EventEmitter: removeListener event (expanded)', async () => {
|
|
1282
|
+
await it('should fire when once listener is removed by emit', async () => {
|
|
1283
|
+
const emitter = new EventEmitter();
|
|
1284
|
+
const removed: string[] = [];
|
|
1285
|
+
emitter.on('removeListener', (name: string) => { removed.push(name); });
|
|
1286
|
+
emitter.once('test', () => {});
|
|
1287
|
+
emitter.emit('test');
|
|
1288
|
+
expect(removed).toContain('test');
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
await it('should fire for each removed listener from removeAllListeners', async () => {
|
|
1292
|
+
const emitter = new EventEmitter();
|
|
1293
|
+
let removeCount = 0;
|
|
1294
|
+
emitter.on('removeListener', () => { removeCount++; });
|
|
1295
|
+
emitter.on('test', () => {});
|
|
1296
|
+
emitter.on('test', () => {});
|
|
1297
|
+
emitter.on('test', () => {});
|
|
1298
|
+
emitter.removeAllListeners('test');
|
|
1299
|
+
expect(removeCount).toBe(3);
|
|
1300
|
+
});
|
|
1301
|
+
});
|
|
1302
|
+
|
|
1303
|
+
// ==================== expanded tests: EventEmitter.EventEmitter backward compat ====================
|
|
1304
|
+
|
|
1305
|
+
await describe('EventEmitter: backward compatibility', async () => {
|
|
1306
|
+
await it('EventEmitter.EventEmitter should reference itself', async () => {
|
|
1307
|
+
expect((EventEmitter as any).EventEmitter).toBe(EventEmitter);
|
|
1308
|
+
});
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
// ==================== expanded tests: listeners copy behavior ====================
|
|
1312
|
+
|
|
1313
|
+
await describe('EventEmitter: listeners returns a copy', async () => {
|
|
1314
|
+
await it('should return a copy, not a reference', async () => {
|
|
1315
|
+
const emitter = new EventEmitter();
|
|
1316
|
+
const fn = () => {};
|
|
1317
|
+
emitter.on('test', fn);
|
|
1318
|
+
const list1 = emitter.listeners('test');
|
|
1319
|
+
const list2 = emitter.listeners('test');
|
|
1320
|
+
// They should be different array objects
|
|
1321
|
+
expect(list1.length).toBe(list2.length);
|
|
1322
|
+
expect(list1[0]).toBe(list2[0]);
|
|
1323
|
+
// Mutating one should not affect the other
|
|
1324
|
+
list1.push(() => {});
|
|
1325
|
+
expect(list2.length).toBe(1);
|
|
1326
|
+
});
|
|
1327
|
+
});
|
|
1328
|
+
|
|
1329
|
+
// ==================== expanded tests: addListener chaining ====================
|
|
1330
|
+
|
|
1331
|
+
await describe('EventEmitter: chaining', async () => {
|
|
1332
|
+
await it('should support fluent chaining of multiple methods', async () => {
|
|
1333
|
+
const emitter = new EventEmitter();
|
|
1334
|
+
let count = 0;
|
|
1335
|
+
emitter
|
|
1336
|
+
.on('a', () => { count++; })
|
|
1337
|
+
.on('b', () => { count++; })
|
|
1338
|
+
.once('c', () => { count++; });
|
|
1339
|
+
emitter.emit('a');
|
|
1340
|
+
emitter.emit('b');
|
|
1341
|
+
emitter.emit('c');
|
|
1342
|
+
expect(count).toBe(3);
|
|
1343
|
+
});
|
|
1344
|
+
});
|
|
1345
|
+
|
|
1346
|
+
// ==================== expanded tests: this binding in listeners ====================
|
|
1347
|
+
|
|
1348
|
+
await describe('EventEmitter: this in listeners', async () => {
|
|
1349
|
+
await it('should bind this to the emitter in on listeners', async () => {
|
|
1350
|
+
const emitter = new EventEmitter();
|
|
1351
|
+
let self: unknown;
|
|
1352
|
+
emitter.on('test', function(this: unknown) { self = this; });
|
|
1353
|
+
emitter.emit('test');
|
|
1354
|
+
expect(self).toBe(emitter);
|
|
1355
|
+
});
|
|
1356
|
+
|
|
1357
|
+
await it('should bind this to the emitter in once listeners', async () => {
|
|
1358
|
+
const emitter = new EventEmitter();
|
|
1359
|
+
let self: unknown;
|
|
1360
|
+
emitter.once('test', function(this: unknown) { self = this; });
|
|
1361
|
+
emitter.emit('test');
|
|
1362
|
+
expect(self).toBe(emitter);
|
|
1363
|
+
});
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
// ==================== expanded tests: listener validation ====================
|
|
1367
|
+
|
|
1368
|
+
await describe('EventEmitter: listener validation', async () => {
|
|
1369
|
+
await it('should throw TypeError for non-function listener on on()', async () => {
|
|
1370
|
+
const emitter = new EventEmitter();
|
|
1371
|
+
expect(() => emitter.on('test', 'notfn' as any)).toThrow();
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
await it('should throw TypeError for non-function listener on once()', async () => {
|
|
1375
|
+
const emitter = new EventEmitter();
|
|
1376
|
+
expect(() => emitter.once('test', 42 as any)).toThrow();
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1379
|
+
await it('should throw TypeError for non-function listener on removeListener()', async () => {
|
|
1380
|
+
const emitter = new EventEmitter();
|
|
1381
|
+
expect(() => emitter.removeListener('test', null as any)).toThrow();
|
|
1382
|
+
});
|
|
1383
|
+
});
|
|
158
1384
|
}
|