Advertisement
Guest User

Untitled

a guest
Nov 2nd, 2023
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TypeScript 4.21 KB | Software | 0 0
  1. import { describe, expect, test, jest } from "@jest/globals";
  2.  
  3. type IListeners = {
  4.   name: string;
  5.   callback: (...args: any[]) => void;
  6.   type: 'once' | 'default';
  7. };
  8.  
  9. class EventEmitter {
  10.   protected Listeners: IListeners[] = [];
  11.  
  12.   protected pushNewListener(eventName: string, callback: (...args: any[]) => void, type:  'once' | 'default') {
  13.     this.Listeners.push({
  14.       callback,
  15.       name: eventName,
  16.       type,
  17.     })
  18.     this.Listeners = this.Listeners.sort((a, b) => {
  19.       if (a.name < b.name) return -1;
  20.       if (a.name > b.name) return 1;
  21.       return 0;
  22.     })
  23.   }
  24.  
  25.   public addEventListener(eventName: string, callback: (...args: any[]) => void) {
  26.     this.pushNewListener(eventName, callback, 'default');
  27.   }
  28.  
  29.   public once(eventName: string, callback: (...args: any[]) => void) {
  30.     this.pushNewListener(eventName, callback, 'once');
  31.   }
  32.  
  33.   public async promise(eventName: string) {
  34.     return new Promise((resolve, _) => {
  35.       this.Listeners.push({
  36.         callback: (...args: any[]) => {
  37.           resolve.apply(this, args);
  38.         },
  39.         name: eventName,
  40.         type: 'default',
  41.       });
  42.     });
  43.   }
  44.  
  45.   public trigger(eventName: string, data?: any) {
  46.     for (let index=0; index<this.Listeners.length; index++) {
  47.       const eventNameIsMatched = this.Listeners[index].name === eventName;
  48.       if (eventNameIsMatched) {
  49.         this.Listeners[index].callback(data);
  50.         if (this.Listeners[index].type === 'once') {
  51.           this.Listeners.splice(index, 1);
  52.         }
  53.         const nextEventIsIdentical = this.Listeners[index]?.callback===this.Listeners[index+1]?.callback && this.Listeners[index]?.name===this.Listeners[index+1]?.name;
  54.         if (nextEventIsIdentical) {
  55.           break;
  56.         }
  57.       }
  58.     }
  59.   }
  60.  
  61.   public removeEventListener(eventName: string, callback: (...args: any[]) => void) {
  62.     this.Listeners = this.Listeners.filter(
  63.       (event) => !(event.name === eventName && event.callback === callback)
  64.     );
  65.   }
  66. }
  67.  
  68. describe("Event emitter", () => {
  69.   const emitter = new EventEmitter();
  70.   const callback = jest.fn();
  71.  
  72.   test("adds a listener", () => {
  73.     emitter.addEventListener("click", callback);
  74.     expect(callback.mock.calls.length).toBe(0);
  75.   });
  76.  
  77.   test("emits an event", () => {
  78.     let sentEvent = {
  79.       x: 123,
  80.       y: 42
  81.     };
  82.  
  83.     emitter.trigger("click", sentEvent);
  84.  
  85.     expect(callback.mock.calls.length).toBe(1);
  86.  
  87.     expect(callback.mock.calls[0][0]).toBe(sentEvent);
  88.  
  89.     emitter.trigger("mousemove");
  90.     expect(callback.mock.calls.length).toBe(1);
  91.  
  92.   });
  93.  
  94.   test("removes the listener", () => {
  95.     emitter.trigger("click");
  96.     expect(callback.mock.calls.length).toBe(2);
  97.  
  98.     emitter.removeEventListener("click", callback);
  99.     emitter.trigger("click");
  100.     expect(callback.mock.calls.length).toBe(2);
  101.   });
  102.  
  103.   test("handles handlers", () => {
  104.     let cb = jest.fn();
  105.     emitter.addEventListener("handler", cb);
  106.     emitter.addEventListener("handler", cb);
  107.  
  108.     emitter.trigger("handler");
  109.     expect(cb.mock.calls.length).toBe(1);
  110.  
  111.     emitter.removeEventListener("handler", cb);//no need to remove the handler twice
  112.  
  113.     emitter.trigger("handler");
  114.     expect(cb.mock.calls.length).toBe(1);
  115.   });
  116.  
  117.   test("supports once", () => {
  118.     let cb = jest.fn();
  119.     emitter.once("onlyOnce", cb);
  120.  
  121.     emitter.trigger("onlyOnce");
  122.     emitter.trigger("onlyOnce");
  123.  
  124.     expect(cb.mock.calls.length).toBe(1);
  125.   });
  126.  
  127.   test("promises", async () => {
  128.     let cb = jest.fn();
  129.     let p = emitter.promise("promise").then(cb);
  130.     emitter.trigger("promise", "call");
  131.  
  132.     await p;
  133.     expect(cb.mock.calls.length).toBe(1);
  134.     expect(cb.mock.calls[0][0]).toBe("call");
  135.   });
  136.  
  137.   test("removes only the needed handler", async () => {
  138.     let cb1 = jest.fn();
  139.     let cb2 = jest.fn();
  140.     emitter.addEventListener("click", cb1);
  141.     emitter.addEventListener("click", cb2);
  142.  
  143.     emitter.trigger("click");
  144.     expect(cb1.mock.calls.length).toBe(1);
  145.     expect(cb2.mock.calls.length).toBe(1);
  146.  
  147.     emitter.removeEventListener("click", cb2);
  148.  
  149.     emitter.trigger("click");
  150.     expect(cb1.mock.calls.length).toBe(2);
  151.     expect(cb2.mock.calls.length).toBe(1);
  152.   });
  153. });
Tags: typescript
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement