cojson-transport-ws 0.8.12 → 0.8.16

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.
@@ -1,463 +1,459 @@
1
- import { describe, test, expect, vi, Mocked } from "vitest";
2
- import {
3
- BUFFER_LIMIT,
4
- BUFFER_LIMIT_POLLING_INTERVAL,
5
- createWebSocketPeer,
6
- CreateWebSocketPeerOpts,
7
- } from "../index.js";
8
- import { AnyWebSocket } from "../types.js";
9
1
  import { SyncMessage } from "cojson";
10
2
  import { Channel } from "cojson/src/streamUtils.ts";
3
+ import { Mocked, describe, expect, test, vi } from "vitest";
11
4
  import { MAX_OUTGOING_MESSAGES_CHUNK_BYTES } from "../BatchedOutgoingMessages.js";
5
+ import {
6
+ BUFFER_LIMIT,
7
+ BUFFER_LIMIT_POLLING_INTERVAL,
8
+ CreateWebSocketPeerOpts,
9
+ createWebSocketPeer,
10
+ } from "../index.js";
11
+ import { AnyWebSocket } from "../types.js";
12
12
 
13
13
  function setup(opts: Partial<CreateWebSocketPeerOpts> = {}) {
14
- const listeners = new Map<string, (event: MessageEvent) => void>();
15
-
16
- const mockWebSocket = {
17
- readyState: 1,
18
- addEventListener: vi.fn().mockImplementation((type, listener) => {
19
- listeners.set(type, listener);
20
- }),
21
- close: vi.fn(),
22
- send: vi.fn(),
23
- } as unknown as Mocked<AnyWebSocket>;
24
-
25
- const peer = createWebSocketPeer({
26
- id: "test-peer",
27
- websocket: mockWebSocket,
28
- role: "client",
29
- batchingByDefault: true,
30
- ...opts,
31
- });
32
-
33
- return { mockWebSocket, peer, listeners };
14
+ const listeners = new Map<string, (event: MessageEvent) => void>();
15
+
16
+ const mockWebSocket = {
17
+ readyState: 1,
18
+ addEventListener: vi.fn().mockImplementation((type, listener) => {
19
+ listeners.set(type, listener);
20
+ }),
21
+ removeEventListener: vi.fn().mockImplementation((type) => {
22
+ listeners.delete(type);
23
+ }),
24
+ close: vi.fn(),
25
+ send: vi.fn(),
26
+ } as unknown as Mocked<AnyWebSocket>;
27
+
28
+ const peer = createWebSocketPeer({
29
+ id: "test-peer",
30
+ websocket: mockWebSocket,
31
+ role: "client",
32
+ batchingByDefault: true,
33
+ ...opts,
34
+ });
35
+
36
+ return { mockWebSocket, peer, listeners };
34
37
  }
35
38
 
36
39
  function serializeMessages(messages: SyncMessage[]) {
37
- return messages.map((msg) => JSON.stringify(msg)).join("\n");
40
+ return messages.map((msg) => JSON.stringify(msg)).join("\n");
38
41
  }
39
42
 
