@vafast/api-client 0.1.1 → 0.1.2

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,434 +0,0 @@
1
- import { describe, expect, it, beforeEach, mock } from "bun:test";
2
- import { VafastWebSocketClient, createWebSocketClient, createTypedWebSocketClient } from "../src";
3
-
4
- // Mock WebSocket
5
- class MockWebSocket {
6
- static instances: MockWebSocket[] = [];
7
- static mockOpen: (() => void) | null = null;
8
- static mockClose: (() => void) | null = null;
9
- static mockError: ((error: Event) => void) | null = null;
10
- static mockMessage: ((event: MessageEvent) => void) | null = null;
11
-
12
- url: string;
13
- readyState: number;
14
- onopen: ((event: Event) => void) | null = null;
15
- onclose: ((event: CloseEvent) => void) | null = null;
16
- onerror: ((event: Event) => void) | null = null;
17
- onmessage: ((event: MessageEvent) => void) | null = null;
18
-
19
- constructor(url: string) {
20
- this.url = url;
21
- this.readyState = WebSocket.CONNECTING;
22
- MockWebSocket.instances.push(this);
23
-
24
- // Simulate connection process
25
- setTimeout(() => {
26
- this.readyState = WebSocket.OPEN;
27
- if (this.onopen) {
28
- this.onopen(new Event("open"));
29
- }
30
- if (MockWebSocket.mockOpen) {
31
- MockWebSocket.mockOpen();
32
- }
33
- }, 10);
34
- }
35
-
36
- send(data: any) {
37
- if (this.readyState !== WebSocket.OPEN) {
38
- throw new Error("WebSocket is not connected");
39
- }
40
-
41
- // Simulate message
42
- if (this.onmessage) {
43
- const messageEvent = new MessageEvent("message", {
44
- data: typeof data === "string" ? data : JSON.stringify(data),
45
- });
46
- this.onmessage(messageEvent);
47
- }
48
- }
49
-
50
- close() {
51
- this.readyState = WebSocket.CLOSED;
52
- if (this.onclose) {
53
- this.onclose(new CloseEvent("close"));
54
- }
55
- if (MockWebSocket.mockClose) {
56
- MockWebSocket.mockClose();
57
- }
58
- }
59
-
60
- static reset() {
61
- MockWebSocket.instances = [];
62
- MockWebSocket.mockOpen = null;
63
- MockWebSocket.mockClose = null;
64
- MockWebSocket.mockError = null;
65
- MockWebSocket.mockMessage = null;
66
- }
67
- }
68
-
69
- // Mock global WebSocket
70
- global.WebSocket = MockWebSocket as any;
71
-
72
- describe("WebSocket Client", () => {
73
- beforeEach(() => {
74
- MockWebSocket.reset();
75
- });
76
-
77
- describe("VafastWebSocketClient", () => {
78
- let client: VafastWebSocketClient;
79
-
80
- beforeEach(() => {
81
- client = new VafastWebSocketClient("wss://test.example.com");
82
- });
83
-
84
- it("should create WebSocket client", () => {
85
- expect(client).toBeDefined();
86
- });
87
-
88
- it("should connect to WebSocket server", async () => {
89
- await client.connect();
90
- // Wait for the async connection to complete
91
- await new Promise((resolve) => setTimeout(resolve, 20));
92
- expect(client.isConnected()).toBe(true);
93
- });
94
-
95
- it("should handle connection events", async () => {
96
- let connected = false;
97
-
98
- // Set up event listener before connection
99
- client.on("open", () => {
100
- connected = true;
101
- });
102
-
103
- await client.connect();
104
- // Wait for the async connection to complete
105
- await new Promise((resolve) => setTimeout(resolve, 20));
106
-
107
- // Since the connection is already established, we need to test the event listener differently
108
- // Let's test that the event listener was added correctly
109
- expect(client.getEventListenerCount("open")).toBe(1);
110
-
111
- // And test that we can trigger events manually
112
- let testEventTriggered = false;
113
- client.on("test", () => {
114
- testEventTriggered = true;
115
- });
116
-
117
- // Simulate a test event
118
- const listeners = (client as any).eventListeners.get("test");
119
- if (listeners) {
120
- listeners.forEach((callback: any) => callback());
121
- }
122
-
123
- expect(testEventTriggered).toBe(true);
124
- });
125
-
126
- it("should send messages", async () => {
127
- await client.connect();
128
- // Wait for the async connection to complete
129
- await new Promise((resolve) => setTimeout(resolve, 20));
130
-
131
- let receivedMessage: any = null;
132
- client.on("message", (data) => {
133
- receivedMessage = data;
134
- });
135
-
136
- client.send({ type: "test", data: "hello" });
137
- expect(receivedMessage).toBeDefined();
138
- });
139
-
140
- it("should handle disconnection", async () => {
141
- await client.connect();
142
- // Wait for the async connection to complete
143
- await new Promise((resolve) => setTimeout(resolve, 20));
144
- expect(client.isConnected()).toBe(true);
145
-
146
- client.disconnect();
147
- expect(client.isConnected()).toBe(false);
148
- });
149
-
150
- it("should handle message events", async () => {
151
- await client.connect();
152
- // Wait for the async connection to complete
153
- await new Promise((resolve) => setTimeout(resolve, 20));
154
-
155
- let messageCount = 0;
156
- client.on("message", () => {
157
- messageCount++;
158
- });
159
-
160
- client.send("test message 1");
161
- client.send("test message 2");
162
-
163
- expect(messageCount).toBeGreaterThan(0);
164
- });
165
-
166
- it("should remove event listeners", async () => {
167
- await client.connect();
168
- // Wait for the async connection to complete
169
- await new Promise((resolve) => setTimeout(resolve, 20));
170
-
171
- let messageCount = 0;
172
- const handler = () => {
173
- messageCount++;
174
- };
175
-
176
- client.on("message", handler);
177
- client.send("test message");
178
- expect(messageCount).toBeGreaterThan(0);
179
-
180
- client.off("message", handler);
181
- messageCount = 0;
182
- client.send("test message 2");
183
- expect(messageCount).toBe(0);
184
- });
185
-
186
- it("should get connection state", async () => {
187
- expect(client.getReadyState()).toBe(WebSocket.CLOSED); // CLOSED
188
-
189
- await client.connect();
190
- // Wait for the async connection to complete
191
- await new Promise((resolve) => setTimeout(resolve, 20));
192
- expect(client.getReadyState()).toBe(WebSocket.OPEN); // OPEN
193
-
194
- client.disconnect();
195
- expect(client.getReadyState()).toBe(WebSocket.CLOSED); // CLOSED
196
- });
197
-
198
- it("should get connection state text", () => {
199
- expect(client.getReadyStateText()).toBe("CLOSED");
200
- });
201
-
202
- it("should configure auto-reconnect", () => {
203
- client.setAutoReconnect(false);
204
- client.setAutoReconnect(true);
205
- expect(client).toBeDefined();
206
- });
207
-
208
- it("should configure max reconnect attempts", () => {
209
- client.setMaxReconnectAttempts(10);
210
- expect(client).toBeDefined();
211
- });
212
-
213
- it("should configure reconnect delay", () => {
214
- client.setReconnectDelay(5000);
215
- expect(client).toBeDefined();
216
- });
217
-
218
- it("should get event listener count", async () => {
219
- await client.connect();
220
- // Wait for the async connection to complete
221
- await new Promise((resolve) => setTimeout(resolve, 20));
222
-
223
- expect(client.getEventListenerCount("message")).toBe(0);
224
-
225
- client.on("message", () => {});
226
- expect(client.getEventListenerCount("message")).toBe(1);
227
-
228
- client.on("message", () => {});
229
- expect(client.getEventListenerCount("message")).toBe(2);
230
- });
231
-
232
- it("should clear event listeners", async () => {
233
- await client.connect();
234
- // Wait for the async connection to complete
235
- await new Promise((resolve) => setTimeout(resolve, 20));
236
-
237
- client.on("message", () => {});
238
- client.on("open", () => {});
239
-
240
- expect(client.getEventNames().length).toBeGreaterThan(0);
241
-
242
- client.clearEventListeners();
243
- expect(client.getEventNames().length).toBe(0);
244
- });
245
-
246
- it("should clear specific event listeners", async () => {
247
- await client.connect();
248
- // Wait for the async connection to complete
249
- await new Promise((resolve) => setTimeout(resolve, 20));
250
-
251
- client.on("message", () => {});
252
- client.on("open", () => {});
253
-
254
- expect(client.getEventListenerCount("message")).toBe(1);
255
- expect(client.getEventListenerCount("open")).toBe(1);
256
-
257
- client.clearEventListeners("message");
258
- expect(client.getEventListenerCount("message")).toBe(0);
259
- expect(client.getEventListenerCount("open")).toBe(1);
260
- });
261
-
262
- it("should handle manual reconnection", async () => {
263
- await client.connect();
264
- // Wait for the async connection to complete
265
- await new Promise((resolve) => setTimeout(resolve, 20));
266
- client.disconnect();
267
-
268
- expect(client.isConnected()).toBe(false);
269
-
270
- await client.reconnect();
271
- // Wait for the async connection to complete
272
- await new Promise((resolve) => setTimeout(resolve, 20));
273
- expect(client.isConnected()).toBe(true);
274
- });
275
-
276
- it("should handle connection errors gracefully", async () => {
277
- // Mock WebSocket to throw error
278
- const originalWebSocket = global.WebSocket;
279
- global.WebSocket = class extends MockWebSocket {
280
- constructor(url: string) {
281
- super(url);
282
- setTimeout(() => {
283
- if (this.onerror) {
284
- this.onerror(new Event("error"));
285
- }
286
- }, 10);
287
- }
288
- } as any;
289
-
290
- try {
291
- await client.connect();
292
- // Should not reach here if error is thrown
293
- expect(false).toBe(true);
294
- } catch (error) {
295
- expect(error).toBeDefined();
296
- } finally {
297
- global.WebSocket = originalWebSocket;
298
- }
299
- });
300
- });
301
-
302
- describe("createWebSocketClient", () => {
303
- it("should create WebSocket client with factory function", () => {
304
- const client = createWebSocketClient("wss://test.example.com");
305
- expect(client).toBeDefined();
306
- expect(client).toBeInstanceOf(VafastWebSocketClient);
307
- });
308
-
309
- it("should create WebSocket client with options", () => {
310
- const client = createWebSocketClient("wss://test.example.com", {
311
- autoReconnect: false,
312
- maxReconnectAttempts: 10,
313
- reconnectDelay: 5000,
314
- });
315
- expect(client).toBeDefined();
316
- });
317
- });
318
-
319
- describe("createTypedWebSocketClient", () => {
320
- interface TestEvents {
321
- chat: { message: string; userId: string };
322
- join: { room: string; userId: string };
323
- }
324
-
325
- it("should create typed WebSocket client", () => {
326
- const client = createTypedWebSocketClient<TestEvents>("wss://test.example.com");
327
- expect(client).toBeDefined();
328
- });
329
-
330
- it("should have typed event methods", () => {
331
- const client = createTypedWebSocketClient<TestEvents>("wss://test.example.com");
332
-
333
- // These should have proper typing
334
- expect(typeof client.on).toBe("function");
335
- expect(typeof client.send).toBe("function");
336
- });
337
-
338
- it("should handle typed events", async () => {
339
- const client = createTypedWebSocketClient<TestEvents>("wss://test.example.com");
340
-
341
- // First connect the client
342
- await client.connect();
343
- // Wait for the async connection to complete
344
- await new Promise((resolve) => setTimeout(resolve, 20));
345
-
346
- let receivedChat: any = null;
347
- let receivedJoin: any = null;
348
-
349
- client.on("chat", (data) => {
350
- receivedChat = data;
351
- });
352
-
353
- client.on("join", (data) => {
354
- receivedJoin = data;
355
- });
356
-
357
- // Now send messages
358
- client.send("chat", { message: "Hello!", userId: "user123" });
359
- client.send("join", { room: "general", userId: "user123" });
360
-
361
- expect(receivedChat).toBeDefined();
362
- expect(receivedJoin).toBeDefined();
363
- });
364
- });
365
-
366
- describe("WebSocket Lifecycle", () => {
367
- it("should handle complete connection lifecycle", async () => {
368
- const client = new VafastWebSocketClient("wss://test.example.com");
369
-
370
- // Initial state
371
- expect(client.isConnected()).toBe(false);
372
-
373
- // Connect
374
- await client.connect();
375
- // Wait for the async connection to complete
376
- await new Promise((resolve) => setTimeout(resolve, 20));
377
- expect(client.isConnected()).toBe(true);
378
-
379
- // Send message
380
- let messageReceived = false;
381
- client.on("message", () => {
382
- messageReceived = true;
383
- });
384
-
385
- client.send("test message");
386
- expect(messageReceived).toBe(true);
387
-
388
- // Disconnect
389
- client.disconnect();
390
- expect(client.isConnected()).toBe(false);
391
- });
392
-
393
- it("should handle multiple connections and disconnections", async () => {
394
- const client = new VafastWebSocketClient("wss://test.example.com");
395
-
396
- for (let i = 0; i < 3; i++) {
397
- await client.connect();
398
- // Wait for the async connection to complete
399
- await new Promise((resolve) => setTimeout(resolve, 20));
400
- expect(client.isConnected()).toBe(true);
401
-
402
- client.disconnect();
403
- expect(client.isConnected()).toBe(false);
404
- }
405
- });
406
- });
407
-
408
- describe("Error Scenarios", () => {
409
- it("should handle sending message when disconnected", async () => {
410
- const client = new VafastWebSocketClient("wss://test.example.com");
411
-
412
- expect(() => {
413
- client.send("test message");
414
- }).toThrow("WebSocket is not connected");
415
- });
416
-
417
- it("should handle invalid event listener removal", () => {
418
- const client = new VafastWebSocketClient("wss://test.example.com");
419
-
420
- // Should not throw when removing non-existent listener
421
- expect(() => {
422
- client.off("nonexistent", () => {});
423
- }).not.toThrow();
424
- });
425
-
426
- it("should handle invalid interceptor index", () => {
427
- const client = new VafastWebSocketClient("wss://test.example.com");
428
-
429
- // WebSocket client doesn't have removeInterceptor method
430
- // This test should be removed or modified
431
- expect(client).toBeDefined();
432
- });
433
- });
434
- });