airdcpp-apisocket 3.0.0-beta.5 → 3.0.0-beta.7

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,7 +1,7 @@
1
1
  import {
2
2
  DEFAULT_AUTH_RESPONSE, DEFAULT_CONNECT_PARAMS,
3
- getConnectedSocket, getMockServer, getSocket, waitForExpect
4
- } from './helpers.js';
3
+ getConnectedSocket, getMockServer, getSocket
4
+ } from './mock-server.js';
5
5
 
6
6
  import ApiConstants from '../ApiConstants.js';
7
7
 
@@ -9,6 +9,7 @@ import { HookCallback, HookSubscriberInfo, SubscriptionRemoveHandler } from '../
9
9
  import { IncomingSubscriptionEvent } from '../types/api_internal.js';
10
10
 
11
11
  import { jest } from '@jest/globals';
12
+ import { defusedPromise, waitForExpect } from './test-utils.js';
12
13
 
13
14
  let server: ReturnType<typeof getMockServer>;
14
15
 
@@ -29,7 +30,7 @@ describe('socket', () => {
29
30
 
30
31
  describe('auth', () => {
31
32
  test('should handle valid credentials', async () => {
32
- server.addDataHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE);
33
+ server.addRequestHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE);
33
34
  const connectedCallback = jest.fn();
34
35
 
35
36
  const { socket, mockConsole } = getSocket();
@@ -48,7 +49,7 @@ describe('socket', () => {
48
49
  });
49
50
 
50
51
  test('should handle valid refresh token', async () => {
51
- server.addDataHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE);
52
+ server.addRequestHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE);
52
53
  const connectedCallback = jest.fn();
53
54
 
54
55
  const { socket, mockConsole } = getSocket();
@@ -106,7 +107,7 @@ describe('socket', () => {
106
107
 
107
108
  // Valid connect attempt
108
109
  server = getMockServer();
109
- server.addDataHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE);
110
+ server.addRequestHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE);
110
111
 
111
112
  await socket.connect(DEFAULT_CONNECT_PARAMS.username, DEFAULT_CONNECT_PARAMS.password, false);
112
113
 
@@ -125,22 +126,23 @@ describe('socket', () => {
125
126
  socket.onDisconnected = disconnectedCallback;
126
127
 
127
128
  // Dummy listener
128
- server.addDataHandler('POST', 'hubs/listeners/hub_updated', undefined);
129
+ server.addRequestHandler('POST', 'hubs/listeners/hub_updated', undefined);
129
130
  await socket.addListener('hubs', 'hub_updated', dummyfn);
130
131
 
131
132
  // Dummy pending request
132
- socket.delete('dummyLogoutDelete').catch((error: Error) => {
133
- // TODO: fix, too unreliable at the moment (depends on the timings)
134
- //expect(error.message).toEqual('Socket disconnected');
135
- });
133
+ server.ignoreMissingHandler('DELETE', 'dummyLogoutDelete');
134
+
135
+ const pendingRequestPromise = defusedPromise(socket.delete('dummyLogoutDelete'));
136
136
 
137
137
  // Logout
138
- server.addDataHandler('DELETE', ApiConstants.LOGOUT_URL);
138
+ server.addRequestHandler('DELETE', ApiConstants.LOGOUT_URL);
139
139
  await socket.logout();
140
140
 
141
141
  expect(sessionResetCallback.mock.calls.length).toBe(1);
142
142
  await waitForExpect(() => expect(disconnectedCallback.mock.calls.length).toBe(1));
143
143
 
144
+ await expect(pendingRequestPromise).rejects.toMatchInlineSnapshot(`"Socket disconnected"`);
145
+
144
146
  expect(socket.isActive()).toEqual(false);
145
147
  expect(socket.hasListeners()).toEqual(false);
146
148
  expect(socket.getPendingRequestCount()).toEqual(0);
@@ -166,14 +168,14 @@ describe('socket', () => {
166
168
  test('should handle wait disconnected timeout', async () => {
167
169
  const { socket, mockConsole } = await getConnectedSocket(server);
168
170
 
169
- let error;
171
+ let error: Error | null = null;
170
172
  try {
171
173
  await socket.waitDisconnected(50);
172
174
  } catch (e) {
173
175
  error = e;
174
176
  }
175
177
 
176
- expect(error).toEqual('Socket disconnect timed out');
178
+ expect(error?.message).toEqual('Socket disconnect timed out');
177
179
 
178
180
  expect(mockConsole.error.mock.calls.length).toBe(1);
179
181
  expect(mockConsole.warn.mock.calls.length).toBe(0);
@@ -192,12 +194,7 @@ describe('socket', () => {
192
194
  socket.disconnect(true);
193
195
  jest.runOnlyPendingTimers();
194
196
 
195
- // TODO: fix
196
- /*{
197
- const waitForExpectTask = await waitForExpect(() => expect(socket.isActive()).toEqual(false));
198
- jest.advanceTimersByTime(1000);
199
- await waitForExpectTask;
200
- }*/
197
+ expect(socket.isActive()).toEqual(false);
201
198
 
202
199
  // Let it fail once
203
200
  server.stop();
@@ -206,7 +203,7 @@ describe('socket', () => {
206
203
  expect(mockConsole.error.mock.calls.length).toBe(1);
207
204
 
208
205
  server = getMockServer();
209
- server.addDataHandler('POST', ApiConstants.CONNECT_URL, undefined);
206
+ server.addRequestHandler('POST', ApiConstants.CONNECT_URL, undefined);
210
207
  jest.runOnlyPendingTimers();
211
208
  jest.runOnlyPendingTimers();
212
209
  jest.runOnlyPendingTimers();
@@ -257,7 +254,7 @@ describe('socket', () => {
257
254
  socket.disconnect();
258
255
  await waitForExpect(() => expect(socket.isActive()).toEqual(false));
259
256
 
260
- server.addDataHandler('POST', ApiConstants.CONNECT_URL, undefined);
257
+ server.addRequestHandler('POST', ApiConstants.CONNECT_URL, undefined);
261
258
  await socket.reconnect();
262
259
  expect(socket.isConnected()).toEqual(true);
263
260
 
@@ -268,9 +265,10 @@ describe('socket', () => {
268
265
  await waitForExpect(() => expect(socket.isActive()).toEqual(false));
269
266
  });
270
267
 
271
- // TODO: fix
272
- test.skip('should re-authenticate on lost session', async () => {
268
+ test('should re-authenticate on lost session', async () => {
273
269
  const ErrorResponse = 'Invalid session token';
270
+ const authCallback = jest.fn();
271
+ const connectErrorCallback = jest.fn();
274
272
 
275
273
  // Connect and disconnect
276
274
  const { socket, mockConsole } = await getConnectedSocket(server);
@@ -282,25 +280,16 @@ describe('socket', () => {
282
280
 
283
281
  // Fail the initial reconnect attempt with 'Invalid session token'
284
282
  // and connect with credentials afterwards
285
- server.addErrorHandler('POST', ApiConstants.CONNECT_URL, ErrorResponse, 400);
283
+ server.addErrorHandler('POST', ApiConstants.CONNECT_URL, ErrorResponse, 400, connectErrorCallback);
286
284
 
287
- const authCallback = jest.fn();
288
- server.addDataHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE, authCallback);
285
+ server.addRequestHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE, authCallback);
289
286
 
290
287
  jest.runOnlyPendingTimers();
291
288
  socket.reconnect();
292
289
 
293
- {
294
- const waitForExpectTask = waitForExpect(
295
- () => {
296
- jest.runOnlyPendingTimers();
297
- expect(authCallback.mock.calls.length).toBe(1);
298
- }
299
- );
300
-
301
- jest.advanceTimersByTime(1000);
302
- await waitForExpectTask;
303
- }
290
+ await jest.advanceTimersByTimeAsync(1000);
291
+ expect(authCallback.mock.calls.length).toBe(1);
292
+ expect(connectErrorCallback.mock.calls.length).toBe(1);
304
293
 
305
294
  expect(socket.isConnected()).toEqual(true);
306
295
  expect(mockConsole.error.mock.calls.length).toBe(0);
@@ -328,6 +317,9 @@ describe('socket', () => {
328
317
  test('should report request timeouts', async () => {
329
318
  const { socket, mockConsole } = await getConnectedSocket(server);
330
319
 
320
+ server.ignoreMissingHandler('POST', 'hubs/listeners/hub_updated');
321
+ server.ignoreMissingHandler('POST', 'hubs/listeners/hub_added');
322
+
331
323
  jest.useFakeTimers();
332
324
  socket.addListener('hubs', 'hub_updated', dummyfn)
333
325
  .catch(() => {});
@@ -388,8 +380,8 @@ describe('socket', () => {
388
380
 
389
381
  test('should handle listener messages', async () => {
390
382
  const { socket, mockConsole } = await getConnectedSocket(server);
391
- server.addDataHandler('POST', 'hubs/listeners/hub_updated', undefined);
392
- server.addDataHandler('POST', `hubs/${entityId}/listeners/hub_updated`, undefined);
383
+ server.addSubscriptionHandler('hubs', 'hub_updated');
384
+ server.addSubscriptionHandler('hubs', 'hub_updated', entityId);
393
385
 
394
386
  const commonSubscriptionCallback = jest.fn();
395
387
  const entitySubscriptionCallback = jest.fn();
@@ -415,8 +407,7 @@ describe('socket', () => {
415
407
  test('should handle listener removal', async () => {
416
408
  const { socket, mockConsole } = await getConnectedSocket(server);
417
409
 
418
- const subscribeCallback = jest.fn();
419
- server.addDataHandler('POST', 'hubs/listeners/hub_updated', undefined, subscribeCallback);
410
+ const hubUpdatedListener = server.addSubscriptionHandler('hubs', 'hub_updated');
420
411
 
421
412
  // Add two simultaneous pending add events
422
413
  const p1 = socket.addListener('hubs', 'hub_updated', dummyfn);
@@ -428,17 +419,14 @@ describe('socket', () => {
428
419
  const removeListener1 = await p1;
429
420
  const removeListener2 = await p2;
430
421
 
431
- expect(subscribeCallback.mock.calls.length).toBe(1);
422
+ expect(hubUpdatedListener.subscribeFn.mock.calls.length).toBe(1);
432
423
  expect(socket.getPendingSubscriptionCount()).toBe(0);
433
424
 
434
- const deleteCallback = jest.fn();
435
- server.addDataHandler('DELETE', 'hubs/listeners/hub_updated', undefined, deleteCallback);
436
-
437
425
  removeListener1();
438
- expect(deleteCallback.mock.calls.length).toBe(0); // Shouldn't call API yet, still one left
426
+ expect(hubUpdatedListener.unsubscribeFn.mock.calls.length).toBe(0); // Shouldn't call API yet, still one left
439
427
 
440
428
  removeListener2();
441
- await waitForExpect(() => expect(deleteCallback.mock.calls.length).toBe(1));
429
+ await waitForExpect(() => expect(hubUpdatedListener.unsubscribeFn.mock.calls.length).toBe(1));
442
430
 
443
431
  expect(socket.hasListeners()).toBe(false);
444
432
 
@@ -466,11 +454,9 @@ describe('socket', () => {
466
454
  });
467
455
 
468
456
  describe('hooks', () => {
469
- const hookEventData: IncomingSubscriptionEvent = {
470
- event: 'queue_bundle_finished_hook',
471
- data: {},
472
- completion_id: 1,
473
- };
457
+ const HOOK_MODULE = 'queue';
458
+ const HOOK_NAME = 'queue_bundle_finished_hook';
459
+ const HOOK_COMPLETION_ID = 1;
474
460
 
475
461
  const hookSubscriberInfo: HookSubscriberInfo = {
476
462
  id: 'sfv_checker',
@@ -487,33 +473,27 @@ describe('socket', () => {
487
473
 
488
474
  // Add hook
489
475
  {
490
- const hookAddCallback = jest.fn();
491
- server.addDataHandler('POST', 'queue/hooks/queue_bundle_finished_hook', undefined, hookAddCallback);
476
+ const hook = server.addHookHandler(HOOK_MODULE, HOOK_NAME);
492
477
 
493
478
  removeListener = await socket.addHook(
494
- 'queue',
495
- 'queue_bundle_finished_hook',
479
+ HOOK_MODULE,
480
+ HOOK_NAME,
496
481
  rejectCallback,
497
482
  hookSubscriberInfo
498
483
  );
499
484
 
500
- expect((hookAddCallback.mock.calls[0][0] as any).data).toEqual(hookSubscriberInfo);
501
- expect(hookAddCallback.mock.calls.length).toBe(1);
502
- }
485
+ expect((hook.subscribeFn.mock.calls[0][0] as any).data).toEqual(hookSubscriberInfo);
486
+ expect(hook.subscribeFn.mock.calls.length).toBe(1);
503
487
 
504
- // Simulate action
505
- {
506
- const hookEventCallback = jest.fn();
507
- server.addDataHandler('POST', 'queue/hooks/queue_bundle_finished_hook/1/reject', undefined, hookEventCallback);
508
- server.send(hookEventData);
509
- await waitForExpect(() => expect(hookEventCallback.mock.calls.length).toBe(1));
488
+ // Simulate action
489
+ const hookResolver = hook.addResolver(HOOK_COMPLETION_ID);
490
+ hookResolver.fire({});
491
+ await waitForExpect(() => expect(hookResolver.rejectFn.mock.calls.length).toBe(1));
510
492
  }
511
493
 
512
494
  // Clean up
513
- {
514
- removeListener();
515
- expect(socket.hasListeners()).toBe(false);
516
- }
495
+ removeListener();
496
+ expect(socket.hasListeners()).toBe(false);
517
497
 
518
498
  expect(mockConsole.warn.mock.calls.length).toBe(0);
519
499
 
@@ -0,0 +1,336 @@
1
+ import { Socket } from '../NodeSocket.js';
2
+ import { Client, Server, WebSocket } from 'mock-socket';
3
+ import { jest } from '@jest/globals';
4
+
5
+ import { OutgoingRequest, RequestSuccessResponse, RequestErrorResponse } from '../types/api_internal.js';
6
+ import * as Options from '../types/options.js';
7
+ import ApiConstants from '../ApiConstants.js';
8
+ import { EventEmitter } from 'events';
9
+
10
+ const VERBOSE = false;
11
+
12
+ export const getMockConsole = () => ({
13
+ log: jest.fn((a1: any, a2: any, a3: any, a4: any) => {
14
+ if (VERBOSE) {
15
+ console.log(a1, a2, a3, a4);
16
+ }
17
+ }),
18
+ info: jest.fn((a1: any, a2: any, a3: any, a4: any) => {
19
+ if (VERBOSE) {
20
+ console.info(a1, a2, a3, a4);
21
+ }
22
+ }),
23
+ warn: jest.fn((a1: any, a2: any, a3: any, a4: any) => {
24
+ console.warn(a1, a2, a3, a4);
25
+ }),
26
+ error: jest.fn((a1: any, a2: any, a3: any, a4: any) => {
27
+ console.error(a1, a2, a3, a4);
28
+ }),
29
+ });
30
+
31
+ const DEFAULT_CONNECT_PARAMS = {
32
+ username: 'test',
33
+ password: 'test',
34
+ url: 'ws://localhost:7171/api/v1/',
35
+ };
36
+
37
+ const getDefaultSocketOptions = (mockConsole: Options.LogOutput): Options.APISocketOptions => ({
38
+ ...DEFAULT_CONNECT_PARAMS,
39
+ logOutput: mockConsole,
40
+ logLevel: VERBOSE ? 'verbose' : 'warn',
41
+ });
42
+
43
+ const DEFAULT_AUTH_RESPONSE = {
44
+ auth_token: 'b823187f-4aab-4b71-9764-e63e88401a26',
45
+ refresh_token: '5124faasf-4aab-4b71-9764-e63e88401a26',
46
+ user: {
47
+ permissions: [ 'admin' ],
48
+ username: 'test',
49
+ active_sessions: 1,
50
+ last_login: 0,
51
+ },
52
+ system: {
53
+ cid: 'AHLUODI2YZ2U7FDWMHFNJU65ERGKUN4MH7GW5LY',
54
+ hostname: 'ubuntu-htpc',
55
+ network_type: 'private',
56
+ path_separator: '/',
57
+ platform: 'other',
58
+ language: 'fi',
59
+ },
60
+ wizard_pending: false,
61
+ };
62
+
63
+ export type MockSocketOptions = Omit<Options.APISocketOptions, 'username' | 'password' | 'url'> & {
64
+ username?: string;
65
+ password?: string;
66
+ url?: string;
67
+ };
68
+
69
+ const getSocket = (socketOptions: MockSocketOptions = {}, mockConsole = getMockConsole()) => {
70
+ const socket = Socket(
71
+ {
72
+ ...getDefaultSocketOptions(mockConsole),
73
+ ...socketOptions,
74
+ },
75
+ WebSocket as any
76
+ );
77
+
78
+ return { socket, mockConsole };
79
+ };
80
+
81
+
82
+ type Callback = (requestData: object) => void;
83
+
84
+ interface ConnectOptions {
85
+ socketOptions?: MockSocketOptions;
86
+ authCallback?: Callback;
87
+ authResponse?: object;
88
+ console?: ReturnType<typeof getMockConsole>;
89
+ }
90
+
91
+ const getDefaultConnectOptions = () => ({
92
+ console: getMockConsole(),
93
+ authResponse: DEFAULT_AUTH_RESPONSE,
94
+ });
95
+
96
+ const getConnectedSocket = async (
97
+ server: ReturnType<typeof getMockServer>,
98
+ userOptions?: ConnectOptions,
99
+ ) => {
100
+ const options = {
101
+ ...getDefaultConnectOptions(),
102
+ ...userOptions,
103
+ };
104
+
105
+ server.addRequestHandler('POST', ApiConstants.LOGIN_URL, options.authResponse, options.authCallback);
106
+
107
+ const { socket, mockConsole } = getSocket(options.socketOptions, options.console);
108
+ await socket.connect();
109
+
110
+ return { socket, mockConsole };
111
+ };
112
+
113
+ const toEmitId = (path: string, method: string) => {
114
+ return `${path}_${method}`;
115
+ };
116
+
117
+ interface MockServerOptions {
118
+ url: string;
119
+ reportMissingListeners?: boolean;
120
+ }
121
+
122
+ const DEFAULT_MOCK_SERVER_OPTIONS: MockServerOptions = {
123
+ url: DEFAULT_CONNECT_PARAMS.url,
124
+ reportMissingListeners: true,
125
+ }
126
+
127
+ type MockRequestResponseDataObject<DataT extends object | undefined> = Omit<RequestSuccessResponse<DataT>, 'callback_id'> | Omit<RequestErrorResponse, 'callback_id'>;
128
+ type MockRequestResponseDataHandler<DataT extends object | undefined> = (request: OutgoingRequest, s: WebSocket) => MockRequestResponseDataObject<DataT>;
129
+ type MockRequestResponseData<DataT extends object | undefined> = MockRequestResponseDataObject<DataT> | MockRequestResponseDataHandler<DataT>;
130
+
131
+ const getMockServer = (initialOptions: Partial<MockServerOptions> = {}) => {
132
+ const { url, reportMissingListeners }: MockServerOptions = {
133
+ ...DEFAULT_MOCK_SERVER_OPTIONS,
134
+ ...initialOptions,
135
+ };
136
+
137
+ const mockServer = new Server(url);
138
+ let socket: Client;
139
+ const emitter = new EventEmitter();
140
+
141
+ const send = (data: object) => {
142
+ socket.send(JSON.stringify(data));
143
+ };
144
+
145
+ const addServerHandler = <DataT extends object | undefined>(
146
+ method: string,
147
+ path: string,
148
+ responseData: MockRequestResponseData<DataT>,
149
+ subscriptionCallback?: Callback
150
+ ) => {
151
+ emitter.addListener(
152
+ toEmitId(path, method),
153
+ (request: OutgoingRequest, s: WebSocket) => {
154
+ if (subscriptionCallback) {
155
+ subscriptionCallback(request);
156
+ }
157
+
158
+ const data = typeof responseData === 'function' ? responseData(request, s) : responseData;
159
+ const response: RequestSuccessResponse | RequestErrorResponse = {
160
+ callback_id: request.callback_id,
161
+ ...data,
162
+ };
163
+
164
+ s.send(JSON.stringify(response));
165
+ }
166
+ );
167
+ };
168
+
169
+ const addDummyDataHandler = (method: string, path: string) => {
170
+ emitter.addListener(
171
+ toEmitId(path, method),
172
+ (request: OutgoingRequest, s: WebSocket) => {
173
+ // Do nothing
174
+ }
175
+ );
176
+ }
177
+
178
+ const addRequestHandler = <DataT extends object | undefined>(
179
+ method: string,
180
+ path: string,
181
+ data?: DataT | MockRequestResponseDataHandler<DataT>,
182
+ subscriptionCallback?: Callback
183
+ ) => {
184
+ const handlerData = typeof data === 'function' ? data : {
185
+ data,
186
+ code: data ? 200 : 204,
187
+ }
188
+
189
+ addServerHandler<DataT>(
190
+ method,
191
+ path,
192
+ handlerData,
193
+ subscriptionCallback
194
+ );
195
+ }
196
+
197
+ const addErrorHandler = (
198
+ method: string,
199
+ path: string,
200
+ errorStr: string | null,
201
+ errorCode: number,
202
+ subscriptionCallback?: Callback
203
+ ) => {
204
+ addServerHandler(
205
+ method,
206
+ path,
207
+ {
208
+ error: !errorStr ? null as any : {
209
+ message: errorStr,
210
+ },
211
+ code: errorCode,
212
+ },
213
+ subscriptionCallback
214
+ );
215
+ }
216
+
217
+ const addSubscriptionHandlerImpl = (
218
+ moduleName: string,
219
+ type: string,
220
+ listenerName: string,
221
+ entityId?: string | number,
222
+ ) => {
223
+ const subscribeFn = jest.fn();
224
+ const unsubscribeFn = jest.fn();
225
+
226
+ const path = entityId ? `${moduleName}/${entityId}/${type}/${listenerName}` : `${moduleName}/${type}/${listenerName}`;
227
+
228
+ addRequestHandler('POST', path, undefined, subscribeFn);
229
+ addRequestHandler('DELETE', path, undefined, unsubscribeFn);
230
+
231
+ const fire = (data: object, entityId?: string | number) => {
232
+ send({
233
+ event: listenerName,
234
+ data,
235
+ id: entityId,
236
+ });
237
+ }
238
+
239
+ return {
240
+ fire,
241
+
242
+ subscribeFn,
243
+ unsubscribeFn,
244
+
245
+ path,
246
+ }
247
+ }
248
+
249
+
250
+ const addSubscriptionHandler = (
251
+ moduleName: string,
252
+ listenerName: string,
253
+ entityId?: string | number,
254
+ ) => {
255
+ return addSubscriptionHandlerImpl(moduleName, 'listeners', listenerName, entityId);
256
+ }
257
+
258
+ const addHookHandler = (
259
+ moduleName: string,
260
+ listenerName: string,
261
+ ) => {
262
+ const subscriber = addSubscriptionHandlerImpl(moduleName, 'hooks', listenerName);
263
+
264
+ const addResolver = (completionId: number) => {
265
+ const resolveFn = jest.fn();
266
+ const rejectFn = jest.fn();
267
+
268
+ addRequestHandler(
269
+ 'POST',
270
+ `${subscriber.path}/${completionId}/resolve`,
271
+ undefined,
272
+ resolveFn
273
+ );
274
+
275
+ addRequestHandler(
276
+ 'POST',
277
+ `${subscriber.path}/${completionId}/reject`,
278
+ undefined,
279
+ rejectFn
280
+ );
281
+
282
+ const fire = (data: object) => {
283
+ send({
284
+ event: listenerName,
285
+ data,
286
+ completion_id: completionId,
287
+ });
288
+ }
289
+
290
+ return { fire, resolveFn, rejectFn };
291
+ };
292
+
293
+ return {
294
+ addResolver,
295
+
296
+ ...subscriber,
297
+ }
298
+ }
299
+
300
+
301
+ mockServer.on('connection', s => {
302
+ socket = s;
303
+
304
+ socket.on('message', (messageObj) => {
305
+ const request: OutgoingRequest = JSON.parse(messageObj as string);
306
+ const emitId = toEmitId(request.path, request.method);
307
+ const processed = emitter.emit(emitId, request, s);
308
+ if (reportMissingListeners && !processed) {
309
+ console.warn(`Mock server: no listeners for event ${request.method} ${request.path}`);
310
+ }
311
+ });
312
+ });
313
+
314
+ mockServer.on('close', () => {
315
+ emitter.removeAllListeners();
316
+ });
317
+
318
+ return {
319
+ addRequestHandler,
320
+ addErrorHandler,
321
+
322
+ addSubscriptionHandler,
323
+ addHookHandler,
324
+
325
+ ignoreMissingHandler: addDummyDataHandler,
326
+ stop: () => {
327
+ mockServer.stop(() => {
328
+ // ...
329
+ });
330
+ },
331
+ send,
332
+ url,
333
+ };
334
+ };
335
+
336
+ export { getMockServer, getSocket, getConnectedSocket, DEFAULT_CONNECT_PARAMS, DEFAULT_AUTH_RESPONSE };