From efdd9d980e35df49b7b91e9ba4421ab7b6fe410c Mon Sep 17 00:00:00 2001 From: David Charbonnier Date: Thu, 6 Sep 2018 19:20:46 +0200 Subject: [PATCH] fizz draft --- mock.mjs | 8 +-- src/Shell.spec.ts | 2 +- src/Shell.ts | 14 ++--- src/fizz/Fizz.spec.ts | 117 ++++++++++++++++++++++++++++++++++++++++++ src/fizz/Fizz.ts | 87 +++++++++++++++++++++++++++++++ src/polyfill/Dict.ts | 4 +- 6 files changed, 218 insertions(+), 14 deletions(-) create mode 100644 src/fizz/Fizz.spec.ts create mode 100644 src/fizz/Fizz.ts diff --git a/mock.mjs b/mock.mjs index bf1d28d..a9f5765 100644 --- a/mock.mjs +++ b/mock.mjs @@ -81,10 +81,10 @@ wss.on('connection', (ws, request) => { } else if (message.substr(4) === "ping") { ws.send(message.replace("ping", "pong")); } - try { - ws.send("hello"); - } catch (e) { - } + // try { + // ws.send("hello"); + // } catch (e) { + // } }); } diff --git a/src/Shell.spec.ts b/src/Shell.spec.ts index a717526..239f7b0 100644 --- a/src/Shell.spec.ts +++ b/src/Shell.spec.ts @@ -136,7 +136,7 @@ describe("Shell", () => { setTimeout(done, 100); }); it("should remove a non existing listener", () => { - expect(() => shell.removeEventListener("message", () => null)).to.not.throw(); + expect(() => shell.removeEventListener("message", () => null)).to.not.throw(); }); it("should accept more than one listener", (done) => { let i = 0; diff --git a/src/Shell.ts b/src/Shell.ts index bc926ca..bb47858 100644 --- a/src/Shell.ts +++ b/src/Shell.ts @@ -29,7 +29,7 @@ export abstract class Shell implements WebSocket { private _onmessage: (ev: MessageEvent) => any; private _onopen: (ev: Event) => any; private _onclose: (ev: CloseEvent) => any; - private listeners: Dict any, @@ -141,7 +141,7 @@ export abstract class Shell implements WebSocket { * This string must be no longer than 123 bytes of UTF-8 text (not characters). */ public close(code: number = 1000, reason?: string) { - this.ws.close(code, reason); + this.ws.close(code, reason || ""); } /** @@ -192,10 +192,10 @@ export abstract class Shell implements WebSocket { listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, useCapture?: boolean): void { - let listeners = this.listeners.get(type); + let listeners = this.listenersDict.get(type); if (!listeners) { listeners = []; - this.listeners.set(type, listeners); + this.listenersDict.set(type, listeners); } listeners.push({listener, useCapture}); } @@ -212,9 +212,9 @@ export abstract class Shell implements WebSocket { listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, useCapture?: boolean): void { - const listeners = this.listeners.get(type); + const listeners = this.listenersDict.get(type); if (listeners) { - this.listeners.set( + this.listenersDict.set( type, listeners.filter((l) => l.listener !== listener || l.useCapture !== useCapture), ); @@ -232,7 +232,7 @@ export abstract class Shell implements WebSocket { if (typeof method === "function") { method.call(this, evt); } - return (this.listeners.get(evt.type as keyof WebSocketEventMap) || []) + return (this.listenersDict.get(evt.type as keyof WebSocketEventMap) || []) .some(({listener}) => listener.call(this, evt) === false) === void 0; } diff --git a/src/fizz/Fizz.spec.ts b/src/fizz/Fizz.spec.ts new file mode 100644 index 0000000..ec2ff42 --- /dev/null +++ b/src/fizz/Fizz.spec.ts @@ -0,0 +1,117 @@ +import { expect } from "chai"; +import WebSocket from "../polyfill/WebSocket"; +import { expectEventually, rnd, sleep, supervisor, TIMEOUT_FACTOR } from "../wrench.spec"; +import { Fizz } from "./Fizz"; + +let ws: WebSocket; +let testCase: string; + +const testListener = (method: "addListener"|"on"|"once") => { + + describe(`listener with ${method}`, () => { + + it ("close", (done) => { + const fizz = new Fizz(ws); + fizz[method]("close", (...args: any[]) => { + expect(args).to.deep.equal([1000, ""]); + done(); + }); + fizz.close(); + }); + + it.skip ("error", (done) => { + const fizz = new Fizz(ws); + fizz[method]("error", (...args: any[]) => { + expect(args).to.have.lengthOf(1); + expect(args[0]).to.be.instanceof(Error); + done(); + }); + }); + + it ("message", (done) => { + const fizz = new Fizz(ws); + fizz[method]("message", (...args: any[]) => { + expect(args).to.deep.equal(["pong"]); + done(); + }); + ws.send("ping"); + }); + + it ("open", (done) => { + const fizz = new Fizz(new WebSocket(`ws://localtest.me:4752/${rnd()}`)); + fizz[method]("open", (...args: any[]) => { + expect(args).to.deep.equal([]); + done(); + }); + }); + + }); +}; + +describe("Fizz", () => { + before(async () => { + await expectEventually(() => supervisor.ws.readyState === WebSocket.OPEN, + "The supervisor failed to connect"); + }); + + beforeEach((done) => { + testCase = rnd(); + ws = new WebSocket(`ws://localtest.me:4752/${testCase}`); + ws.onopen = () => done(); + }); + + afterEach(async () => { + if (ws) { + ws.close(); + } + }); + + describe("addListener", () => { + testListener("addListener"); + }); + + describe("on", () => { + testListener("on"); + }); + + describe("once", () => { + testListener("once"); + }); + + describe("prependListener", () => { + + }); + + describe("prependOnceListener", () => { + + }); + + describe("removeListener", () => { + + }); + + describe("off", () => { + + }); + + describe("removeAllListeners", () => { + + }); + + describe("setMaxListeners", () => { + + }); + + describe("getMaxListeners", () => { + + }); + + describe("listeners", () => { + + }); + + describe("rawListeners", () => { + + }); + +}); diff --git a/src/fizz/Fizz.ts b/src/fizz/Fizz.ts new file mode 100644 index 0000000..40c2131 --- /dev/null +++ b/src/fizz/Fizz.ts @@ -0,0 +1,87 @@ +import { EventEmitter } from "events"; +import { Shell } from "../Shell"; + +export class Fizz extends Shell implements EventEmitter { + + public addListener(event: string | symbol, listener: (...args: any[]) => void): this { + switch (event) { + case "close": + this.addEventListener("close", (evt: CloseEvent) => listener(evt.code, evt.reason)); + break; + case "error": + this.addEventListener("error", (evt: ErrorEvent) => listener(evt.error)); + break; + case "message": + this.addEventListener("message", (evt: MessageEvent) => listener(evt.data)); + break; + case "open": + this.addEventListener("open", () => listener()); + break; + default: + console.log("not impelmented"); + } + return this; + } + + public on(event: string | symbol, listener: (...args: any[]) => void): this { + return this.addListener(event, listener); + } + + public once(event: string | symbol, listener: (...args: any[]) => void): this { + return this.addListener(event, listener); + } + + public prependListener(event: string | symbol, listener: (...args: any[]) => void): this { + return this.addListener(event, listener); + } + + public prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this { + return this.addListener(event, listener); + } + + public removeListener(event: string | symbol, listener: (...args: any[]) => void): this { + super.removeEventListener(event as any, listener); + return this; + } + + public off(event: string | symbol, listener: (...args: any[]) => void): this { + return this.removeListener(event, listener); + } + + public removeAllListeners(event?: string | symbol): this { + for (const key of this.listenersDict.keys()) { + this.listenersDict.get(key).length = 0; + } + return this; + } + + public setMaxListeners(n: number): this { + return this; + } + + public getMaxListeners(): number { + return 0; + } + + public listeners(event: string | symbol): Array<() => void> { + return []; + } + + public rawListeners(event: string | symbol): Array<() => void> { + return []; + + } + + public emit(event: string | symbol, ...args: any[]): boolean { + // return this.dispatchEvent(event, args); + return true; + } + + public eventNames(): Array { + return this.listenersDict.keys(); + } + + public listenerCount(type: string | symbol): number { + return this.listenersDict[type] ? this.listenersDict[type].length : 0; + } +} diff --git a/src/polyfill/Dict.ts b/src/polyfill/Dict.ts index 65cfb51..eea6bb8 100644 --- a/src/polyfill/Dict.ts +++ b/src/polyfill/Dict.ts @@ -17,7 +17,7 @@ export class Dict { public delete(key: K) { delete this.values[key]; } - public keys() { - return Object.keys(this.values); + public keys(): K[] { + return Object.keys(this.values) as K[]; } }