First stage renames, rpc-{core,provider,rx} (#220)
* Docs renames (& removal for re-gen) * Rename api, api-provider & api-rx * Apoi -> Rpc, RxApi -> RpcRx (classes) * Add .nodoc * Bump version * Link updates (summary) * Cleanup deleted (master version) * Deleted re-instated * More... ;) * Types... * Revert .nodoc
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
describe('onConnect', () => {
|
||||
let mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mock = mockWs([]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (mock) {
|
||||
mock.done();
|
||||
mock = null;
|
||||
}
|
||||
});
|
||||
|
||||
it('sets up the on* handlers', () => {
|
||||
const ws = new Ws(TEST_WS_URL, false);
|
||||
|
||||
ws.connect();
|
||||
|
||||
expect(ws.websocket.onclose[0]).toBeDefined();
|
||||
expect(ws.websocket.onerror[0]).toBeDefined();
|
||||
expect(ws.websocket.onmessage[0]).toBeDefined();
|
||||
expect(ws.websocket.onopen[0]).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
let ws;
|
||||
let mock;
|
||||
|
||||
function createWs (requests, autoConnect) {
|
||||
mock = mockWs(requests);
|
||||
ws = new Ws(TEST_WS_URL, autoConnect);
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
describe('Ws', () => {
|
||||
afterEach(() => {
|
||||
if (mock) {
|
||||
mock.done();
|
||||
mock = null;
|
||||
}
|
||||
});
|
||||
|
||||
it('returns the connected state', () => {
|
||||
expect(
|
||||
createWs([]).isConnected()
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,316 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { Logger } from '@polkadot/util/types';
|
||||
import { RpcCoder } from '../coder/json/types';
|
||||
import { JsonRpcResponse, ProviderInterface, ProviderInterface$Callback, ProviderInterface$Emitted, ProviderInterface$EmitCb } from '../types';
|
||||
|
||||
import './polyfill';
|
||||
|
||||
import E3 from 'eventemitter3';
|
||||
import assert from '@polkadot/util/assert';
|
||||
import isNull from '@polkadot/util/is/null';
|
||||
import isUndefined from '@polkadot/util/is/undefined';
|
||||
import logger from '@polkadot/util/logger';
|
||||
|
||||
import coder from '../coder/json';
|
||||
|
||||
type SubscriptionHandler = {
|
||||
callback: ProviderInterface$Callback,
|
||||
type: string
|
||||
};
|
||||
|
||||
type WsState$Awaiting = {
|
||||
callback: ProviderInterface$Callback,
|
||||
method: string,
|
||||
params: Array<any>,
|
||||
subscription?: SubscriptionHandler
|
||||
};
|
||||
|
||||
type WsState$Subscription = SubscriptionHandler & {
|
||||
method: string,
|
||||
params: Array<any>
|
||||
};
|
||||
|
||||
interface WSProviderInterface extends ProviderInterface {
|
||||
connect (): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name WsProvider
|
||||
* @summary The WebSocket Provider allows sending requests using WebSocket to a WebSocket RPC server TCP port.
|
||||
* @description Unlike the [[HttpProvider]], it does support subscriptions and allows
|
||||
* listening to events such as new blocks or balance changes.
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* import Api from '@polkadot/rpc-core';
|
||||
* import WsProvider from '@polkadot/rpc-provider/ws';
|
||||
*
|
||||
* const provider = new WsProvider('ws://127.0.0.1:9944');
|
||||
* const api = new Api(provider);
|
||||
* ```
|
||||
*
|
||||
* @see [[HttpProvider]]
|
||||
*/
|
||||
export default class WsProvider extends E3.EventEmitter implements WSProviderInterface {
|
||||
private autoConnect: boolean;
|
||||
private coder: RpcCoder;
|
||||
private endpoint: string;
|
||||
private handlers: {
|
||||
[index: number]: WsState$Awaiting
|
||||
};
|
||||
private _isConnected: boolean;
|
||||
private l: Logger;
|
||||
private queued: {
|
||||
[index: string]: string
|
||||
};
|
||||
private subscriptions: {
|
||||
[index: string]: WsState$Subscription
|
||||
};
|
||||
private websocket: WebSocket | null;
|
||||
|
||||
/**
|
||||
* @param {string} endpoint The endpoint url. Usually `ws://ip:9944` or `wss://ip:9944`
|
||||
* @param {boolean} autoConnect Whether to connect automatically or not.
|
||||
*/
|
||||
constructor (endpoint: string, autoConnect: boolean = true) {
|
||||
super();
|
||||
|
||||
assert(/^(wss|ws):\/\//.test(endpoint), `Endpoint should start with 'ws://', received '${endpoint}'`);
|
||||
|
||||
this.autoConnect = autoConnect;
|
||||
this.coder = coder();
|
||||
this.endpoint = endpoint;
|
||||
this._isConnected = false;
|
||||
this.handlers = {};
|
||||
this.l = logger('api-ws');
|
||||
this.queued = {};
|
||||
this.subscriptions = {};
|
||||
this.websocket = null;
|
||||
|
||||
if (autoConnect) {
|
||||
this.connect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Manually connect
|
||||
* @description The [[WsProvider]] connects automatically by default, however if you decided otherwise, you may
|
||||
* connect manually using this method.
|
||||
*/
|
||||
connect (): void {
|
||||
try {
|
||||
this.websocket = new WebSocket(this.endpoint);
|
||||
|
||||
this.websocket.onclose = this.onSocketClose;
|
||||
this.websocket.onerror = this.onSocketError;
|
||||
this.websocket.onmessage = this.onSocketMessage;
|
||||
this.websocket.onopen = this.onSocketOpen;
|
||||
} catch (error) {
|
||||
this.l.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Whether the node is connected or not.
|
||||
* @return {boolean} true if connected
|
||||
*/
|
||||
isConnected (): boolean {
|
||||
return this._isConnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Listens on events after having subscribed using the [[subscribe]] function.
|
||||
* @param {ProviderInterface$Emitted} type Event
|
||||
* @param {ProviderInterface$EmitCb} sub Callback
|
||||
* @return {this} [description]
|
||||
*/
|
||||
on (type: ProviderInterface$Emitted, sub: ProviderInterface$EmitCb): this {
|
||||
return super.on(type, sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Send JSON data using WebSockets to configured HTTP Endpoint or queue.
|
||||
*/
|
||||
async send (method: string, params: Array<any>, subscription?: SubscriptionHandler): Promise<any> {
|
||||
return new Promise((resolve, reject): void => {
|
||||
try {
|
||||
const json = this.coder.encodeJson(method, params);
|
||||
const id = this.coder.getId();
|
||||
const callback = (error: Error | null, result: any) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
|
||||
this.l.debug(() => ['calling', method, params, json, !!subscription]);
|
||||
|
||||
this.handlers[id] = {
|
||||
callback,
|
||||
method,
|
||||
params,
|
||||
subscription
|
||||
};
|
||||
|
||||
if (this.isConnected() && !isNull(this.websocket)) {
|
||||
this.websocket.send(json);
|
||||
} else {
|
||||
this.queued[id] = json;
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @name subscribe
|
||||
* @summary Allows subscribing to a specific event.
|
||||
* @param {string} type Subscription type
|
||||
* @param {string} method Subscription method
|
||||
* @param {Array<any>} params Parameters
|
||||
* @param {ProviderInterface$Callback} callback Callback
|
||||
* @return {Promise<number>} Promise resolving to the dd of the subscription you can use with [[unsubscribe]].
|
||||
*
|
||||
* @example
|
||||
* <BR>
|
||||
*
|
||||
* ```javascript
|
||||
* const provider = new WsProvider('ws://127.0.0.1:9944');
|
||||
* const api = new Api(provider);
|
||||
*
|
||||
* api.state.storage([[storage.balances.freeBalance, <Address>]], (_, values) => {
|
||||
* console.log(values)
|
||||
* }).then((subscriptionId) => {
|
||||
* console.log('balance changes subscription id: ', subscriptionId)
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
async subscribe (type: string, method: string, params: Array<any>, callback: ProviderInterface$Callback): Promise<number> {
|
||||
const id = await this.send(method, params, { callback, type });
|
||||
|
||||
return id as number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Allows unsubscribing to subscriptions made with [[subscribe]].
|
||||
*/
|
||||
async unsubscribe (type: string, method: string, id: number): Promise<boolean> {
|
||||
const subscription = `${type}::${id}`;
|
||||
|
||||
assert(!isUndefined(this.subscriptions[subscription]), `Unable to find active subscription=${subscription}`);
|
||||
|
||||
delete this.subscriptions[subscription];
|
||||
|
||||
const result = await this.send(method, [id]);
|
||||
|
||||
return result as boolean;
|
||||
}
|
||||
|
||||
private onSocketClose = (): void => {
|
||||
this.l.debug(() => ['disconnected from', this.endpoint]);
|
||||
|
||||
this._isConnected = false;
|
||||
this.emit('disconnected');
|
||||
|
||||
if (this.autoConnect) {
|
||||
setTimeout(() => {
|
||||
this.connect();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
private onSocketError = (error: Event): void => {
|
||||
this.l.error(error);
|
||||
}
|
||||
|
||||
private onSocketMessage = (message: MessageEvent): void => {
|
||||
this.l.debug(() => ['received', message.data]);
|
||||
|
||||
const response: JsonRpcResponse = JSON.parse(message.data as string);
|
||||
|
||||
return isUndefined(response.method)
|
||||
? this.onSocketMessageResult(response)
|
||||
: this.onSocketMessageSubscribe(response);
|
||||
}
|
||||
|
||||
private onSocketMessageResult = (response: JsonRpcResponse): void => {
|
||||
this.l.debug(() => ['handling: response =', response, 'id =', response.id]);
|
||||
|
||||
const handler = this.handlers[response.id];
|
||||
|
||||
if (!handler) {
|
||||
this.l.error(`Unable to find handler for id=${response.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { method, params, subscription } = handler;
|
||||
const result = this.coder.decodeResponse(response);
|
||||
|
||||
if (subscription) {
|
||||
this.subscriptions[`${subscription.type}::${result}`] = {
|
||||
...subscription,
|
||||
method,
|
||||
params
|
||||
};
|
||||
}
|
||||
|
||||
handler.callback(null, result);
|
||||
} catch (error) {
|
||||
handler.callback(error, undefined);
|
||||
}
|
||||
|
||||
delete this.handlers[response.id];
|
||||
}
|
||||
|
||||
private onSocketMessageSubscribe = (response: JsonRpcResponse): void => {
|
||||
const subscription = `${response.method}::${response.params.subscription}`;
|
||||
|
||||
this.l.debug(() => ['handling: response =', response, 'subscription =', subscription]);
|
||||
|
||||
const handler = this.subscriptions[subscription];
|
||||
|
||||
if (!handler) {
|
||||
this.l.error(`Unable to find handler for subscription=${subscription}`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = this.coder.decodeResponse(response);
|
||||
|
||||
handler.callback(null, result);
|
||||
} catch (error) {
|
||||
handler.callback(error, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
private onSocketOpen = (): boolean => {
|
||||
assert(!isNull(this.websocket), 'WebSocket cannot be null in onOpen');
|
||||
|
||||
this.l.debug(() => ['connected to', this.endpoint]);
|
||||
|
||||
this._isConnected = true;
|
||||
this.emit('connected');
|
||||
|
||||
Object.keys(this.queued).forEach((id) => {
|
||||
try {
|
||||
// @ts-ignore checked above
|
||||
this.websocket.send(
|
||||
this.queued[id]
|
||||
);
|
||||
|
||||
delete this.queued[id];
|
||||
} catch (error) {
|
||||
this.l.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
describe('onError', () => {
|
||||
let ws;
|
||||
let errorSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
ws = new Ws('ws://127.0.0.1:1234', false);
|
||||
errorSpy = jest.spyOn(console, 'error');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('logs the error', () => {
|
||||
ws.onSocketError('test error');
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
expect.anything(), expect.anything(), 'test error'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
describe('onMessageResult', () => {
|
||||
let ws;
|
||||
let errorSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
ws = new Ws('ws://127.0.0.1:1234', false);
|
||||
errorSpy = jest.spyOn(console, 'error');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('fails with log when handler not found', () => {
|
||||
ws.onSocketMessage({ data: '{"id":2}' });
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
expect.anything(), expect.anything(), 'Unable to find handler for id=2'
|
||||
);
|
||||
});
|
||||
|
||||
it('calls the handler when found', (done) => {
|
||||
ws.handlers[5] = {
|
||||
callback: (_, result) => {
|
||||
expect(result).toEqual('test');
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
ws.onSocketMessage({ data: '{"jsonrpc":"2.0","id":5,"result":"test"}' });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
describe('onMessageSubscribe', () => {
|
||||
let ws;
|
||||
let errorSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
ws = new Ws('ws://127.0.0.1:1234', false);
|
||||
errorSpy = jest.spyOn(console, 'error');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('fails with log when handler not found', () => {
|
||||
ws.onSocketMessage({ data: '{"method":"test","params":{"subscription":2}}' });
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
expect.anything(), expect.anything(), 'Unable to find handler for subscription=test::2'
|
||||
);
|
||||
});
|
||||
|
||||
it('calls the subscriber with data', (done) => {
|
||||
ws.handlers[11] = {
|
||||
callback: (_, id) => {},
|
||||
method: 'test',
|
||||
subscription: {
|
||||
callback: (_, result) => {
|
||||
expect(result).toEqual('test');
|
||||
done();
|
||||
},
|
||||
type: 'test'
|
||||
}
|
||||
};
|
||||
|
||||
ws.onSocketMessage({ data: '{"jsonrpc":"2.0","id":11,"result":22}' });
|
||||
ws.onSocketMessage({ data: '{"jsonrpc":"2.0","method":"test","params":{"subscription":22,"result":"test"}}' });
|
||||
});
|
||||
|
||||
it('calls the subscriber with error', (done) => {
|
||||
ws.handlers[11] = {
|
||||
callback: (_, id) => {},
|
||||
method: 'test',
|
||||
subscription: {
|
||||
callback: (error) => {
|
||||
expect(error.message).toMatch(/test/);
|
||||
done();
|
||||
},
|
||||
type: 'test'
|
||||
}
|
||||
};
|
||||
|
||||
ws.onSocketMessage({ data: '{"jsonrpc":"2.0","id":11,"result":22}' });
|
||||
ws.onSocketMessage({ data: '{"jsonrpc":"2.0","method":"test","params":{"subscription":22,"error":{"message":"test"}}}' });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
let ws;
|
||||
let mock;
|
||||
|
||||
function createWs (requests, autoConnect) {
|
||||
mock = mockWs(requests);
|
||||
ws = new Ws(TEST_WS_URL, autoConnect);
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
describe('onOpen', () => {
|
||||
afterEach(() => {
|
||||
if (mock) {
|
||||
mock.done();
|
||||
mock = null;
|
||||
}
|
||||
});
|
||||
|
||||
it('sends messages when connected', () => {
|
||||
const ws = createWs([{
|
||||
id: 1,
|
||||
method: 'test_queue',
|
||||
reply: {
|
||||
result: 'ok'
|
||||
}
|
||||
}], false);
|
||||
const sendPromise = ws.send('test_queue', []);
|
||||
|
||||
ws.connect();
|
||||
|
||||
return sendPromise.then((result) => {
|
||||
expect(result).toEqual('ok');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
describe('ws/polyfill', () => {
|
||||
let origWs;
|
||||
|
||||
beforeEach(() => {
|
||||
origWs = global.WebSocket;
|
||||
global.WebSocket = null;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.WebSocket = origWs;
|
||||
});
|
||||
|
||||
it('polyfills with no exceptions (without WebSocket)', () => {
|
||||
expect(require('./polyfill')).toBeDefined();
|
||||
});
|
||||
|
||||
it('polyfills with no exceptions (with WebSocket)', () => {
|
||||
global.WebSocket = () => true;
|
||||
|
||||
expect(require('./polyfill')).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
// tslint:disable-next-line
|
||||
if (typeof WebSocket === 'undefined') {
|
||||
// @ts-ignore
|
||||
global.WebSocket = require('websocket').w3cwebsocket;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
let ws;
|
||||
let mock;
|
||||
|
||||
function createMock (requests) {
|
||||
mock = mockWs(requests);
|
||||
}
|
||||
|
||||
function createWs (autoConnect) {
|
||||
ws = new Ws(TEST_WS_URL, autoConnect);
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
describe('send', () => {
|
||||
let globalWs;
|
||||
|
||||
beforeEach(() => {
|
||||
globalWs = global.WebSocket;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.WebSocket = globalWs;
|
||||
|
||||
if (mock) {
|
||||
mock.done();
|
||||
mock = null;
|
||||
}
|
||||
});
|
||||
|
||||
it('handles internal errors', () => {
|
||||
createMock([]);
|
||||
|
||||
let websocket;
|
||||
|
||||
global.WebSocket = class {
|
||||
constructor () {
|
||||
websocket = this;
|
||||
}
|
||||
|
||||
send () {
|
||||
throw new Error('send error');
|
||||
}
|
||||
};
|
||||
|
||||
ws = createWs();
|
||||
websocket.onopen();
|
||||
|
||||
return ws
|
||||
.send('test_encoding', ['param'])
|
||||
.catch((error) => {
|
||||
expect(error.message).toEqual('send error');
|
||||
});
|
||||
});
|
||||
|
||||
it('passes the body through correctly', () => {
|
||||
createMock([{
|
||||
id: 1,
|
||||
method: 'test_body',
|
||||
reply: {
|
||||
result: 'ok'
|
||||
}
|
||||
}]);
|
||||
|
||||
return createWs()
|
||||
.send('test_body', ['param'])
|
||||
.then((result) => {
|
||||
expect(
|
||||
mock.body['test_body']
|
||||
).toEqual('{"id":1,"jsonrpc":"2.0","method":"test_body","params":["param"]}');
|
||||
});
|
||||
});
|
||||
|
||||
it('throws error when !response.ok', () => {
|
||||
createMock([{
|
||||
id: 1,
|
||||
error: {
|
||||
code: 666,
|
||||
message: 'error'
|
||||
}
|
||||
}]);
|
||||
|
||||
return createWs()
|
||||
.send('test_error', [])
|
||||
.catch((error) => {
|
||||
expect(error.message).toMatch(/\[666\]: error/);
|
||||
});
|
||||
});
|
||||
|
||||
it('adds subscriptions', () => {
|
||||
createMock([{
|
||||
id: 1,
|
||||
method: 'test_sub',
|
||||
reply: {
|
||||
result: 1
|
||||
}
|
||||
}]);
|
||||
|
||||
return createWs()
|
||||
.send('test_sub', [], () => {})
|
||||
.then((id) => {
|
||||
expect(id).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
describe('state', () => {
|
||||
it('requires an ws:// prefixed endpoint', () => {
|
||||
expect(
|
||||
() => new Ws('http://', false)
|
||||
).toThrow(/with 'ws/);
|
||||
});
|
||||
|
||||
it('allows wss:// endpoints', () => {
|
||||
expect(
|
||||
() => new Ws('wss://', false)
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
let ws;
|
||||
let mock;
|
||||
|
||||
function createMock (requests) {
|
||||
mock = mockWs(requests);
|
||||
}
|
||||
|
||||
function createWs (autoConnect) {
|
||||
ws = new Ws(TEST_WS_URL, autoConnect);
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
describe('subscribe', () => {
|
||||
let globalWs;
|
||||
|
||||
beforeEach(() => {
|
||||
globalWs = global.WebSocket;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.WebSocket = globalWs;
|
||||
|
||||
if (mock) {
|
||||
mock.done();
|
||||
mock = null;
|
||||
}
|
||||
});
|
||||
|
||||
it('adds subscriptions', () => {
|
||||
createMock([{
|
||||
id: 1,
|
||||
method: 'test_sub',
|
||||
reply: {
|
||||
result: 1
|
||||
}
|
||||
}]);
|
||||
|
||||
return createWs()
|
||||
.subscribe('test_sub', [], () => {})
|
||||
.then((id) => {
|
||||
expect(id).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright 2017-2018 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { mockWs, TEST_WS_URL } from '../../test/mockWs';
|
||||
|
||||
import Ws from './index';
|
||||
|
||||
let ws;
|
||||
let mock;
|
||||
|
||||
function createMock (requests) {
|
||||
mock = mockWs(requests);
|
||||
}
|
||||
|
||||
function createWs (autoConnect) {
|
||||
ws = new Ws(TEST_WS_URL, autoConnect);
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
describe('subscribe', () => {
|
||||
let globalWs;
|
||||
|
||||
beforeEach(() => {
|
||||
globalWs = global.WebSocket;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
global.WebSocket = globalWs;
|
||||
|
||||
if (mock) {
|
||||
mock.done();
|
||||
mock = null;
|
||||
}
|
||||
});
|
||||
|
||||
it('removes subscriptions', () => {
|
||||
createMock([
|
||||
{
|
||||
id: 1,
|
||||
method: 'subscribe_test',
|
||||
reply: {
|
||||
result: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
method: 'unsubscribe_test',
|
||||
reply: {
|
||||
result: true
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const ws = createWs();
|
||||
|
||||
return ws
|
||||
.subscribe('test', 'subscribe_test', [], () => {})
|
||||
.then((id) => {
|
||||
return ws.unsubscribe('test', 'subscribe_test', id);
|
||||
});
|
||||
});
|
||||
|
||||
it('fails when sub not found', () => {
|
||||
createMock([{
|
||||
id: 1,
|
||||
method: 'subscribe_test',
|
||||
reply: {
|
||||
result: 1
|
||||
}
|
||||
}]);
|
||||
|
||||
const ws = createWs();
|
||||
|
||||
return ws
|
||||
.subscribe('test', 'subscribe_test', [], () => {})
|
||||
.then((id) => {
|
||||
return ws.unsubscribe('test', 'subscribe_test', 111);
|
||||
})
|
||||
.catch((error) => {
|
||||
expect(error.message).toMatch(/find active subscription/);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user