-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathrun-ws-json-rpc.spec.ts
More file actions
116 lines (106 loc) · 3.84 KB
/
run-ws-json-rpc.spec.ts
File metadata and controls
116 lines (106 loc) · 3.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
* JSON-RPC 2.0: WebSocket Transport Protocol Integration
*
* This test suite demonstrates JSON-RPC 2.0 protocol implementation over WebSocket transport.
* WebSocket provides bidirectional, full-duplex communication for real-time RPC operations.
* It verifies that standard JSON-RPC requests, batch operations, and error handling work
* correctly over persistent WebSocket connections.
*
* Examples include:
* - Single method invocations over WebSocket connection
* - Batch requests (multiple method calls in a single WebSocket message)
* - Error handling for MethodNotFound, InvalidParams, and ServerError
* - Type-safe RPC client usage with TypeScript
* - Connection lifecycle management and cleanup
*/
import {
ResultRpcFactoryPromise,
ErrorCodeType,
RpcError,
} from '@klerick/nestjs-json-rpc-sdk';
import {
creatWsRpcSdk,
MapperRpc,
destroySubject,
} from '../utils/run-application';
afterAll(async () => {
destroySubject.next(true);
destroySubject.complete();
});
describe('JSON-RPC 2.0 over WebSocket', () => {
let rpc: ResultRpcFactoryPromise<MapperRpc>['rpc'];
let rpcBatch: ResultRpcFactoryPromise<MapperRpc>['rpcBatch'];
let rpcForBatch: ResultRpcFactoryPromise<MapperRpc>['rpcForBatch'];
beforeEach(() => {
({ rpc, rpcBatch, rpcForBatch } = creatWsRpcSdk());
});
describe('Successful RPC Calls', () => {
it('should invoke a single RPC method and return the correct result', async () => {
const input = 1;
const result = await rpc.RpcService.someMethode(input);
expect(result).toBe(input);
});
it('should execute multiple RPC methods in a single batch request', async () => {
const input = 1;
const input2 = {
a: 1,
b: 2,
};
const call1 = rpcForBatch.RpcService.someMethode(input);
const call2 = rpcForBatch.RpcService.methodeWithObjectParams(input2);
const [result1, result2] = await rpcBatch(call1, call2);
expect(result1).toBe(input);
if ('error' in result2) {
throw Error('Return error');
}
expect(result2.d).toEqual(`${input2.a}`);
expect(result2.c).toEqual(`${input2.b}`);
});
});
describe('Error Handling', () => {
it('should return MethodNotFound error (-32601) when calling non-existent service or method', async () => {
const input = 1;
expect.assertions(6);
try {
// @ts-ignore
await rpc.IncorrectService.incorrectMethode(input);
} catch (e) {
expect(e).toBeInstanceOf(RpcError);
expect((e as RpcError).code).toBe(-32601);
expect((e as RpcError).message).toBe(ErrorCodeType.MethodNotFound);
}
try {
// @ts-ignore
await rpc.RpcService.incorrectMethode(input);
} catch (e) {
expect(e).toBeInstanceOf(RpcError);
expect((e as RpcError).code).toBe(-32601);
expect((e as RpcError).message).toBe(ErrorCodeType.MethodNotFound);
}
});
it('should return InvalidParams error (-32602) when providing incorrect parameter types', async () => {
const input = 'llll';
expect.assertions(3);
try {
// @ts-ignore
await rpc.RpcService.someMethode(input);
} catch (e) {
expect(e).toBeInstanceOf(RpcError);
expect((e as RpcError).code).toBe(-32602);
expect((e as RpcError).message).toBe(ErrorCodeType.InvalidParams);
}
});
it('should return ServerError (-32099) with custom error data when method throws an exception', async () => {
const input = 5;
expect.assertions(4);
try {
await rpc.RpcService.someMethode(input);
} catch (e) {
expect(e).toBeInstanceOf(RpcError);
expect((e as RpcError).code).toBe(-32099);
expect((e as RpcError).message).toBe(ErrorCodeType.ServerError);
expect((e as RpcError).data.title).toBe('Custom Error');
}
});
});
});