matterbridge-roborock-vacuum-plugin 1.0.8-rc09 → 1.1.0-rc02

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,333 @@
1
+ import { MQTTClient } from '../../../../roborockCommunication/broadcast/client/MQTTClient';
2
+
3
+ // Pseudocode plan:
4
+ // 1. Mock dependencies: mqtt, CryptoUtils, AbstractClient, serializer, deserializer, logger, connectionListeners, messageListeners.
5
+ // 2. Test constructor: verify username/password are generated as expected.
6
+ // 3. Test connect():
7
+ // - Should call mqtt.connect with correct params.
8
+ // - Should set up event listeners.
9
+ // - Should not connect if already connected.
10
+ // 4. Test disconnect():
11
+ // - Should call client.end if connected.
12
+ // - Should not call if not connected.
13
+ // - Should log error if exception thrown.
14
+ // 5. Test send():
15
+ // - Should publish correct topic/message if connected.
16
+ // - Should log error if not connected.
17
+ // 6. Test onConnect():
18
+ // - Should set connected, call onConnected, subscribeToQueue.
19
+ // 7. Test subscribeToQueue():
20
+ // - Should call client.subscribe with correct topic.
21
+ // 8. Test onSubscribe():
22
+ // - Should log error and call onDisconnected if error.
23
+ // - Should do nothing if no error.
24
+ // 9. Test onDisconnect():
25
+ // - Should call onDisconnected.
26
+ // 10. Test onError():
27
+ // - Should log error, set connected false, call onError.
28
+ // 11. Test onReconnect():
29
+ // - Should call subscribeToQueue.
30
+ // 12. Test onMessage():
31
+ // - Should call deserializer and messageListeners.onMessage if message.
32
+ // - Should log notice if message is falsy.
33
+ // - Should log error if deserializer throws.
34
+
35
+ const mockConnect = jest.fn();
36
+ jest.mock('mqtt', () => {
37
+ const actual = jest.requireActual('mqtt');
38
+ return {
39
+ ...actual,
40
+ connect: mockConnect,
41
+ };
42
+ });
43
+
44
+ describe('MQTTClient', () => {
45
+ let logger: any;
46
+ let context: any;
47
+ let userdata: any;
48
+ let client: any;
49
+ let serializer: any;
50
+ let deserializer: any;
51
+ let connectionListeners: any;
52
+ let messageListeners: any;
53
+
54
+ beforeEach(() => {
55
+ logger = { error: jest.fn(), debug: jest.fn(), notice: jest.fn() };
56
+ context = {};
57
+ userdata = {
58
+ rriot: {
59
+ u: 'user',
60
+ k: 'key',
61
+ s: 'secret',
62
+ r: { m: 'mqtt://broker' },
63
+ },
64
+ };
65
+ serializer = { serialize: jest.fn(() => ({ buffer: Buffer.from('msg') })) };
66
+ deserializer = { deserialize: jest.fn(() => 'deserialized') };
67
+ connectionListeners = {
68
+ onConnected: jest.fn().mockResolvedValue(undefined),
69
+ onDisconnected: jest.fn().mockResolvedValue(undefined),
70
+ onError: jest.fn().mockResolvedValue(undefined),
71
+ };
72
+ messageListeners = { onMessage: jest.fn().mockResolvedValue(undefined) };
73
+
74
+ // Mock mqtt client instance
75
+ client = {
76
+ on: jest.fn(),
77
+ end: jest.fn(),
78
+ publish: jest.fn(),
79
+ subscribe: jest.fn(),
80
+ };
81
+ mockConnect.mockReturnValue(client);
82
+ });
83
+
84
+ function createMQTTClient() {
85
+ // Pass dependencies via constructor if possible, or use a factory/mockable subclass for testing
86
+ class TestMQTTClient extends MQTTClient {
87
+ constructor() {
88
+ super(logger, context, userdata);
89
+ (this as any).serializer = serializer;
90
+ (this as any).deserializer = deserializer;
91
+ (this as any).connectionListeners = connectionListeners;
92
+ (this as any).messageListeners = messageListeners;
93
+ }
94
+ }
95
+ return new TestMQTTClient();
96
+ }
97
+
98
+ afterEach(() => {
99
+ jest.clearAllMocks();
100
+ });
101
+
102
+ it('should generate username and password in constructor', () => {
103
+ const mqttClient = createMQTTClient();
104
+ expect(mqttClient['mqttUsername']).toBe('c6d6afb9');
105
+ expect(mqttClient['mqttPassword']).toBe('938f62d6603bde9c');
106
+ });
107
+
108
+ it('should not connect if already connected', () => {
109
+ const mqttClient = createMQTTClient();
110
+ mqttClient['client'] = client;
111
+ mqttClient.connect();
112
+ expect(mockConnect).not.toHaveBeenCalled();
113
+ });
114
+
115
+ it('should disconnect if connected', async () => {
116
+ const mqttClient = createMQTTClient();
117
+ mqttClient['client'] = client;
118
+ mqttClient['connected'] = true;
119
+ await mqttClient.disconnect();
120
+ expect(client.end).toHaveBeenCalled();
121
+ });
122
+
123
+ it('should not disconnect if not connected', async () => {
124
+ const mqttClient = createMQTTClient();
125
+ mqttClient['client'] = undefined;
126
+ mqttClient['connected'] = false;
127
+ await mqttClient.disconnect();
128
+ expect(client.end).not.toHaveBeenCalled();
129
+ });
130
+
131
+ it('should log error if disconnect throws', async () => {
132
+ const mqttClient = createMQTTClient();
133
+ mqttClient['client'] = {
134
+ end: jest.fn(() => {
135
+ throw new Error('fail');
136
+ }),
137
+ on: jest.fn(),
138
+ publish: jest.fn(),
139
+ subscribe: jest.fn(),
140
+ connected: true,
141
+ disconnecting: false,
142
+ disconnected: false,
143
+ reconnecting: false,
144
+ options: {},
145
+ removeListener: jest.fn(),
146
+ removeAllListeners: jest.fn(),
147
+ addListener: jest.fn(),
148
+ emit: jest.fn(),
149
+ eventNames: jest.fn(),
150
+ getMaxListeners: jest.fn(),
151
+ listenerCount: jest.fn(),
152
+ listeners: jest.fn(),
153
+ off: jest.fn(),
154
+ once: jest.fn(),
155
+ prependListener: jest.fn(),
156
+ prependOnceListener: jest.fn(),
157
+ rawListeners: jest.fn(),
158
+ setMaxListeners: jest.fn(),
159
+ handleMessage: jest.fn(),
160
+ subscribeAsync: jest.fn(),
161
+ unsubscribe: jest.fn(),
162
+ unsubscribeAsync: jest.fn(),
163
+ publishAsync: jest.fn(),
164
+ reconnect: jest.fn(),
165
+ destroy: jest.fn(),
166
+ removeOutgoingMessage: jest.fn(),
167
+ connectedTime: 0,
168
+ disconnect: jest.fn(),
169
+ stream: {} as any,
170
+ messageIdToTopic: {},
171
+ outgoingStore: {} as any,
172
+ incomingStore: {} as any,
173
+ queueQoSZero: jest.fn(),
174
+ _resubscribeTopics: {},
175
+ _resubscribeTopicsList: [],
176
+ _resubscribeTopicsMap: {},
177
+ _resubscribeTopicsTimer: null,
178
+ _resubscribeTopicsTimeout: 0,
179
+ _resubscribeTopicsInProgress: false,
180
+ _resubscribeTopicsCallback: jest.fn(),
181
+ _resubscribeTopicsError: null,
182
+ _resubscribeTopicsErrorCallback: jest.fn(),
183
+ _resubscribeTopicsErrorTimer: null,
184
+ _resubscribeTopicsErrorTimeout: 0,
185
+ _resubscribeTopicsErrorInProgress: false,
186
+ _resubscribeTopicsErrorCallback2: jest.fn(),
187
+ _resubscribeTopicsError2: null,
188
+ _resubscribeTopicsErrorTimer2: null,
189
+ _resubscribeTopicsErrorTimeout2: 0,
190
+ _resubscribeTopicsErrorInProgress2: false,
191
+ _resubscribeTopicsErrorCallback3: jest.fn(),
192
+ _resubscribeTopicsError3: null,
193
+ _resubscribeTopicsErrorTimer3: null,
194
+ _resubscribeTopicsErrorTimeout3: 0,
195
+ _resubscribeTopicsErrorInProgress3: false,
196
+ _resubscribeTopicsErrorCallback4: jest.fn(),
197
+ _resubscribeTopicsError4: null,
198
+ _resubscribeTopicsErrorTimer4: null,
199
+ _resubscribeTopicsErrorTimeout4: 0,
200
+ _resubscribeTopicsErrorInProgress4: false,
201
+ _resubscribeTopicsErrorCallback5: jest.fn(),
202
+ _resubscribeTopicsError5: null,
203
+ _resubscribeTopicsErrorTimer5: null,
204
+ _resubscribeTopicsErrorTimeout5: 0,
205
+ _resubscribeTopicsErrorInProgress5: false,
206
+ _resubscribeTopicsErrorCallback6: jest.fn(),
207
+ _resubscribeTopicsError6: null,
208
+ _resubscribeTopicsErrorTimer6: null,
209
+ _resubscribeTopicsErrorTimeout6: 0,
210
+ _resubscribeTopicsErrorInProgress6: false,
211
+ _resubscribeTopicsErrorCallback7: jest.fn(),
212
+ _resubscribeTopicsError7: null,
213
+ _resubscribeTopicsErrorTimer7: null,
214
+ _resubscribeTopicsErrorTimeout7: 0,
215
+ _resubscribeTopicsErrorInProgress7: false,
216
+ _resubscribeTopicsErrorCallback8: jest.fn(),
217
+ _resubscribeTopicsError8: null,
218
+ _resubscribeTopicsErrorTimer8: null,
219
+ _resubscribeTopicsErrorTimeout8: 0,
220
+ _resubscribeTopicsErrorInProgress8: false,
221
+ _resubscribeTopicsErrorCallback9: jest.fn(),
222
+ _resubscribeTopicsError9: null,
223
+ _resubscribeTopicsErrorTimer9: null,
224
+ _resubscribeTopicsErrorTimeout9: 0,
225
+ _resubscribeTopicsErrorInProgress9: false,
226
+ _resubscribeTopicsErrorCallback10: jest.fn(),
227
+ _resubscribeTopicsError10: null,
228
+ _resubscribeTopicsErrorTimer10: null,
229
+ _resubscribeTopicsErrorTimeout10: 0,
230
+ _resubscribeTopicsErrorInProgress10: false,
231
+ // Add more properties as needed for your codebase or use a proper mock library
232
+ } as any;
233
+ mqttClient['connected'] = true;
234
+ await mqttClient.disconnect();
235
+ expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('MQTT client failed to disconnect'));
236
+ });
237
+
238
+ it('should publish message if connected', async () => {
239
+ const mqttClient = createMQTTClient();
240
+ mqttClient['client'] = client;
241
+ mqttClient['connected'] = true;
242
+ const request = { toMqttRequest: jest.fn(() => 'req') };
243
+ await mqttClient.send('duid1', request as any);
244
+ expect(serializer.serialize).toHaveBeenCalledWith('duid1', 'req');
245
+ expect(client.publish).toHaveBeenCalledWith('rr/m/i/user/c6d6afb9/duid1', Buffer.from('msg'), { qos: 1 });
246
+ });
247
+
248
+ it('should log error if send called when not connected', async () => {
249
+ const mqttClient = createMQTTClient();
250
+ mqttClient['client'] = undefined;
251
+ mqttClient['connected'] = false;
252
+ const request = { toMqttRequest: jest.fn() };
253
+ await mqttClient.send('duid1', request as any);
254
+ expect(logger.error).toHaveBeenCalled();
255
+ expect(client.publish).not.toHaveBeenCalled();
256
+ });
257
+
258
+ it('onConnect should set connected, call onConnected, and subscribeToQueue', async () => {
259
+ const mqttClient = createMQTTClient();
260
+ mqttClient['client'] = client;
261
+ mqttClient['subscribeToQueue'] = jest.fn();
262
+ await mqttClient['onConnect']({} as any);
263
+ expect(mqttClient['connected']).toBe(true);
264
+ expect(connectionListeners.onConnected).toHaveBeenCalled();
265
+ expect(mqttClient['subscribeToQueue']).toHaveBeenCalled();
266
+ });
267
+
268
+ it('subscribeToQueue should call client.subscribe with correct topic', () => {
269
+ const mqttClient = createMQTTClient();
270
+ mqttClient['client'] = client;
271
+ mqttClient['subscribeToQueue']();
272
+ expect(client.subscribe).toHaveBeenCalledWith('rr/m/o/user/c6d6afb9/#', expect.any(Function));
273
+ });
274
+
275
+ it('onSubscribe should log error and call onDisconnected if error', async () => {
276
+ const mqttClient = createMQTTClient();
277
+ await mqttClient['onSubscribe'](new Error('fail'));
278
+ expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('failed to subscribe'));
279
+ expect(mqttClient['connected']).toBe(false);
280
+ expect(connectionListeners.onDisconnected).toHaveBeenCalled();
281
+ });
282
+
283
+ it('onSubscribe should do nothing if no error', async () => {
284
+ const mqttClient = createMQTTClient();
285
+ await mqttClient['onSubscribe'](null);
286
+ expect(logger.error).not.toHaveBeenCalled();
287
+ expect(connectionListeners.onDisconnected).not.toHaveBeenCalled();
288
+ });
289
+
290
+ it('onDisconnect should call onDisconnected', async () => {
291
+ const mqttClient = createMQTTClient();
292
+ await mqttClient['onDisconnect']();
293
+ expect(connectionListeners.onDisconnected).toHaveBeenCalled();
294
+ });
295
+
296
+ it('onError should log error, set connected false, and call onError', async () => {
297
+ const mqttClient = createMQTTClient();
298
+ mqttClient['connected'] = true;
299
+ await mqttClient['onError'](new Error('fail'));
300
+ expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('MQTT connection error'));
301
+ expect(mqttClient['connected']).toBe(false);
302
+ expect(connectionListeners.onError).toHaveBeenCalledWith(expect.stringContaining('fail'));
303
+ });
304
+
305
+ it('onReconnect should call subscribeToQueue', () => {
306
+ const mqttClient = createMQTTClient();
307
+ mqttClient['subscribeToQueue'] = jest.fn();
308
+ mqttClient['onReconnect']();
309
+ expect(mqttClient['subscribeToQueue']).toHaveBeenCalled();
310
+ });
311
+
312
+ it('onMessage should call deserializer and messageListeners.onMessage if message', async () => {
313
+ const mqttClient = createMQTTClient();
314
+ await mqttClient['onMessage']('rr/m/o/user/c6d6afb9/duid1', Buffer.from('msg'));
315
+ expect(deserializer.deserialize).toHaveBeenCalledWith('duid1', Buffer.from('msg'));
316
+ expect(messageListeners.onMessage).toHaveBeenCalledWith('deserialized');
317
+ });
318
+
319
+ it('onMessage should log notice if message is falsy', async () => {
320
+ const mqttClient = createMQTTClient();
321
+ await mqttClient['onMessage']('topic', null as any);
322
+ expect(logger.notice).toHaveBeenCalledWith(expect.stringContaining('received empty message'));
323
+ });
324
+
325
+ it('onMessage should log error if deserializer throws', async () => {
326
+ const mqttClient = createMQTTClient();
327
+ deserializer.deserialize.mockImplementation(() => {
328
+ throw new Error('fail');
329
+ });
330
+ await mqttClient['onMessage']('topic/duid', Buffer.from('msg'));
331
+ expect(logger.error).toHaveBeenCalledWith(expect.stringContaining('unable to process message'));
332
+ });
333
+ });
@@ -0,0 +1,59 @@
1
+ import { ChainedConnectionListener } from '../../../../../roborockCommunication/broadcast/listener/implementation/chainedConnectionListener';
2
+
3
+ describe('ChainedConnectionListener', () => {
4
+ let chained: ChainedConnectionListener;
5
+ let listener1: any;
6
+ let listener2: any;
7
+
8
+ beforeEach(() => {
9
+ chained = new ChainedConnectionListener();
10
+ listener1 = {
11
+ onConnected: jest.fn().mockResolvedValue(undefined),
12
+ onDisconnected: jest.fn().mockResolvedValue(undefined),
13
+ onError: jest.fn().mockResolvedValue(undefined),
14
+ };
15
+ listener2 = {
16
+ onConnected: jest.fn().mockResolvedValue(undefined),
17
+ onDisconnected: jest.fn().mockResolvedValue(undefined),
18
+ onError: jest.fn().mockResolvedValue(undefined),
19
+ };
20
+ });
21
+
22
+ it('should register listeners', () => {
23
+ chained.register(listener1);
24
+ chained.register(listener2);
25
+
26
+ // @ts-expect-error Accessing private property for testing
27
+ expect(chained.listeners).toEqual([listener1, listener2]);
28
+ });
29
+
30
+ it('should call onConnected on all listeners', async () => {
31
+ chained.register(listener1);
32
+ chained.register(listener2);
33
+ await chained.onConnected();
34
+ expect(listener1.onConnected).toHaveBeenCalled();
35
+ expect(listener2.onConnected).toHaveBeenCalled();
36
+ });
37
+
38
+ it('should call onDisconnected on all listeners', async () => {
39
+ chained.register(listener1);
40
+ chained.register(listener2);
41
+ await chained.onDisconnected();
42
+ expect(listener1.onDisconnected).toHaveBeenCalled();
43
+ expect(listener2.onDisconnected).toHaveBeenCalled();
44
+ });
45
+
46
+ it('should call onError on all listeners with the same message', async () => {
47
+ chained.register(listener1);
48
+ chained.register(listener2);
49
+ await chained.onError('error message');
50
+ expect(listener1.onError).toHaveBeenCalledWith('error message');
51
+ expect(listener2.onError).toHaveBeenCalledWith('error message');
52
+ });
53
+
54
+ it('should work with no listeners registered', async () => {
55
+ await expect(chained.onConnected()).resolves.toBeUndefined();
56
+ await expect(chained.onDisconnected()).resolves.toBeUndefined();
57
+ await expect(chained.onError('msg')).resolves.toBeUndefined();
58
+ });
59
+ });
@@ -0,0 +1,46 @@
1
+ import { ChainedMessageListener } from '../../../../../roborockCommunication/broadcast/listener/implementation/chainedMessageListener';
2
+ import { AbstractMessageListener } from '../../../../../roborockCommunication/broadcast/listener/abstractMessageListener';
3
+
4
+ describe('ChainedMessageListener', () => {
5
+ let chained: ChainedMessageListener;
6
+ let listener1: jest.Mocked<AbstractMessageListener>;
7
+ let listener2: jest.Mocked<AbstractMessageListener>;
8
+ const message = { foo: 'bar' } as any;
9
+
10
+ beforeEach(() => {
11
+ chained = new ChainedMessageListener();
12
+ listener1 = { onMessage: jest.fn().mockResolvedValue(undefined) } as any;
13
+ listener2 = { onMessage: jest.fn().mockResolvedValue(undefined) } as any;
14
+ });
15
+
16
+ it('should call onMessage on all registered listeners', async () => {
17
+ chained.register(listener1);
18
+ chained.register(listener2);
19
+
20
+ await chained.onMessage(message);
21
+
22
+ expect(listener1.onMessage).toHaveBeenCalledWith(message);
23
+ expect(listener2.onMessage).toHaveBeenCalledWith(message);
24
+ });
25
+
26
+ it('should not fail if no listeners registered', async () => {
27
+ await expect(chained.onMessage(message)).resolves.toBeUndefined();
28
+ });
29
+
30
+ it('should call listeners in order', async () => {
31
+ const callOrder: string[] = [];
32
+ listener1.onMessage.mockImplementation(async () => {
33
+ callOrder.push('first');
34
+ });
35
+ listener2.onMessage.mockImplementation(async () => {
36
+ callOrder.push('second');
37
+ });
38
+
39
+ chained.register(listener1);
40
+ chained.register(listener2);
41
+
42
+ await chained.onMessage(message);
43
+
44
+ expect(callOrder).toEqual(['first', 'second']);
45
+ });
46
+ });
@@ -0,0 +1,71 @@
1
+ import { SimpleMessageListener } from '../../../../../roborockCommunication/broadcast/listener/implementation/simpleMessageListener';
2
+ import { Protocol } from '../../../../../roborockCommunication/broadcast/model/protocol';
3
+
4
+ describe('SimpleMessageListener', () => {
5
+ let listener: SimpleMessageListener;
6
+ let handler: any;
7
+ let message: any;
8
+
9
+ beforeEach(() => {
10
+ listener = new SimpleMessageListener();
11
+ handler = {
12
+ onStatusChanged: jest.fn().mockResolvedValue(undefined),
13
+ onError: jest.fn().mockResolvedValue(undefined),
14
+ onBatteryUpdate: jest.fn().mockResolvedValue(undefined),
15
+ onAdditionalProps: jest.fn().mockResolvedValue(undefined),
16
+ };
17
+ message = {
18
+ contain: jest.fn(),
19
+ get: jest.fn(),
20
+ };
21
+ listener.registerListener(handler);
22
+ });
23
+
24
+ it('should do nothing if no handler registered', async () => {
25
+ const l = new SimpleMessageListener();
26
+ await expect(l.onMessage(message)).resolves.toBeUndefined();
27
+ });
28
+
29
+ it('should do nothing if message is rpc_response or map_response', async () => {
30
+ message.contain.mockImplementation((proto: Protocol) => proto === Protocol.rpc_response || proto === Protocol.map_response);
31
+ await listener.onMessage(message);
32
+ expect(handler.onStatusChanged).not.toHaveBeenCalled();
33
+ expect(handler.onError).not.toHaveBeenCalled();
34
+ expect(handler.onBatteryUpdate).not.toHaveBeenCalled();
35
+ expect(handler.onAdditionalProps).not.toHaveBeenCalled();
36
+ });
37
+
38
+ it('should call onStatusChanged if status_update present', async () => {
39
+ message.contain.mockImplementation((proto: Protocol) => proto === Protocol.status_update);
40
+ await listener.onMessage(message);
41
+ expect(handler.onStatusChanged).toHaveBeenCalled();
42
+ });
43
+
44
+ it('should call onError if error present', async () => {
45
+ message.contain.mockImplementation((proto: Protocol) => proto === Protocol.error);
46
+ message.get.mockReturnValue('42');
47
+ await listener.onMessage(message);
48
+ expect(handler.onError).toHaveBeenCalledWith(42);
49
+ });
50
+
51
+ it('should call onBatteryUpdate if battery present', async () => {
52
+ message.contain.mockImplementation((proto: Protocol) => proto === Protocol.battery);
53
+ message.get.mockReturnValue('77');
54
+ await listener.onMessage(message);
55
+ expect(handler.onBatteryUpdate).toHaveBeenCalledWith(77);
56
+ });
57
+
58
+ it('should call onAdditionalProps if additional_props present', async () => {
59
+ message.contain.mockImplementation((proto: Protocol) => proto === Protocol.additional_props);
60
+ message.get.mockReturnValue('99');
61
+ await listener.onMessage(message);
62
+ expect(handler.onAdditionalProps).toHaveBeenCalledWith(99);
63
+ });
64
+
65
+ it('should not call handler methods if they are undefined', async () => {
66
+ const handlerPartial = {};
67
+ listener.registerListener(handlerPartial as any);
68
+ message.contain.mockReturnValue(true);
69
+ await expect(listener.onMessage(message)).resolves.toBeUndefined();
70
+ });
71
+ });
@@ -0,0 +1,85 @@
1
+ import { SyncMessageListener } from '../../../../../roborockCommunication/broadcast/listener/implementation/syncMessageListener';
2
+ import { Protocol } from '../../../../../roborockCommunication/broadcast/model/protocol';
3
+
4
+ describe('SyncMessageListener', () => {
5
+ let listener: SyncMessageListener;
6
+ let logger: any;
7
+
8
+ beforeEach(() => {
9
+ logger = { info: jest.fn(), error: jest.fn(), debug: jest.fn(), warn: jest.fn() };
10
+ listener = new SyncMessageListener(logger);
11
+ jest.useFakeTimers();
12
+ });
13
+
14
+ afterEach(() => {
15
+ jest.clearAllTimers();
16
+ jest.useRealTimers();
17
+ });
18
+
19
+ it('should call resolve and remove pending on rpc_response', async () => {
20
+ const resolve = jest.fn();
21
+ const reject = jest.fn();
22
+ const messageId = 123;
23
+ listener.waitFor(messageId, resolve, reject);
24
+
25
+ const dps = { id: messageId, result: { foo: 'bar' } };
26
+ const message = {
27
+ contain: (proto: Protocol) => proto === Protocol.rpc_response,
28
+ get: () => dps,
29
+ } as any;
30
+
31
+ await listener.onMessage(message);
32
+
33
+ expect(resolve).toHaveBeenCalledWith(dps.result);
34
+ expect(listener['pending'].has(messageId)).toBe(false);
35
+ });
36
+
37
+ it('should not call resolve if result is ["ok"]', async () => {
38
+ const resolve = jest.fn();
39
+ const reject = jest.fn();
40
+ const messageId = 456;
41
+ listener.waitFor(messageId, resolve, reject);
42
+
43
+ const dps = { id: messageId, result: ['ok'] };
44
+ const message = {
45
+ contain: (proto: Protocol) => proto === Protocol.rpc_response,
46
+ get: () => dps,
47
+ } as any;
48
+
49
+ await listener.onMessage(message);
50
+
51
+ expect(resolve).not.toHaveBeenCalled();
52
+ expect(listener['pending'].has(messageId)).toBe(true);
53
+ });
54
+
55
+ it('should remove pending on map_response', async () => {
56
+ const resolve = jest.fn();
57
+ const reject = jest.fn();
58
+ const messageId = 789;
59
+ listener.waitFor(messageId, resolve, reject);
60
+
61
+ const dps = { id: messageId };
62
+ const message = {
63
+ contain: (proto: Protocol) => proto === Protocol.map_response,
64
+ get: () => dps,
65
+ } as any;
66
+
67
+ await listener.onMessage(message);
68
+
69
+ expect(listener['pending'].has(messageId)).toBe(false);
70
+ });
71
+
72
+ it('should call reject after timeout if not resolved', () => {
73
+ const resolve = jest.fn();
74
+ const reject = jest.fn();
75
+ const messageId = 321;
76
+ listener.waitFor(messageId, resolve, reject);
77
+
78
+ expect(listener['pending'].has(messageId)).toBe(true);
79
+
80
+ jest.advanceTimersByTime(10000);
81
+
82
+ expect(reject).toHaveBeenCalled();
83
+ expect(listener['pending'].has(messageId)).toBe(false);
84
+ });
85
+ });
@@ -11,5 +11,11 @@
11
11
  "**/*.spec.ts",
12
12
  "**/*.test.ts",
13
13
  "**/__test__/*"
14
+ ],
15
+ "exclude": [
16
+ "node_modules",
17
+ "dist",
18
+ "build",
19
+ "coverage",
14
20
  ]
15
21
  }