event-emitters
Version:
122 lines • 4.84 kB
JavaScript
import { EventEmitter } from './EventEmitter';
describe('EventEmitter', () => {
/* eslint-disable @typescript-eslint/explicit-function-return-type */
let emitter = new EventEmitter();
beforeEach(() => {
emitter = new EventEmitter();
});
it('updates subscribed listener with statuses as they change', () => {
let current;
emitter.subscribe((newVal) => {
current = newVal;
});
expect(current).toEqual(undefined);
const secondVal = 2;
emitter.emit(secondVal);
expect(current).toEqual(secondVal);
});
it('supports multiple listeners', () => {
let current1;
let current2;
emitter.subscribe((newVal) => {
current1 = newVal;
});
emitter.subscribe((newVal) => {
current2 = newVal;
});
expect(current1).toEqual(undefined);
expect(current2).toEqual(undefined);
const secondVal = 2;
emitter.emit(secondVal);
expect(current1).toEqual(secondVal);
expect(current2).toEqual(secondVal);
});
it('stops updating a listener after `unsubscribe` is called', () => {
let current1;
let current2;
const secondListener = (newVal) => {
current2 = newVal;
};
emitter.subscribe((newVal) => {
current1 = newVal;
});
emitter.subscribe(secondListener);
expect(current1).toEqual(undefined);
expect(current2).toEqual(undefined);
const secondVal = 2;
emitter.emit(secondVal);
expect(current1).toEqual(secondVal);
expect(current2).toEqual(secondVal);
emitter.unsubscribe(secondListener);
const thirdVal = 3;
emitter.emit(thirdVal);
expect(current1).toEqual(thirdVal);
expect(current2).toEqual(secondVal);
});
it('throws an error when trying to subscribe the same listener twice', () => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
const listener = () => { };
emitter.subscribe(listener);
expect(() => {
emitter.subscribe(listener);
}).toThrow();
});
it('throws an error when trying to unsubscribe a listener that is not listening', () => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
const listener1 = () => { };
// eslint-disable-next-line @typescript-eslint/no-empty-function
const listener2 = () => { };
emitter.subscribe(listener1);
expect(() => {
emitter.unsubscribe(listener2);
}).toThrow();
});
describe('async iterator', () => {
it('can be iterated over in order using "for await" loop', async () => {
const allVals = [];
async function iterate(iterator) {
for await (const val of iterator) {
allVals.push(val);
if (val === 3)
break;
}
}
const promise = iterate(emitter);
emitter.emit(1);
emitter.emit(2);
emitter.emit(3);
expect(emitter.hasListeners()).toEqual(true);
await expect(promise).resolves.not.toThrow();
expect(allVals).toEqual([1, 2, 3]);
// ensure that the iterator's return() method was called
expect(emitter.hasListeners()).toEqual(false);
});
it('queues calls to next() such that emissions are delivered in sequence via emitted queue', async () => {
const iterator = emitter.asyncIterator();
// by calling emit() before next() the emitted items are queued via iterator.emitted
emitter.emit(1);
emitter.emit(2);
emitter.emit(3);
const vals = await Promise.all([iterator.next(), iterator.next(), iterator.next()]);
expect(vals).toEqual([
{ done: false, value: 1 },
{ done: false, value: 2 },
{ done: false, value: 3 },
]);
});
it('queues calls to next such that emissions are delivered in sequence via pending listener queue', async () => {
const iterator = emitter.asyncIterator();
// by calling next() before emit() the pending listeners are queued via iterator.pendingListens
const promises = [iterator.next(), iterator.next(), iterator.next()];
emitter.emit(1);
emitter.emit(2);
emitter.emit(3);
expect(await Promise.all(promises)).toEqual([
{ done: false, value: 1 },
{ done: false, value: 2 },
{ done: false, value: 3 },
]);
});
});
});
//# sourceMappingURL=EventEmitter.spec.js.map