-
Notifications
You must be signed in to change notification settings - Fork 368
/
publisher.client.unit.test.ts
110 lines (89 loc) · 3.53 KB
/
publisher.client.unit.test.ts
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
import { describe, it, expect, vi, beforeEach } from 'vitest';
import type { WebSocketClientId } from './publisher.client';
import { Publisher } from './publisher.client';
import type { WebSocket } from 'ws';
import * as uuid from 'uuid';
const mockWebsocket = () => {
const mock = {} as any;
mock.send = vi.fn();
return mock as WebSocket;
};
const mockRes = ({ status }: { status: number }) => {
const mock = {} as any;
mock.status = () => status;
mock.set = vi.fn();
mock.send = vi.fn();
return mock;
};
class MockRedis {
// Caveat: only one subscription per channel is supported
private subscriptions = new Map<string, (message: string, channel: string) => void>();
public async publish(channel: string, message: string) {
const onMessage = this.subscriptions.get(channel);
if (onMessage) {
onMessage(message, channel);
}
return true;
}
public async subscribe(channel: string, onMessage: (message: string, channel: string) => void) {
this.subscriptions.set(channel, onMessage);
return true;
}
public async unsubscribe(channel: string) {
this.subscriptions.delete(channel);
return true;
}
}
const mockRedis = new MockRedis() as any;
describe('Publisher', () => {
let publisher1: Publisher;
let publisher2: Publisher;
let wsClientId: WebSocketClientId;
let ws: WebSocket;
beforeEach(() => {
publisher1 = new Publisher(mockRedis);
publisher2 = new Publisher(mockRedis);
wsClientId = uuid.v4();
ws = mockWebsocket();
});
it('knowns about the websocket connection', async () => {
const res = mockRes({ status: 200 });
vi.spyOn(publisher1, 'unsubscribe');
vi.spyOn(publisher2, 'unsubscribe');
await publisher1.subscribe(ws, wsClientId);
expect(ws.send).toHaveBeenCalledWith(
JSON.stringify({
message_type: 'connection_ack',
ws_client_id: wsClientId
})
);
await publisher1.notifySuccess(res, wsClientId, 'provider-key', 'connection-id');
expect(ws.send).toHaveBeenCalledWith(
JSON.stringify({
message_type: 'success',
provider_config_key: 'provider-key',
connection_id: 'connection-id',
is_pending: false
})
);
expect(ws.send).toHaveBeenCalledTimes(2); // connection_ack + success
expect(publisher1.unsubscribe).toHaveBeenCalledTimes(1);
expect(publisher2.unsubscribe).toHaveBeenCalledTimes(0);
});
it('does not known about the websocket connection', async () => {
const res = mockRes({ status: 200 });
vi.spyOn(publisher1, 'unsubscribe');
await publisher1.subscribe(ws, wsClientId);
await publisher2.notifySuccess(res, wsClientId, 'provider-key', 'connection-id'); // publisher2 does not know about the websocket connection
expect(ws.send).toHaveBeenCalledTimes(2); // connection_ack + success
expect(publisher1.unsubscribe).toHaveBeenCalledTimes(1);
});
it('notifies of an error', async () => {
const res = mockRes({ status: 500 });
vi.spyOn(publisher1, 'unsubscribe');
await publisher1.subscribe(ws, wsClientId);
await publisher1.notifyErr(res, wsClientId, 'provider-key', 'connection-id', {} as any);
expect(ws.send).toHaveBeenCalledTimes(2); // connection_ack + error
expect(publisher1.unsubscribe).toHaveBeenCalledTimes(1);
});
});