From 237c5945d20994f7a9ee0d5b28368518d490b62b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Tue, 11 Dec 2018 18:57:22 +0100 Subject: [PATCH 01/26] WIP; Migrating @storybook/channels to TypeScript --- .../src/{index.test.js => index.test.ts} | 7 +- lib/channels/src/{index.js => index.ts} | 80 +++++++++++++------ lib/channels/tsconfig.json | 13 +++ 3 files changed, 70 insertions(+), 30 deletions(-) rename lib/channels/src/{index.test.js => index.test.ts} (98%) rename lib/channels/src/{index.js => index.ts} (53%) create mode 100644 lib/channels/tsconfig.json diff --git a/lib/channels/src/index.test.js b/lib/channels/src/index.test.ts similarity index 98% rename from lib/channels/src/index.test.js rename to lib/channels/src/index.test.ts index ce954dbf5f06..bc4ce4ac84e4 100644 --- a/lib/channels/src/index.test.js +++ b/lib/channels/src/index.test.ts @@ -1,11 +1,10 @@ -/* eslint no-underscore-dangle: 0 */ -import Channel from '.'; +import { Channel, ChannelTransport } from '.'; jest.useFakeTimers(); describe('Channel', () => { - let transport = null; - let channel = null; + let transport: ChannelTransport; + let channel: Channel; beforeEach(() => { transport = { setHandler: jest.fn(), send: jest.fn() }; diff --git a/lib/channels/src/index.js b/lib/channels/src/index.ts similarity index 53% rename from lib/channels/src/index.js rename to lib/channels/src/index.ts index fba29bbedc99..9801e52f6241 100644 --- a/lib/channels/src/index.js +++ b/lib/channels/src/index.ts @@ -1,27 +1,60 @@ -/* eslint no-underscore-dangle: 0 */ +export interface ChannelTransport { + send: any; + setHandler(handler: (event: ChannelEvent) => void): void; +} + +export interface ChannelEvent { + type: string; + from: string; + args: TEventArgs[]; +} + +interface Listener { + (...args: TEventArgs[]): void; + ignorePeer?: boolean; +} + +interface ListenersKeyValue { + [key: string]: Listener[]; +} -export default class Channel { - constructor({ transport, async } = {}) { - this._sender = this._randomId(); +interface ChannelArgs { + transport?: ChannelTransport; + async?: boolean; +} + +const generateRandomId = () => { + // generates a random 13 character string + return Math.random() + .toString(16) + .slice(2); +}; + +export class Channel { + private _sender = generateRandomId(); + private _listeners: ListenersKeyValue = {}; + private readonly _async: boolean = false; + private readonly _transport: ChannelTransport; + + constructor({ transport, async }: ChannelArgs = {}) { this._async = async; if (transport) { this._transport = transport; this._transport.setHandler(event => this._handleEvent(event)); } - this._listeners = {}; } - addListener(type, listener) { + addListener(type: string, listener: Listener) { this.on(type, listener); } - addPeerListener(type, listener) { + addPeerListener(type: string, listener: Listener) { const peerListener = listener; peerListener.ignorePeer = true; this.on(type, peerListener); } - emit(type, ...args) { + emit(type: string, ...args: any[]) { const event = { type, args, from: this._sender }; const handler = () => { @@ -42,36 +75,36 @@ export default class Channel { return Object.keys(this._listeners); } - listenerCount(type) { + listenerCount(type: string) { const listeners = this._listeners[type]; return listeners ? listeners.length : 0; } - listeners(type) { + listeners(type: string) { return this._listeners[type]; } - on(type, listener) { + on(type: string, listener: Listener) { this._listeners[type] = this._listeners[type] || []; this._listeners[type].push(listener); } - once(type, listener) { + once(type: string, listener: Listener) { const onceListener = this._onceListener(type, listener); this.on(type, onceListener); } - prependListener(type, listener) { + prependListener(type: string, listener: Listener) { this._listeners[type] = this._listeners[type] || []; this._listeners[type].unshift(listener); } - prependOnceListener(type, listener) { + prependOnceListener(type: string, listener: Listener) { const onceListener = this._onceListener(type, listener); this.prependListener(type, onceListener); } - removeAllListeners(type) { + removeAllListeners(type: string) { if (!type) { this._listeners = {}; } else if (this._listeners[type]) { @@ -79,32 +112,27 @@ export default class Channel { } } - removeListener(type, listener) { + removeListener(type: string, listener: Listener) { const listeners = this._listeners[type]; if (listeners) { this._listeners[type] = listeners.filter(l => l !== listener); } } - _randomId() { - // generates a random 13 character string - return Math.random() - .toString(16) - .slice(2); - } - - _handleEvent(event, isPeer) { + private _handleEvent(event: ChannelEvent, isPeer = false) { const listeners = this._listeners[event.type]; if (listeners && (isPeer || event.from !== this._sender)) { listeners.forEach(fn => !(isPeer && fn.ignorePeer) && fn(...event.args)); } } - _onceListener(type, listener) { - const onceListener = (...args) => { + private _onceListener(type: string, listener: Listener) { + const onceListener = (...args: any[]) => { this.removeListener(type, onceListener); return listener(...args); }; return onceListener; } } + +export default Channel; diff --git a/lib/channels/tsconfig.json b/lib/channels/tsconfig.json new file mode 100644 index 000000000000..f7c7ea71c14c --- /dev/null +++ b/lib/channels/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src" + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx" + ], + "exclude": [ + "src/index.test.ts" + ] +} From 176b65036cb1a91f4f572fa38d4f1387f8a216ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Tue, 11 Dec 2018 19:20:00 +0100 Subject: [PATCH 02/26] WIP; Updated tests --- lib/channels/src/index.test.ts | 24 +++++++++++++++++++----- lib/channels/src/index.ts | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/channels/src/index.test.ts b/lib/channels/src/index.test.ts index bc4ce4ac84e4..01f2a2525395 100644 --- a/lib/channels/src/index.test.ts +++ b/lib/channels/src/index.test.ts @@ -1,4 +1,4 @@ -import { Channel, ChannelTransport } from '.'; +import { Channel, ChannelEvent, ChannelTransport } from '.'; jest.useFakeTimers(); @@ -17,18 +17,22 @@ describe('Channel', () => { expect(transport.setHandler).toHaveBeenCalled(); }); + // todo this needs to be tested differently; _transport is a private property it('should not try to set handler if handler is missing', () => { channel = new Channel(); - expect(channel._transport).not.toBeDefined(); + // expect(channel._transport).not.toBeDefined(); + expect(true).toBe(false); // let it fail, until this is rewritten }); }); + // todo before, addListener was called with numbers; is this still the correct test? describe('method:addListener', () => { it('should call channel.on with args', () => { + const testFn = jest.fn(); channel.on = jest.fn(); - channel.addListener(1, 2); + channel.addListener('A', testFn); expect(channel.on).toHaveBeenCalled(); - expect(channel.on).toHaveBeenCalledWith(1, 2); + expect(channel.on).toHaveBeenCalledWith('A', testFn); }); }); @@ -42,13 +46,23 @@ describe('Channel', () => { channel.emit(type, ...args); expect(transport.send).toHaveBeenCalled(); - const event = transport.send.mock.calls[0][0]; + const event: ChannelEvent = transport.send.mock.calls[0][0]; expect(typeof event.from).toEqual('string'); delete event.from; expect(event).toEqual(expected); }); + it('should be type safe', () => { + transport.send = jest.fn(); + const type = 'test-type'; + const args = [1, 2, 3]; + const expected = { type, args }; + + // todo check if generic argument typing works + expect(true).toBe(false); + }); + it('should call handle async option', () => { transport.send = jest.fn(); const type = 'test-type'; diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index 9801e52f6241..e6bb833d0804 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -54,7 +54,7 @@ export class Channel { this.on(type, peerListener); } - emit(type: string, ...args: any[]) { + emit(type: string, ...args: TEventArgs[]) { const event = { type, args, from: this._sender }; const handler = () => { From 6ae40eded18eb3692602fdb83af397093c283efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Tue, 11 Dec 2018 19:20:31 +0100 Subject: [PATCH 03/26] Added todo --- lib/channels/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index e6bb833d0804..0bc0720c955c 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -1,5 +1,5 @@ export interface ChannelTransport { - send: any; + send: any; // todo Check actual type setHandler(handler: (event: ChannelEvent) => void): void; } From f029b4ca103f83b1982e06b9996a8f5d0c99e5fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Tue, 11 Dec 2018 19:26:36 +0100 Subject: [PATCH 04/26] Added missing export --- lib/channels/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index 0bc0720c955c..cd7a184e4a75 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -9,7 +9,7 @@ export interface ChannelEvent { args: TEventArgs[]; } -interface Listener { +export interface Listener { (...args: TEventArgs[]): void; ignorePeer?: boolean; } From 766e576ce874d3886fc0dd3f9a801b8444a704d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Tue, 11 Dec 2018 22:45:13 +0100 Subject: [PATCH 05/26] Added lots of todos to tests and made them fail on purpose until they are fixed --- lib/channels/src/index.test.ts | 238 +++++++++++++++++++-------------- lib/channels/src/index.ts | 4 + 2 files changed, 141 insertions(+), 101 deletions(-) diff --git a/lib/channels/src/index.test.ts b/lib/channels/src/index.test.ts index 01f2a2525395..67f8a3f097f3 100644 --- a/lib/channels/src/index.test.ts +++ b/lib/channels/src/index.test.ts @@ -1,4 +1,4 @@ -import { Channel, ChannelEvent, ChannelTransport } from '.'; +import { Channel, ChannelEvent, ChannelTransport, Listener } from '.'; jest.useFakeTimers(); @@ -17,11 +17,9 @@ describe('Channel', () => { expect(transport.setHandler).toHaveBeenCalled(); }); - // todo this needs to be tested differently; _transport is a private property it('should not try to set handler if handler is missing', () => { channel = new Channel(); - // expect(channel._transport).not.toBeDefined(); - expect(true).toBe(false); // let it fail, until this is rewritten + expect(channel.hasTransport()).not.toBeFalsy(); }); }); @@ -80,9 +78,9 @@ describe('Channel', () => { describe('method:eventNames', () => { it('should return an array of strings', () => { - channel.on('type-1', 11); - channel.on('type-2', 21); - channel.on('type-2', 22); + channel.on('type-1', jest.fn()); + channel.on('type-2', jest.fn()); + channel.on('type-2', jest.fn()); const expected = ['type-1', 'type-2']; expect(channel.eventNames()).toEqual(expected); }); @@ -90,168 +88,206 @@ describe('Channel', () => { describe('method:listenerCount', () => { it('should return the correct count', () => { - channel.on('type-1', 11); - channel.on('type-2', 21); - channel.on('type-2', 22); + channel.on('type-1', jest.fn()); + channel.on('type-2', jest.fn()); + channel.on('type-2', jest.fn()); expect(channel.listenerCount('type-1')).toEqual(1); expect(channel.listenerCount('type-2')).toEqual(2); }); }); describe('method:listeners', () => { + const fn1 = jest.fn(); + const fn2 = jest.fn(); + const fn3 = jest.fn(); + it('should return an array of listeners', () => { - channel.on('type-1', 11); - channel.on('type-2', 21); - channel.on('type-2', 22); - expect(channel.listeners('type-1')).toEqual([11]); - expect(channel.listeners('type-2')).toEqual([21, 22]); + channel.on('type-1', fn1); + channel.on('type-2', fn2); + channel.on('type-2', fn3); + expect(channel.listeners('type-1')).toEqual([fn1]); + expect(channel.listeners('type-2')).toEqual([fn2, fn3]); }); }); describe('method:on', () => { + const fn1 = jest.fn(); + const fn2 = jest.fn(); + const fn3 = jest.fn(); + + // todo kinda duplicated? See method:listeners => should return an array of listeners + // todo _listeners is a private member now it('should add event listeners', () => { - channel.on('type-1', 11); - channel.on('type-2', 21); - channel.on('type-2', 22); - const expected = { - 'type-1': [11], - 'type-2': [21, 22], - }; - expect(channel._listeners).toEqual(expected); + expect(true).toBeFalsy(); + // channel.on('type-1', fn1); + // channel.on('type-2', fn2); + // channel.on('type-2', fn3); + // const expected = { + // 'type-1': [11], + // 'type-2': [21, 22], + // }; + // expect(channel._listeners).toEqual(expected); }); + // todo _handleEvent is private; rewrite test it('should call event listeners on event', () => { - const received = []; - channel.on('type-1', n => received.push(n)); - channel._handleEvent({ type: 'type-1', args: [11] }); - channel._handleEvent({ type: 'type-1', args: [12] }); - expect(received).toEqual([11, 12]); + expect(true).toBeFalsy(); + // const received: Listener[] = []; + // channel.on('type-1', n => received.push(n)); + // channel._handleEvent({ type: 'type-1', args: [11] }); + // channel._handleEvent({ type: 'type-1', args: [12] }); + // expect(received).toEqual([11, 12]); }); }); + // todo _listeners is private; rewrite test describe('method:once', () => { it('should add event listeners', () => { - channel.once('type-1', 11); - channel.once('type-2', 21); - channel.once('type-2', 22); - expect(channel._listeners['type-1']).toHaveLength(1); - expect(channel._listeners['type-2']).toHaveLength(2); + expect(true).toBeFalsy(); + // channel.once('type-1', 11); + // channel.once('type-2', 21); + // channel.once('type-2', 22); + // expect(channel._listeners['type-1']).toHaveLength(1); + // expect(channel._listeners['type-2']).toHaveLength(2); }); + // todo _handleEvent is private; rewrite test it('should call event listeners only once', () => { - const received = []; - channel.once('type-1', n => received.push(n)); - channel._handleEvent({ type: 'type-1', args: [11] }); - channel._handleEvent({ type: 'type-1', args: [12] }); - expect(received).toEqual([11]); + expect(true).toBeFalsy(); + // const received = []; + // channel.once('type-1', n => received.push(n)); + // channel._handleEvent({ type: 'type-1', args: [11] }); + // channel._handleEvent({ type: 'type-1', args: [12] }); + // expect(received).toEqual([11]); }); }); + // todo _listeners is private; rewrite test describe('method:addPeerListener', () => { it('should add event listeners', () => { - channel.addPeerListener('type-1', () => {}); - channel.addPeerListener('type-2', () => {}); - channel.addPeerListener('type-2', () => {}); - expect(channel._listeners['type-1']).toHaveLength(1); - expect(channel._listeners['type-2']).toHaveLength(2); + expect(true).toBeFalsy(); + // channel.addPeerListener('type-1', () => {}); + // channel.addPeerListener('type-2', () => {}); + // channel.addPeerListener('type-2', () => {}); + // expect(channel._listeners['type-1']).toHaveLength(1); + // expect(channel._listeners['type-2']).toHaveLength(2); }); + // todo _handleEvent is private; rewrite test it('should call event listeners on event', () => { - const received = []; - channel.addPeerListener('type-1', n => received.push(n)); - channel._handleEvent({ type: 'type-1', args: [11] }); - channel._handleEvent({ type: 'type-1', args: [12] }); - expect(received).toEqual([11, 12]); + expect(true).toBeFalsy(); + // const received = []; + // channel.addPeerListener('type-1', n => received.push(n)); + // channel._handleEvent({ type: 'type-1', args: [11] }); + // channel._handleEvent({ type: 'type-1', args: [12] }); + // expect(received).toEqual([11, 12]); }); }); + // todo _listeners is private; rewrite test describe('method:prependListener', () => { it('should add event listeners', () => { - channel.prependListener('type-1', 11); - channel.prependListener('type-2', 21); - channel.prependListener('type-2', 22); - const expected = { - 'type-1': [11], - 'type-2': [22, 21], - }; - expect(channel._listeners).toEqual(expected); + expect(true).toBeFalsy(); + // channel.prependListener('type-1', 11); + // channel.prependListener('type-2', 21); + // channel.prependListener('type-2', 22); + // const expected = { + // 'type-1': [11], + // 'type-2': [22, 21], + // }; + // expect(channel._listeners).toEqual(expected); }); }); describe('method:prependOnceListener', () => { + // todo _listeners is private; rewrite test it('should add event listeners', () => { - channel.prependOnceListener('type-1', 11); - channel.prependOnceListener('type-2', 21); - channel.prependOnceListener('type-2', 22); - expect(channel._listeners['type-1']).toHaveLength(1); - expect(channel._listeners['type-2']).toHaveLength(2); + expect(true).toBeFalsy(); + // channel.prependOnceListener('type-1', 11); + // channel.prependOnceListener('type-2', 21); + // channel.prependOnceListener('type-2', 22); + // expect(channel._listeners['type-1']).toHaveLength(1); + // expect(channel._listeners['type-2']).toHaveLength(2); }); + // todo _handleEvent is private; rewrite test it('should call event listeners only once', () => { - const received = []; - channel.prependOnceListener('type-1', n => received.push(n)); - channel._handleEvent({ type: 'type-1', args: [11] }); - channel._handleEvent({ type: 'type-1', args: [12] }); - expect(received).toEqual([11]); + expect(true).toBeFalsy(); + // const received = []; + // channel.prependOnceListener('type-1', n => received.push(n)); + // channel._handleEvent({ type: 'type-1', args: [11] }); + // channel._handleEvent({ type: 'type-1', args: [12] }); + // expect(received).toEqual([11]); }); }); + // todo _listeners is private; rewrite test describe('method:removeAllListeners', () => { it('should remove all listeners', () => { - channel.on('type-1', 11); - channel.on('type-2', 21); - channel.on('type-2', 22); - channel.removeAllListeners(); - expect(channel._listeners).toEqual({}); + expect(true).toBeFalsy(); + // channel.on('type-1', 11); + // channel.on('type-2', 21); + // channel.on('type-2', 22); + // channel.removeAllListeners(); + // expect(channel._listeners).toEqual({}); }); it('should remove all listeners for a type', () => { - channel.on('type-1', 11); - channel.on('type-2', 21); - channel.on('type-2', 22); - channel.removeAllListeners('type-2'); - expect(channel._listeners).toEqual({ 'type-1': [11] }); + expect(true).toBeFalsy(); + // channel.on('type-1', 11); + // channel.on('type-2', 21); + // channel.on('type-2', 22); + // channel.removeAllListeners('type-2'); + // expect(channel._listeners).toEqual({ 'type-1': [11] }); }); }); + // todo _listeners is private; rewrite test describe('method:removeListener', () => { it('should remove all listeners', () => { - channel.on('type-1', 11); - channel.on('type-2', 21); - channel.on('type-2', 22); - const expected = { - 'type-1': [11], - 'type-2': [21], - }; - channel.removeListener('type-2', 22); - expect(channel._listeners).toEqual(expected); + expect(true).toBeFalsy(); + // channel.on('type-1', 11); + // channel.on('type-2', 21); + // channel.on('type-2', 22); + // const expected = { + // 'type-1': [11], + // 'type-2': [21], + // }; + // channel.removeListener('type-2', 22); + // expect(channel._listeners).toEqual(expected); }); }); describe('_miscellaneous', () => { + // todo _handleEvent is private; rewrite test it('should ignore if event came from own sender', () => { - const received = []; - channel.on('type-1', n => received.push(n)); - channel._handleEvent({ type: 'type-1', args: [11] }); - channel._handleEvent({ type: 'type-1', args: [12], from: channel._sender }); - expect(received).toEqual([11]); + expect(true).toBeFalsy(); + // const received = []; + // channel.on('type-1', n => received.push(n)); + // channel._handleEvent({ type: 'type-1', args: [11] }); + // channel._handleEvent({ type: 'type-1', args: [12], from: channel._sender }); + // expect(received).toEqual([11]); }); + // todo _handleEvent is private; rewrite test it('should not ignore peer event', () => { - const received = []; - channel.on('type-1', n => received.push(n)); - channel._handleEvent({ type: 'type-1', args: [11] }); - channel._handleEvent({ type: 'type-1', args: [12] }, true); - expect(received).toEqual([11, 12]); + expect(true).toBeFalsy(); + // const received = []; + // channel.on('type-1', n => received.push(n)); + // channel._handleEvent({ type: 'type-1', args: [11] }); + // channel._handleEvent({ type: 'type-1', args: [12] }, true); + // expect(received).toEqual([11, 12]); }); + // todo _handleEvent is private; rewrite test it('should ignore if event handled by addPeerListener', () => { - const received = []; - channel.addPeerListener('type-1', n => received.push(n)); - channel._handleEvent({ type: 'type-1', args: [11], from: channel._sender }); - channel._handleEvent({ type: 'type-1', args: [12], from: '_' }); - channel._handleEvent({ type: 'type-1', args: [13] }, true); - expect(received).toEqual([12]); + expect(true).toBeFalsy(); + // const received = []; + // channel.addPeerListener('type-1', n => received.push(n)); + // channel._handleEvent({ type: 'type-1', args: [11], from: channel._sender }); + // channel._handleEvent({ type: 'type-1', args: [12], from: '_' }); + // channel._handleEvent({ type: 'type-1', args: [13] }, true); + // expect(received).toEqual([12]); }); }); }); diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index cd7a184e4a75..776c08da903f 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -119,6 +119,10 @@ export class Channel { } } + hasTransport() { + return !!this._transport; + } + private _handleEvent(event: ChannelEvent, isPeer = false) { const listeners = this._listeners[event.type]; if (listeners && (isPeer || event.from !== this._sender)) { From 4008a90b7eafc536dc4bd255450ce9492b88f6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Sat, 15 Dec 2018 19:35:19 +0100 Subject: [PATCH 06/26] Removed tests in order to write new ones that actually test the usage of this class --- lib/channels/src/index.test.ts | 175 --------------------------------- 1 file changed, 175 deletions(-) diff --git a/lib/channels/src/index.test.ts b/lib/channels/src/index.test.ts index 67f8a3f097f3..201e5700a0bb 100644 --- a/lib/channels/src/index.test.ts +++ b/lib/channels/src/index.test.ts @@ -114,180 +114,5 @@ describe('Channel', () => { const fn1 = jest.fn(); const fn2 = jest.fn(); const fn3 = jest.fn(); - - // todo kinda duplicated? See method:listeners => should return an array of listeners - // todo _listeners is a private member now - it('should add event listeners', () => { - expect(true).toBeFalsy(); - // channel.on('type-1', fn1); - // channel.on('type-2', fn2); - // channel.on('type-2', fn3); - // const expected = { - // 'type-1': [11], - // 'type-2': [21, 22], - // }; - // expect(channel._listeners).toEqual(expected); - }); - - // todo _handleEvent is private; rewrite test - it('should call event listeners on event', () => { - expect(true).toBeFalsy(); - // const received: Listener[] = []; - // channel.on('type-1', n => received.push(n)); - // channel._handleEvent({ type: 'type-1', args: [11] }); - // channel._handleEvent({ type: 'type-1', args: [12] }); - // expect(received).toEqual([11, 12]); - }); - }); - - // todo _listeners is private; rewrite test - describe('method:once', () => { - it('should add event listeners', () => { - expect(true).toBeFalsy(); - // channel.once('type-1', 11); - // channel.once('type-2', 21); - // channel.once('type-2', 22); - // expect(channel._listeners['type-1']).toHaveLength(1); - // expect(channel._listeners['type-2']).toHaveLength(2); - }); - - // todo _handleEvent is private; rewrite test - it('should call event listeners only once', () => { - expect(true).toBeFalsy(); - // const received = []; - // channel.once('type-1', n => received.push(n)); - // channel._handleEvent({ type: 'type-1', args: [11] }); - // channel._handleEvent({ type: 'type-1', args: [12] }); - // expect(received).toEqual([11]); - }); - }); - - // todo _listeners is private; rewrite test - describe('method:addPeerListener', () => { - it('should add event listeners', () => { - expect(true).toBeFalsy(); - // channel.addPeerListener('type-1', () => {}); - // channel.addPeerListener('type-2', () => {}); - // channel.addPeerListener('type-2', () => {}); - // expect(channel._listeners['type-1']).toHaveLength(1); - // expect(channel._listeners['type-2']).toHaveLength(2); - }); - - // todo _handleEvent is private; rewrite test - it('should call event listeners on event', () => { - expect(true).toBeFalsy(); - // const received = []; - // channel.addPeerListener('type-1', n => received.push(n)); - // channel._handleEvent({ type: 'type-1', args: [11] }); - // channel._handleEvent({ type: 'type-1', args: [12] }); - // expect(received).toEqual([11, 12]); - }); - }); - - // todo _listeners is private; rewrite test - describe('method:prependListener', () => { - it('should add event listeners', () => { - expect(true).toBeFalsy(); - // channel.prependListener('type-1', 11); - // channel.prependListener('type-2', 21); - // channel.prependListener('type-2', 22); - // const expected = { - // 'type-1': [11], - // 'type-2': [22, 21], - // }; - // expect(channel._listeners).toEqual(expected); - }); - }); - - describe('method:prependOnceListener', () => { - // todo _listeners is private; rewrite test - it('should add event listeners', () => { - expect(true).toBeFalsy(); - // channel.prependOnceListener('type-1', 11); - // channel.prependOnceListener('type-2', 21); - // channel.prependOnceListener('type-2', 22); - // expect(channel._listeners['type-1']).toHaveLength(1); - // expect(channel._listeners['type-2']).toHaveLength(2); - }); - - // todo _handleEvent is private; rewrite test - it('should call event listeners only once', () => { - expect(true).toBeFalsy(); - // const received = []; - // channel.prependOnceListener('type-1', n => received.push(n)); - // channel._handleEvent({ type: 'type-1', args: [11] }); - // channel._handleEvent({ type: 'type-1', args: [12] }); - // expect(received).toEqual([11]); - }); - }); - - // todo _listeners is private; rewrite test - describe('method:removeAllListeners', () => { - it('should remove all listeners', () => { - expect(true).toBeFalsy(); - // channel.on('type-1', 11); - // channel.on('type-2', 21); - // channel.on('type-2', 22); - // channel.removeAllListeners(); - // expect(channel._listeners).toEqual({}); - }); - - it('should remove all listeners for a type', () => { - expect(true).toBeFalsy(); - // channel.on('type-1', 11); - // channel.on('type-2', 21); - // channel.on('type-2', 22); - // channel.removeAllListeners('type-2'); - // expect(channel._listeners).toEqual({ 'type-1': [11] }); - }); - }); - - // todo _listeners is private; rewrite test - describe('method:removeListener', () => { - it('should remove all listeners', () => { - expect(true).toBeFalsy(); - // channel.on('type-1', 11); - // channel.on('type-2', 21); - // channel.on('type-2', 22); - // const expected = { - // 'type-1': [11], - // 'type-2': [21], - // }; - // channel.removeListener('type-2', 22); - // expect(channel._listeners).toEqual(expected); - }); - }); - - describe('_miscellaneous', () => { - // todo _handleEvent is private; rewrite test - it('should ignore if event came from own sender', () => { - expect(true).toBeFalsy(); - // const received = []; - // channel.on('type-1', n => received.push(n)); - // channel._handleEvent({ type: 'type-1', args: [11] }); - // channel._handleEvent({ type: 'type-1', args: [12], from: channel._sender }); - // expect(received).toEqual([11]); - }); - - // todo _handleEvent is private; rewrite test - it('should not ignore peer event', () => { - expect(true).toBeFalsy(); - // const received = []; - // channel.on('type-1', n => received.push(n)); - // channel._handleEvent({ type: 'type-1', args: [11] }); - // channel._handleEvent({ type: 'type-1', args: [12] }, true); - // expect(received).toEqual([11, 12]); - }); - - // todo _handleEvent is private; rewrite test - it('should ignore if event handled by addPeerListener', () => { - expect(true).toBeFalsy(); - // const received = []; - // channel.addPeerListener('type-1', n => received.push(n)); - // channel._handleEvent({ type: 'type-1', args: [11], from: channel._sender }); - // channel._handleEvent({ type: 'type-1', args: [12], from: '_' }); - // channel._handleEvent({ type: 'type-1', args: [13] }, true); - // expect(received).toEqual([12]); - }); }); }); From ec73e52217a423d429ea0b7df86355876c516fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Sat, 15 Dec 2018 21:04:42 +0100 Subject: [PATCH 07/26] Working on tests and some smaller refactorings --- lib/channels/src/index.test.ts | 203 ++++++++++++++++++++------------- lib/channels/src/index.ts | 95 +++++++-------- 2 files changed, 172 insertions(+), 126 deletions(-) diff --git a/lib/channels/src/index.test.ts b/lib/channels/src/index.test.ts index 201e5700a0bb..4ac002710eeb 100644 --- a/lib/channels/src/index.test.ts +++ b/lib/channels/src/index.test.ts @@ -17,102 +17,143 @@ describe('Channel', () => { expect(transport.setHandler).toHaveBeenCalled(); }); - it('should not try to set handler if handler is missing', () => { + it('should not set transport if not passed as an argument', () => { channel = new Channel(); - expect(channel.hasTransport()).not.toBeFalsy(); + expect(channel.hasTransport).toBeFalsy(); }); - }); - - // todo before, addListener was called with numbers; is this still the correct test? - describe('method:addListener', () => { - it('should call channel.on with args', () => { - const testFn = jest.fn(); - channel.on = jest.fn(); - channel.addListener('A', testFn); - expect(channel.on).toHaveBeenCalled(); - expect(channel.on).toHaveBeenCalledWith('A', testFn); - }); - }); - describe('method:emit', () => { - it('should call transport.send', () => { - transport.send = jest.fn(); - const type = 'test-type'; - const args = [1, 2, 3]; - const expected = { type, args }; - - channel.emit(type, ...args); - expect(transport.send).toHaveBeenCalled(); - - const event: ChannelEvent = transport.send.mock.calls[0][0]; - expect(typeof event.from).toEqual('string'); - - delete event.from; - expect(event).toEqual(expected); + it('should set transport if passed as an argument', () => { + channel = new Channel({ transport }); + expect(channel.hasTransport).toBeTruthy(); }); - it('should be type safe', () => { - transport.send = jest.fn(); - const type = 'test-type'; - const args = [1, 2, 3]; - const expected = { type, args }; - - // todo check if generic argument typing works - expect(true).toBe(false); + it('should set isAsync to false as default value', () => { + channel = new Channel(); + expect(channel.isAsync).toBeFalsy(); }); - it('should call handle async option', () => { - transport.send = jest.fn(); - const type = 'test-type'; - const args = [1, 2, 3]; - - channel = new Channel({ async: true, transport }); - - channel.emit(type, ...args); - expect(transport.send).not.toHaveBeenCalled(); - - jest.runAllImmediates(); - expect(transport.send).toHaveBeenCalled(); + it('should set isAsync to true if passed as an argument', () => { + channel = new Channel({ async: true }); + expect(channel.isAsync).toBeTruthy(); }); }); - describe('method:eventNames', () => { - it('should return an array of strings', () => { - channel.on('type-1', jest.fn()); - channel.on('type-2', jest.fn()); - channel.on('type-2', jest.fn()); - const expected = ['type-1', 'type-2']; - expect(channel.eventNames()).toEqual(expected); - }); - }); + describe('method:addListener', () => { + it('should create one listener', () => { + const keyValue = 'stringAsKey'; - describe('method:listenerCount', () => { - it('should return the correct count', () => { - channel.on('type-1', jest.fn()); - channel.on('type-2', jest.fn()); - channel.on('type-2', jest.fn()); - expect(channel.listenerCount('type-1')).toEqual(1); - expect(channel.listenerCount('type-2')).toEqual(2); + channel.addListener(keyValue, jest.fn()); + expect(channel.listeners(keyValue).length).toBe(1); }); }); - describe('method:listeners', () => { - const fn1 = jest.fn(); - const fn2 = jest.fn(); - const fn3 = jest.fn(); - - it('should return an array of listeners', () => { - channel.on('type-1', fn1); - channel.on('type-2', fn2); - channel.on('type-2', fn3); - expect(channel.listeners('type-1')).toEqual([fn1]); - expect(channel.listeners('type-2')).toEqual([fn2, fn3]); + describe('method:emit', () => { + // todo check if [] or string is returned + it('should emit the added listener', () => { + const keyValue = 'stringAsKey'; + const mockListener: Listener = (data: string) => { + return data; + }; + const mockReturnValue = ['string1', 'string2', 'string3']; + + channel.addListener(keyValue, mockListener); + channel.emit(keyValue, ...mockReturnValue); + expect(mockListener).toReturnWith(mockReturnValue); }); }); - describe('method:on', () => { - const fn1 = jest.fn(); - const fn2 = jest.fn(); - const fn3 = jest.fn(); - }); + describe('method:addPeerListener', () => {}); + + // todo before, addListener was called with numbers; is this still the correct test? + // describe('method:addListener', () => { + // it('should call channel.on with args', () => { + // const testFn = jest.fn(); + // channel.on = jest.fn(); + // channel.addListener('A', testFn); + // expect(channel.on).toHaveBeenCalled(); + // expect(channel.on).toHaveBeenCalledWith('A', testFn); + // }); + // }); + // + // describe('method:emit', () => { + // it('should call transport.send', () => { + // transport.send = jest.fn(); + // const type = 'test-type'; + // const args = [1, 2, 3]; + // const expected = { type, args }; + // + // channel.emit(type, ...args); + // expect(transport.send).toHaveBeenCalled(); + // + // const event: ChannelEvent = transport.send.mock.calls[0][0]; + // expect(typeof event.from).toEqual('string'); + // + // delete event.from; + // expect(event).toEqual(expected); + // }); + // + // it('should be type safe', () => { + // transport.send = jest.fn(); + // const type = 'test-type'; + // const args = [1, 2, 3]; + // const expected = { type, args }; + // + // // todo check if generic argument typing works + // expect(true).toBe(false); + // }); + // + // it('should call handle async option', () => { + // transport.send = jest.fn(); + // const type = 'test-type'; + // const args = [1, 2, 3]; + // + // channel = new Channel({ async: true, transport }); + // + // channel.emit(type, ...args); + // expect(transport.send).not.toHaveBeenCalled(); + // + // jest.runAllImmediates(); + // expect(transport.send).toHaveBeenCalled(); + // }); + // }); + // + // describe('method:eventNames', () => { + // it('should return an array of strings', () => { + // channel.on('type-1', jest.fn()); + // channel.on('type-2', jest.fn()); + // channel.on('type-2', jest.fn()); + // const expected = ['type-1', 'type-2']; + // expect(channel.eventNames()).toEqual(expected); + // }); + // }); + // + // describe('method:listenerCount', () => { + // it('should return the correct count', () => { + // channel.on('type-1', jest.fn()); + // channel.on('type-2', jest.fn()); + // channel.on('type-2', jest.fn()); + // expect(channel.listenerCount('type-1')).toEqual(1); + // expect(channel.listenerCount('type-2')).toEqual(2); + // }); + // }); + // + // describe('method:listeners', () => { + // const fn1 = jest.fn(); + // const fn2 = jest.fn(); + // const fn3 = jest.fn(); + // + // it('should return an array of listeners', () => { + // channel.on('type-1', fn1); + // channel.on('type-2', fn2); + // channel.on('type-2', fn3); + // expect(channel.listeners('type-1')).toEqual([fn1]); + // expect(channel.listeners('type-2')).toEqual([fn2, fn3]); + // }); + // }); + // + // describe('method:on', () => { + // const fn1 = jest.fn(); + // const fn2 = jest.fn(); + // const fn3 = jest.fn(); + // }); }); diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index 776c08da903f..3af951b35398 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -4,7 +4,7 @@ export interface ChannelTransport { } export interface ChannelEvent { - type: string; + type: string; // todo deprecate in favor of prop name eventName? type totally confused me after I saw eventNames() from: string; args: TEventArgs[]; } @@ -14,7 +14,7 @@ export interface Listener { ignorePeer?: boolean; } -interface ListenersKeyValue { +interface EventsKeyValue { [key: string]: Listener[]; } @@ -31,31 +31,37 @@ const generateRandomId = () => { }; export class Channel { + readonly isAsync: boolean; + private _sender = generateRandomId(); - private _listeners: ListenersKeyValue = {}; - private readonly _async: boolean = false; + private _events: EventsKeyValue = {}; private readonly _transport: ChannelTransport; - constructor({ transport, async }: ChannelArgs = {}) { - this._async = async; + constructor({ transport, async = false }: ChannelArgs = {}) { + this.isAsync = async; if (transport) { this._transport = transport; this._transport.setHandler(event => this._handleEvent(event)); } } - addListener(type: string, listener: Listener) { - this.on(type, listener); + get hasTransport() { + return !!this._transport; + } + + addListener(eventName: string, listener: Listener) { + this._events[eventName] = this._events[eventName] || []; + this._events[eventName].push(listener); } - addPeerListener(type: string, listener: Listener) { + addPeerListener(eventName: string, listener: Listener) { const peerListener = listener; peerListener.ignorePeer = true; - this.on(type, peerListener); + this.addListener(eventName, peerListener); } - emit(type: string, ...args: TEventArgs[]) { - const event = { type, args, from: this._sender }; + emit(eventName: string, ...args: TEventArgs[]) { + const event = { type: eventName, args, from: this._sender }; const handler = () => { if (this._transport) { @@ -64,7 +70,7 @@ export class Channel { this._handleEvent(event, true); }; - if (this._async) { + if (this.isAsync) { setImmediate(handler); } else { handler(); @@ -72,67 +78,66 @@ export class Channel { } eventNames() { - return Object.keys(this._listeners); + return Object.keys(this._events); } - listenerCount(type: string) { - const listeners = this._listeners[type]; + listenerCount(eventName: string) { + const listeners = this.listeners(eventName); return listeners ? listeners.length : 0; } - listeners(type: string) { - return this._listeners[type]; + listeners(eventName: string): Listener[] | undefined { + const listeners = this._events[eventName]; + return listeners ? listeners : undefined; } - on(type: string, listener: Listener) { - this._listeners[type] = this._listeners[type] || []; - this._listeners[type].push(listener); + once(eventName: string, listener: Listener) { + const onceListener = this._onceListener(eventName, listener); + this.addListener(eventName, onceListener); } - once(type: string, listener: Listener) { - const onceListener = this._onceListener(type, listener); - this.on(type, onceListener); + prependListener(eventName: string, listener: Listener) { + this._events[eventName] = this._events[eventName] || []; + this._events[eventName].unshift(listener); } - prependListener(type: string, listener: Listener) { - this._listeners[type] = this._listeners[type] || []; - this._listeners[type].unshift(listener); + prependOnceListener(eventName: string, listener: Listener) { + const onceListener = this._onceListener(eventName, listener); + this.prependListener(eventName, onceListener); } - prependOnceListener(type: string, listener: Listener) { - const onceListener = this._onceListener(type, listener); - this.prependListener(type, onceListener); - } - - removeAllListeners(type: string) { - if (!type) { - this._listeners = {}; - } else if (this._listeners[type]) { - delete this._listeners[type]; + removeAllListeners(eventName: string) { + if (!eventName) { + this._events = {}; + } else if (this._events[eventName]) { + delete this._events[eventName]; } } - removeListener(type: string, listener: Listener) { - const listeners = this._listeners[type]; + removeListener(eventName: string, listener: Listener) { + const listeners = this._events[eventName]; if (listeners) { - this._listeners[type] = listeners.filter(l => l !== listener); + this._events[eventName] = listeners.filter(l => l !== listener); } } - hasTransport() { - return !!this._transport; + /** + * @deprecated use addListener + */ + on(eventName: string, listener: Listener) { + this.addListener(eventName, listener); } private _handleEvent(event: ChannelEvent, isPeer = false) { - const listeners = this._listeners[event.type]; + const listeners = this._events[event.type]; if (listeners && (isPeer || event.from !== this._sender)) { listeners.forEach(fn => !(isPeer && fn.ignorePeer) && fn(...event.args)); } } - private _onceListener(type: string, listener: Listener) { + private _onceListener(eventName: string, listener: Listener) { const onceListener = (...args: any[]) => { - this.removeListener(type, onceListener); + this.removeListener(eventName, onceListener); return listener(...args); }; return onceListener; From 22c2139dd933b2c20f0f52a1d36e04ff89a25127 Mon Sep 17 00:00:00 2001 From: igor-dv Date: Sun, 16 Dec 2018 12:12:26 +0200 Subject: [PATCH 08/26] Support tests in TS --- examples/angular-cli/jest.config.js | 4 +- jest.config.js | 10 +- lib/channels/src/index.test.ts | 182 ++++++++++++++-------------- package.json | 1 + yarn.lock | 50 +++++--- 5 files changed, 136 insertions(+), 111 deletions(-) diff --git a/examples/angular-cli/jest.config.js b/examples/angular-cli/jest.config.js index 41856c987271..faadcb13f9a2 100644 --- a/examples/angular-cli/jest.config.js +++ b/examples/angular-cli/jest.config.js @@ -7,9 +7,9 @@ module.exports = { }, roots: [__dirname], transform: { - ...config.transform, + '^.+\\.jsx?$': '/scripts/babel-jest.js', '^.+[/\\\\].storybook[/\\\\]config\\.ts$': '/scripts/jest-ts-babel.js', '^.+\\.(ts|html)$': '/node_modules/jest-preset-angular/preprocessor.js', }, - moduleFileExtensions: [...config.moduleFileExtensions, 'ts', 'tsx', 'html'], + moduleFileExtensions: [...config.moduleFileExtensions, 'html'], }; diff --git a/jest.config.js b/jest.config.js index 0896d5a284e7..0c62ff283c01 100644 --- a/jest.config.js +++ b/jest.config.js @@ -26,13 +26,15 @@ module.exports = { snapshotSerializers: ['@emotion/snapshot-serializer'], transform: { '^.+\\.jsx?$': '/scripts/babel-jest.js', + '^.+\\.tsx?$': '/node_modules/ts-jest', }, + testMatch: ['**/__tests__/**/*.(j|t)s?(x)', '**/?(*.)+(spec|test).(j|t)s?(x)'], testPathIgnorePatterns: ['/node_modules/', '/dist/', 'addon-jest.test.js', '/cli/test/'], collectCoverage: false, collectCoverageFrom: [ - 'app/**/*.{js,jsx}', - 'lib/**/*.{js,jsx}', - 'addons/**/*.{js,jsx}', + 'app/**/*.{js,jsx,ts,tsx}', + 'lib/**/*.{js,jsx,ts,tsx}', + 'addons/**/*.{js,jsx,ts,tsx}', '!**/cli/test/**', '!**/dist/**', '!**/generators/**', @@ -44,5 +46,5 @@ module.exports = { setupFiles: ['raf/polyfill'], testURL: 'http://localhost', modulePathIgnorePatterns: ['/dist/.*/__mocks__/'], - moduleFileExtensions: ['js', 'jsx', 'json', 'node'], + moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'], }; diff --git a/lib/channels/src/index.test.ts b/lib/channels/src/index.test.ts index 4ac002710eeb..937f7c89849d 100644 --- a/lib/channels/src/index.test.ts +++ b/lib/channels/src/index.test.ts @@ -65,95 +65,95 @@ describe('Channel', () => { describe('method:addPeerListener', () => {}); // todo before, addListener was called with numbers; is this still the correct test? - // describe('method:addListener', () => { - // it('should call channel.on with args', () => { - // const testFn = jest.fn(); - // channel.on = jest.fn(); - // channel.addListener('A', testFn); - // expect(channel.on).toHaveBeenCalled(); - // expect(channel.on).toHaveBeenCalledWith('A', testFn); - // }); - // }); - // - // describe('method:emit', () => { - // it('should call transport.send', () => { - // transport.send = jest.fn(); - // const type = 'test-type'; - // const args = [1, 2, 3]; - // const expected = { type, args }; - // - // channel.emit(type, ...args); - // expect(transport.send).toHaveBeenCalled(); - // - // const event: ChannelEvent = transport.send.mock.calls[0][0]; - // expect(typeof event.from).toEqual('string'); - // - // delete event.from; - // expect(event).toEqual(expected); - // }); - // - // it('should be type safe', () => { - // transport.send = jest.fn(); - // const type = 'test-type'; - // const args = [1, 2, 3]; - // const expected = { type, args }; - // - // // todo check if generic argument typing works - // expect(true).toBe(false); - // }); - // - // it('should call handle async option', () => { - // transport.send = jest.fn(); - // const type = 'test-type'; - // const args = [1, 2, 3]; - // - // channel = new Channel({ async: true, transport }); - // - // channel.emit(type, ...args); - // expect(transport.send).not.toHaveBeenCalled(); - // - // jest.runAllImmediates(); - // expect(transport.send).toHaveBeenCalled(); - // }); - // }); - // - // describe('method:eventNames', () => { - // it('should return an array of strings', () => { - // channel.on('type-1', jest.fn()); - // channel.on('type-2', jest.fn()); - // channel.on('type-2', jest.fn()); - // const expected = ['type-1', 'type-2']; - // expect(channel.eventNames()).toEqual(expected); - // }); - // }); - // - // describe('method:listenerCount', () => { - // it('should return the correct count', () => { - // channel.on('type-1', jest.fn()); - // channel.on('type-2', jest.fn()); - // channel.on('type-2', jest.fn()); - // expect(channel.listenerCount('type-1')).toEqual(1); - // expect(channel.listenerCount('type-2')).toEqual(2); - // }); - // }); - // - // describe('method:listeners', () => { - // const fn1 = jest.fn(); - // const fn2 = jest.fn(); - // const fn3 = jest.fn(); - // - // it('should return an array of listeners', () => { - // channel.on('type-1', fn1); - // channel.on('type-2', fn2); - // channel.on('type-2', fn3); - // expect(channel.listeners('type-1')).toEqual([fn1]); - // expect(channel.listeners('type-2')).toEqual([fn2, fn3]); - // }); - // }); - // - // describe('method:on', () => { - // const fn1 = jest.fn(); - // const fn2 = jest.fn(); - // const fn3 = jest.fn(); - // }); + describe('method:addListener', () => { + it('should call channel.on with args', () => { + const testFn = jest.fn(); + channel.on = jest.fn(); + channel.addListener('A', testFn); + expect(channel.on).toHaveBeenCalled(); + expect(channel.on).toHaveBeenCalledWith('A', testFn); + }); + }); + + describe('method:emit', () => { + it('should call transport.send', () => { + transport.send = jest.fn(); + const type = 'test-type'; + const args = [1, 2, 3]; + const expected = { type, args }; + + channel.emit(type, ...args); + expect(transport.send).toHaveBeenCalled(); + + const event: ChannelEvent = transport.send.mock.calls[0][0]; + expect(typeof event.from).toEqual('string'); + + delete event.from; + expect(event).toEqual(expected); + }); + + it('should be type safe', () => { + transport.send = jest.fn(); + const type = 'test-type'; + const args = [1, 2, 3]; + const expected = { type, args }; + + // todo check if generic argument typing works + expect(true).toBe(false); + }); + + it('should call handle async option', () => { + transport.send = jest.fn(); + const type = 'test-type'; + const args = [1, 2, 3]; + + channel = new Channel({ async: true, transport }); + + channel.emit(type, ...args); + expect(transport.send).not.toHaveBeenCalled(); + + jest.runAllImmediates(); + expect(transport.send).toHaveBeenCalled(); + }); + }); + + describe('method:eventNames', () => { + it('should return an array of strings', () => { + channel.on('type-1', jest.fn()); + channel.on('type-2', jest.fn()); + channel.on('type-2', jest.fn()); + const expected = ['type-1', 'type-2']; + expect(channel.eventNames()).toEqual(expected); + }); + }); + + describe('method:listenerCount', () => { + it('should return the correct count', () => { + channel.on('type-1', jest.fn()); + channel.on('type-2', jest.fn()); + channel.on('type-2', jest.fn()); + expect(channel.listenerCount('type-1')).toEqual(1); + expect(channel.listenerCount('type-2')).toEqual(2); + }); + }); + + describe('method:listeners', () => { + const fn1 = jest.fn(); + const fn2 = jest.fn(); + const fn3 = jest.fn(); + + it('should return an array of listeners', () => { + channel.on('type-1', fn1); + channel.on('type-2', fn2); + channel.on('type-2', fn3); + expect(channel.listeners('type-1')).toEqual([fn1]); + expect(channel.listeners('type-2')).toEqual([fn2, fn3]); + }); + }); + + describe('method:on', () => { + const fn1 = jest.fn(); + const fn2 = jest.fn(); + const fn3 = jest.fn(); + }); }); diff --git a/package.json b/package.json index d96f08d3c7a4..1f73b59fc30b 100644 --- a/package.json +++ b/package.json @@ -122,6 +122,7 @@ "riot-jest-transformer": "^1.0.10", "shelljs": "^0.8.2", "svelte-jest": "^0.2.0", + "ts-jest": "^23.10.5", "tslint": "~5.11.0", "tslint-config-prettier": "^1.15.0", "tslint-plugin-prettier": "^2.0.1", diff --git a/yarn.lock b/yarn.lock index 022492924314..0349d52c8150 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5809,6 +5809,13 @@ browserstack@^1.5.1: dependencies: https-proxy-agent "^2.2.1" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -5844,7 +5851,7 @@ buffer-fill@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= -buffer-from@^1.0.0, buffer-from@^1.1.0: +buffer-from@1.x, buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -9797,7 +9804,7 @@ fast-glob@^2.0.2: merge2 "^1.2.3" micromatch "^3.1.10" -fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= @@ -13415,6 +13422,13 @@ json3@^3.3.2: resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= +json5@2.x, json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== + dependencies: + minimist "^1.2.0" + json5@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" @@ -13432,13 +13446,6 @@ json5@^1.0.0, json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ== - dependencies: - minimist "^1.2.0" - jsonc-parser@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.2.tgz#42fcf56d70852a043fadafde51ddb4a85649978d" @@ -14844,7 +14851,7 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" -make-error@^1.1.1, make-error@^1.3.5: +make-error@1.x, make-error@^1.1.1, make-error@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== @@ -15569,7 +15576,7 @@ mixin-object@^2.0.1: for-in "^0.1.3" is-extendable "^0.1.1" -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -19857,7 +19864,7 @@ resolve@1.1.7, resolve@1.1.x: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@1.8.1, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.8.1: +resolve@1.8.1, resolve@1.x, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.6.0, resolve@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== @@ -20345,7 +20352,7 @@ semver-intersect@1.4.0: dependencies: semver "^5.0.0" -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@5.x, semver@^5.0.0, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@5.x, semver@^5.0.0, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== @@ -22161,6 +22168,21 @@ tryer@^1.0.0: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== +ts-jest@^23.10.5: + version "23.10.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-23.10.5.tgz#cdb550df4466a30489bf70ba867615799f388dd5" + integrity sha512-MRCs9qnGoyKgFc8adDEntAOP64fWK1vZKnOYU1o2HxaqjdJvGqmkLCPCnVq1/If4zkUmEjKPnCiUisTrlX2p2A== + dependencies: + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + json5 "2.x" + make-error "1.x" + mkdirp "0.x" + resolve "1.x" + semver "^5.5" + yargs-parser "10.x" + ts-jest@~23.1.3: version "23.1.4" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-23.1.4.tgz#66ac1d8d3fbf8f9a98432b11aa377aa850664b2b" @@ -23974,7 +23996,7 @@ yam@^0.0.24: fs-extra "^4.0.2" lodash.merge "^4.6.0" -yargs-parser@^10.1.0: +yargs-parser@10.x, yargs-parser@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== From f67bf03cd25f22ce06841bcfbb58cda3027a33ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Sun, 16 Dec 2018 15:33:20 +0100 Subject: [PATCH 09/26] Big refactoring + testing --- lib/channels/src/index.test.ts | 229 ++++++++++++++++++++++----------- lib/channels/src/index.ts | 36 +++--- 2 files changed, 170 insertions(+), 95 deletions(-) diff --git a/lib/channels/src/index.test.ts b/lib/channels/src/index.test.ts index 937f7c89849d..41288138f23c 100644 --- a/lib/channels/src/index.test.ts +++ b/lib/channels/src/index.test.ts @@ -40,120 +40,193 @@ describe('Channel', () => { describe('method:addListener', () => { it('should create one listener', () => { - const keyValue = 'stringAsKey'; + const eventName = 'event1'; - channel.addListener(keyValue, jest.fn()); - expect(channel.listeners(keyValue).length).toBe(1); + 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.addListener(eventName, jest.fn()); + expect(channel.listeners(eventName).length).toBe(1); }); }); describe('method:emit', () => { - // todo check if [] or string is returned - it('should emit the added listener', () => { - const keyValue = 'stringAsKey'; - const mockListener: Listener = (data: string) => { - return data; + 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; }; - const mockReturnValue = ['string1', 'string2', 'string3']; - channel.addListener(keyValue, mockListener); - channel.emit(keyValue, ...mockReturnValue); - expect(mockListener).toReturnWith(mockReturnValue); + channel.addListener(eventName, mockListener); + channel.emit(eventName, listenerInputData); + expect(listenerOutputData).toBe(listenerInputData); }); - }); - describe('method:addPeerListener', () => {}); + it('should be callable with a spread operator as event arguments', () => { + const eventName = 'event1'; + const listenerInputData = ['string1', 'string2', 'string3']; + let listenerOutputData: string[] = null; - // todo before, addListener was called with numbers; is this still the correct test? - describe('method:addListener', () => { - it('should call channel.on with args', () => { - const testFn = jest.fn(); - channel.on = jest.fn(); - channel.addListener('A', testFn); - expect(channel.on).toHaveBeenCalled(); - expect(channel.on).toHaveBeenCalledWith('A', testFn); + channel.addListener(eventName, (...data) => { + listenerOutputData = data; + }); + channel.emit(eventName, ...listenerInputData); + expect(listenerOutputData).toEqual(listenerInputData); + }); + + it('should use setImmediate if async is true', () => { + channel = new Channel({ async: true, transport }); + channel.addListener('event1', jest.fn()); }); }); - describe('method:emit', () => { - it('should call transport.send', () => { - transport.send = jest.fn(); - const type = 'test-type'; - const args = [1, 2, 3]; - const expected = { type, args }; + describe('method:addPeerListener', () => { + it('should add a listener and set ignorePeer to true', () => { + const eventName = 'event1'; - channel.emit(type, ...args); - expect(transport.send).toHaveBeenCalled(); + channel.addPeerListener(eventName, jest.fn()); + expect(channel.listeners(eventName)[0].ignorePeer).toBe(true); + }); + }); - const event: ChannelEvent = transport.send.mock.calls[0][0]; - expect(typeof event.from).toEqual('string'); + 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())); - delete event.from; - expect(event).toEqual(expected); + expect(channel.eventNames()).toEqual(eventNames); }); + }); - it('should be type safe', () => { - transport.send = jest.fn(); - const type = 'test-type'; - const args = [1, 2, 3]; - const expected = { type, args }; + 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); + event.listenerCount++; + }); + }); + + events.forEach(event => { + expect(channel.listenerCount(event.eventName)).toBe(event.listenerCount); + }); + }); + }); - // todo check if generic argument typing works - expect(true).toBe(false); + 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 call handle async option', () => { - transport.send = jest.fn(); - const type = 'test-type'; - const args = [1, 2, 3]; + 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 = new Channel({ async: true, transport }); + channel.once(eventName, args => mockListener(args)); + channel.emit(eventName, listenerInputData); + + expect(listenerOutputData).toEqual(listenerInputData); + }); - channel.emit(type, ...args); - expect(transport.send).not.toHaveBeenCalled(); + it('should be removable', () => { + const eventName = 'event1'; + const listenerToBeRemoved = jest.fn(); - jest.runAllImmediates(); - expect(transport.send).toHaveBeenCalled(); + channel.once(eventName, listenerToBeRemoved); + channel.removeListener(eventName, listenerToBeRemoved); }); }); - describe('method:eventNames', () => { - it('should return an array of strings', () => { - channel.on('type-1', jest.fn()); - channel.on('type-2', jest.fn()); - channel.on('type-2', jest.fn()); - const expected = ['type-1', 'type-2']; - expect(channel.eventNames()).toEqual(expected); + describe('method:prependListener', () => { + it('should prepend listener', () => { + const eventName = 'event1'; + const prependFn = jest.fn(); + channel.addListener(eventName, jest.fn()); + channel.prependListener(eventName, prependFn); + + expect(channel.listeners(eventName)[0]).toBe(prependFn); }); }); - describe('method:listenerCount', () => { - it('should return the correct count', () => { - channel.on('type-1', jest.fn()); - channel.on('type-2', jest.fn()); - channel.on('type-2', jest.fn()); - expect(channel.listenerCount('type-1')).toEqual(1); - expect(channel.listenerCount('type-2')).toEqual(2); + describe('method:prependOnceListener', () => { + it('should prepend listener and remove it after one execution', () => { + const eventName = 'event1'; + const prependFn = jest.fn(); + const otherFns = [jest.fn(), jest.fn(), jest.fn()]; + + otherFns.forEach(fn => channel.addListener(eventName, fn)); + channel.prependOnceListener(eventName, prependFn); + channel.emit(eventName); + + otherFns.forEach(listener => { + expect(listener).toBe( + channel.listeners(eventName).find(_listener => _listener === listener) + ); + }); }); }); - describe('method:listeners', () => { - const fn1 = jest.fn(); - const fn2 = jest.fn(); - const fn3 = jest.fn(); + 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(); - it('should return an array of listeners', () => { - channel.on('type-1', fn1); - channel.on('type-2', fn2); - channel.on('type-2', fn3); - expect(channel.listeners('type-1')).toEqual([fn1]); - expect(channel.listeners('type-2')).toEqual([fn2, fn3]); + 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:on', () => { - const fn1 = jest.fn(); - const fn2 = jest.fn(); - const fn3 = jest.fn(); + 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(); + }); }); }); diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index 3af951b35398..1b8e15ac415f 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -4,9 +4,9 @@ export interface ChannelTransport { } export interface ChannelEvent { - type: string; // todo deprecate in favor of prop name eventName? type totally confused me after I saw eventNames() + type: string; // eventName from: string; - args: TEventArgs[]; + args: TEventArgs; } export interface Listener { @@ -49,12 +49,12 @@ export class Channel { return !!this._transport; } - addListener(eventName: string, listener: Listener) { + addListener(eventName: string, listener: Listener) { this._events[eventName] = this._events[eventName] || []; this._events[eventName].push(listener); } - addPeerListener(eventName: string, listener: Listener) { + addPeerListener(eventName: string, listener: Listener) { const peerListener = listener; peerListener.ignorePeer = true; this.addListener(eventName, peerListener); @@ -71,6 +71,7 @@ export class Channel { }; if (this.isAsync) { + // todo I'm not sure how to test this setImmediate(handler); } else { handler(); @@ -91,22 +92,23 @@ export class Channel { return listeners ? listeners : undefined; } - once(eventName: string, listener: Listener) { - const onceListener = this._onceListener(eventName, listener); - this.addListener(eventName, onceListener); + once(eventName: string, listener: Listener) { + const onceListener: Listener = this._onceListener(eventName, listener); + this.addListener(eventName, onceListener); } - prependListener(eventName: string, listener: Listener) { + prependListener(eventName: string, listener: Listener) { this._events[eventName] = this._events[eventName] || []; this._events[eventName].unshift(listener); } - prependOnceListener(eventName: string, listener: Listener) { - const onceListener = this._onceListener(eventName, listener); + // todo 'listener' is getting mutated by _onceListener, therefore: Input fn() !== Output fn(). This makes testing more difficult + prependOnceListener(eventName: string, listener: Listener) { + const onceListener: Listener = this._onceListener(eventName, listener); this.prependListener(eventName, onceListener); } - removeAllListeners(eventName: string) { + removeAllListeners(eventName?: string) { if (!eventName) { this._events = {}; } else if (this._events[eventName]) { @@ -115,7 +117,7 @@ export class Channel { } removeListener(eventName: string, listener: Listener) { - const listeners = this._events[eventName]; + const listeners = this.listeners(eventName); if (listeners) { this._events[eventName] = listeners.filter(l => l !== listener); } @@ -124,19 +126,19 @@ export class Channel { /** * @deprecated use addListener */ - on(eventName: string, listener: Listener) { - this.addListener(eventName, listener); + on(eventName: string, listener: Listener) { + this.addListener(eventName, listener); } - private _handleEvent(event: ChannelEvent, isPeer = false) { + private _handleEvent(event: ChannelEvent, isPeer = false) { const listeners = this._events[event.type]; if (listeners && (isPeer || event.from !== this._sender)) { listeners.forEach(fn => !(isPeer && fn.ignorePeer) && fn(...event.args)); } } - private _onceListener(eventName: string, listener: Listener) { - const onceListener = (...args: any[]) => { + private _onceListener(eventName: string, listener: Listener) { + const onceListener: Listener = (...args: TEventArgs[]) => { this.removeListener(eventName, onceListener); return listener(...args); }; From f000c52fb0954d01ee8e7426988d78873cc333e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Sun, 16 Dec 2018 15:41:02 +0100 Subject: [PATCH 10/26] Resolved any --- lib/channels/src/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index 1b8e15ac415f..8cd382154f8d 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -1,6 +1,6 @@ -export interface ChannelTransport { - send: any; // todo Check actual type - setHandler(handler: (event: ChannelEvent) => void): void; +export interface ChannelTransport { + send(event: ChannelEvent): void; + setHandler(handler: (event: ChannelEvent) => void): void; } export interface ChannelEvent { @@ -61,7 +61,7 @@ export class Channel { } emit(eventName: string, ...args: TEventArgs[]) { - const event = { type: eventName, args, from: this._sender }; + const event: ChannelEvent = { type: eventName, args, from: this._sender }; const handler = () => { if (this._transport) { From 8db6baf9b303d82703d14f70437de57a33cd051b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Sun, 16 Dec 2018 16:15:38 +0100 Subject: [PATCH 11/26] Refactoring --- lib/channels/src/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index 8cd382154f8d..c01ad819291f 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -54,10 +54,10 @@ export class Channel { this._events[eventName].push(listener); } - addPeerListener(eventName: string, listener: Listener) { + addPeerListener(eventName: string, listener: Listener) { const peerListener = listener; peerListener.ignorePeer = true; - this.addListener(eventName, peerListener); + this.addListener(eventName, peerListener); } emit(eventName: string, ...args: TEventArgs[]) { @@ -131,7 +131,7 @@ export class Channel { } private _handleEvent(event: ChannelEvent, isPeer = false) { - const listeners = this._events[event.type]; + const listeners = this.listeners(event.type); if (listeners && (isPeer || event.from !== this._sender)) { listeners.forEach(fn => !(isPeer && fn.ignorePeer) && fn(...event.args)); } From 77b928ea80189234504a6c69c5f09f2d640aed3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Sun, 16 Dec 2018 16:17:29 +0100 Subject: [PATCH 12/26] Fixed jsnext:main --- lib/channels/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/channels/package.json b/lib/channels/package.json index 168cb803852c..f18a8b156a03 100644 --- a/lib/channels/package.json +++ b/lib/channels/package.json @@ -15,7 +15,7 @@ }, "license": "MIT", "main": "dist/index.js", - "jsnext:main": "src/index.js", + "jsnext:main": "src/index.ts", "scripts": { "prepare": "node ../../scripts/prepare.js" }, From e47c34830f1a01120cec1722207a0ab92d89f6cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Mon, 17 Dec 2018 01:37:52 +0100 Subject: [PATCH 13/26] Starting to migrate @storybook/channel-websocket --- lib/channel-websocket/package.json | 2 +- .../src/{index.js => index.ts} | 38 ++++++++++++------- lib/channel-websocket/src/typings.d.ts | 1 + lib/channel-websocket/tsconfig.json | 13 +++++++ 4 files changed, 40 insertions(+), 14 deletions(-) rename lib/channel-websocket/src/{index.js => index.ts} (59%) create mode 100644 lib/channel-websocket/src/typings.d.ts create mode 100644 lib/channel-websocket/tsconfig.json diff --git a/lib/channel-websocket/package.json b/lib/channel-websocket/package.json index a761fed85b21..11b71c82737a 100644 --- a/lib/channel-websocket/package.json +++ b/lib/channel-websocket/package.json @@ -15,7 +15,7 @@ }, "license": "MIT", "main": "dist/index.js", - "jsnext:main": "src/index.js", + "jsnext:main": "src/index.ts", "scripts": { "prepare": "node ../../scripts/prepare.js" }, diff --git a/lib/channel-websocket/src/index.js b/lib/channel-websocket/src/index.ts similarity index 59% rename from lib/channel-websocket/src/index.js rename to lib/channel-websocket/src/index.ts index 4c2907ea9963..5710a251ab07 100644 --- a/lib/channel-websocket/src/index.js +++ b/lib/channel-websocket/src/index.ts @@ -1,14 +1,26 @@ -/* eslint-disable no-underscore-dangle */ - import { WebSocket } from 'global'; -import Channel from '@storybook/channels'; +import { Channel } from '@storybook/channels'; + +type OnError = (message: Event) => void; + +interface WebsocketTransportArgs { + url: string; + onError: OnError; +} + +interface CreateChannelArgs { + url: string; + async: boolean; + onError: OnError; +} export class WebsocketTransport { - constructor({ url, onError }) { - this._socket = null; - this._buffer = []; - this._handler = null; - this._isReady = false; + private _socket: WebSocket; + private _handler: any; + private _buffer: string[] = []; + private _isReady = false; + + constructor({ url, onError }: WebsocketTransportArgs) { this._connect(url, onError); } @@ -24,22 +36,22 @@ export class WebsocketTransport { } } - _sendLater(event) { + private _sendLater(event) { this._buffer.push(event); } - _sendNow(event) { + private _sendNow(event) { const data = JSON.stringify(event); this._socket.send(data); } - _flush() { + private _flush() { const buffer = this._buffer; this._buffer = []; buffer.forEach(event => this.send(event)); } - _connect(url, onError) { + private _connect(url: string, onError: OnError) { this._socket = new WebSocket(url); this._socket.onopen = () => { this._isReady = true; @@ -57,7 +69,7 @@ export class WebsocketTransport { } } -export default function createChannel({ url, async, onError }) { +export default function createChannel({ url, async, onError }: CreateChannelArgs) { const transport = new WebsocketTransport({ url, onError }); return new Channel({ transport, async }); } diff --git a/lib/channel-websocket/src/typings.d.ts b/lib/channel-websocket/src/typings.d.ts new file mode 100644 index 000000000000..2f4eb9cf4fd9 --- /dev/null +++ b/lib/channel-websocket/src/typings.d.ts @@ -0,0 +1 @@ +declare module 'global'; diff --git a/lib/channel-websocket/tsconfig.json b/lib/channel-websocket/tsconfig.json new file mode 100644 index 000000000000..f7c7ea71c14c --- /dev/null +++ b/lib/channel-websocket/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src" + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx" + ], + "exclude": [ + "src/index.test.ts" + ] +} From fa1d5486034ba8aaacc5ddab2559500346368d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Mon, 17 Dec 2018 01:48:00 +0100 Subject: [PATCH 14/26] Added more types --- lib/channel-websocket/src/index.ts | 12 ++++++------ lib/channels/src/index.ts | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/channel-websocket/src/index.ts b/lib/channel-websocket/src/index.ts index 5710a251ab07..cebad805228c 100644 --- a/lib/channel-websocket/src/index.ts +++ b/lib/channel-websocket/src/index.ts @@ -1,5 +1,5 @@ import { WebSocket } from 'global'; -import { Channel } from '@storybook/channels'; +import { Channel, ChannelHandler } from '@storybook/channels'; type OnError = (message: Event) => void; @@ -16,7 +16,7 @@ interface CreateChannelArgs { export class WebsocketTransport { private _socket: WebSocket; - private _handler: any; + private _handler: ChannelHandler; private _buffer: string[] = []; private _isReady = false; @@ -24,11 +24,11 @@ export class WebsocketTransport { this._connect(url, onError); } - setHandler(handler) { + setHandler(handler: ChannelHandler) { this._handler = handler; } - send(event) { + send(event: any) { if (!this._isReady) { this._sendLater(event); } else { @@ -36,11 +36,11 @@ export class WebsocketTransport { } } - private _sendLater(event) { + private _sendLater(event: any) { this._buffer.push(event); } - private _sendNow(event) { + private _sendNow(event: any) { const data = JSON.stringify(event); this._socket.send(data); } diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index c01ad819291f..b974cbce63d9 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -1,6 +1,8 @@ +export type ChannelHandler = (event: ChannelEvent) => void; + export interface ChannelTransport { send(event: ChannelEvent): void; - setHandler(handler: (event: ChannelEvent) => void): void; + setHandler(handler: ChannelHandler): void; } export interface ChannelEvent { @@ -11,6 +13,7 @@ export interface ChannelEvent { export interface Listener { (...args: TEventArgs[]): void; + ignorePeer?: boolean; } From 6ceb33844e21a197370c2a30cb109d80aa6f25e3 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 17 Dec 2018 12:47:26 +0100 Subject: [PATCH 15/26] FIX CI by ignoring ng cli generated test file --- jest.config.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index 0c62ff283c01..169754d3ccd9 100644 --- a/jest.config.js +++ b/jest.config.js @@ -29,7 +29,14 @@ module.exports = { '^.+\\.tsx?$': '/node_modules/ts-jest', }, testMatch: ['**/__tests__/**/*.(j|t)s?(x)', '**/?(*.)+(spec|test).(j|t)s?(x)'], - testPathIgnorePatterns: ['/node_modules/', '/dist/', 'addon-jest.test.js', '/cli/test/'], + testPathIgnorePatterns: [ + '/node_modules/', + '/dist/', + 'addon-jest.test.js', + '/cli/test/', + '/examples/*/src/test.*', + '/examples/*/src/*.test.*', + ], collectCoverage: false, collectCoverageFrom: [ 'app/**/*.{js,jsx,ts,tsx}', From 7fc0eb6b8cec67bf698283206b74d05b1407d24f Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 17 Dec 2018 14:51:17 +0100 Subject: [PATCH 16/26] RENAME test.ts to karma.ts --- examples/angular-cli/.storybook/tsconfig.json | 2 +- examples/angular-cli/angular.json | 2 +- examples/angular-cli/src/{test.ts => karma.ts} | 0 examples/angular-cli/src/tsconfig.app.json | 2 +- examples/angular-cli/src/tsconfig.spec.json | 2 +- jest.config.js | 9 +-------- 6 files changed, 5 insertions(+), 12 deletions(-) rename examples/angular-cli/src/{test.ts => karma.ts} (100%) diff --git a/examples/angular-cli/.storybook/tsconfig.json b/examples/angular-cli/.storybook/tsconfig.json index 0fe3eca4868e..4de48e82d32f 100644 --- a/examples/angular-cli/.storybook/tsconfig.json +++ b/examples/angular-cli/.storybook/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "../src/tsconfig.app.json", - "exclude": ["../src/test.ts", "../src/**/*.spec.ts"], + "exclude": ["../src/karma.ts", "../src/**/*.spec.ts"], "include": ["../src/**/*"] } diff --git a/examples/angular-cli/angular.json b/examples/angular-cli/angular.json index 91e93c7f865c..ee8548869302 100644 --- a/examples/angular-cli/angular.json +++ b/examples/angular-cli/angular.json @@ -73,7 +73,7 @@ "test": { "builder": "@angular-devkit/build-angular:karma", "options": { - "main": "src/test.ts", + "main": "src/karma.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.spec.json", "karmaConfig": "src/karma.conf.js", diff --git a/examples/angular-cli/src/test.ts b/examples/angular-cli/src/karma.ts similarity index 100% rename from examples/angular-cli/src/test.ts rename to examples/angular-cli/src/karma.ts diff --git a/examples/angular-cli/src/tsconfig.app.json b/examples/angular-cli/src/tsconfig.app.json index 16b78476d452..a2e2c05f4a36 100644 --- a/examples/angular-cli/src/tsconfig.app.json +++ b/examples/angular-cli/src/tsconfig.app.json @@ -9,7 +9,7 @@ ] }, "exclude": [ - "test.ts", + "karma.ts", "**/*.spec.ts" ] } diff --git a/examples/angular-cli/src/tsconfig.spec.json b/examples/angular-cli/src/tsconfig.spec.json index 63d89ff283f6..108fd301e8cb 100644 --- a/examples/angular-cli/src/tsconfig.spec.json +++ b/examples/angular-cli/src/tsconfig.spec.json @@ -11,7 +11,7 @@ ] }, "files": [ - "test.ts" + "karma.ts" ], "include": [ "**/*.spec.ts", diff --git a/jest.config.js b/jest.config.js index 169754d3ccd9..0c62ff283c01 100644 --- a/jest.config.js +++ b/jest.config.js @@ -29,14 +29,7 @@ module.exports = { '^.+\\.tsx?$': '/node_modules/ts-jest', }, testMatch: ['**/__tests__/**/*.(j|t)s?(x)', '**/?(*.)+(spec|test).(j|t)s?(x)'], - testPathIgnorePatterns: [ - '/node_modules/', - '/dist/', - 'addon-jest.test.js', - '/cli/test/', - '/examples/*/src/test.*', - '/examples/*/src/*.test.*', - ], + testPathIgnorePatterns: ['/node_modules/', '/dist/', 'addon-jest.test.js', '/cli/test/'], collectCoverage: false, collectCoverageFrom: [ 'app/**/*.{js,jsx,ts,tsx}', From 58154867ee0ee9761381b52ec7a6473e9a77202c Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 17 Dec 2018 16:47:47 +0100 Subject: [PATCH 17/26] FIX CI by removing .spec. from jest testPattern --- jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest.config.js b/jest.config.js index 0c62ff283c01..34f3aca159f3 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,7 +28,7 @@ module.exports = { '^.+\\.jsx?$': '/scripts/babel-jest.js', '^.+\\.tsx?$': '/node_modules/ts-jest', }, - testMatch: ['**/__tests__/**/*.(j|t)s?(x)', '**/?(*.)+(spec|test).(j|t)s?(x)'], + testMatch: ['**/__tests__/**/*.(j|t)s?(x)', '**/?(*.)+test.(j|t)s?(x)'], testPathIgnorePatterns: ['/node_modules/', '/dist/', 'addon-jest.test.js', '/cli/test/'], collectCoverage: false, collectCoverageFrom: [ From 1e860feca36801f3fe2c76c02b02b0fbc444f94a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Mon, 17 Dec 2018 18:31:45 +0100 Subject: [PATCH 18/26] Refactoring --- lib/channel-websocket/package.json | 2 +- lib/channel-websocket/src/index.ts | 51 ++++++++++++++-------------- lib/channels/src/index.ts | 53 ++++++++++++++---------------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/lib/channel-websocket/package.json b/lib/channel-websocket/package.json index f207def23e3d..fc9825b582ea 100644 --- a/lib/channel-websocket/package.json +++ b/lib/channel-websocket/package.json @@ -15,7 +15,7 @@ }, "license": "MIT", "main": "dist/index.js", - "jsnext:main": "src/index.ts", + "types": "dist/index.d.ts", "scripts": { "prepare": "node ../../scripts/prepare.js" }, diff --git a/lib/channel-websocket/src/index.ts b/lib/channel-websocket/src/index.ts index cebad805228c..9a4121b7ad75 100644 --- a/lib/channel-websocket/src/index.ts +++ b/lib/channel-websocket/src/index.ts @@ -15,53 +15,56 @@ interface CreateChannelArgs { } export class WebsocketTransport { - private _socket: WebSocket; - private _handler: ChannelHandler; - private _buffer: string[] = []; - private _isReady = false; + private socket: WebSocket; + private handler: ChannelHandler; + private buffer: string[] = []; + private isReady = false; constructor({ url, onError }: WebsocketTransportArgs) { - this._connect(url, onError); + this.connect( + url, + onError + ); } setHandler(handler: ChannelHandler) { - this._handler = handler; + this.handler = handler; } send(event: any) { - if (!this._isReady) { - this._sendLater(event); + if (!this.isReady) { + this.sendLater(event); } else { - this._sendNow(event); + this.sendNow(event); } } - private _sendLater(event: any) { - this._buffer.push(event); + private sendLater(event: any) { + this.buffer.push(event); } - private _sendNow(event: any) { + private sendNow(event: any) { const data = JSON.stringify(event); - this._socket.send(data); + this.socket.send(data); } - private _flush() { - const buffer = this._buffer; - this._buffer = []; + private flush() { + const buffer = this.buffer; + this.buffer = []; buffer.forEach(event => this.send(event)); } - private _connect(url: string, onError: OnError) { - this._socket = new WebSocket(url); - this._socket.onopen = () => { - this._isReady = true; - this._flush(); + private connect(url: string, onError: OnError) { + this.socket = new WebSocket(url); + this.socket.onopen = () => { + this.isReady = true; + this.flush(); }; - this._socket.onmessage = e => { + this.socket.onmessage = e => { const event = JSON.parse(e.data); - this._handler(event); + this.handler(event); }; - this._socket.onerror = e => { + this.socket.onerror = e => { if (onError) { onError(e); } diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index b974cbce63d9..b42552bbdff0 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -36,25 +36,25 @@ const generateRandomId = () => { export class Channel { readonly isAsync: boolean; - private _sender = generateRandomId(); - private _events: EventsKeyValue = {}; - private readonly _transport: ChannelTransport; + private sender = generateRandomId(); + private events: EventsKeyValue = {}; + private readonly transport: ChannelTransport; constructor({ transport, async = false }: ChannelArgs = {}) { this.isAsync = async; if (transport) { - this._transport = transport; - this._transport.setHandler(event => this._handleEvent(event)); + this.transport = transport; + this.transport.setHandler(event => this.handleEvent(event)); } } get hasTransport() { - return !!this._transport; + return !!this.transport; } addListener(eventName: string, listener: Listener) { - this._events[eventName] = this._events[eventName] || []; - this._events[eventName].push(listener); + this.events[eventName] = this.events[eventName] || []; + this.events[eventName].push(listener); } addPeerListener(eventName: string, listener: Listener) { @@ -64,13 +64,13 @@ export class Channel { } emit(eventName: string, ...args: TEventArgs[]) { - const event: ChannelEvent = { type: eventName, args, from: this._sender }; + const event: ChannelEvent = { type: eventName, args, from: this.sender }; const handler = () => { - if (this._transport) { - this._transport.send(event); + if (this.transport) { + this.transport.send(event); } - this._handleEvent(event, true); + this.handleEvent(event, true); }; if (this.isAsync) { @@ -82,7 +82,7 @@ export class Channel { } eventNames() { - return Object.keys(this._events); + return Object.keys(this.events); } listenerCount(eventName: string) { @@ -91,56 +91,53 @@ export class Channel { } listeners(eventName: string): Listener[] | undefined { - const listeners = this._events[eventName]; + const listeners = this.events[eventName]; return listeners ? listeners : undefined; } once(eventName: string, listener: Listener) { - const onceListener: Listener = this._onceListener(eventName, listener); + const onceListener: Listener = this.onceListener(eventName, listener); this.addListener(eventName, onceListener); } prependListener(eventName: string, listener: Listener) { - this._events[eventName] = this._events[eventName] || []; - this._events[eventName].unshift(listener); + this.events[eventName] = this.events[eventName] || []; + this.events[eventName].unshift(listener); } // todo 'listener' is getting mutated by _onceListener, therefore: Input fn() !== Output fn(). This makes testing more difficult prependOnceListener(eventName: string, listener: Listener) { - const onceListener: Listener = this._onceListener(eventName, listener); + const onceListener: Listener = this.onceListener(eventName, listener); this.prependListener(eventName, onceListener); } removeAllListeners(eventName?: string) { if (!eventName) { - this._events = {}; - } else if (this._events[eventName]) { - delete this._events[eventName]; + this.events = {}; + } else if (this.events[eventName]) { + delete this.events[eventName]; } } removeListener(eventName: string, listener: Listener) { const listeners = this.listeners(eventName); if (listeners) { - this._events[eventName] = listeners.filter(l => l !== listener); + this.events[eventName] = listeners.filter(l => l !== listener); } } - /** - * @deprecated use addListener - */ on(eventName: string, listener: Listener) { this.addListener(eventName, listener); } - private _handleEvent(event: ChannelEvent, isPeer = false) { + private handleEvent(event: ChannelEvent, isPeer = false) { const listeners = this.listeners(event.type); - if (listeners && (isPeer || event.from !== this._sender)) { + if (listeners && (isPeer || event.from !== this.sender)) { listeners.forEach(fn => !(isPeer && fn.ignorePeer) && fn(...event.args)); } } - private _onceListener(eventName: string, listener: Listener) { + private onceListener(eventName: string, listener: Listener) { const onceListener: Listener = (...args: TEventArgs[]) => { this.removeListener(eventName, onceListener); return listener(...args); From fad28494e1ec39a4e9a0dd10a903e42a84a688fd Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 17 Dec 2018 18:38:48 +0100 Subject: [PATCH 19/26] FIX missing tests, maybe --- .eslintrc.js | 2 +- .../tests/{viewportInfo.spec.js => viewportInfo.test.js} | 0 jest.config.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename addons/viewport/src/manager/components/tests/{viewportInfo.spec.js => viewportInfo.test.js} (100%) diff --git a/.eslintrc.js b/.eslintrc.js index 6d53d20298bf..075aa02e5c87 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -125,7 +125,7 @@ module.exports = { }, overrides: [ { - files: ['**/__tests__/**', '**/*.test.js/**', '**/*.spec.js/**'], + files: ['**/__tests__/**', '**/*.test.js/**'], rules: { 'import/no-extraneous-dependencies': ignore, }, diff --git a/addons/viewport/src/manager/components/tests/viewportInfo.spec.js b/addons/viewport/src/manager/components/tests/viewportInfo.test.js similarity index 100% rename from addons/viewport/src/manager/components/tests/viewportInfo.spec.js rename to addons/viewport/src/manager/components/tests/viewportInfo.test.js diff --git a/jest.config.js b/jest.config.js index 34f3aca159f3..dce293f2eefb 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,7 +28,7 @@ module.exports = { '^.+\\.jsx?$': '/scripts/babel-jest.js', '^.+\\.tsx?$': '/node_modules/ts-jest', }, - testMatch: ['**/__tests__/**/*.(j|t)s?(x)', '**/?(*.)+test.(j|t)s?(x)'], + testMatch: ['**/__tests__/**/*.(j|t)s?(x)', '**/?(*.)+(spek|test).(j|t)s?(x)'], testPathIgnorePatterns: ['/node_modules/', '/dist/', 'addon-jest.test.js', '/cli/test/'], collectCoverage: false, collectCoverageFrom: [ From a96a0b25bd22a629c1a9b73097ed10ee3e8f4e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Mon, 17 Dec 2018 18:41:33 +0100 Subject: [PATCH 20/26] removed prepend and prependonce listener --- lib/channels/src/index.test.ts | 29 ----------------------------- lib/channels/src/index.ts | 11 ----------- 2 files changed, 40 deletions(-) diff --git a/lib/channels/src/index.test.ts b/lib/channels/src/index.test.ts index 41288138f23c..9020d3614bdf 100644 --- a/lib/channels/src/index.test.ts +++ b/lib/channels/src/index.test.ts @@ -157,35 +157,6 @@ describe('Channel', () => { }); }); - describe('method:prependListener', () => { - it('should prepend listener', () => { - const eventName = 'event1'; - const prependFn = jest.fn(); - channel.addListener(eventName, jest.fn()); - channel.prependListener(eventName, prependFn); - - expect(channel.listeners(eventName)[0]).toBe(prependFn); - }); - }); - - describe('method:prependOnceListener', () => { - it('should prepend listener and remove it after one execution', () => { - const eventName = 'event1'; - const prependFn = jest.fn(); - const otherFns = [jest.fn(), jest.fn(), jest.fn()]; - - otherFns.forEach(fn => channel.addListener(eventName, fn)); - channel.prependOnceListener(eventName, prependFn); - channel.emit(eventName); - - otherFns.forEach(listener => { - expect(listener).toBe( - channel.listeners(eventName).find(_listener => _listener === listener) - ); - }); - }); - }); - describe('method:removeAllListeners', () => { it('should remove all listeners', () => { const eventName1 = 'event1'; diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index b42552bbdff0..77cba909acb4 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -100,17 +100,6 @@ export class Channel { this.addListener(eventName, onceListener); } - prependListener(eventName: string, listener: Listener) { - this.events[eventName] = this.events[eventName] || []; - this.events[eventName].unshift(listener); - } - - // todo 'listener' is getting mutated by _onceListener, therefore: Input fn() !== Output fn(). This makes testing more difficult - prependOnceListener(eventName: string, listener: Listener) { - const onceListener: Listener = this.onceListener(eventName, listener); - this.prependListener(eventName, onceListener); - } - removeAllListeners(eventName?: string) { if (!eventName) { this.events = {}; From d328c27a5501d69d5f3a75f809b26c9b2d79ebea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Wed, 19 Dec 2018 10:50:10 +0100 Subject: [PATCH 21/26] Trying to fix CI error --- lib/channel-websocket/package.json | 1 + lib/channel-websocket/tsconfig.json | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/channel-websocket/package.json b/lib/channel-websocket/package.json index fc9825b582ea..5d654ad90752 100644 --- a/lib/channel-websocket/package.json +++ b/lib/channel-websocket/package.json @@ -15,6 +15,7 @@ }, "license": "MIT", "main": "dist/index.js", + "jsnext:main": "src/index.ts", "types": "dist/index.d.ts", "scripts": { "prepare": "node ../../scripts/prepare.js" diff --git a/lib/channel-websocket/tsconfig.json b/lib/channel-websocket/tsconfig.json index f7c7ea71c14c..11744d2a8c36 100644 --- a/lib/channel-websocket/tsconfig.json +++ b/lib/channel-websocket/tsconfig.json @@ -4,10 +4,6 @@ "rootDir": "./src" }, "include": [ - "src/**/*.ts", - "src/**/*.tsx" - ], - "exclude": [ - "src/index.test.ts" + "src/**/*.ts" ] } From 068c118715552ff4682016c400991f46d6cca590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Wed, 19 Dec 2018 10:55:57 +0100 Subject: [PATCH 22/26] Removed jsnext:main again --- lib/channel-websocket/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/channel-websocket/package.json b/lib/channel-websocket/package.json index 5d654ad90752..fc9825b582ea 100644 --- a/lib/channel-websocket/package.json +++ b/lib/channel-websocket/package.json @@ -15,7 +15,6 @@ }, "license": "MIT", "main": "dist/index.js", - "jsnext:main": "src/index.ts", "types": "dist/index.d.ts", "scripts": { "prepare": "node ../../scripts/prepare.js" From 3f9579b86a5dd68a81fe6d45087b79e18c8c04c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Wed, 19 Dec 2018 11:12:03 +0100 Subject: [PATCH 23/26] Reverted channel-websocket migration due to CI issues; the changes are going to be in a separate PR --- lib/channel-websocket/package.json | 6 +- lib/channel-websocket/src/index.js | 63 +++++++++++++++++++++ lib/channel-websocket/src/index.ts | 78 -------------------------- lib/channel-websocket/src/typings.d.ts | 1 - lib/channel-websocket/tsconfig.json | 9 --- 5 files changed, 66 insertions(+), 91 deletions(-) create mode 100644 lib/channel-websocket/src/index.js delete mode 100644 lib/channel-websocket/src/index.ts delete mode 100644 lib/channel-websocket/src/typings.d.ts delete mode 100644 lib/channel-websocket/tsconfig.json diff --git a/lib/channel-websocket/package.json b/lib/channel-websocket/package.json index fc9825b582ea..d50397074eed 100644 --- a/lib/channel-websocket/package.json +++ b/lib/channel-websocket/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/channel-websocket", - "version": "4.2.0-alpha.2", + "version": "4.2.0-alpha.4", "description": "", "keywords": [ "storybook" @@ -15,12 +15,12 @@ }, "license": "MIT", "main": "dist/index.js", - "types": "dist/index.d.ts", + "jsnext:main": "src/index.js", "scripts": { "prepare": "node ../../scripts/prepare.js" }, "dependencies": { - "@storybook/channels": "4.2.0-alpha.2", + "@storybook/channels": "4.2.0-alpha.4", "global": "^4.3.2" }, "publishConfig": { diff --git a/lib/channel-websocket/src/index.js b/lib/channel-websocket/src/index.js new file mode 100644 index 000000000000..4c2907ea9963 --- /dev/null +++ b/lib/channel-websocket/src/index.js @@ -0,0 +1,63 @@ +/* eslint-disable no-underscore-dangle */ + +import { WebSocket } from 'global'; +import Channel from '@storybook/channels'; + +export class WebsocketTransport { + constructor({ url, onError }) { + this._socket = null; + this._buffer = []; + this._handler = null; + this._isReady = false; + this._connect(url, onError); + } + + setHandler(handler) { + this._handler = handler; + } + + send(event) { + if (!this._isReady) { + this._sendLater(event); + } else { + this._sendNow(event); + } + } + + _sendLater(event) { + this._buffer.push(event); + } + + _sendNow(event) { + const data = JSON.stringify(event); + this._socket.send(data); + } + + _flush() { + const buffer = this._buffer; + this._buffer = []; + buffer.forEach(event => this.send(event)); + } + + _connect(url, onError) { + this._socket = new WebSocket(url); + this._socket.onopen = () => { + this._isReady = true; + this._flush(); + }; + this._socket.onmessage = e => { + const event = JSON.parse(e.data); + this._handler(event); + }; + this._socket.onerror = e => { + if (onError) { + onError(e); + } + }; + } +} + +export default function createChannel({ url, async, onError }) { + const transport = new WebsocketTransport({ url, onError }); + return new Channel({ transport, async }); +} diff --git a/lib/channel-websocket/src/index.ts b/lib/channel-websocket/src/index.ts deleted file mode 100644 index 9a4121b7ad75..000000000000 --- a/lib/channel-websocket/src/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { WebSocket } from 'global'; -import { Channel, ChannelHandler } from '@storybook/channels'; - -type OnError = (message: Event) => void; - -interface WebsocketTransportArgs { - url: string; - onError: OnError; -} - -interface CreateChannelArgs { - url: string; - async: boolean; - onError: OnError; -} - -export class WebsocketTransport { - private socket: WebSocket; - private handler: ChannelHandler; - private buffer: string[] = []; - private isReady = false; - - constructor({ url, onError }: WebsocketTransportArgs) { - this.connect( - url, - onError - ); - } - - setHandler(handler: ChannelHandler) { - this.handler = handler; - } - - send(event: any) { - if (!this.isReady) { - this.sendLater(event); - } else { - this.sendNow(event); - } - } - - private sendLater(event: any) { - this.buffer.push(event); - } - - private sendNow(event: any) { - const data = JSON.stringify(event); - this.socket.send(data); - } - - private flush() { - const buffer = this.buffer; - this.buffer = []; - buffer.forEach(event => this.send(event)); - } - - private connect(url: string, onError: OnError) { - this.socket = new WebSocket(url); - this.socket.onopen = () => { - this.isReady = true; - this.flush(); - }; - this.socket.onmessage = e => { - const event = JSON.parse(e.data); - this.handler(event); - }; - this.socket.onerror = e => { - if (onError) { - onError(e); - } - }; - } -} - -export default function createChannel({ url, async, onError }: CreateChannelArgs) { - const transport = new WebsocketTransport({ url, onError }); - return new Channel({ transport, async }); -} diff --git a/lib/channel-websocket/src/typings.d.ts b/lib/channel-websocket/src/typings.d.ts deleted file mode 100644 index 2f4eb9cf4fd9..000000000000 --- a/lib/channel-websocket/src/typings.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'global'; diff --git a/lib/channel-websocket/tsconfig.json b/lib/channel-websocket/tsconfig.json deleted file mode 100644 index 11744d2a8c36..000000000000 --- a/lib/channel-websocket/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "./src" - }, - "include": [ - "src/**/*.ts" - ] -} From b0ded4753716c1212b9b8ae014ab89889e37d670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Wed, 19 Dec 2018 12:16:55 +0100 Subject: [PATCH 24/26] yarn.lock --- yarn.lock | 57 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index d08ed42074d2..3a381a2be8a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5134,6 +5134,13 @@ browserstack@^1.5.1: dependencies: https-proxy-agent "^2.2.1" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -5163,7 +5170,7 @@ buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" -buffer-from@^1.0.0, buffer-from@^1.1.0: +buffer-from@1.x, buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -8621,7 +8628,7 @@ fast-glob@^2.0.2: merge2 "^1.2.3" micromatch "^3.1.10" -fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -11765,6 +11772,12 @@ json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" +json5@2.x, json5@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" + dependencies: + minimist "^1.2.0" + json5@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" @@ -11779,12 +11792,6 @@ json5@^1.0.0, json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850" - dependencies: - minimist "^1.2.0" - jsonc-parser@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.2.tgz#42fcf56d70852a043fadafde51ddb4a85649978d" @@ -13004,9 +13011,10 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" -make-error@^1.1.1, make-error@^1.3.5: +make-error@1.x, make-error@^1.1.1, make-error@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== make-fetch-happen@^4.0.1: version "4.0.1" @@ -13644,7 +13652,7 @@ mixin-object@^2.0.1: for-in "^0.1.3" is-extendable "^0.1.1" -mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -14832,7 +14840,7 @@ path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" -path-parse@^1.0.5: +path-parse@^1.0.5, path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" @@ -17401,6 +17409,13 @@ resolve@1.8.1, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2, r dependencies: path-parse "^1.0.5" +resolve@1.x: + version "1.9.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" + integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== + dependencies: + path-parse "^1.0.6" + response-time@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/response-time/-/response-time-2.3.2.tgz#ffa71bab952d62f7c1d49b7434355fbc68dffc5a" @@ -17814,7 +17829,7 @@ semver-intersect@1.4.0: dependencies: semver "^5.0.0" -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@5.x, semver@^5.0.0, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@5.x, semver@^5.0.0, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" @@ -19383,6 +19398,21 @@ tryer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" +ts-jest@^23.10.5: + version "23.10.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-23.10.5.tgz#cdb550df4466a30489bf70ba867615799f388dd5" + integrity sha512-MRCs9qnGoyKgFc8adDEntAOP64fWK1vZKnOYU1o2HxaqjdJvGqmkLCPCnVq1/If4zkUmEjKPnCiUisTrlX2p2A== + dependencies: + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + json5 "2.x" + make-error "1.x" + mkdirp "0.x" + resolve "1.x" + semver "^5.5" + yargs-parser "10.x" + ts-jest@~23.1.3: version "23.1.4" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-23.1.4.tgz#66ac1d8d3fbf8f9a98432b11aa377aa850664b2b" @@ -20959,9 +20989,10 @@ yam@^0.0.24: fs-extra "^4.0.2" lodash.merge "^4.6.0" -yargs-parser@^10.1.0: +yargs-parser@10.x, yargs-parser@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== dependencies: camelcase "^4.1.0" From 708fdc7eb344039843566cd702d8826e2c9cdbb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Thu, 20 Dec 2018 07:52:50 +0100 Subject: [PATCH 25/26] Removed generics; they do not make sense - see PR discussion https://github.com/storybooks/storybook/pull/4977#discussion_r243117931 --- lib/channels/src/index.test.ts | 14 +++++------ lib/channels/src/index.ts | 44 +++++++++++++++++----------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/lib/channels/src/index.test.ts b/lib/channels/src/index.test.ts index 9020d3614bdf..201a8aabf32a 100644 --- a/lib/channels/src/index.test.ts +++ b/lib/channels/src/index.test.ts @@ -61,12 +61,12 @@ describe('Channel', () => { const eventName = 'event1'; const listenerInputData = ['string1', 'string2', 'string3']; let listenerOutputData: string[] = null; - const mockListener: Listener = data => { + const mockListener: Listener = data => { listenerOutputData = data; }; channel.addListener(eventName, mockListener); - channel.emit(eventName, listenerInputData); + channel.emit(eventName, listenerInputData); expect(listenerOutputData).toBe(listenerInputData); }); @@ -75,10 +75,10 @@ describe('Channel', () => { const listenerInputData = ['string1', 'string2', 'string3']; let listenerOutputData: string[] = null; - channel.addListener(eventName, (...data) => { + channel.addListener(eventName, (...data) => { listenerOutputData = data; }); - channel.emit(eventName, ...listenerInputData); + channel.emit(eventName, ...listenerInputData); expect(listenerOutputData).toEqual(listenerInputData); }); @@ -138,12 +138,12 @@ describe('Channel', () => { const eventName = 'event1'; const listenerInputData = ['string1', 'string2', 'string3']; let listenerOutputData = null; - const mockListener: Listener = (data: string[]) => { + const mockListener: Listener = (data: string[]) => { listenerOutputData = data; }; - channel.once(eventName, args => mockListener(args)); - channel.emit(eventName, listenerInputData); + channel.once(eventName, args => mockListener(args)); + channel.emit(eventName, listenerInputData); expect(listenerOutputData).toEqual(listenerInputData); }); diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index 77cba909acb4..a9692c8d7c8b 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -1,18 +1,18 @@ -export type ChannelHandler = (event: ChannelEvent) => void; +export type ChannelHandler = (event: ChannelEvent) => void; -export interface ChannelTransport { - send(event: ChannelEvent): void; - setHandler(handler: ChannelHandler): void; +export interface ChannelTransport { + send(event: ChannelEvent): void; + setHandler(handler: ChannelHandler): void; } -export interface ChannelEvent { +export interface ChannelEvent { type: string; // eventName - from: string; - args: TEventArgs; + from: string | 'preview' | 'manager'; + args: any[]; } -export interface Listener { - (...args: TEventArgs[]): void; +export interface Listener { + (...args: any[]): void; ignorePeer?: boolean; } @@ -52,19 +52,19 @@ export class Channel { return !!this.transport; } - addListener(eventName: string, listener: Listener) { + addListener(eventName: string, listener: Listener) { this.events[eventName] = this.events[eventName] || []; this.events[eventName].push(listener); } - addPeerListener(eventName: string, listener: Listener) { + addPeerListener(eventName: string, listener: Listener) { const peerListener = listener; peerListener.ignorePeer = true; - this.addListener(eventName, peerListener); + this.addListener(eventName, peerListener); } - emit(eventName: string, ...args: TEventArgs[]) { - const event: ChannelEvent = { type: eventName, args, from: this.sender }; + emit(eventName: string, ...args: any[]) { + const event: ChannelEvent = { type: eventName, args, from: this.sender }; const handler = () => { if (this.transport) { @@ -95,9 +95,9 @@ export class Channel { return listeners ? listeners : undefined; } - once(eventName: string, listener: Listener) { - const onceListener: Listener = this.onceListener(eventName, listener); - this.addListener(eventName, onceListener); + once(eventName: string, listener: Listener) { + const onceListener: Listener = this.onceListener(eventName, listener); + this.addListener(eventName, onceListener); } removeAllListeners(eventName?: string) { @@ -115,19 +115,19 @@ export class Channel { } } - on(eventName: string, listener: Listener) { - this.addListener(eventName, listener); + on(eventName: string, listener: Listener) { + this.addListener(eventName, listener); } - private handleEvent(event: ChannelEvent, isPeer = false) { + private handleEvent(event: ChannelEvent, isPeer = false) { const listeners = this.listeners(event.type); if (listeners && (isPeer || event.from !== this.sender)) { listeners.forEach(fn => !(isPeer && fn.ignorePeer) && fn(...event.args)); } } - private onceListener(eventName: string, listener: Listener) { - const onceListener: Listener = (...args: TEventArgs[]) => { + private onceListener(eventName: string, listener: Listener) { + const onceListener: Listener = (...args: any[]) => { this.removeListener(eventName, onceListener); return listener(...args); }; From a92a3c5fd8e5c1da263fac6cd1ddef555a726f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kai=20R=C3=B6der?= Date: Thu, 20 Dec 2018 11:42:10 +0100 Subject: [PATCH 26/26] This enum was wrong here, it should stick to string --- lib/channels/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/channels/src/index.ts b/lib/channels/src/index.ts index a9692c8d7c8b..a468a8015faf 100644 --- a/lib/channels/src/index.ts +++ b/lib/channels/src/index.ts @@ -7,7 +7,7 @@ export interface ChannelTransport { export interface ChannelEvent { type: string; // eventName - from: string | 'preview' | 'manager'; + from: string; args: any[]; }