UNPKG

@ch1/rpc

Version:

JavaScript Remote Procedure Call (RPC)

228 lines (190 loc) 5.39 kB
import * as rpc from './js-rpc'; import { DEFAULT_MESSAGE } from './constants'; import { noop } from './utils'; describe('basic async e2e', () => { let configA; let configB; let callbacksA; let callbacksB; beforeEach(() => { callbacksA = []; callbacksB = []; configA = { emit: (...args) => { setTimeout(() => { callbacksB.filter(Boolean).forEach(cb => cb.apply(null, args)); }, 0); }, enableStackTrace: false, message: '', on: listener => { const offset = callbacksA.push(listener); return () => { callbacksA[offset - 1] = null; }; }, remote: {}, }; configB = { emit: (...args) => { setTimeout(() => { callbacksA.filter(Boolean).forEach(cb => cb.apply(null, args)); }, 0); }, enableStackTrace: false, message: '', on: listener => { const offset = callbacksB.push(listener); return () => { callbacksB[offset - 1] = null; }; }, remote: {}, }; }); it('should work for two simple functions (promises)', done => { interface Test1 { test1(): string; } interface Test2 { test2(): string; } const a = rpc.create<Test2>(configA, { test1: () => new Promise(resolve => resolve('testA')), }); const b = rpc.create<Test1>(configB, { test2: () => new Promise(resolve => resolve('testB')), }); Promise.all([a.ready, b.ready]) .then(() => { return Promise.all([a.remote.test2(), b.remote.test1()]).then( results => { expect(results[0]).toBe('testB'); expect(results[1]).toBe('testA'); }, ); }) .catch(err => { expect(err.message).toBeUndefined(); }) .then(() => { a.destroy(); b.destroy(); done(); }); }); it('should work for two simple functions (synchronous invocations)', done => { interface Test1 { test1(): string; } interface Test2 { test2(): string; } const a = rpc.create<Test2>(configA, { test1: () => 'test A', }); const b = rpc.create<Test1>(configB, { test2: () => 'test B', }); Promise.all([a.ready, b.ready]) .then(() => { return Promise.all([a.remote.test2(), b.remote.test1()]).then( results => { expect(results[0]).toBe('test B'); expect(results[1]).toBe('test A'); }, ); }) .catch(err => { expect(err.message).toBeUndefined(); }) .then(() => { a.destroy(); b.destroy(); done(); }); }); it('has an on destroy notification system', done => { interface Test2 { test2(): string; } const a = rpc.create<Test2>(configA, { test1: () => new Promise(resolve => resolve('testA')), }); a.onDestroy(reason => { expect(reason).toBe('test fails'); done(); }); a.destroy('test fails').catch(done); }); it('can deregister on destroy handlers', done => { interface Test2 { test2(): string; } const a = rpc.create<Test2>(configA, { test1: () => new Promise(resolve => resolve('testA')), }); let onDestroyRan = false; const dereg = a.onDestroy(reason => { onDestroyRan = true; }); dereg(); a.destroy('test fails') .then(() => { // this seems hackier than it actually is setTimeout(() => { expect(onDestroyRan).toBe(false); done(); }, 10); }) .catch(done); }); }); describe('js-rpc functions', () => { let config; beforeEach(() => { config = { emit: noop, enableStackTrace: false, message: '', on: noop, remote: {}, }; }); describe('create function', () => { it('should run without incident if given valid parameters', () => { expect(() => rpc.create<Object>(config, {})).not.toThrowError(); }); it('should provide a destroy function', () => { const test = rpc.create<Object>(config, {}); expect(() => test.destroy()).not.toThrowError(); }); }); describe('validateRemote function', () => { it('should resolve if a given value is falsey', () => { expect(() => rpc.validateRemote(null)).not.toThrowError(); }); it('should throw if given value is truthy and also not an object', () => { expect(() => rpc.validateRemote('hello')).toThrowError(); }); it('should not throw if given a valid object', () => { expect(() => rpc.validateRemote({})).not.toThrowError(); }); }); describe('validateConfig function', () => { it('should return an immutable (frozen) object', () => { const validConfig = rpc.validateConfig(config, {}); expect(() => (validConfig.message = 'test')).toThrowError(); }); it('should default to having a false stack prop', () => { config.enableStackTrace = ''; const validConfig = rpc.validateConfig(config, {}); expect(validConfig.enableStackTrace).toBe(false); }); it('should default to using DEFAULT_MESSAGE', () => { config.message = ''; const validConfig = rpc.validateConfig(config, {}); expect(validConfig.message).toBe(DEFAULT_MESSAGE); }); }); });