Adjust class privates via #, where applicable (#1921)
* Adjust class priates via #, where applicable * Remove stray log * Cleanup rpc-provider * Small adjustments * No private access in tests * Submittable privates * Use derive for nonce derivation * Tweak observers * Alphabetical privates
This commit is contained in:
@@ -8,7 +8,7 @@ import { assert, isUndefined, isNumber, isString } from '@polkadot/util';
|
||||
|
||||
/** @internal */
|
||||
export default class RpcCoder {
|
||||
private id = 0;
|
||||
#id = 0;
|
||||
|
||||
public decodeResponse (response: JsonRpcResponse): any {
|
||||
assert(response, 'Empty response object received');
|
||||
@@ -39,7 +39,7 @@ export default class RpcCoder {
|
||||
|
||||
public encodeObject (method: string, params: any | any[]): JsonRpcRequest {
|
||||
return {
|
||||
id: ++this.id,
|
||||
id: ++this.#id,
|
||||
jsonrpc: '2.0',
|
||||
method,
|
||||
params
|
||||
@@ -47,7 +47,7 @@ export default class RpcCoder {
|
||||
}
|
||||
|
||||
public getId (): number {
|
||||
return this.id;
|
||||
return this.#id;
|
||||
}
|
||||
|
||||
private checkError (error?: JsonRpcResponseBaseError): void {
|
||||
|
||||
@@ -36,9 +36,9 @@ const l = logger('api-http');
|
||||
* @see [[WsProvider]]
|
||||
*/
|
||||
export default class HttpProvider implements ProviderInterface {
|
||||
private coder: Coder;
|
||||
readonly #coder: Coder;
|
||||
|
||||
private endpoint: string;
|
||||
readonly #endpoint: string;
|
||||
|
||||
/**
|
||||
* @param {string} endpoint The endpoint url starting with http://
|
||||
@@ -46,8 +46,8 @@ export default class HttpProvider implements ProviderInterface {
|
||||
constructor (endpoint: string = defaults.HTTP_URL) {
|
||||
assert(/^(https|http):\/\//.test(endpoint), `Endpoint should start with 'http://', received '${endpoint}'`);
|
||||
|
||||
this.coder = new Coder();
|
||||
this.endpoint = endpoint;
|
||||
this.#coder = new Coder();
|
||||
this.#endpoint = endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,8 +95,8 @@ export default class HttpProvider implements ProviderInterface {
|
||||
* @summary Send HTTP POST Request with Body to configured HTTP Endpoint.
|
||||
*/
|
||||
public async send (method: string, params: any[]): Promise<any> {
|
||||
const body = this.coder.encodeJson(method, params);
|
||||
const response = await fetch(this.endpoint, {
|
||||
const body = this.#coder.encodeJson(method, params);
|
||||
const response = await fetch(this.#endpoint, {
|
||||
body,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
@@ -110,7 +110,7 @@ export default class HttpProvider implements ProviderInterface {
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
return this.coder.decodeResponse(result);
|
||||
return this.#coder.decodeResponse(result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -65,25 +65,25 @@ const l = logger('api-ws');
|
||||
* @see [[HttpProvider]]
|
||||
*/
|
||||
export default class WsProvider implements WSProviderInterface {
|
||||
private _eventemitter: EventEmitter;
|
||||
readonly #coder: Coder;
|
||||
|
||||
private _isConnected = false;
|
||||
readonly #endpoint: string;
|
||||
|
||||
private autoConnect: boolean;
|
||||
readonly #eventemitter: EventEmitter;
|
||||
|
||||
private coder: Coder;
|
||||
readonly #handlers: Record<string, WsStateAwaiting> = {};
|
||||
|
||||
private endpoint: string;
|
||||
readonly #queued: Record<string, string> = {};
|
||||
|
||||
private handlers: Record<string, WsStateAwaiting>;
|
||||
readonly #waitingForId: Record<string, JsonRpcResponse> = {};
|
||||
|
||||
private queued: Record<string, string>;
|
||||
#autoConnect: boolean;
|
||||
|
||||
private subscriptions: Record<string, WsStateSubscription>;
|
||||
#isConnected = false;
|
||||
|
||||
private waitingForId: Record<string, JsonRpcResponse>;
|
||||
#subscriptions: Record<string, WsStateSubscription> = {};
|
||||
|
||||
private websocket: WebSocket | null;
|
||||
#websocket: WebSocket | null;
|
||||
|
||||
/**
|
||||
* @param {string} endpoint The endpoint url. Usually `ws://ip:9944` or `wss://ip:9944`
|
||||
@@ -92,15 +92,11 @@ export default class WsProvider implements WSProviderInterface {
|
||||
constructor (endpoint: string = defaults.WS_URL, autoConnect = true) {
|
||||
assert(/^(wss|ws):\/\//.test(endpoint), `Endpoint should start with 'ws://', received '${endpoint}'`);
|
||||
|
||||
this._eventemitter = new EventEmitter();
|
||||
this.autoConnect = autoConnect;
|
||||
this.coder = new Coder();
|
||||
this.endpoint = endpoint;
|
||||
this.handlers = {};
|
||||
this.queued = {};
|
||||
this.subscriptions = {};
|
||||
this.waitingForId = {};
|
||||
this.websocket = null;
|
||||
this.#eventemitter = new EventEmitter();
|
||||
this.#autoConnect = autoConnect;
|
||||
this.#coder = new Coder();
|
||||
this.#endpoint = endpoint;
|
||||
this.#websocket = null;
|
||||
|
||||
if (autoConnect) {
|
||||
this.connect();
|
||||
@@ -118,7 +114,7 @@ export default class WsProvider implements WSProviderInterface {
|
||||
* @description Returns a clone of the object
|
||||
*/
|
||||
public clone (): WsProvider {
|
||||
return new WsProvider(this.endpoint);
|
||||
return new WsProvider(this.#endpoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,12 +124,11 @@ export default class WsProvider implements WSProviderInterface {
|
||||
*/
|
||||
public 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;
|
||||
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) {
|
||||
l.error(error);
|
||||
}
|
||||
@@ -143,16 +138,16 @@ export default class WsProvider implements WSProviderInterface {
|
||||
* @description Manually disconnect from the connection, clearing autoconnect logic
|
||||
*/
|
||||
public disconnect (): void {
|
||||
if (isNull(this.websocket)) {
|
||||
if (isNull(this.#websocket)) {
|
||||
throw new Error('Cannot disconnect on a non-open websocket');
|
||||
}
|
||||
|
||||
// switch off autoConnect, we are in manual mode now
|
||||
this.autoConnect = false;
|
||||
this.#autoConnect = false;
|
||||
|
||||
// 1000 - Normal closure; the connection successfully completed
|
||||
this.websocket.close(1000);
|
||||
this.websocket = null;
|
||||
this.#websocket.close(1000);
|
||||
this.#websocket = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +155,7 @@ export default class WsProvider implements WSProviderInterface {
|
||||
* @return {boolean} true if connected
|
||||
*/
|
||||
public isConnected (): boolean {
|
||||
return this._isConnected;
|
||||
return this.#isConnected;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,9 +165,10 @@ export default class WsProvider implements WSProviderInterface {
|
||||
* @return unsubscribe function
|
||||
*/
|
||||
public on (type: ProviderInterfaceEmitted, sub: ProviderInterfaceEmitCb): () => void {
|
||||
this._eventemitter.on(type, sub);
|
||||
this.#eventemitter.on(type, sub);
|
||||
|
||||
return (): void => {
|
||||
this._eventemitter.removeListener(type, sub);
|
||||
this.#eventemitter.removeListener(type, sub);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -185,8 +181,8 @@ export default class WsProvider implements WSProviderInterface {
|
||||
public send (method: string, params: 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 json = this.#coder.encodeJson(method, params);
|
||||
const id = this.#coder.getId();
|
||||
const callback = (error?: Error | null, result?: any): void => {
|
||||
error
|
||||
? reject(error)
|
||||
@@ -195,17 +191,17 @@ export default class WsProvider implements WSProviderInterface {
|
||||
|
||||
l.debug((): string[] => ['calling', method, json]);
|
||||
|
||||
this.handlers[id] = {
|
||||
this.#handlers[id] = {
|
||||
callback,
|
||||
method,
|
||||
params,
|
||||
subscription
|
||||
};
|
||||
|
||||
if (this.isConnected() && !isNull(this.websocket)) {
|
||||
this.websocket.send(json);
|
||||
if (this.isConnected() && !isNull(this.#websocket)) {
|
||||
this.#websocket.send(json);
|
||||
} else {
|
||||
this.queued[id] = json;
|
||||
this.#queued[id] = json;
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
@@ -252,55 +248,55 @@ export default class WsProvider implements WSProviderInterface {
|
||||
// the assigned id now does not match what the API user originally received. It has
|
||||
// a slight complication in solving - since we cannot rely on the send id, but rather
|
||||
// need to find the actual subscription id to map it
|
||||
if (isUndefined(this.subscriptions[subscription])) {
|
||||
if (isUndefined(this.#subscriptions[subscription])) {
|
||||
l.debug((): string => `Unable to find active subscription=${subscription}`);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
delete this.subscriptions[subscription];
|
||||
delete this.#subscriptions[subscription];
|
||||
|
||||
const result = await this.send(method, [id]);
|
||||
|
||||
return result as boolean;
|
||||
}
|
||||
|
||||
private emit (type: ProviderInterfaceEmitted, ...args: any[]): void {
|
||||
this._eventemitter.emit(type, ...args);
|
||||
#emit = (type: ProviderInterfaceEmitted, ...args: any[]): void => {
|
||||
this.#eventemitter.emit(type, ...args);
|
||||
}
|
||||
|
||||
private onSocketClose = (event: CloseEvent): void => {
|
||||
if (this.autoConnect) {
|
||||
l.error(`disconnected from ${this.endpoint} code: '${event.code}' reason: '${event.reason}'`);
|
||||
#onSocketClose = (event: CloseEvent): void => {
|
||||
if (this.#autoConnect) {
|
||||
l.error(`disconnected from ${this.#endpoint} code: '${event.code}' reason: '${event.reason}'`);
|
||||
}
|
||||
|
||||
this._isConnected = false;
|
||||
this.emit('disconnected');
|
||||
this.#isConnected = false;
|
||||
this.#emit('disconnected');
|
||||
|
||||
if (this.autoConnect) {
|
||||
if (this.#autoConnect) {
|
||||
setTimeout((): void => {
|
||||
this.connect();
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
private onSocketError = (error: Event): void => {
|
||||
#onSocketError = (error: Event): void => {
|
||||
l.debug((): any => ['socket error', error]);
|
||||
this.emit('error', error);
|
||||
this.#emit('error', error);
|
||||
}
|
||||
|
||||
private onSocketMessage = (message: MessageEvent): void => {
|
||||
#onSocketMessage = (message: MessageEvent): void => {
|
||||
l.debug((): any => ['received', message.data]);
|
||||
|
||||
const response: JsonRpcResponse = JSON.parse(message.data as string);
|
||||
|
||||
return isUndefined(response.method)
|
||||
? this.onSocketMessageResult(response)
|
||||
: this.onSocketMessageSubscribe(response);
|
||||
? this.#onSocketMessageResult(response)
|
||||
: this.#onSocketMessageSubscribe(response);
|
||||
}
|
||||
|
||||
private onSocketMessageResult = (response: JsonRpcResponse): void => {
|
||||
const handler = this.handlers[response.id];
|
||||
#onSocketMessageResult = (response: JsonRpcResponse): void => {
|
||||
const handler = this.#handlers[response.id];
|
||||
|
||||
if (!handler) {
|
||||
l.debug((): string => `Unable to find handler for id=${response.id}`);
|
||||
@@ -309,7 +305,7 @@ export default class WsProvider implements WSProviderInterface {
|
||||
|
||||
try {
|
||||
const { method, params, subscription } = handler;
|
||||
const result = this.coder.decodeResponse(response);
|
||||
const result = this.#coder.decodeResponse(response);
|
||||
|
||||
// first send the result - in case of subs, we may have an update
|
||||
// immediately if we have some queued results already
|
||||
@@ -318,42 +314,42 @@ export default class WsProvider implements WSProviderInterface {
|
||||
if (subscription) {
|
||||
const subId = `${subscription.type}::${result}`;
|
||||
|
||||
this.subscriptions[subId] = {
|
||||
this.#subscriptions[subId] = {
|
||||
...subscription,
|
||||
method,
|
||||
params
|
||||
};
|
||||
|
||||
// if we have a result waiting for this subscription already
|
||||
if (this.waitingForId[subId]) {
|
||||
this.onSocketMessageSubscribe(this.waitingForId[subId]);
|
||||
if (this.#waitingForId[subId]) {
|
||||
this.#onSocketMessageSubscribe(this.#waitingForId[subId]);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
handler.callback(error, undefined);
|
||||
}
|
||||
|
||||
delete this.handlers[response.id];
|
||||
delete this.#handlers[response.id];
|
||||
}
|
||||
|
||||
private onSocketMessageSubscribe = (response: JsonRpcResponse): void => {
|
||||
#onSocketMessageSubscribe = (response: JsonRpcResponse): void => {
|
||||
const method = ALIASSES[response.method as string] || response.method;
|
||||
const subId = `${method}::${response.params.subscription}`;
|
||||
const handler = this.subscriptions[subId];
|
||||
const handler = this.#subscriptions[subId];
|
||||
|
||||
if (!handler) {
|
||||
// store the JSON, we could have out-of-order subid coming in
|
||||
this.waitingForId[subId] = response;
|
||||
this.#waitingForId[subId] = response;
|
||||
|
||||
l.debug((): string => `Unable to find handler for subscription=${subId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// housekeeping
|
||||
delete this.waitingForId[subId];
|
||||
delete this.#waitingForId[subId];
|
||||
|
||||
try {
|
||||
const result = this.coder.decodeResponse(response);
|
||||
const result = this.#coder.decodeResponse(response);
|
||||
|
||||
handler.callback(null, result);
|
||||
} catch (error) {
|
||||
@@ -361,24 +357,24 @@ export default class WsProvider implements WSProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
private onSocketOpen = (): boolean => {
|
||||
assert(!isNull(this.websocket), 'WebSocket cannot be null in onOpen');
|
||||
#onSocketOpen = (): boolean => {
|
||||
assert(!isNull(this.#websocket), 'WebSocket cannot be null in onOpen');
|
||||
|
||||
l.debug((): any[] => ['connected to', this.endpoint]);
|
||||
l.debug((): any[] => ['connected to', this.#endpoint]);
|
||||
|
||||
this._isConnected = true;
|
||||
this.emit('connected');
|
||||
this.#isConnected = true;
|
||||
|
||||
this.sendQueue();
|
||||
this.resubscribe();
|
||||
this.#emit('connected');
|
||||
this.#sendQueue();
|
||||
this.#resubscribe();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private resubscribe (): void {
|
||||
const subscriptions = this.subscriptions;
|
||||
#resubscribe = (): void => {
|
||||
const subscriptions = this.#subscriptions;
|
||||
|
||||
this.subscriptions = {};
|
||||
this.#subscriptions = {};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
Object.keys(subscriptions).forEach(async (id): Promise<void> => {
|
||||
@@ -399,15 +395,15 @@ export default class WsProvider implements WSProviderInterface {
|
||||
});
|
||||
}
|
||||
|
||||
private sendQueue (): void {
|
||||
Object.keys(this.queued).forEach((id): void => {
|
||||
#sendQueue = (): void => {
|
||||
Object.keys(this.#queued).forEach((id): void => {
|
||||
try {
|
||||
// we have done the websocket check in onSocketOpen, if an issue, will catch it
|
||||
(this.websocket as WebSocket).send(
|
||||
this.queued[id]
|
||||
(this.#websocket as WebSocket).send(
|
||||
this.#queued[id]
|
||||
);
|
||||
|
||||
delete this.queued[id];
|
||||
delete this.#queued[id];
|
||||
} catch (error) {
|
||||
l.error(error);
|
||||
}
|
||||
|
||||
@@ -21,38 +21,23 @@ describe('onConnect', (): void => {
|
||||
|
||||
it('Does not connect when autoConnect is false', (): void => {
|
||||
const provider: WsProvider = new WsProvider(TEST_WS_URL, false);
|
||||
// We need to access the private WsProvider property 'websocket' here which would otherwise trigger a tslint error.
|
||||
expect((provider as any).websocket).toBeNull();
|
||||
|
||||
expect(provider.isConnected()).toBe(false);
|
||||
});
|
||||
|
||||
it('Does connect when autoConnect is true', (): void => {
|
||||
const provider: WsProvider = new WsProvider(TEST_WS_URL, true);
|
||||
|
||||
expect((provider as any).websocket).not.toBeNull();
|
||||
expect(provider.isConnected()).not.toBe(true);
|
||||
});
|
||||
|
||||
it('Creates a new WebSocket instance by calling the connect() method', (): void => {
|
||||
const provider: WsProvider = new WsProvider(TEST_WS_URL, false);
|
||||
|
||||
expect((provider as any).websocket).toBeNull();
|
||||
expect(provider.isConnected()).toBe(false);
|
||||
|
||||
provider.connect();
|
||||
|
||||
expect((provider as any).websocket).not.toBeNull();
|
||||
expect((provider as any).websocket instanceof WebSocket).toBe(true);
|
||||
});
|
||||
|
||||
it('Creates the on handlers', (): void => {
|
||||
const provider: WsProvider = new WsProvider(TEST_WS_URL);
|
||||
|
||||
expect((provider as any).websocket).not.toBeNull();
|
||||
expect((provider as any).websocket).toEqual(expect.objectContaining({
|
||||
listeners: expect.objectContaining({
|
||||
close: [expect.any(Function)],
|
||||
error: [expect.any(Function)],
|
||||
message: [expect.any(Function)],
|
||||
open: [expect.any(Function)]
|
||||
})
|
||||
}));
|
||||
expect(provider.isConnected()).not.toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import WsProvider from './';
|
||||
|
||||
describe('WsProvider', (): void => {
|
||||
let provider: WsProvider;
|
||||
|
||||
beforeEach((): void => {
|
||||
provider = new WsProvider('ws://127.0.0.1:1234', false);
|
||||
});
|
||||
|
||||
it('calls the handler when found', (done): void => {
|
||||
// We need to access the private WsProvider property 'handlers' here which otherwise trigger a tslint error..
|
||||
(provider as any).handlers[5] = {
|
||||
callback: (_: any, result: any): void => {
|
||||
expect(result).toEqual('test');
|
||||
done();
|
||||
},
|
||||
method: '',
|
||||
params: []
|
||||
};
|
||||
|
||||
// We need to access the private WsProvider property 'onSocketMessage' here which would otherwise trigger a tslint error.
|
||||
(provider as any).onSocketMessage(
|
||||
new MessageEvent('test', { data: '{"jsonrpc":"2.0","id":5,"result":"test"}' })
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright 2017-2020 @polkadot/rpc-provider authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import WsProvider from './';
|
||||
|
||||
describe('onMessageSubscribe', (): void => {
|
||||
let provider: WsProvider;
|
||||
|
||||
beforeEach((): void => {
|
||||
provider = new WsProvider('ws://127.0.0.1:1234', false);
|
||||
});
|
||||
|
||||
it('calls the subscriber with data', (done): void => {
|
||||
// We need to access the private WsProvider property 'handlers' here which otherwise triggers a tslint error..
|
||||
(provider as any).handlers[11] = {
|
||||
callback: (_: any, id: number): void => {
|
||||
expect(typeof id).toBe('number');
|
||||
},
|
||||
method: 'test',
|
||||
params: [],
|
||||
subscription: {
|
||||
callback: (_: any, result: any): void => {
|
||||
expect(result).toEqual('test');
|
||||
done();
|
||||
},
|
||||
type: 'test'
|
||||
}
|
||||
};
|
||||
|
||||
// We need to access the private WsProvider property 'onSocketMessage' here which would otherwise trigger a tslint error.
|
||||
(provider as any).onSocketMessage(new MessageEvent('test', { data: '{"jsonrpc":"2.0","id":11,"result":22}' }));
|
||||
(provider as any).onSocketMessage(new MessageEvent('test', { data: '{"jsonrpc":"2.0","method":"test","params":{"subscription":22,"result":"test"}}' }));
|
||||
});
|
||||
|
||||
it('calls the subscriber with error', (done): void => {
|
||||
// We need to access the private WsProvider property 'handlers' here which otherwise trigger a tslint error..
|
||||
(provider as any).handlers[11] = {
|
||||
callback: (_: any, id: number): void => {
|
||||
expect(typeof id).toBe('number');
|
||||
},
|
||||
method: 'test',
|
||||
params: [],
|
||||
subscription: {
|
||||
callback: (error: any): void => {
|
||||
expect(error.message).toMatch(/test/);
|
||||
done();
|
||||
},
|
||||
type: 'test'
|
||||
}
|
||||
};
|
||||
|
||||
// We need to access the private WsProvider property 'onSocketMessage' here which would otherwise trigger a tslint error.
|
||||
(provider as any).onSocketMessage(new MessageEvent('test', { data: '{"jsonrpc":"2.0","id":11,"result":22}' }));
|
||||
(provider as any).onSocketMessage(new MessageEvent('test', { data: '{"jsonrpc":"2.0","method":"test","params":{"subscription":22,"error":{"message":"test"}}}' }));
|
||||
});
|
||||
});
|
||||
@@ -39,21 +39,16 @@ describe('send', (): void => {
|
||||
});
|
||||
|
||||
it('handles internal errors', (): Promise<any> => {
|
||||
createMock([]);
|
||||
|
||||
(global as any).WebSocket = class {
|
||||
public send (): void {
|
||||
throw new Error('send error');
|
||||
createMock([{
|
||||
id: 1,
|
||||
method: 'test_body',
|
||||
reply: {
|
||||
result: 'ok'
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
provider = createWs(true);
|
||||
|
||||
// HACK this is a private method...
|
||||
(provider as any).websocket.onopen();
|
||||
|
||||
return provider
|
||||
.send('test_encoding', ['param'])
|
||||
return createWs(true)
|
||||
.send('test_encoding', [{ error: 'send error' }])
|
||||
.catch((error): void => {
|
||||
expect(error.message).toEqual('send error');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user