40
43
  describe("createWebSocketPeer", () => {
41
- test("should create a peer with correct properties", () => {
42
- const { peer } = setup();
43
-
44
- expect(peer).toHaveProperty("id", "test-peer");
45
- expect(peer).toHaveProperty("incoming");
46
- expect(peer).toHaveProperty("outgoing");
47
- expect(peer).toHaveProperty("role", "client");
48
- expect(peer).toHaveProperty("crashOnClose", false);
44
+ test("should create a peer with correct properties", () => {
45
+ const { peer } = setup();
46
+
47
+ expect(peer).toHaveProperty("id", "test-peer");
48
+ expect(peer).toHaveProperty("incoming");
49
+ expect(peer).toHaveProperty("outgoing");
50
+ expect(peer).toHaveProperty("role", "client");
51
+ expect(peer).toHaveProperty("crashOnClose", false);
52
+ });
53
+
54
+ test("should handle disconnection", async () => {
55
+ expect.assertions(1);
56
+
57
+ const { listeners, peer } = setup();
58
+
59
+ const incoming = peer.incoming as Channel<
60
+ SyncMessage | "Disconnected" | "PingTimeout"
61
+ >;
62
+ const pushSpy = vi.spyOn(incoming, "push");
63
+
64
+ const closeHandler = listeners.get("close");
65
+
66
+ closeHandler?.(new MessageEvent("close"));
67
+
68
+ expect(pushSpy).toHaveBeenCalledWith("Disconnected");
69
+ });
70
+
71
+ test("should handle ping timeout", async () => {
72
+ vi.useFakeTimers();
73
+ const { listeners, peer } = setup();
74
+
75
+ const incoming = peer.incoming as Channel<
76
+ SyncMessage | "Disconnected" | "PingTimeout"
77
+ >;
78
+ const pushSpy = vi.spyOn(incoming, "push");
79
+
80
+ const messageHandler = listeners.get("message");
81
+
82
+ messageHandler?.(new MessageEvent("message", { data: "{}" }));
83
+
84
+ await vi.advanceTimersByTimeAsync(10_000);
85
+
86
+ expect(pushSpy).toHaveBeenCalledWith("PingTimeout");
87
+
88
+ vi.useRealTimers();
89
+ });
90
+
91
+ test("should send outgoing messages", async () => {
92
+ const { peer, mockWebSocket } = setup();
93
+
94
+ const testMessage: SyncMessage = {
95
+ action: "known",
96
+ id: "co_ztest",
97
+ header: false,
98
+ sessions: {},
99
+ };
100
+ const promise = peer.outgoing.push(testMessage);
101
+
102
+ await waitFor(() => {
103
+ expect(mockWebSocket.send).toHaveBeenCalledWith(
104
+ JSON.stringify(testMessage),
105
+ );
49
106
  });
50
107
 
51
- test("should handle disconnection", async () => {
52
- expect.assertions(1);
108
+ await expect(promise).resolves.toBeUndefined();
109
+ });
110
+
111
+ test("should stop sending messages when the websocket is closed", async () => {
112
+ const { peer, mockWebSocket } = setup();
53
113
 
54
- const { listeners, peer } = setup();
114
+ mockWebSocket.send.mockImplementation(() => {
115
+ mockWebSocket.readyState = 0;
116
+ });
55
117
 
56
- const incoming = peer.incoming as Channel<
57
- SyncMessage | "Disconnected" | "PingTimeout"
58
- >;
59
- const pushSpy = vi.spyOn(incoming, "push");
118
+ const message1: SyncMessage = {
119
+ action: "known",
120
+ id: "co_ztest",
121
+ header: false,
122
+ sessions: {},
123
+ };
60
124
 
61
- const closeHandler = listeners.get("close");
125
+ const message2: SyncMessage = {
126
+ action: "content",
127
+ id: "co_zlow",
128
+ new: {},
129
+ priority: 1,
130
+ };
62
131
 
63
- closeHandler?.(new MessageEvent("close"));
132
+ void peer.outgoing.push(message1);
64
133
 
65
- expect(pushSpy).toHaveBeenCalledWith("Disconnected");
134
+ await waitFor(() => {
135
+ expect(mockWebSocket.send).toHaveBeenCalled();
66
136
  });
67
137
 
68
- test("should handle ping timeout", async () => {
69
- vi.useFakeTimers();
70
- const { listeners, peer } = setup();
138
+ expect(mockWebSocket.send).toHaveBeenCalledWith(JSON.stringify(message1));
139
+
140
+ mockWebSocket.send.mockClear();
141
+ void peer.outgoing.push(message2);
142
+
143
+ await new Promise<void>((resolve) => setTimeout(resolve, 100));
144
+
145
+ expect(mockWebSocket.send).not.toHaveBeenCalled();
146
+ });
147
+
148
+ test("should close the websocket connection", () => {
149
+ const { mockWebSocket, peer } = setup();
71
150
 
72
- const incoming = peer.incoming as Channel<
73
- SyncMessage | "Disconnected" | "PingTimeout"
74
- >;
75
- const pushSpy = vi.spyOn(incoming, "push");
151
+ peer.outgoing.close();
76
152
 
77
- const messageHandler = listeners.get("message");
153
+ expect(mockWebSocket.close).toHaveBeenCalled();
154
+ });
78
155
 
79
- messageHandler?.(new MessageEvent("message", { data: "{}" }));
156
+ describe("batchingByDefault = true", () => {
157
+ test("should batch outgoing messages", async () => {
158
+ const { peer, mockWebSocket } = setup();
80
159
 
81
- await vi.advanceTimersByTimeAsync(10_000);
160
+ mockWebSocket.send.mockImplementation(() => {
161
+ mockWebSocket.readyState = 0;
162
+ });
82
163
 
83
- expect(pushSpy).toHaveBeenCalledWith("PingTimeout");
164
+ const message1: SyncMessage = {
165
+ action: "known",
166
+ id: "co_ztest",
167
+ header: false,
168
+ sessions: {},
169
+ };
84
170
 
85
- vi.useRealTimers();
171
+ const message2: SyncMessage = {
172
+ action: "content",
173
+ id: "co_zlow",
174
+ new: {},
175
+ priority: 1,
176
+ };
177
+
178
+ void peer.outgoing.push(message1);
179
+ void peer.outgoing.push(message2);
180
+
181
+ await waitFor(() => {
182
+ expect(mockWebSocket.send).toHaveBeenCalled();
183
+ });
184
+
185
+ expect(mockWebSocket.send).toHaveBeenCalledWith(
186
+ [message1, message2].map((msg) => JSON.stringify(msg)).join("\n"),
187
+ );
86
188
  });
87
189
 
88
- test("should send outgoing messages", async () => {
89
- const { peer, mockWebSocket } = setup();
190
+ test("should send all the pending messages when the websocket is closed", async () => {
191
+ const { peer, mockWebSocket } = setup();
90
192
 
91
- const testMessage: SyncMessage = {
92
- action: "known",
93
- id: "co_ztest",
94
- header: false,
95
- sessions: {},
96
- };
97
- const promise = peer.outgoing.push(testMessage);
193
+ const message1: SyncMessage = {
194
+ action: "known",
195
+ id: "co_ztest",
196
+ header: false,
197
+ sessions: {},
198
+ };
98
199
 
99
- await waitFor(() => {
100
- expect(mockWebSocket.send).toHaveBeenCalledWith(
101
- JSON.stringify(testMessage),
102
- );
103
- });
200
+ const message2: SyncMessage = {
201
+ action: "content",
202
+ id: "co_zlow",
203
+ new: {},
204
+ priority: 1,
205
+ };
104
206
 
105
- await expect(promise).resolves.toBeUndefined();
207
+ void peer.outgoing.push(message1);
208
+ void peer.outgoing.push(message2);
209
+
210
+ peer.outgoing.close();
211
+
212
+ expect(mockWebSocket.send).toHaveBeenCalledWith(
213
+ [message1, message2].map((msg) => JSON.stringify(msg)).join("\n"),
214
+ );
106
215
  });
107
216
 
108
- test("should stop sending messages when the websocket is closed", async () => {
109
- const { peer, mockWebSocket } = setup();
217
+ test("should limit the chunk size to MAX_OUTGOING_MESSAGES_CHUNK_SIZE", async () => {
218
+ const { peer, mockWebSocket } = setup();
219
+
220
+ const message1: SyncMessage = {
221
+ action: "known",
222
+ id: "co_ztest",
223
+ header: false,
224
+ sessions: {},
225
+ };
226
+ const message2: SyncMessage = {
227
+ action: "content",
228
+ id: "co_zlow",
229
+ new: {},
230
+ priority: 1,
231
+ };
232
+
233
+ const stream: SyncMessage[] = [];
234
+
235
+ while (
236
+ serializeMessages(stream.concat(message1)).length <
237
+ MAX_OUTGOING_MESSAGES_CHUNK_BYTES
238
+ ) {
239
+ stream.push(message1);
240
+ void peer.outgoing.push(message1);
241
+ }
242
+
243
+ void peer.outgoing.push(message2);
110
244
 
111
- mockWebSocket.send.mockImplementation(() => {
112
- mockWebSocket.readyState = 0;
113
- });
245
+ await waitFor(() => {
246
+ expect(mockWebSocket.send).toHaveBeenCalledTimes(2);
247
+ });
114
248
 
115
- const message1: SyncMessage = {
116
- action: "known",
117
- id: "co_ztest",
118
- header: false,
119
- sessions: {},
120
- };
249
+ expect(mockWebSocket.send).toHaveBeenCalledWith(
250
+ serializeMessages(stream),
251
+ );
121
252
 
122
- const message2: SyncMessage = {
123
- action: "content",
124
- id: "co_zlow",
125
- new: {},
126
- priority: 1,
127
- };
253
+ expect(mockWebSocket.send).toHaveBeenNthCalledWith(
254
+ 2,
255
+ JSON.stringify(message2),
256
+ );
257
+ });
128
258
 
259
+ test("should wait for the buffer to be under BUFFER_LIMIT before sending more messages", async () => {
260
+ vi.useFakeTimers();
261
+ const { peer, mockWebSocket } = setup();
262
+
263
+ mockWebSocket.send.mockImplementation(() => {
264
+ mockWebSocket.bufferedAmount = BUFFER_LIMIT + 1;
265
+ });
266
+
267
+ const message1: SyncMessage = {
268
+ action: "known",
269
+ id: "co_ztest",
270
+ header: false,
271
+ sessions: {},
272
+ };
273
+ const message2: SyncMessage = {
274
+ action: "content",
275
+ id: "co_zlow",
276
+ new: {},
277
+ priority: 1,
278
+ };
279
+
280
+ const stream: SyncMessage[] = [];
281
+
282
+ while (
283
+ serializeMessages(stream.concat(message1)).length <
284
+ MAX_OUTGOING_MESSAGES_CHUNK_BYTES
285
+ ) {
286
+ stream.push(message1);
129
287
  void peer.outgoing.push(message1);
288
+ }
289
+
290
+ void peer.outgoing.push(message2);
291
+
292
+ await vi.advanceTimersByTimeAsync(100);
130
293
 
131
- await waitFor(() => {
132
- expect(mockWebSocket.send).toHaveBeenCalled();
133
- });
294
+ expect(mockWebSocket.send).toHaveBeenCalledWith(
295
+ serializeMessages(stream),
296
+ );
134
297
 
135
- expect(mockWebSocket.send).toHaveBeenCalledWith(JSON.stringify(message1));
298
+ mockWebSocket.bufferedAmount = 0;
136
299
 
137
- mockWebSocket.send.mockClear();
138
- void peer.outgoing.push(message2);
300
+ await vi.advanceTimersByTimeAsync(BUFFER_LIMIT_POLLING_INTERVAL + 1);
139
301
 
140
- await new Promise<void>((resolve) => setTimeout(resolve, 100))
302
+ expect(mockWebSocket.send).toHaveBeenNthCalledWith(
303
+ 2,
304
+ JSON.stringify(message2),
305
+ );
141
306
 
142
- expect(mockWebSocket.send).not.toHaveBeenCalled();
307
+ vi.useRealTimers();
308
+ });
309
+ });
310
+
311
+ describe("batchingByDefault = false", () => {
312
+ test("should not batch outgoing messages", async () => {
313
+ const { peer, mockWebSocket } = setup({ batchingByDefault: false });
314
+
315
+ const message1: SyncMessage = {
316
+ action: "known",
317
+ id: "co_ztest",
318
+ header: false,
319
+ sessions: {},
320
+ };
321
+
322
+ const message2: SyncMessage = {
323
+ action: "content",
324
+ id: "co_zlow",
325
+ new: {},
326
+ priority: 1,
327
+ };
328
+
329
+ void peer.outgoing.push(message1);
330
+ void peer.outgoing.push(message2);
331
+
332
+ await waitFor(() => {
333
+ expect(mockWebSocket.send).toHaveBeenCalled();
334
+ });
335
+
336
+ expect(mockWebSocket.send).toHaveBeenNthCalledWith(
337
+ 1,
338
+ JSON.stringify(message1),
339
+ );
340
+ expect(mockWebSocket.send).toHaveBeenNthCalledWith(
341
+ 2,
342
+ JSON.stringify(message2),
343
+ );
143
344
  });
144
345
 
145
- test("should close the websocket connection", () => {
146
- const { mockWebSocket, peer } = setup();
346
+ test("should start batching outgoing messages when reiceving a batched message", async () => {
347
+ const { peer, mockWebSocket, listeners } = setup({
348
+ batchingByDefault: false,
349
+ });
350
+
351
+ const message1: SyncMessage = {
352
+ action: "known",
353
+ id: "co_ztest",
354
+ header: false,
355
+ sessions: {},
356
+ };
357
+
358
+ const messageHandler = listeners.get("message");
359
+
360
+ messageHandler?.(
361
+ new MessageEvent("message", {
362
+ data: Array.from({ length: 5 }, () => message1)
363
+ .map((msg) => JSON.stringify(msg))
364
+ .join("\n"),
365
+ }),
366
+ );
147
367
 
148
- peer.outgoing.close();
368
+ const message2: SyncMessage = {
369
+ action: "content",
370
+ id: "co_zlow",
371
+ new: {},
372
+ priority: 1,
373
+ };
149
374
 
150
- expect(mockWebSocket.close).toHaveBeenCalled();
151
- });
375
+ void peer.outgoing.push(message1);
376
+ void peer.outgoing.push(message2);
152
377
 
153
- describe("batchingByDefault = true", () => {
154
- test("should batch outgoing messages", async () => {
155
- const { peer, mockWebSocket } = setup();
156
-
157
- mockWebSocket.send.mockImplementation(() => {
158
- mockWebSocket.readyState = 0;
159
- });
160
-
161
- const message1: SyncMessage = {
162
- action: "known",
163
- id: "co_ztest",
164
- header: false,
165
- sessions: {},
166
- };
167
-
168
- const message2: SyncMessage = {
169
- action: "content",
170
- id: "co_zlow",
171
- new: {},
172
- priority: 1,
173
- };
174
-
175
- void peer.outgoing.push(message1);
176
- void peer.outgoing.push(message2);
177
-
178
- await waitFor(() => {
179
- expect(mockWebSocket.send).toHaveBeenCalled();
180
- });
181
-
182
- expect(mockWebSocket.send).toHaveBeenCalledWith(
183
- [message1, message2]
184
- .map((msg) => JSON.stringify(msg))
185
- .join("\n"),
186
- );
187
- });
188
-
189
- test("should send all the pending messages when the websocket is closed", async () => {
190
- const { peer, mockWebSocket } = setup();
191
-
192
- const message1: SyncMessage = {
193
- action: "known",
194
- id: "co_ztest",
195
- header: false,
196
- sessions: {},
197
- };
198
-
199
- const message2: SyncMessage = {
200
- action: "content",
201
- id: "co_zlow",
202
- new: {},
203
- priority: 1,
204
- };
205
-
206
- void peer.outgoing.push(message1);
207
- void peer.outgoing.push(message2);
208
-
209
- peer.outgoing.close();
210
-
211
- expect(mockWebSocket.send).toHaveBeenCalledWith(
212
- [message1, message2]
213
- .map((msg) => JSON.stringify(msg))
214
- .join("\n"),
215
- );
216
- });
217
-
218
- test("should limit the chunk size to MAX_OUTGOING_MESSAGES_CHUNK_SIZE", async () => {
219
- const { peer, mockWebSocket } = setup();
220
-
221
- const message1: SyncMessage = {
222
- action: "known",
223
- id: "co_ztest",
224
- header: false,
225
- sessions: {},
226
- };
227
- const message2: SyncMessage = {
228
- action: "content",
229
- id: "co_zlow",
230
- new: {},
231
- priority: 1,
232
- };
233
-
234
- const stream: SyncMessage[] = [];
235
-
236
- while (serializeMessages(stream.concat(message1)).length < MAX_OUTGOING_MESSAGES_CHUNK_BYTES) {
237
- stream.push(message1);
238
- void peer.outgoing.push(message1);
239
- }
240
-
241
- void peer.outgoing.push(message2);
242
-
243
- await waitFor(() => {
244
- expect(mockWebSocket.send).toHaveBeenCalledTimes(2);
245
- });
246
-
247
- expect(mockWebSocket.send).toHaveBeenCalledWith(
248
- serializeMessages(stream),
249
- );
250
-
251
- expect(mockWebSocket.send).toHaveBeenNthCalledWith(
252
- 2,
253
- JSON.stringify(message2),
254
- );
255
- });
256
-
257
- test("should wait for the buffer to be under BUFFER_LIMIT before sending more messages", async () => {
258
- vi.useFakeTimers();
259
- const { peer, mockWebSocket } = setup();
260
-
261
- mockWebSocket.send.mockImplementation(() => {
262
- mockWebSocket.bufferedAmount = BUFFER_LIMIT + 1;
263
- });
264
-
265
- const message1: SyncMessage = {
266
- action: "known",
267
- id: "co_ztest",
268
- header: false,
269
- sessions: {},
270
- };
271
- const message2: SyncMessage = {
272
- action: "content",
273
- id: "co_zlow",
274
- new: {},
275
- priority: 1,
276
- };
277
-
278
- const stream: SyncMessage[] = [];
279
-
280
- while (serializeMessages(stream.concat(message1)).length < MAX_OUTGOING_MESSAGES_CHUNK_BYTES) {
281
- stream.push(message1);
282
- void peer.outgoing.push(message1);
283
- }
284
-
285
- void peer.outgoing.push(message2);
286
-
287
- await vi.advanceTimersByTimeAsync(100);
288
-
289
- expect(mockWebSocket.send).toHaveBeenCalledWith(
290
- serializeMessages(stream),
291
- );
292
-
293
- mockWebSocket.bufferedAmount = 0;
294
-
295
- await vi.advanceTimersByTimeAsync(
296
- BUFFER_LIMIT_POLLING_INTERVAL + 1,
297
- );
298
-
299
- expect(mockWebSocket.send).toHaveBeenNthCalledWith(
300
- 2,
301
- JSON.stringify(message2),
302
- );
303
-
304
- vi.useRealTimers();
305
- });
378
+ await waitFor(() => {
379
+ expect(mockWebSocket.send).toHaveBeenCalled();
380
+ });
381
+
382
+ expect(mockWebSocket.send).toHaveBeenCalledWith(
383
+ [message1, message2].map((msg) => JSON.stringify(msg)).join("\n"),
384
+ );
306
385
  });
307
386
 
308
- describe("batchingByDefault = false", () => {
309
- test("should not batch outgoing messages", async () => {
310
- const { peer, mockWebSocket } = setup({ batchingByDefault: false });
311
-
312
- const message1: SyncMessage = {
313
- action: "known",
314
- id: "co_ztest",
315
- header: false,
316
- sessions: {},
317
- };
318
-
319
- const message2: SyncMessage = {
320
- action: "content",
321
- id: "co_zlow",
322
- new: {},
323
- priority: 1,
324
- };
325
-
326
- void peer.outgoing.push(message1);
327
- void peer.outgoing.push(message2);
328
-
329
- await waitFor(() => {
330
- expect(mockWebSocket.send).toHaveBeenCalled();
331
- });
332
-
333
- expect(mockWebSocket.send).toHaveBeenNthCalledWith(
334
- 1,
335
- JSON.stringify(message1),
336
- );
337
- expect(mockWebSocket.send).toHaveBeenNthCalledWith(
338
- 2,
339
- JSON.stringify(message2),
340
- );
341
- });
342
-
343
- test("should start batching outgoing messages when reiceving a batched message", async () => {
344
- const { peer, mockWebSocket, listeners } = setup({
345
- batchingByDefault: false,
346
- });
347
-
348
- const message1: SyncMessage = {
349
- action: "known",
350
- id: "co_ztest",
351
- header: false,
352
- sessions: {},
353
- };
354
-
355
- const messageHandler = listeners.get("message");
356
-
357
- messageHandler?.(
358
- new MessageEvent("message", {
359
- data: Array.from(
360
- { length: 5 },
361
- () => message1,
362
- )
363
- .map((msg) => JSON.stringify(msg))
364
- .join("\n"),
365
- }),
366
- );
367
-
368
-
369
- const message2: SyncMessage = {
370
- action: "content",
371
- id: "co_zlow",
372
- new: {},
373
- priority: 1,
374
- };
375
-
376
- void peer.outgoing.push(message1);
377
- void peer.outgoing.push(message2);
378
-
379
- await waitFor(() => {
380
- expect(mockWebSocket.send).toHaveBeenCalled();
381
- });
382
-
383
- expect(mockWebSocket.send).toHaveBeenCalledWith(
384
- [message1, message2]
385
- .map((msg) => JSON.stringify(msg))
386
- .join("\n"),
387
- );
388
- });
389
-
390
- test("should not start batching outgoing messages when reiceving non-batched message", async () => {
391
- const { peer, mockWebSocket, listeners } = setup({
392
- batchingByDefault: false,
393
- });
394
-
395
- const message1: SyncMessage = {
396
- action: "known",
397
- id: "co_ztest",
398
- header: false,
399
- sessions: {},
400
- };
401
-
402
- const messageHandler = listeners.get("message");
403
-
404
- messageHandler?.(
405
- new MessageEvent("message", {
406
- data: JSON.stringify(message1),
407
- }),
408
- );
409
-
410
-
411
- const message2: SyncMessage = {
412
- action: "content",
413
- id: "co_zlow",
414
- new: {},
415
- priority: 1,
416
- };
417
-
418
- void peer.outgoing.push(message1);
419
- void peer.outgoing.push(message2);
420
-
421
- await waitFor(() => {
422
- expect(mockWebSocket.send).toHaveBeenCalled();
423
- });
424
-
425
- expect(mockWebSocket.send).toHaveBeenNthCalledWith(
426
- 1,
427
- JSON.stringify(message1),
428
- );
429
- expect(mockWebSocket.send).toHaveBeenNthCalledWith(
430
- 2,
431
- JSON.stringify(message2),
432
- );
433
- });
387
+ test("should not start batching outgoing messages when reiceving non-batched message", async () => {
388
+ const { peer, mockWebSocket, listeners } = setup({
389
+ batchingByDefault: false,
390
+ });
391
+
392
+ const message1: SyncMessage = {
393
+ action: "known",
394
+ id: "co_ztest",
395
+ header: false,
396
+ sessions: {},
397
+ };
398
+
399
+ const messageHandler = listeners.get("message");
400
+
401
+ messageHandler?.(
402
+ new MessageEvent("message", {
403
+ data: JSON.stringify(message1),
404
+ }),
405
+ );
406
+
407
+ const message2: SyncMessage = {
408
+ action: "content",
409
+ id: "co_zlow",
410
+ new: {},
411
+ priority: 1,
412
+ };
413
+
414
+ void peer.outgoing.push(message1);
415
+ void peer.outgoing.push(message2);
416
+
417
+ await waitFor(() => {
418
+ expect(mockWebSocket.send).toHaveBeenCalled();
419
+ });
420
+
421
+ expect(mockWebSocket.send).toHaveBeenNthCalledWith(
422
+ 1,
423
+ JSON.stringify(message1),
424
+ );
425
+ expect(mockWebSocket.send).toHaveBeenNthCalledWith(
426
+ 2,
427
+ JSON.stringify(message2),
428
+ );
434
429
  });
430
+ });
435
431
  });
436
432
 
437
433
  function waitFor(callback: () => boolean | void) {
438
- return new Promise<void>((resolve, reject) => {
439
- const checkPassed = () => {
440
- try {
441
- return { ok: callback(), error: null };
442
- } catch (error) {
443
- return { ok: false, error };
444
- }
445
- };
446
-
447
- let retries = 0;
448
-
449
- const interval = setInterval(() => {
450
- const { ok, error } = checkPassed();
451
-
452
- if (ok !== false) {
453
- clearInterval(interval);
454
- resolve();
455
- }
456
-
457
- if (++retries > 10) {
458
- clearInterval(interval);
459
- reject(error);
460
- }
461
- }, 100);
462
- });
434
+ return new Promise<void>((resolve, reject) => {
435
+ const checkPassed = () => {
436
+ try {
437
+ return { ok: callback(), error: null };
438
+ } catch (error) {
439
+ return { ok: false, error };
440
+ }
441
+ };
442
+
443
+ let retries = 0;
444
+
445
+ const interval = setInterval(() => {
446
+ const { ok, error } = checkPassed();
447
+
448
+ if (ok !== false) {
449
+ clearInterval(interval);
450
+ resolve();
451
+ }
452
+
453
+ if (++retries > 10) {
454
+ clearInterval(interval);
455
+ reject(error);
456
+ }
457
+ }, 100);
458
+ });
463
459
  }