storybook/code/lib/channels/src/index.test.ts
2022-10-27 19:33:39 -04:00

225 lines
7.3 KiB
TypeScript

import type { ChannelTransport, Listener } from '.';
import { Channel } from '.';
jest.useFakeTimers();
describe('Channel', () => {
let transport: ChannelTransport;
let channel: Channel;
beforeEach(() => {
transport = { setHandler: jest.fn(), send: jest.fn() };
channel = new Channel({ transport });
});
describe('constructor', () => {
it('should set the handler if handler is preset', () => {
channel = new Channel({ transport });
expect(transport.setHandler).toHaveBeenCalled();
});
it('should not set transport if not passed as an argument', () => {
channel = new Channel();
expect(channel.hasTransport).toBeFalsy();
});
it('should set transport if passed as an argument', () => {
channel = new Channel({ transport });
expect(channel.hasTransport).toBeTruthy();
});
it('should set isAsync to false as default value', () => {
channel = new Channel();
expect(channel.isAsync).toBeFalsy();
});
it('should set isAsync to true if passed as an argument', () => {
channel = new Channel({ async: true });
expect(channel.isAsync).toBeTruthy();
});
});
describe('method:addListener', () => {
it('should create one listener', () => {
const eventName = 'event1';
channel.addListener(eventName, jest.fn());
expect(channel.listeners(eventName).length).toBe(1);
});
});
describe('method:on', () => {
it('should do the same as addListener', () => {
const eventName = 'event1';
channel.on(eventName, jest.fn());
expect(channel.listeners(eventName).length).toBe(1);
});
});
describe('method:off', () => {
it('should remove listeners', () => {
const eventName = 'event1';
const fn = jest.fn();
channel.on(eventName, fn);
expect(channel.listeners(eventName).length).toBe(1);
channel.off(eventName, fn);
expect(channel.listeners(eventName).length).toBe(0);
});
});
describe('method:emit', () => {
it('should execute the callback fn of a listener', () => {
const eventName = 'event1';
const listenerInputData = ['string1', 'string2', 'string3'];
let listenerOutputData: string[] = null;
const mockListener: Listener = (data) => {
listenerOutputData = data;
};
channel.addListener(eventName, mockListener);
channel.emit(eventName, listenerInputData);
expect(listenerOutputData).toBe(listenerInputData);
});
it('should be callable with a spread operator as event arguments', () => {
const eventName = 'event1';
const listenerInputData = ['string1', 'string2', 'string3'];
let listenerOutputData: string[] = null;
channel.addListener(eventName, (...data) => {
listenerOutputData = data;
});
channel.emit(eventName, ...listenerInputData);
expect(listenerOutputData).toEqual(listenerInputData);
});
it('should be callable with options on the event', () => {
const eventName = 'event1';
const listenerInputData = [{ event: {}, options: { depth: 1 } }];
let listenerOutputData: any = null;
channel.addListener(eventName, (...data) => {
listenerOutputData = data;
});
const sendSpy = jest.fn();
// @ts-expect-error (Converted from ts-ignore)
channel.transport.send = sendSpy;
channel.emit(eventName, ...listenerInputData);
expect(listenerOutputData).toEqual(listenerInputData);
expect(sendSpy.mock.calls[0][1]).toEqual({ depth: 1 });
});
it('should use setImmediate if async is true', () => {
channel = new Channel({ async: true, transport });
channel.addListener('event1', jest.fn());
});
});
describe('method:eventNames', () => {
it('should return a list of all registered events', () => {
const eventNames = ['event1', 'event2', 'event3'];
eventNames.forEach((eventName) => channel.addListener(eventName, jest.fn()));
expect(channel.eventNames()).toEqual(eventNames);
});
});
describe('method:listenerCount', () => {
it('should return a list of all registered events', () => {
const events = [
{ eventName: 'event1', listeners: [jest.fn(), jest.fn(), jest.fn()], listenerCount: 0 },
{ eventName: 'event2', listeners: [jest.fn()], listenerCount: 0 },
];
events.forEach((event) => {
event.listeners.forEach((listener) => {
channel.addListener(event.eventName, listener);
// eslint-disable-next-line no-plusplus, no-param-reassign
event.listenerCount++;
});
});
events.forEach((event) => {
expect(channel.listenerCount(event.eventName)).toBe(event.listenerCount);
});
});
});
describe('method:once', () => {
it('should execute a listener once and remove it afterwards', () => {
const eventName = 'event1';
channel.once(eventName, jest.fn());
channel.emit(eventName);
expect(channel.listenerCount(eventName)).toBe(0);
});
it('should pass all event arguments correctly to the listener', () => {
const eventName = 'event1';
const listenerInputData = ['string1', 'string2', 'string3'];
let listenerOutputData = null;
const mockListener: Listener = (data: string[]) => {
listenerOutputData = data;
};
channel.once(eventName, (args) => mockListener(args));
channel.emit(eventName, listenerInputData);
expect(listenerOutputData).toEqual(listenerInputData);
});
it('should be removable', () => {
const eventName = 'event1';
const listenerToBeRemoved = jest.fn();
channel.once(eventName, listenerToBeRemoved);
channel.removeListener(eventName, listenerToBeRemoved);
});
});
describe('method:removeAllListeners', () => {
it('should remove all listeners', () => {
const eventName1 = 'event1';
const eventName2 = 'event2';
const listeners1 = [jest.fn(), jest.fn(), jest.fn()];
const listeners2 = [jest.fn()];
listeners1.forEach((fn) => channel.addListener(eventName1, fn));
listeners2.forEach((fn) => channel.addListener(eventName2, fn));
channel.removeAllListeners();
expect(channel.listenerCount(eventName1)).toBe(0);
expect(channel.listenerCount(eventName2)).toBe(0);
});
it('should remove all listeners of a certain event', () => {
const eventName = 'event1';
const listeners = [jest.fn(), jest.fn(), jest.fn()];
listeners.forEach((fn) => channel.addListener(eventName, fn));
expect(channel.listenerCount(eventName)).toBe(listeners.length);
channel.removeAllListeners(eventName);
expect(channel.listenerCount(eventName)).toBe(0);
});
});
describe('method:removeListener', () => {
it('should remove one listener', () => {
const eventName = 'event1';
const listenerToBeRemoved = jest.fn();
const listeners = [jest.fn(), jest.fn()];
const findListener = (listener: Listener) =>
channel.listeners(eventName).find((_listener) => _listener === listener);
listeners.forEach((fn) => channel.addListener(eventName, fn));
channel.addListener(eventName, listenerToBeRemoved);
expect(findListener(listenerToBeRemoved)).toBe(listenerToBeRemoved);
channel.removeListener(eventName, listenerToBeRemoved);
expect(findListener(listenerToBeRemoved)).toBeUndefined();
});
});
});