airdcpp-apisocket 3.0.0-beta.4 → 3.0.0-beta.6

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,6 +1,5 @@
1
1
  import * as Options from '../types/options.js';
2
- export declare const waitForExpect: (func: () => void | Promise<void>) => Promise<{}>;
3
- declare const getMockConsole: () => {
2
+ export declare const getMockConsole: () => {
4
3
  log: import("jest-mock").Mock<(a1: any, a2: any, a3: any, a4: any) => void>;
5
4
  info: import("jest-mock").Mock<(a1: any, a2: any, a3: any, a4: any) => void>;
6
5
  warn: import("jest-mock").Mock<(a1: any, a2: any, a3: any, a4: any) => void>;
@@ -65,10 +64,33 @@ declare const getConnectedSocket: (server: ReturnType<typeof getMockServer>, use
65
64
  error: import("jest-mock").Mock<(a1: any, a2: any, a3: any, a4: any) => void>;
66
65
  };
67
66
  }>;
68
- declare const getMockServer: (url?: string) => {
69
- addDataHandler: <DataT extends object | undefined>(method: string, path: string, data?: DataT, subscriptionCallback?: Callback) => void;
67
+ interface MockServerOptions {
68
+ url: string;
69
+ reportMissingListeners?: boolean;
70
+ }
71
+ declare const getMockServer: (initialOptions?: Partial<MockServerOptions>) => {
72
+ addRequestHandler: <DataT extends object | undefined>(method: string, path: string, data?: DataT, subscriptionCallback?: Callback) => void;
70
73
  addErrorHandler: (method: string, path: string, errorStr: string | null, errorCode: number, subscriptionCallback?: Callback) => void;
74
+ addSubscriptionHandler: (moduleName: string, listenerName: string, entityId?: string | number) => {
75
+ fire: (data: object, entityId?: string | number) => void;
76
+ subscribeFn: import("jest-mock").Mock<import("jest-mock").UnknownFunction>;
77
+ unsubscribeFn: import("jest-mock").Mock<import("jest-mock").UnknownFunction>;
78
+ path: string;
79
+ };
80
+ addHookHandler: (moduleName: string, listenerName: string) => {
81
+ fire: (data: object, entityId?: string | number) => void;
82
+ subscribeFn: import("jest-mock").Mock<import("jest-mock").UnknownFunction>;
83
+ unsubscribeFn: import("jest-mock").Mock<import("jest-mock").UnknownFunction>;
84
+ path: string;
85
+ addResolver: (completionId: number) => {
86
+ fire: (data: object) => void;
87
+ resolveFn: import("jest-mock").Mock<import("jest-mock").UnknownFunction>;
88
+ rejectFn: import("jest-mock").Mock<import("jest-mock").UnknownFunction>;
89
+ };
90
+ };
91
+ ignoreMissingHandler: (method: string, path: string) => void;
71
92
  stop: () => void;
72
93
  send: (data: object) => void;
94
+ url: string;
73
95
  };
74
96
  export { getMockServer, getSocket, getConnectedSocket, DEFAULT_CONNECT_PARAMS, DEFAULT_AUTH_RESPONSE };
@@ -0,0 +1,198 @@
1
+ import { Socket } from '../NodeSocket.js';
2
+ import { Server, WebSocket } from 'mock-socket';
3
+ import { jest } from '@jest/globals';
4
+ import ApiConstants from '../ApiConstants.js';
5
+ import { EventEmitter } from 'events';
6
+ const VERBOSE = false;
7
+ export const getMockConsole = () => ({
8
+ log: jest.fn((a1, a2, a3, a4) => {
9
+ if (VERBOSE) {
10
+ console.log(a1, a2, a3, a4);
11
+ }
12
+ }),
13
+ info: jest.fn((a1, a2, a3, a4) => {
14
+ if (VERBOSE) {
15
+ console.info(a1, a2, a3, a4);
16
+ }
17
+ }),
18
+ warn: jest.fn((a1, a2, a3, a4) => {
19
+ console.warn(a1, a2, a3, a4);
20
+ }),
21
+ error: jest.fn((a1, a2, a3, a4) => {
22
+ console.error(a1, a2, a3, a4);
23
+ }),
24
+ });
25
+ const DEFAULT_CONNECT_PARAMS = {
26
+ username: 'test',
27
+ password: 'test',
28
+ url: 'ws://localhost:7171/api/v1/',
29
+ };
30
+ const getDefaultSocketOptions = (mockConsole) => ({
31
+ ...DEFAULT_CONNECT_PARAMS,
32
+ logOutput: mockConsole,
33
+ logLevel: VERBOSE ? 'verbose' : 'warn',
34
+ });
35
+ const DEFAULT_AUTH_RESPONSE = {
36
+ auth_token: 'b823187f-4aab-4b71-9764-e63e88401a26',
37
+ refresh_token: '5124faasf-4aab-4b71-9764-e63e88401a26',
38
+ user: {
39
+ permissions: ['admin'],
40
+ username: 'test',
41
+ active_sessions: 1,
42
+ last_login: 0,
43
+ },
44
+ system: {
45
+ cid: 'AHLUODI2YZ2U7FDWMHFNJU65ERGKUN4MH7GW5LY',
46
+ hostname: 'ubuntu-htpc',
47
+ network_type: 'private',
48
+ path_separator: '/',
49
+ platform: 'other',
50
+ language: 'fi',
51
+ },
52
+ wizard_pending: false,
53
+ };
54
+ const getSocket = (socketOptions = {}, mockConsole = getMockConsole()) => {
55
+ const socket = Socket({
56
+ ...getDefaultSocketOptions(mockConsole),
57
+ ...socketOptions,
58
+ }, WebSocket);
59
+ return { socket, mockConsole };
60
+ };
61
+ const getDefaultConnectOptions = () => ({
62
+ console: getMockConsole(),
63
+ authResponse: DEFAULT_AUTH_RESPONSE,
64
+ });
65
+ const getConnectedSocket = async (server, userOptions) => {
66
+ const options = {
67
+ ...getDefaultConnectOptions(),
68
+ ...userOptions,
69
+ };
70
+ server.addRequestHandler('POST', ApiConstants.LOGIN_URL, options.authResponse, options.authCallback);
71
+ const { socket, mockConsole } = getSocket(options.socketOptions, options.console);
72
+ await socket.connect();
73
+ return { socket, mockConsole };
74
+ };
75
+ const toEmitId = (path, method) => {
76
+ return `${path}_${method}`;
77
+ };
78
+ const DEFAULT_MOCK_SERVER_OPTIONS = {
79
+ url: DEFAULT_CONNECT_PARAMS.url,
80
+ reportMissingListeners: true,
81
+ };
82
+ const getMockServer = (initialOptions = {}) => {
83
+ const { url, reportMissingListeners } = {
84
+ ...DEFAULT_MOCK_SERVER_OPTIONS,
85
+ ...initialOptions,
86
+ };
87
+ const mockServer = new Server(url);
88
+ let socket;
89
+ const emitter = new EventEmitter();
90
+ const send = (data) => {
91
+ socket.send(JSON.stringify(data));
92
+ };
93
+ const addServerHandler = (method, path, responseData, subscriptionCallback) => {
94
+ emitter.addListener(toEmitId(path, method), (request, s) => {
95
+ if (subscriptionCallback) {
96
+ subscriptionCallback(request);
97
+ }
98
+ const response = {
99
+ callback_id: request.callback_id,
100
+ ...responseData,
101
+ };
102
+ s.send(JSON.stringify(response));
103
+ });
104
+ };
105
+ const addDummyDataHandler = (method, path) => {
106
+ emitter.addListener(toEmitId(path, method), (request, s) => {
107
+ // Do nothing
108
+ });
109
+ };
110
+ const addRequestHandler = (method, path, data, subscriptionCallback) => {
111
+ addServerHandler(method, path, {
112
+ data,
113
+ code: 200,
114
+ }, subscriptionCallback);
115
+ };
116
+ const addErrorHandler = (method, path, errorStr, errorCode, subscriptionCallback) => {
117
+ addServerHandler(method, path, {
118
+ error: !errorStr ? null : {
119
+ message: errorStr,
120
+ },
121
+ code: errorCode,
122
+ }, subscriptionCallback);
123
+ };
124
+ const addSubscriptionHandlerImpl = (moduleName, type, listenerName, entityId) => {
125
+ const subscribeFn = jest.fn();
126
+ const unsubscribeFn = jest.fn();
127
+ const path = entityId ? `${moduleName}/${entityId}/${type}/${listenerName}` : `${moduleName}/${type}/${listenerName}`;
128
+ addRequestHandler('POST', path, undefined, subscribeFn);
129
+ addRequestHandler('DELETE', path, undefined, unsubscribeFn);
130
+ const fire = (data, entityId) => {
131
+ send({
132
+ event: listenerName,
133
+ data,
134
+ id: entityId,
135
+ });
136
+ };
137
+ return {
138
+ fire,
139
+ subscribeFn,
140
+ unsubscribeFn,
141
+ path,
142
+ };
143
+ };
144
+ const addSubscriptionHandler = (moduleName, listenerName, entityId) => {
145
+ return addSubscriptionHandlerImpl(moduleName, 'listeners', listenerName, entityId);
146
+ };
147
+ const addHookHandler = (moduleName, listenerName) => {
148
+ const subscriber = addSubscriptionHandlerImpl(moduleName, 'hooks', listenerName);
149
+ const addResolver = (completionId) => {
150
+ const resolveFn = jest.fn();
151
+ const rejectFn = jest.fn();
152
+ addRequestHandler('POST', `${subscriber.path}/${completionId}/resolve`, undefined, resolveFn);
153
+ addRequestHandler('POST', `${subscriber.path}/${completionId}/reject`, undefined, rejectFn);
154
+ const fire = (data) => {
155
+ send({
156
+ event: listenerName,
157
+ data,
158
+ completion_id: completionId,
159
+ });
160
+ };
161
+ return { fire, resolveFn, rejectFn };
162
+ };
163
+ return {
164
+ addResolver,
165
+ ...subscriber,
166
+ };
167
+ };
168
+ mockServer.on('connection', s => {
169
+ socket = s;
170
+ socket.on('message', (messageObj) => {
171
+ const request = JSON.parse(messageObj);
172
+ const emitId = toEmitId(request.path, request.method);
173
+ const processed = emitter.emit(emitId, request, s);
174
+ if (reportMissingListeners && !processed) {
175
+ console.warn(`Mock server: no listeners for event ${request.method} ${request.path}`);
176
+ }
177
+ });
178
+ });
179
+ mockServer.on('close', () => {
180
+ emitter.removeAllListeners();
181
+ });
182
+ return {
183
+ addRequestHandler,
184
+ addErrorHandler,
185
+ addSubscriptionHandler,
186
+ addHookHandler,
187
+ ignoreMissingHandler: addDummyDataHandler,
188
+ stop: () => {
189
+ mockServer.stop(() => {
190
+ // ...
191
+ });
192
+ },
193
+ send,
194
+ url,
195
+ };
196
+ };
197
+ export { getMockServer, getSocket, getConnectedSocket, DEFAULT_CONNECT_PARAMS, DEFAULT_AUTH_RESPONSE };
198
+ //# sourceMappingURL=mock-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-server.js","sourceRoot":"","sources":["../../src/tests/mock-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAU,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAIrC,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,OAAO,GAAG,KAAK,CAAC;AAEtB,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,CAAC;IACnC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAE;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC;IACF,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAE;QACnD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;IACF,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAE;QACnD,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC;IACF,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAO,EAAE,EAAE;QACpD,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC,CAAC;CACH,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG;IAC7B,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IAChB,GAAG,EAAE,6BAA6B;CACnC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAAC,WAA8B,EAA4B,EAAE,CAAC,CAAC;IAC7F,GAAG,sBAAsB;IACzB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;CACvC,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG;IAC5B,UAAU,EAAE,sCAAsC;IAClD,aAAa,EAAE,uCAAuC;IACtD,IAAI,EAAE;QACJ,WAAW,EAAE,CAAE,OAAO,CAAE;QACxB,QAAQ,EAAE,MAAM;QAChB,eAAe,EAAE,CAAC;QAClB,UAAU,EAAE,CAAC;KACd;IACD,MAAM,EAAE;QACN,GAAG,EAAE,yCAAyC;QAC9C,QAAQ,EAAE,aAAa;QACvB,YAAY,EAAE,SAAS;QACvB,cAAc,EAAE,GAAG;QACnB,QAAQ,EAAE,OAAO;QACjB,QAAQ,EAAE,IAAI;KACf;IACD,cAAc,EAAE,KAAK;CACtB,CAAC;AAQF,MAAM,SAAS,GAAG,CAAC,gBAAmC,EAAE,EAAE,WAAW,GAAG,cAAc,EAAE,EAAE,EAAE;IAC1F,MAAM,MAAM,GAAG,MAAM,CACnB;QACE,GAAG,uBAAuB,CAAC,WAAW,CAAC;QACvC,GAAG,aAAa;KACjB,EACD,SAAgB,CACjB,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACjC,CAAC,CAAC;AAYF,MAAM,wBAAwB,GAAG,GAAG,EAAE,CAAC,CAAC;IACtC,OAAO,EAAE,cAAc,EAAE;IACzB,YAAY,EAAE,qBAAqB;CACpC,CAAC,CAAC;AAEH,MAAM,kBAAkB,GAAG,KAAK,EAC9B,MAAwC,EACxC,WAA4B,EAC5B,EAAE;IACF,MAAM,OAAO,GAAG;QACd,GAAG,wBAAwB,EAAE;QAC7B,GAAG,WAAW;KACf,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAErG,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;IAEvB,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AACjC,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE;IAChD,OAAO,GAAG,IAAI,IAAI,MAAM,EAAE,CAAC;AAC7B,CAAC,CAAC;AAOF,MAAM,2BAA2B,GAAsB;IACrD,GAAG,EAAE,sBAAsB,CAAC,GAAG;IAC/B,sBAAsB,EAAE,IAAI;CAC7B,CAAA;AAED,MAAM,aAAa,GAAG,CAAC,iBAA6C,EAAE,EAAE,EAAE;IACxE,MAAM,EAAE,GAAG,EAAE,sBAAsB,EAAE,GAAsB;QACzD,GAAG,2BAA2B;QAC9B,GAAG,cAAc;KAClB,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,MAAc,CAAC;IACnB,MAAM,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;IAEnC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;QAC5B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,CACvB,MAAc,EACd,IAAY,EACZ,YAA4G,EAC5G,oBAA+B,EAC/B,EAAE;QACF,OAAO,CAAC,WAAW,CACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,EACtB,CAAC,OAAwB,EAAE,CAAY,EAAE,EAAE;YACzC,IAAI,oBAAoB,EAAE,CAAC;gBACzB,oBAAoB,CAAC,OAAO,CAAC,CAAC;YAChC,CAAC;YAED,MAAM,QAAQ,GAAkD;gBAC9D,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,GAAG,YAAY;aAChB,CAAC;YAEF,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QACnC,CAAC,CACF,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,mBAAmB,GAAG,CAAC,MAAc,EAAE,IAAY,EAAE,EAAE;QAC3D,OAAO,CAAC,WAAW,CACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,EACtB,CAAC,OAAwB,EAAE,CAAY,EAAE,EAAE;YACzC,aAAa;QACf,CAAC,CACF,CAAC;IACJ,CAAC,CAAA;IAED,MAAM,iBAAiB,GAAG,CACxB,MAAc,EACd,IAAY,EACZ,IAAY,EACZ,oBAA+B,EAC/B,EAAE;QACF,gBAAgB,CACd,MAAM,EACN,IAAI,EAAE;YACJ,IAAI;YACJ,IAAI,EAAE,GAAG;SACV,EACD,oBAAoB,CACrB,CAAC;IACJ,CAAC,CAAA;IAED,MAAM,eAAe,GAAG,CACtB,MAAc,EACd,IAAY,EACZ,QAAuB,EACvB,SAAiB,EACjB,oBAA+B,EAC/B,EAAE;QACF,gBAAgB,CACd,MAAM,EACN,IAAI,EACJ;YACE,KAAK,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAW,CAAC,CAAC,CAAC;gBAC/B,OAAO,EAAE,QAAQ;aAClB;YACD,IAAI,EAAE,SAAS;SAChB,EACD,oBAAoB,CACrB,CAAC;IACJ,CAAC,CAAA;IAED,MAAM,0BAA0B,GAAG,CACjC,UAAkB,EAClB,IAAY,EACZ,YAAoB,EACpB,QAA0B,EAC1B,EAAE;QACF,MAAM,WAAW,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QAC9B,MAAM,aAAa,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;QAEhC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,QAAQ,IAAI,IAAI,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,GAAG,UAAU,IAAI,IAAI,IAAI,YAAY,EAAE,CAAC;QAEtH,iBAAiB,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;QACxD,iBAAiB,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;QAE5D,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,QAA0B,EAAE,EAAE;YACxD,IAAI,CAAC;gBACH,KAAK,EAAE,YAAY;gBACnB,IAAI;gBACJ,EAAE,EAAE,QAAQ;aACb,CAAC,CAAC;QACL,CAAC,CAAA;QAED,OAAO;YACL,IAAI;YAEJ,WAAW;YACX,aAAa;YAEb,IAAI;SACL,CAAA;IACH,CAAC,CAAA;IAGD,MAAM,sBAAsB,GAAG,CAC7B,UAAkB,EAClB,YAAoB,EACpB,QAA0B,EAC1B,EAAE;QACF,OAAO,0BAA0B,CAAC,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IACrF,CAAC,CAAA;IAED,MAAM,cAAc,GAAG,CACrB,UAAkB,EAClB,YAAoB,EACpB,EAAE;QACF,MAAM,UAAU,GAAG,0BAA0B,CAAC,UAAU,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;QAEjF,MAAM,WAAW,GAAG,CAAC,YAAoB,EAAE,EAAE;YAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;YAE3B,iBAAiB,CACf,MAAM,EACN,GAAG,UAAU,CAAC,IAAI,IAAI,YAAY,UAAU,EAC5C,SAAS,EACT,SAAS,CACV,CAAC;YAEF,iBAAiB,CACf,MAAM,EACN,GAAG,UAAU,CAAC,IAAI,IAAI,YAAY,SAAS,EAC3C,SAAS,EACT,QAAQ,CACT,CAAC;YAEF,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;gBAC5B,IAAI,CAAC;oBACH,KAAK,EAAE,YAAY;oBACnB,IAAI;oBACJ,aAAa,EAAE,YAAY;iBAC5B,CAAC,CAAC;YACL,CAAC,CAAA;YAED,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;QACvC,CAAC,CAAC;QAEF,OAAO;YACL,WAAW;YAEX,GAAG,UAAU;SACd,CAAA;IACH,CAAC,CAAA;IAGD,UAAU,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE;QAC9B,MAAM,GAAG,CAAC,CAAC;QAEX,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,UAAU,EAAE,EAAE;YAClC,MAAM,OAAO,GAAoB,IAAI,CAAC,KAAK,CAAC,UAAoB,CAAC,CAAC;YAClE,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YACtD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YACnD,IAAI,sBAAsB,IAAI,CAAC,SAAS,EAAE,CAAC;gBACzC,OAAO,CAAC,IAAI,CAAC,uCAAuC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACxF,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAC1B,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,iBAAiB;QACjB,eAAe;QAEf,sBAAsB;QACtB,cAAc;QAEd,oBAAoB,EAAE,mBAAmB;QACzC,IAAI,EAAE,GAAG,EAAE;YACT,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE;gBACnB,MAAM;YACR,CAAC,CAAC,CAAC;QACL,CAAC;QACD,IAAI;QACJ,GAAG;KACJ,CAAC;AACJ,CAAC,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const waitForExpect: (func: () => void | Promise<void>) => Promise<{}>;
@@ -0,0 +1,5 @@
1
+ import waitForExpectOriginal from 'wait-for-expect';
2
+ const EXCEPT_TIMEOUT = 1000;
3
+ //@ts-ignore
4
+ export const waitForExpect = (func) => waitForExpectOriginal.default(func, EXCEPT_TIMEOUT);
5
+ //# sourceMappingURL=test-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/tests/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,MAAM,iBAAiB,CAAC;AAEpD,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,YAAY;AACZ,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAgC,EAAE,EAAE,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "airdcpp-apisocket",
3
- "version": "3.0.0-beta.4",
3
+ "version": "3.0.0-beta.6",
4
4
  "description": "Javascript connector for AirDC++ Web API",
5
5
  "license": "MIT",
6
6
  "authors": [
@@ -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 { 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,17 +126,19 @@ 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
133
+ server.ignoreMissingHandler('DELETE', 'dummyLogoutDelete');
134
+
132
135
  socket.delete('dummyLogoutDelete').catch((error: Error) => {
133
136
  // TODO: fix, too unreliable at the moment (depends on the timings)
134
137
  //expect(error.message).toEqual('Socket disconnected');
135
138
  });
136
139
 
137
140
  // Logout
138
- server.addDataHandler('DELETE', ApiConstants.LOGOUT_URL);
141
+ server.addRequestHandler('DELETE', ApiConstants.LOGOUT_URL);
139
142
  await socket.logout();
140
143
 
141
144
  expect(sessionResetCallback.mock.calls.length).toBe(1);
@@ -206,7 +209,7 @@ describe('socket', () => {
206
209
  expect(mockConsole.error.mock.calls.length).toBe(1);
207
210
 
208
211
  server = getMockServer();
209
- server.addDataHandler('POST', ApiConstants.CONNECT_URL, undefined);
212
+ server.addRequestHandler('POST', ApiConstants.CONNECT_URL, undefined);
210
213
  jest.runOnlyPendingTimers();
211
214
  jest.runOnlyPendingTimers();
212
215
  jest.runOnlyPendingTimers();
@@ -257,7 +260,7 @@ describe('socket', () => {
257
260
  socket.disconnect();
258
261
  await waitForExpect(() => expect(socket.isActive()).toEqual(false));
259
262
 
260
- server.addDataHandler('POST', ApiConstants.CONNECT_URL, undefined);
263
+ server.addRequestHandler('POST', ApiConstants.CONNECT_URL, undefined);
261
264
  await socket.reconnect();
262
265
  expect(socket.isConnected()).toEqual(true);
263
266
 
@@ -285,7 +288,7 @@ describe('socket', () => {
285
288
  server.addErrorHandler('POST', ApiConstants.CONNECT_URL, ErrorResponse, 400);
286
289
 
287
290
  const authCallback = jest.fn();
288
- server.addDataHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE, authCallback);
291
+ server.addRequestHandler('POST', ApiConstants.LOGIN_URL, DEFAULT_AUTH_RESPONSE, authCallback);
289
292
 
290
293
  jest.runOnlyPendingTimers();
291
294
  socket.reconnect();
@@ -328,6 +331,9 @@ describe('socket', () => {
328
331
  test('should report request timeouts', async () => {
329
332
  const { socket, mockConsole } = await getConnectedSocket(server);
330
333
 
334
+ server.ignoreMissingHandler('POST', 'hubs/listeners/hub_updated');
335
+ server.ignoreMissingHandler('POST', 'hubs/listeners/hub_added');
336
+
331
337
  jest.useFakeTimers();
332
338
  socket.addListener('hubs', 'hub_updated', dummyfn)
333
339
  .catch(() => {});
@@ -388,8 +394,8 @@ describe('socket', () => {
388
394
 
389
395
  test('should handle listener messages', async () => {
390
396
  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);
397
+ server.addSubscriptionHandler('hubs', 'hub_updated');
398
+ server.addSubscriptionHandler('hubs', 'hub_updated', entityId);
393
399
 
394
400
  const commonSubscriptionCallback = jest.fn();
395
401
  const entitySubscriptionCallback = jest.fn();
@@ -415,8 +421,7 @@ describe('socket', () => {
415
421
  test('should handle listener removal', async () => {
416
422
  const { socket, mockConsole } = await getConnectedSocket(server);
417
423
 
418
- const subscribeCallback = jest.fn();
419
- server.addDataHandler('POST', 'hubs/listeners/hub_updated', undefined, subscribeCallback);
424
+ const hubUpdatedListener = server.addSubscriptionHandler('hubs', 'hub_updated');
420
425
 
421
426
  // Add two simultaneous pending add events
422
427
  const p1 = socket.addListener('hubs', 'hub_updated', dummyfn);
@@ -428,17 +433,14 @@ describe('socket', () => {
428
433
  const removeListener1 = await p1;
429
434
  const removeListener2 = await p2;
430
435
 
431
- expect(subscribeCallback.mock.calls.length).toBe(1);
436
+ expect(hubUpdatedListener.subscribeFn.mock.calls.length).toBe(1);
432
437
  expect(socket.getPendingSubscriptionCount()).toBe(0);
433
438
 
434
- const deleteCallback = jest.fn();
435
- server.addDataHandler('DELETE', 'hubs/listeners/hub_updated', undefined, deleteCallback);
436
-
437
439
  removeListener1();
438
- expect(deleteCallback.mock.calls.length).toBe(0); // Shouldn't call API yet, still one left
440
+ expect(hubUpdatedListener.unsubscribeFn.mock.calls.length).toBe(0); // Shouldn't call API yet, still one left
439
441
 
440
442
  removeListener2();
441
- await waitForExpect(() => expect(deleteCallback.mock.calls.length).toBe(1));
443
+ await waitForExpect(() => expect(hubUpdatedListener.unsubscribeFn.mock.calls.length).toBe(1));
442
444
 
443
445
  expect(socket.hasListeners()).toBe(false);
444
446
 
@@ -466,11 +468,9 @@ describe('socket', () => {
466
468
  });
467
469
 
468
470
  describe('hooks', () => {
469
- const hookEventData: IncomingSubscriptionEvent = {
470
- event: 'queue_bundle_finished_hook',
471
- data: {},
472
- completion_id: 1,
473
- };
471
+ const HOOK_MODULE = 'queue';
472
+ const HOOK_NAME = 'queue_bundle_finished_hook';
473
+ const HOOK_COMPLETION_ID = 1;
474
474
 
475
475
  const hookSubscriberInfo: HookSubscriberInfo = {
476
476
  id: 'sfv_checker',
@@ -487,26 +487,22 @@ describe('socket', () => {
487
487
 
488
488
  // Add hook
489
489
  {
490
- const hookAddCallback = jest.fn();
491
- server.addDataHandler('POST', 'queue/hooks/queue_bundle_finished_hook', undefined, hookAddCallback);
490
+ const hook = server.addHookHandler(HOOK_MODULE, HOOK_NAME);
492
491
 
493
492
  removeListener = await socket.addHook(
494
- 'queue',
495
- 'queue_bundle_finished_hook',
493
+ HOOK_MODULE,
494
+ HOOK_NAME,
496
495
  rejectCallback,
497
496
  hookSubscriberInfo
498
497
  );
499
498
 
500
- expect((hookAddCallback.mock.calls[0][0] as any).data).toEqual(hookSubscriberInfo);
501
- expect(hookAddCallback.mock.calls.length).toBe(1);
502
- }
499
+ expect((hook.subscribeFn.mock.calls[0][0] as any).data).toEqual(hookSubscriberInfo);
500
+ expect(hook.subscribeFn.mock.calls.length).toBe(1);
503
501
 
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));
502
+ // Simulate action
503
+ const hookResolver = hook.addResolver(HOOK_COMPLETION_ID);
504
+ hookResolver.fire({});
505
+ await waitForExpect(() => expect(hookResolver.rejectFn.mock.calls.length).toBe(1));
510
506
  }
511
507
 
512
508
  // Clean up
@@ -0,0 +1,328 @@
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
+ const getMockServer = (initialOptions: Partial<MockServerOptions> = {}) => {
128
+ const { url, reportMissingListeners }: MockServerOptions = {
129
+ ...DEFAULT_MOCK_SERVER_OPTIONS,
130
+ ...initialOptions,
131
+ };
132
+
133
+ const mockServer = new Server(url);
134
+ let socket: Client;
135
+ const emitter = new EventEmitter();
136
+
137
+ const send = (data: object) => {
138
+ socket.send(JSON.stringify(data));
139
+ };
140
+
141
+ const addServerHandler = <DataT extends object | undefined>(
142
+ method: string,
143
+ path: string,
144
+ responseData: Omit<RequestSuccessResponse<DataT>, 'callback_id'> | Omit<RequestErrorResponse, 'callback_id'>,
145
+ subscriptionCallback?: Callback
146
+ ) => {
147
+ emitter.addListener(
148
+ toEmitId(path, method),
149
+ (request: OutgoingRequest, s: WebSocket) => {
150
+ if (subscriptionCallback) {
151
+ subscriptionCallback(request);
152
+ }
153
+
154
+ const response: RequestSuccessResponse | RequestErrorResponse = {
155
+ callback_id: request.callback_id,
156
+ ...responseData,
157
+ };
158
+
159
+ s.send(JSON.stringify(response));
160
+ }
161
+ );
162
+ };
163
+
164
+ const addDummyDataHandler = (method: string, path: string) => {
165
+ emitter.addListener(
166
+ toEmitId(path, method),
167
+ (request: OutgoingRequest, s: WebSocket) => {
168
+ // Do nothing
169
+ }
170
+ );
171
+ }
172
+
173
+ const addRequestHandler = <DataT extends object | undefined>(
174
+ method: string,
175
+ path: string,
176
+ data?: DataT,
177
+ subscriptionCallback?: Callback
178
+ ) => {
179
+ addServerHandler<DataT>(
180
+ method,
181
+ path, {
182
+ data,
183
+ code: 200,
184
+ },
185
+ subscriptionCallback
186
+ );
187
+ }
188
+
189
+ const addErrorHandler = (
190
+ method: string,
191
+ path: string,
192
+ errorStr: string | null,
193
+ errorCode: number,
194
+ subscriptionCallback?: Callback
195
+ ) => {
196
+ addServerHandler(
197
+ method,
198
+ path,
199
+ {
200
+ error: !errorStr ? null as any : {
201
+ message: errorStr,
202
+ },
203
+ code: errorCode,
204
+ },
205
+ subscriptionCallback
206
+ );
207
+ }
208
+
209
+ const addSubscriptionHandlerImpl = (
210
+ moduleName: string,
211
+ type: string,
212
+ listenerName: string,
213
+ entityId?: string | number,
214
+ ) => {
215
+ const subscribeFn = jest.fn();
216
+ const unsubscribeFn = jest.fn();
217
+
218
+ const path = entityId ? `${moduleName}/${entityId}/${type}/${listenerName}` : `${moduleName}/${type}/${listenerName}`;
219
+
220
+ addRequestHandler('POST', path, undefined, subscribeFn);
221
+ addRequestHandler('DELETE', path, undefined, unsubscribeFn);
222
+
223
+ const fire = (data: object, entityId?: string | number) => {
224
+ send({
225
+ event: listenerName,
226
+ data,
227
+ id: entityId,
228
+ });
229
+ }
230
+
231
+ return {
232
+ fire,
233
+
234
+ subscribeFn,
235
+ unsubscribeFn,
236
+
237
+ path,
238
+ }
239
+ }
240
+
241
+
242
+ const addSubscriptionHandler = (
243
+ moduleName: string,
244
+ listenerName: string,
245
+ entityId?: string | number,
246
+ ) => {
247
+ return addSubscriptionHandlerImpl(moduleName, 'listeners', listenerName, entityId);
248
+ }
249
+
250
+ const addHookHandler = (
251
+ moduleName: string,
252
+ listenerName: string,
253
+ ) => {
254
+ const subscriber = addSubscriptionHandlerImpl(moduleName, 'hooks', listenerName);
255
+
256
+ const addResolver = (completionId: number) => {
257
+ const resolveFn = jest.fn();
258
+ const rejectFn = jest.fn();
259
+
260
+ addRequestHandler(
261
+ 'POST',
262
+ `${subscriber.path}/${completionId}/resolve`,
263
+ undefined,
264
+ resolveFn
265
+ );
266
+
267
+ addRequestHandler(
268
+ 'POST',
269
+ `${subscriber.path}/${completionId}/reject`,
270
+ undefined,
271
+ rejectFn
272
+ );
273
+
274
+ const fire = (data: object) => {
275
+ send({
276
+ event: listenerName,
277
+ data,
278
+ completion_id: completionId,
279
+ });
280
+ }
281
+
282
+ return { fire, resolveFn, rejectFn };
283
+ };
284
+
285
+ return {
286
+ addResolver,
287
+
288
+ ...subscriber,
289
+ }
290
+ }
291
+
292
+
293
+ mockServer.on('connection', s => {
294
+ socket = s;
295
+
296
+ socket.on('message', (messageObj) => {
297
+ const request: OutgoingRequest = JSON.parse(messageObj as string);
298
+ const emitId = toEmitId(request.path, request.method);
299
+ const processed = emitter.emit(emitId, request, s);
300
+ if (reportMissingListeners && !processed) {
301
+ console.warn(`Mock server: no listeners for event ${request.method} ${request.path}`);
302
+ }
303
+ });
304
+ });
305
+
306
+ mockServer.on('close', () => {
307
+ emitter.removeAllListeners();
308
+ });
309
+
310
+ return {
311
+ addRequestHandler,
312
+ addErrorHandler,
313
+
314
+ addSubscriptionHandler,
315
+ addHookHandler,
316
+
317
+ ignoreMissingHandler: addDummyDataHandler,
318
+ stop: () => {
319
+ mockServer.stop(() => {
320
+ // ...
321
+ });
322
+ },
323
+ send,
324
+ url,
325
+ };
326
+ };
327
+
328
+ export { getMockServer, getSocket, getConnectedSocket, DEFAULT_CONNECT_PARAMS, DEFAULT_AUTH_RESPONSE };
@@ -1,15 +1,14 @@
1
1
  import {
2
2
  getMockServer,
3
3
  getConnectedSocket,
4
- waitForExpect,
5
- } from './helpers.js';
4
+ } from './mock-server.js';
5
+ import { waitForExpect } from './test-utils.js';
6
6
 
7
7
  import { jest } from '@jest/globals';
8
8
 
9
9
  import { addContextMenuItems } from '../PublicHelpers.js';
10
10
  import { SelectedMenuItemListenerData, MenuItemListHookData, MenuItemListHookAcceptData } from '../types/public_helpers_internal.js';
11
11
  import { HookSubscriberInfo, MenuCallbackProperties, MenuClickHandlerProperties } from '../types/index.js';
12
- import { IncomingSubscriptionEvent } from '../types/api_internal.js';
13
12
 
14
13
 
15
14
  let server: ReturnType<typeof getMockServer>;
@@ -97,19 +96,10 @@ describe('public helpers', () => {
97
96
  // Socket handlers
98
97
  const { socket } = await getConnectedSocket(server);
99
98
 
100
- const listenerAddCallback = jest.fn();
101
- server.addDataHandler('POST', `menus/listeners/${MENU_ID}_menuitem_selected`, undefined, listenerAddCallback);
102
-
103
- const hookAddCallback = jest.fn();
104
- const hookResolveCallback = jest.fn();
105
- server.addDataHandler('POST', `menus/hooks/${MENU_ID}_list_menuitems`, undefined, hookAddCallback);
106
- server.addDataHandler(
107
- 'POST',
108
- `menus/hooks/${MENU_ID}_list_menuitems/${HOOK_COMPLETION_ID}/resolve`,
109
- menuItemListData,
110
- hookResolveCallback
111
- );
99
+ const itemSelectedListener = server.addSubscriptionHandler('menus', `${MENU_ID}_menuitem_selected`);
112
100
 
101
+ const listItemsHook = server.addHookHandler('menus', `${MENU_ID}_list_menuitems`);
102
+ const listItemsResolver = listItemsHook.addResolver(HOOK_COMPLETION_ID);
113
103
 
114
104
  // Add menu items
115
105
  const onClickItem1Mock = jest.fn();
@@ -166,33 +156,29 @@ describe('public helpers', () => {
166
156
  SUBSCRIBER_INFO,
167
157
  );
168
158
 
169
- expect(listenerAddCallback).toHaveBeenCalledTimes(1);
170
- expect(hookAddCallback).toHaveBeenCalledTimes(1);
159
+ expect(itemSelectedListener.subscribeFn).toHaveBeenCalledTimes(1);
160
+ expect(listItemsHook.subscribeFn).toHaveBeenCalledTimes(1);
171
161
 
172
162
 
173
163
  // List items hook
174
164
  {
175
- const hookEventData: IncomingSubscriptionEvent<MenuItemListHookData<string, null>> = {
176
- event: `${MENU_ID}_list_menuitems`,
177
- data: {
178
- selected_ids: selectedMenuIds,
179
- entity_id: null,
180
- permissions: PERMISSIONS,
181
- supports: SUPPORTS,
182
- },
183
- completion_id: 1,
165
+ const menuItemListData: MenuItemListHookData<string, null> = {
166
+ selected_ids: selectedMenuIds,
167
+ entity_id: null,
168
+ permissions: PERMISSIONS,
169
+ supports: SUPPORTS,
184
170
  };
185
171
 
186
- server.send(hookEventData);
172
+ listItemsResolver.fire(menuItemListData);
187
173
  }
188
174
 
189
175
  // Validate list items results
190
176
  {
191
177
  await waitForExpect(() => {
192
- expect(hookResolveCallback).toHaveBeenCalledTimes(1);
178
+ expect(listItemsResolver.resolveFn).toHaveBeenCalledTimes(1);
193
179
  });
194
180
 
195
- expect(hookResolveCallback).toHaveBeenCalledWith(
181
+ expect(listItemsResolver.resolveFn).toHaveBeenCalledWith(
196
182
  expect.objectContaining({
197
183
  data: menuItemListData
198
184
  }),
@@ -214,22 +200,18 @@ describe('public helpers', () => {
214
200
 
215
201
  // Select event listener
216
202
  {
217
- const selectEventData: IncomingSubscriptionEvent<SelectedMenuItemListenerData<string, null>> = {
218
- event: `${MENU_ID}_menuitem_selected`,
219
- data: {
220
- menuitem_id: MENU_ITEM1_ID,
221
- hook_id: SUBSCRIBER_INFO.id,
222
- menu_id: MENU_ID,
223
- entity_id: null,
224
- selected_ids: selectedMenuIds,
225
- permissions: PERMISSIONS,
226
- supports: SUPPORTS,
227
- form_values: FORM_VALUES
228
- },
229
- completion_id: HOOK_COMPLETION_ID,
203
+ const selectData: SelectedMenuItemListenerData<string, null> = {
204
+ menuitem_id: MENU_ITEM1_ID,
205
+ hook_id: SUBSCRIBER_INFO.id,
206
+ menu_id: MENU_ID,
207
+ entity_id: null,
208
+ selected_ids: selectedMenuIds,
209
+ permissions: PERMISSIONS,
210
+ supports: SUPPORTS,
211
+ form_values: FORM_VALUES
230
212
  };
231
213
 
232
- server.send(selectEventData);
214
+ itemSelectedListener.fire(selectData);
233
215
  }
234
216
 
235
217
  // Validate select event results
@@ -0,0 +1,5 @@
1
+ import waitForExpectOriginal from 'wait-for-expect';
2
+
3
+ const EXCEPT_TIMEOUT = 1000;
4
+ //@ts-ignore
5
+ export const waitForExpect = (func: () => void | Promise<void>) => waitForExpectOriginal.default(func, EXCEPT_TIMEOUT);
@@ -1,134 +0,0 @@
1
- import { Socket } from '../NodeSocket.js';
2
- import { Server, WebSocket } from 'mock-socket';
3
- import { jest } from '@jest/globals';
4
- import ApiConstants from '../ApiConstants.js';
5
- import { EventEmitter } from 'events';
6
- import waitForExpectOriginal from 'wait-for-expect';
7
- const EXCEPT_TIMEOUT = 1000;
8
- //@ts-ignore
9
- export const waitForExpect = (func) => waitForExpectOriginal.default(func, EXCEPT_TIMEOUT);
10
- const VERBOSE = false;
11
- const getMockConsole = () => ({
12
- log: jest.fn((a1, a2, a3, a4) => {
13
- if (VERBOSE) {
14
- console.log(a1, a2, a3, a4);
15
- }
16
- }),
17
- info: jest.fn((a1, a2, a3, a4) => {
18
- if (VERBOSE) {
19
- console.info(a1, a2, a3, a4);
20
- }
21
- }),
22
- warn: jest.fn((a1, a2, a3, a4) => {
23
- console.warn(a1, a2, a3, a4);
24
- }),
25
- error: jest.fn((a1, a2, a3, a4) => {
26
- console.error(a1, a2, a3, a4);
27
- }),
28
- });
29
- const DEFAULT_CONNECT_PARAMS = {
30
- username: 'test',
31
- password: 'test',
32
- url: 'ws://localhost:7171/api/v1/',
33
- };
34
- const getDefaultSocketOptions = (mockConsole) => ({
35
- ...DEFAULT_CONNECT_PARAMS,
36
- logOutput: mockConsole,
37
- logLevel: VERBOSE ? 'verbose' : 'warn',
38
- });
39
- const DEFAULT_AUTH_RESPONSE = {
40
- auth_token: 'b823187f-4aab-4b71-9764-e63e88401a26',
41
- refresh_token: '5124faasf-4aab-4b71-9764-e63e88401a26',
42
- user: {
43
- permissions: ['admin'],
44
- username: 'test',
45
- active_sessions: 1,
46
- last_login: 0,
47
- },
48
- system: {
49
- cid: 'AHLUODI2YZ2U7FDWMHFNJU65ERGKUN4MH7GW5LY',
50
- hostname: 'ubuntu-htpc',
51
- network_type: 'private',
52
- path_separator: '/',
53
- platform: 'other',
54
- language: 'fi',
55
- },
56
- wizard_pending: false,
57
- };
58
- const getSocket = (socketOptions = {}, mockConsole = getMockConsole()) => {
59
- const socket = Socket({
60
- ...getDefaultSocketOptions(mockConsole),
61
- ...socketOptions,
62
- }, WebSocket);
63
- return { socket, mockConsole };
64
- };
65
- const getDefaultConnectOptions = () => ({
66
- console: getMockConsole(),
67
- authResponse: DEFAULT_AUTH_RESPONSE,
68
- });
69
- const getConnectedSocket = async (server, userOptions) => {
70
- const options = {
71
- ...getDefaultConnectOptions(),
72
- ...userOptions,
73
- };
74
- server.addDataHandler('POST', ApiConstants.LOGIN_URL, options.authResponse, options.authCallback);
75
- const { socket, mockConsole } = getSocket(options.socketOptions, options.console);
76
- await socket.connect();
77
- return { socket, mockConsole };
78
- };
79
- const toEmitId = (path, method) => {
80
- return `${path}_${method}`;
81
- };
82
- const getMockServer = (url = DEFAULT_CONNECT_PARAMS.url) => {
83
- const mockServer = new Server(url);
84
- let socket;
85
- const emitter = new EventEmitter();
86
- const addServerHandler = (method, path, responseData, subscriptionCallback) => {
87
- emitter.addListener(toEmitId(path, method), (request, s) => {
88
- if (subscriptionCallback) {
89
- subscriptionCallback(request);
90
- }
91
- const response = {
92
- callback_id: request.callback_id,
93
- ...responseData,
94
- };
95
- s.send(JSON.stringify(response));
96
- });
97
- };
98
- mockServer.on('connection', s => {
99
- socket = s;
100
- socket.on('message', (messageObj) => {
101
- const request = JSON.parse(messageObj);
102
- emitter.emit(toEmitId(request.path, request.method), request, s);
103
- });
104
- });
105
- mockServer.on('close', () => {
106
- emitter.removeAllListeners();
107
- });
108
- return {
109
- addDataHandler: (method, path, data, subscriptionCallback) => {
110
- addServerHandler(method, path, {
111
- data,
112
- code: 200,
113
- }, subscriptionCallback);
114
- },
115
- addErrorHandler: (method, path, errorStr, errorCode, subscriptionCallback) => {
116
- addServerHandler(method, path, {
117
- error: !errorStr ? null : {
118
- message: errorStr,
119
- },
120
- code: errorCode,
121
- }, subscriptionCallback);
122
- },
123
- stop: () => {
124
- mockServer.stop(() => {
125
- // ...
126
- });
127
- },
128
- send: (data) => {
129
- socket.send(JSON.stringify(data));
130
- },
131
- };
132
- };
133
- export { getMockServer, getSocket, getConnectedSocket, DEFAULT_CONNECT_PARAMS, DEFAULT_AUTH_RESPONSE };
134
- //# sourceMappingURL=helpers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/tests/helpers.ts"],"names":[],"mappings":"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"}
@@ -1,210 +0,0 @@
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
- import waitForExpectOriginal from 'wait-for-expect';
11
-
12
- const EXCEPT_TIMEOUT = 1000;
13
- //@ts-ignore
14
- export const waitForExpect = (func: () => void | Promise<void>) => waitForExpectOriginal.default(func, EXCEPT_TIMEOUT);
15
-
16
- const VERBOSE = false;
17
-
18
- const getMockConsole = () => ({
19
- log: jest.fn((a1: any, a2: any, a3: any, a4: any) => {
20
- if (VERBOSE) {
21
- console.log(a1, a2, a3, a4);
22
- }
23
- }),
24
- info: jest.fn((a1: any, a2: any, a3: any, a4: any) => {
25
- if (VERBOSE) {
26
- console.info(a1, a2, a3, a4);
27
- }
28
- }),
29
- warn: jest.fn((a1: any, a2: any, a3: any, a4: any) => {
30
- console.warn(a1, a2, a3, a4);
31
- }),
32
- error: jest.fn((a1: any, a2: any, a3: any, a4: any) => {
33
- console.error(a1, a2, a3, a4);
34
- }),
35
- });
36
-
37
- const DEFAULT_CONNECT_PARAMS = {
38
- username: 'test',
39
- password: 'test',
40
- url: 'ws://localhost:7171/api/v1/',
41
- };
42
-
43
- const getDefaultSocketOptions = (mockConsole: Options.LogOutput): Options.APISocketOptions => ({
44
- ...DEFAULT_CONNECT_PARAMS,
45
- logOutput: mockConsole,
46
- logLevel: VERBOSE ? 'verbose' : 'warn',
47
- });
48
-
49
- const DEFAULT_AUTH_RESPONSE = {
50
- auth_token: 'b823187f-4aab-4b71-9764-e63e88401a26',
51
- refresh_token: '5124faasf-4aab-4b71-9764-e63e88401a26',
52
- user: {
53
- permissions: [ 'admin' ],
54
- username: 'test',
55
- active_sessions: 1,
56
- last_login: 0,
57
- },
58
- system: {
59
- cid: 'AHLUODI2YZ2U7FDWMHFNJU65ERGKUN4MH7GW5LY',
60
- hostname: 'ubuntu-htpc',
61
- network_type: 'private',
62
- path_separator: '/',
63
- platform: 'other',
64
- language: 'fi',
65
- },
66
- wizard_pending: false,
67
- };
68
-
69
- export type MockSocketOptions = Omit<Options.APISocketOptions, 'username' | 'password' | 'url'> & {
70
- username?: string;
71
- password?: string;
72
- url?: string;
73
- };
74
-
75
- const getSocket = (socketOptions: MockSocketOptions = {}, mockConsole = getMockConsole()) => {
76
- const socket = Socket(
77
- {
78
- ...getDefaultSocketOptions(mockConsole),
79
- ...socketOptions,
80
- },
81
- WebSocket as any
82
- );
83
-
84
- return { socket, mockConsole };
85
- };
86
-
87
-
88
- type Callback = (requestData: object) => void;
89
-
90
- interface ConnectOptions {
91
- socketOptions?: MockSocketOptions;
92
- authCallback?: Callback;
93
- authResponse?: object;
94
- console?: ReturnType<typeof getMockConsole>;
95
- }
96
-
97
- const getDefaultConnectOptions = () => ({
98
- console: getMockConsole(),
99
- authResponse: DEFAULT_AUTH_RESPONSE,
100
- });
101
-
102
- const getConnectedSocket = async (
103
- server: ReturnType<typeof getMockServer>,
104
- userOptions?: ConnectOptions,
105
- ) => {
106
- const options = {
107
- ...getDefaultConnectOptions(),
108
- ...userOptions,
109
- };
110
-
111
- server.addDataHandler('POST', ApiConstants.LOGIN_URL, options.authResponse, options.authCallback);
112
-
113
- const { socket, mockConsole } = getSocket(options.socketOptions, options.console);
114
- await socket.connect();
115
-
116
- return { socket, mockConsole };
117
- };
118
-
119
- const toEmitId = (path: string, method: string) => {
120
- return `${path}_${method}`;
121
- };
122
-
123
- const getMockServer = (url = DEFAULT_CONNECT_PARAMS.url) => {
124
- const mockServer = new Server(url);
125
- let socket: Client;
126
- const emitter = new EventEmitter();
127
-
128
- const addServerHandler = <DataT extends object | undefined>(
129
- method: string,
130
- path: string,
131
- responseData: Omit<RequestSuccessResponse<DataT>, 'callback_id'> | Omit<RequestErrorResponse, 'callback_id'>,
132
- subscriptionCallback?: Callback
133
- ) => {
134
- emitter.addListener(
135
- toEmitId(path, method),
136
- (request: OutgoingRequest, s: WebSocket) => {
137
- if (subscriptionCallback) {
138
- subscriptionCallback(request);
139
- }
140
-
141
- const response: RequestSuccessResponse | RequestErrorResponse = {
142
- callback_id: request.callback_id,
143
- ...responseData,
144
- };
145
-
146
- s.send(JSON.stringify(response));
147
- }
148
- );
149
- };
150
-
151
- mockServer.on('connection', s => {
152
- socket = s;
153
-
154
- socket.on('message', (messageObj) => {
155
- const request: OutgoingRequest = JSON.parse(messageObj as string);
156
- emitter.emit(toEmitId(request.path, request.method), request, s);
157
- });
158
- });
159
-
160
- mockServer.on('close', () => {
161
- emitter.removeAllListeners();
162
- });
163
-
164
- return {
165
- addDataHandler: <DataT extends object | undefined>(
166
- method: string,
167
- path: string,
168
- data?: DataT,
169
- subscriptionCallback?: Callback
170
- ) => {
171
- addServerHandler<DataT>(
172
- method,
173
- path, {
174
- data,
175
- code: 200,
176
- },
177
- subscriptionCallback
178
- );
179
- },
180
- addErrorHandler: (
181
- method: string,
182
- path: string,
183
- errorStr: string | null,
184
- errorCode: number,
185
- subscriptionCallback?: Callback
186
- ) => {
187
- addServerHandler(
188
- method,
189
- path,
190
- {
191
- error: !errorStr ? null as any : {
192
- message: errorStr,
193
- },
194
- code: errorCode,
195
- },
196
- subscriptionCallback
197
- );
198
- },
199
- stop: () => {
200
- mockServer.stop(() => {
201
- // ...
202
- });
203
- },
204
- send: (data: object) => {
205
- socket.send(JSON.stringify(data));
206
- },
207
- };
208
- };
209
-
210
- export { getMockServer, getSocket, getConnectedSocket, DEFAULT_CONNECT_PARAMS, DEFAULT_AUTH_RESPONSE };