Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { describe, expect, test, jest } from "@jest/globals";
- type IListeners = {
- name: string;
- callback: (...args: any[]) => void;
- type: 'once' | 'default';
- };
- class EventEmitter {
- protected Listeners: IListeners[] = [];
- protected pushNewListener(eventName: string, callback: (...args: any[]) => void, type: 'once' | 'default') {
- this.Listeners.push({
- callback,
- name: eventName,
- type,
- })
- this.Listeners = this.Listeners.sort((a, b) => {
- if (a.name < b.name) return -1;
- if (a.name > b.name) return 1;
- return 0;
- })
- }
- public addEventListener(eventName: string, callback: (...args: any[]) => void) {
- this.pushNewListener(eventName, callback, 'default');
- }
- public once(eventName: string, callback: (...args: any[]) => void) {
- this.pushNewListener(eventName, callback, 'once');
- }
- public async promise(eventName: string) {
- return new Promise((resolve, _) => {
- this.Listeners.push({
- callback: (...args: any[]) => {
- resolve.apply(this, args);
- },
- name: eventName,
- type: 'default',
- });
- });
- }
- public trigger(eventName: string, data?: any) {
- for (let index=0; index<this.Listeners.length; index++) {
- const eventNameIsMatched = this.Listeners[index].name === eventName;
- if (eventNameIsMatched) {
- this.Listeners[index].callback(data);
- if (this.Listeners[index].type === 'once') {
- this.Listeners.splice(index, 1);
- }
- const nextEventIsIdentical = this.Listeners[index]?.callback===this.Listeners[index+1]?.callback && this.Listeners[index]?.name===this.Listeners[index+1]?.name;
- if (nextEventIsIdentical) {
- break;
- }
- }
- }
- }
- public removeEventListener(eventName: string, callback: (...args: any[]) => void) {
- this.Listeners = this.Listeners.filter(
- (event) => !(event.name === eventName && event.callback === callback)
- );
- }
- }
- describe("Event emitter", () => {
- const emitter = new EventEmitter();
- const callback = jest.fn();
- test("adds a listener", () => {
- emitter.addEventListener("click", callback);
- expect(callback.mock.calls.length).toBe(0);
- });
- test("emits an event", () => {
- let sentEvent = {
- x: 123,
- y: 42
- };
- emitter.trigger("click", sentEvent);
- expect(callback.mock.calls.length).toBe(1);
- expect(callback.mock.calls[0][0]).toBe(sentEvent);
- emitter.trigger("mousemove");
- expect(callback.mock.calls.length).toBe(1);
- });
- test("removes the listener", () => {
- emitter.trigger("click");
- expect(callback.mock.calls.length).toBe(2);
- emitter.removeEventListener("click", callback);
- emitter.trigger("click");
- expect(callback.mock.calls.length).toBe(2);
- });
- test("handles handlers", () => {
- let cb = jest.fn();
- emitter.addEventListener("handler", cb);
- emitter.addEventListener("handler", cb);
- emitter.trigger("handler");
- expect(cb.mock.calls.length).toBe(1);
- emitter.removeEventListener("handler", cb);//no need to remove the handler twice
- emitter.trigger("handler");
- expect(cb.mock.calls.length).toBe(1);
- });
- test("supports once", () => {
- let cb = jest.fn();
- emitter.once("onlyOnce", cb);
- emitter.trigger("onlyOnce");
- emitter.trigger("onlyOnce");
- expect(cb.mock.calls.length).toBe(1);
- });
- test("promises", async () => {
- let cb = jest.fn();
- let p = emitter.promise("promise").then(cb);
- emitter.trigger("promise", "call");
- await p;
- expect(cb.mock.calls.length).toBe(1);
- expect(cb.mock.calls[0][0]).toBe("call");
- });
- test("removes only the needed handler", async () => {
- let cb1 = jest.fn();
- let cb2 = jest.fn();
- emitter.addEventListener("click", cb1);
- emitter.addEventListener("click", cb2);
- emitter.trigger("click");
- expect(cb1.mock.calls.length).toBe(1);
- expect(cb2.mock.calls.length).toBe(1);
- emitter.removeEventListener("click", cb2);
- emitter.trigger("click");
- expect(cb1.mock.calls.length).toBe(2);
- expect(cb2.mock.calls.length).toBe(1);
- });
- });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement