request-iframe 0.0.3 → 0.0.5
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.
- package/QUICKSTART.CN.md +35 -8
- package/QUICKSTART.md +35 -8
- package/README.CN.md +177 -24
- package/README.md +237 -19
- package/library/__tests__/channel.test.ts +16 -4
- package/library/__tests__/coverage-branches.test.ts +356 -0
- package/library/__tests__/debug.test.ts +22 -0
- package/library/__tests__/dispatcher.test.ts +8 -4
- package/library/__tests__/requestIframe.test.ts +1243 -87
- package/library/__tests__/stream.test.ts +92 -16
- package/library/__tests__/utils.test.ts +41 -1
- package/library/api/client.d.ts.map +1 -1
- package/library/api/client.js +1 -0
- package/library/constants/index.d.ts +2 -0
- package/library/constants/index.d.ts.map +1 -1
- package/library/constants/index.js +3 -1
- package/library/constants/messages.d.ts +3 -0
- package/library/constants/messages.d.ts.map +1 -1
- package/library/constants/messages.js +3 -0
- package/library/core/client-server.d.ts +4 -0
- package/library/core/client-server.d.ts.map +1 -1
- package/library/core/client-server.js +45 -22
- package/library/core/client.d.ts +36 -4
- package/library/core/client.d.ts.map +1 -1
- package/library/core/client.js +508 -285
- package/library/core/request.d.ts +3 -1
- package/library/core/request.d.ts.map +1 -1
- package/library/core/request.js +2 -1
- package/library/core/response.d.ts +26 -4
- package/library/core/response.d.ts.map +1 -1
- package/library/core/response.js +192 -112
- package/library/core/server.d.ts +13 -0
- package/library/core/server.d.ts.map +1 -1
- package/library/core/server.js +221 -6
- package/library/index.d.ts +2 -1
- package/library/index.d.ts.map +1 -1
- package/library/index.js +39 -3
- package/library/message/channel.d.ts +2 -2
- package/library/message/channel.d.ts.map +1 -1
- package/library/message/channel.js +5 -1
- package/library/message/dispatcher.d.ts +2 -2
- package/library/message/dispatcher.d.ts.map +1 -1
- package/library/message/dispatcher.js +6 -5
- package/library/stream/index.d.ts +11 -1
- package/library/stream/index.d.ts.map +1 -1
- package/library/stream/index.js +21 -3
- package/library/stream/types.d.ts +2 -2
- package/library/stream/types.d.ts.map +1 -1
- package/library/stream/writable-stream.d.ts +1 -1
- package/library/stream/writable-stream.d.ts.map +1 -1
- package/library/stream/writable-stream.js +87 -47
- package/library/types/index.d.ts +29 -5
- package/library/types/index.d.ts.map +1 -1
- package/library/utils/debug.d.ts.map +1 -1
- package/library/utils/debug.js +6 -2
- package/library/utils/error.d.ts +21 -0
- package/library/utils/error.d.ts.map +1 -0
- package/library/utils/error.js +34 -0
- package/library/utils/index.d.ts +21 -0
- package/library/utils/index.d.ts.map +1 -1
- package/library/utils/index.js +141 -2
- package/library/utils/path-match.d.ts +16 -0
- package/library/utils/path-match.d.ts.map +1 -1
- package/library/utils/path-match.js +65 -0
- package/package.json +2 -1
- package/react/library/__tests__/index.test.tsx +44 -22
- package/react/library/index.d.ts.map +1 -1
- package/react/library/index.js +81 -23
- package/react/package.json +7 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import { requestIframeClient } from '../api/client';
|
|
2
|
+
import { requestIframeServer } from '../api/server';
|
|
3
|
+
import { clearServerCache } from '../utils/cache';
|
|
4
|
+
import { ErrorCode, getStatusText, Messages } from '../constants';
|
|
5
|
+
import {
|
|
6
|
+
InterceptorManager,
|
|
7
|
+
RequestInterceptorManager,
|
|
8
|
+
ResponseInterceptorManager,
|
|
9
|
+
runRequestInterceptors,
|
|
10
|
+
runResponseInterceptors
|
|
11
|
+
} from '../interceptors';
|
|
12
|
+
import { ServerResponseImpl } from '../core/response';
|
|
13
|
+
import { IframeFileReadableStream, IframeFileWritableStream } from '../stream';
|
|
14
|
+
import { setupClientDebugInterceptors, setupServerDebugListeners } from '../utils/debug';
|
|
15
|
+
|
|
16
|
+
jest.mock('../utils/debug', () => {
|
|
17
|
+
const actual = jest.requireActual('../utils/debug');
|
|
18
|
+
return {
|
|
19
|
+
...actual,
|
|
20
|
+
setupClientDebugInterceptors: jest.fn(actual.setupClientDebugInterceptors),
|
|
21
|
+
setupServerDebugListeners: jest.fn(actual.setupServerDebugListeners)
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('Coverage - branch focused tests', () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
(setupClientDebugInterceptors as unknown as jest.Mock).mockClear();
|
|
28
|
+
(setupServerDebugListeners as unknown as jest.Mock).mockClear();
|
|
29
|
+
clearServerCache();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('src/api/client.ts', () => {
|
|
33
|
+
it('should create client with Window target', () => {
|
|
34
|
+
const client = requestIframeClient(window as any);
|
|
35
|
+
expect(client).toBeDefined();
|
|
36
|
+
expect((client as any).targetWindow || (client as any).targetOrigin).toBeDefined();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should throw IFRAME_NOT_READY when iframe.contentWindow is unavailable', () => {
|
|
40
|
+
const iframe = document.createElement('iframe');
|
|
41
|
+
Object.defineProperty(iframe, 'contentWindow', { value: null, writable: true });
|
|
42
|
+
try {
|
|
43
|
+
requestIframeClient(iframe as any);
|
|
44
|
+
throw new Error('should have thrown');
|
|
45
|
+
} catch (e: any) {
|
|
46
|
+
expect(e).toBeDefined();
|
|
47
|
+
expect(e.code).toBe(ErrorCode.IFRAME_NOT_READY);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should enable trace mode and register debug interceptors', () => {
|
|
52
|
+
const client = requestIframeClient(window as any, { trace: true } as any);
|
|
53
|
+
expect(client).toBeDefined();
|
|
54
|
+
expect(setupClientDebugInterceptors).toHaveBeenCalledTimes(1);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('src/api/server.ts', () => {
|
|
59
|
+
it('should cache server when id is provided', () => {
|
|
60
|
+
const s1 = requestIframeServer({ id: 'server-1' } as any);
|
|
61
|
+
const s2 = requestIframeServer({ id: 'server-1' } as any);
|
|
62
|
+
expect(s1).toBe(s2);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should enable trace mode and register server debug listeners', () => {
|
|
66
|
+
const s = requestIframeServer({ id: 'server-trace', trace: true } as any);
|
|
67
|
+
expect(s).toBeDefined();
|
|
68
|
+
expect(setupServerDebugListeners).toHaveBeenCalledTimes(1);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('src/constants/index.ts + messages.ts', () => {
|
|
73
|
+
it('getStatusText should return Unknown for unknown code', () => {
|
|
74
|
+
expect(getStatusText(999)).toBe('Unknown');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('Messages proxy should return key when missing', () => {
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
|
+
expect((Messages as any).SOME_UNKNOWN_KEY).toBe('SOME_UNKNOWN_KEY');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('formatMessage should keep placeholder when args missing', () => {
|
|
83
|
+
// {1} has no arg, should remain as "{1}"
|
|
84
|
+
expect(Messages.PROTOCOL_VERSION_TOO_LOW.replace('{0}', '0')).toContain('{1}');
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('src/interceptors/index.ts', () => {
|
|
89
|
+
it('runRequestInterceptors should use rejected handler when provided', async () => {
|
|
90
|
+
const m = new RequestInterceptorManager();
|
|
91
|
+
m.use(() => {
|
|
92
|
+
throw new Error('boom');
|
|
93
|
+
});
|
|
94
|
+
m.use(
|
|
95
|
+
(cfg) => cfg,
|
|
96
|
+
(err) => ({ path: 'recovered', body: { message: err.message } } as any)
|
|
97
|
+
);
|
|
98
|
+
const out = await runRequestInterceptors(m, { path: 'x' } as any);
|
|
99
|
+
expect(out.path).toBe('recovered');
|
|
100
|
+
expect((out as any).body.message).toBe('boom');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('runResponseInterceptors should reject when rejected handler is not provided', async () => {
|
|
104
|
+
const m = new ResponseInterceptorManager();
|
|
105
|
+
m.use(() => {
|
|
106
|
+
throw new Error('nope');
|
|
107
|
+
});
|
|
108
|
+
await expect(runResponseInterceptors(m, { data: 1 } as any)).rejects.toBeInstanceOf(Error);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('InterceptorManager.eject should null out handler, and forEach should skip nulls', () => {
|
|
112
|
+
const mgr = new InterceptorManager<any>();
|
|
113
|
+
const id = mgr.use((x) => x);
|
|
114
|
+
mgr.eject(id);
|
|
115
|
+
const seen: any[] = [];
|
|
116
|
+
mgr.forEach((h) => seen.push(h));
|
|
117
|
+
expect(seen.length).toBe(0);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('src/core/response.ts (setHeader/cookie branches)', () => {
|
|
122
|
+
function createRes() {
|
|
123
|
+
const channel = { send: jest.fn() } as any;
|
|
124
|
+
const targetWindow = { postMessage: jest.fn() } as any;
|
|
125
|
+
return { res: new ServerResponseImpl('rid', '/p', undefined, targetWindow, '*', channel), channel };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
it('setHeader should merge Set-Cookie arrays and strings', () => {
|
|
129
|
+
const { res } = createRes();
|
|
130
|
+
res.setHeader('Set-Cookie', 'a=1');
|
|
131
|
+
res.setHeader('Set-Cookie', ['b=2', 'c=3']);
|
|
132
|
+
res.setHeader('Set-Cookie', 'd=4');
|
|
133
|
+
const sc = (res.headers['Set-Cookie'] as string[]) || [];
|
|
134
|
+
expect(sc).toEqual(['a=1', 'b=2', 'c=3', 'd=4']);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('setHeader should join non-Set-Cookie array values', () => {
|
|
138
|
+
const { res } = createRes();
|
|
139
|
+
res.setHeader('X-Test', ['a', 'b']);
|
|
140
|
+
expect(res.headers['X-Test']).toBe('a, b');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('cookie should handle sameSite true/false/string branches', () => {
|
|
144
|
+
const { res } = createRes();
|
|
145
|
+
res.cookie('k1', 'v1', { sameSite: true });
|
|
146
|
+
res.cookie('k2', 'v2', { sameSite: false });
|
|
147
|
+
res.cookie('k3', 'v3', { sameSite: 'Lax' as any });
|
|
148
|
+
expect(Array.isArray(res.headers['Set-Cookie'])).toBe(true);
|
|
149
|
+
expect((res.headers['Set-Cookie'] as string[]).length).toBe(3);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('clearCookie should append Set-Cookie', () => {
|
|
153
|
+
const { res } = createRes();
|
|
154
|
+
res.clearCookie('k', { path: '/' });
|
|
155
|
+
expect(Array.isArray(res.headers['Set-Cookie'])).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('src/stream/file-stream.ts (encode/decode/merge branches)', () => {
|
|
160
|
+
it('IframeFileWritableStream.encodeData should handle ArrayBuffer and other types', () => {
|
|
161
|
+
const ws = new IframeFileWritableStream({
|
|
162
|
+
filename: 'f',
|
|
163
|
+
mimeType: 'text/plain',
|
|
164
|
+
next: async () => ({ data: 'Zg==', done: true })
|
|
165
|
+
});
|
|
166
|
+
const ab = new Uint8Array([1, 2, 3]).buffer;
|
|
167
|
+
expect((ws as any).encodeData(ab)).toBeDefined();
|
|
168
|
+
expect((ws as any).encodeData(123)).toBe('123');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('IframeFileReadableStream.decodeData should handle ArrayBuffer and unknown types', async () => {
|
|
172
|
+
const rh: any = {
|
|
173
|
+
registerStreamHandler: jest.fn(),
|
|
174
|
+
unregisterStreamHandler: jest.fn(),
|
|
175
|
+
postMessage: jest.fn()
|
|
176
|
+
};
|
|
177
|
+
const rs = new IframeFileReadableStream('sid', 'rid', rh);
|
|
178
|
+
const ab = new Uint8Array([7, 8]).buffer;
|
|
179
|
+
expect((rs as any).decodeData(ab)).toBeInstanceOf(Uint8Array);
|
|
180
|
+
expect((rs as any).decodeData(1)).toBeInstanceOf(Uint8Array);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('mergeChunks should handle 0/1/many branches', () => {
|
|
184
|
+
const rh: any = {
|
|
185
|
+
registerStreamHandler: jest.fn(),
|
|
186
|
+
unregisterStreamHandler: jest.fn(),
|
|
187
|
+
postMessage: jest.fn()
|
|
188
|
+
};
|
|
189
|
+
const rs: any = new IframeFileReadableStream('sid', 'rid', rh);
|
|
190
|
+
rs.chunks = [];
|
|
191
|
+
expect(rs.mergeChunks()).toBeInstanceOf(Uint8Array);
|
|
192
|
+
rs.chunks = [new Uint8Array([1])];
|
|
193
|
+
expect(rs.mergeChunks()).toEqual(new Uint8Array([1]));
|
|
194
|
+
rs.chunks = [new Uint8Array([1, 2]), new Uint8Array([3])];
|
|
195
|
+
expect(rs.mergeChunks()).toEqual(new Uint8Array([1, 2, 3]));
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('readAsFile should prefer explicit fileName parameter', async () => {
|
|
199
|
+
const rh: any = {
|
|
200
|
+
registerStreamHandler: jest.fn(),
|
|
201
|
+
unregisterStreamHandler: jest.fn(),
|
|
202
|
+
postMessage: jest.fn()
|
|
203
|
+
};
|
|
204
|
+
const rs: any = new IframeFileReadableStream('sid', 'rid', rh, { filename: 'default.txt', mimeType: 'text/plain' });
|
|
205
|
+
rs.read = jest.fn().mockResolvedValue(new Uint8Array([65])); // 'A'
|
|
206
|
+
const f: File = await rs.readAsFile('explicit.txt');
|
|
207
|
+
expect(f.name).toBe('explicit.txt');
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe('src/utils/debug.ts branches', () => {
|
|
212
|
+
it('setupClientDebugInterceptors should log success for file/stream/plain and log error', async () => {
|
|
213
|
+
const requestUse = jest.fn();
|
|
214
|
+
const responseUse = jest.fn();
|
|
215
|
+
const fakeClient: any = {
|
|
216
|
+
interceptors: {
|
|
217
|
+
request: { use: requestUse },
|
|
218
|
+
response: { use: responseUse }
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const infoSpy = jest.spyOn(console, 'info').mockImplementation(() => undefined);
|
|
223
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
224
|
+
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
225
|
+
|
|
226
|
+
setupClientDebugInterceptors(fakeClient);
|
|
227
|
+
expect(requestUse).toHaveBeenCalled();
|
|
228
|
+
expect(responseUse).toHaveBeenCalled();
|
|
229
|
+
|
|
230
|
+
const [onFulfilled, onRejected] = responseUse.mock.calls[0];
|
|
231
|
+
|
|
232
|
+
// File/Blob branch
|
|
233
|
+
await onFulfilled({ requestId: 'r', status: 200, statusText: 'OK', data: new Blob(['x'], { type: 'text/plain' }) });
|
|
234
|
+
// Stream branch
|
|
235
|
+
await onFulfilled({ requestId: 'r', status: 200, statusText: 'OK', data: { ok: true }, stream: { streamId: 's', type: 'data' } });
|
|
236
|
+
// Plain branch
|
|
237
|
+
await onFulfilled({ requestId: 'r', status: 200, statusText: 'OK', data: { ok: true } });
|
|
238
|
+
|
|
239
|
+
// Error branch
|
|
240
|
+
await expect(
|
|
241
|
+
onRejected({ requestId: 'r', code: 'X', message: 'bad' })
|
|
242
|
+
).rejects.toBeDefined();
|
|
243
|
+
|
|
244
|
+
expect(infoSpy).toHaveBeenCalled();
|
|
245
|
+
expect(errorSpy).toHaveBeenCalled();
|
|
246
|
+
|
|
247
|
+
infoSpy.mockRestore();
|
|
248
|
+
warnSpy.mockRestore();
|
|
249
|
+
errorSpy.mockRestore();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('setupServerDebugListeners should cover server-side debug branches (with and without sendStream)', async () => {
|
|
253
|
+
const infoSpy = jest.spyOn(console, 'info').mockImplementation(() => undefined);
|
|
254
|
+
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
|
255
|
+
|
|
256
|
+
// Fake server implementation shape used by setupServerDebugListeners
|
|
257
|
+
const middlewares: any[] = [];
|
|
258
|
+
const dispatcher: any = {
|
|
259
|
+
sendMessage: jest.fn((target: any, origin: string, type: string, requestId: string, data?: any) => {
|
|
260
|
+
// noop
|
|
261
|
+
void target;
|
|
262
|
+
void origin;
|
|
263
|
+
void type;
|
|
264
|
+
void requestId;
|
|
265
|
+
void data;
|
|
266
|
+
})
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const serverImpl: any = {
|
|
270
|
+
messageDispatcher: dispatcher,
|
|
271
|
+
// Will be wrapped by setupServerMessageDebugging
|
|
272
|
+
handleRequest: jest.fn(),
|
|
273
|
+
runMiddlewares: jest.fn((req: any, res: any, cb: any) => cb())
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const fakeServer: any = {
|
|
277
|
+
use: jest.fn((mw: any) => middlewares.push(mw)),
|
|
278
|
+
// allow setupServerDebugListeners to find impl fields via cast
|
|
279
|
+
messageDispatcher: dispatcher
|
|
280
|
+
};
|
|
281
|
+
// Attach impl fields directly on fakeServer (since code uses `server as any`)
|
|
282
|
+
Object.assign(fakeServer, serverImpl);
|
|
283
|
+
|
|
284
|
+
setupServerDebugListeners(fakeServer);
|
|
285
|
+
expect(fakeServer.use).toHaveBeenCalled();
|
|
286
|
+
|
|
287
|
+
// Grab the middleware registered by setupServerDebugListeners
|
|
288
|
+
const mw = middlewares[0];
|
|
289
|
+
expect(typeof mw).toBe('function');
|
|
290
|
+
|
|
291
|
+
const req: any = {
|
|
292
|
+
requestId: 'rid-1',
|
|
293
|
+
path: '/api/test',
|
|
294
|
+
body: { a: 1 },
|
|
295
|
+
origin: 'https://example.com',
|
|
296
|
+
headers: { h: 'v' },
|
|
297
|
+
cookies: { c: '1' }
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
// Case A: res has sendStream
|
|
301
|
+
const resA: any = {
|
|
302
|
+
statusCode: 200,
|
|
303
|
+
headers: {},
|
|
304
|
+
send: jest.fn(async () => true),
|
|
305
|
+
json: jest.fn(async () => true),
|
|
306
|
+
sendFile: jest.fn(async () => true),
|
|
307
|
+
sendStream: jest.fn(async () => undefined),
|
|
308
|
+
status: jest.fn(function (code: number) { this.statusCode = code; return this; }),
|
|
309
|
+
setHeader: jest.fn(function (name: string, value: any) { this.headers[name] = value; })
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
await new Promise<void>((resolve) => mw(req, resA, resolve));
|
|
313
|
+
// Trigger overridden methods (cover branches)
|
|
314
|
+
resA.status(201);
|
|
315
|
+
resA.setHeader('X-Test', 'v');
|
|
316
|
+
await resA.send({ ok: true }, { requireAck: true });
|
|
317
|
+
await resA.json({ ok: true }, { requireAck: false });
|
|
318
|
+
await resA.sendFile('content', { fileName: 'a.txt', mimeType: 'text/plain' });
|
|
319
|
+
await resA.sendStream({ streamId: 'sid-1' });
|
|
320
|
+
|
|
321
|
+
// Case B: res has NO sendStream (skip that override branch)
|
|
322
|
+
const resB: any = {
|
|
323
|
+
statusCode: 200,
|
|
324
|
+
headers: {},
|
|
325
|
+
send: jest.fn(async () => true),
|
|
326
|
+
json: jest.fn(async () => true),
|
|
327
|
+
sendFile: jest.fn(async () => true),
|
|
328
|
+
status: jest.fn(function (code: number) { this.statusCode = code; return this; }),
|
|
329
|
+
setHeader: jest.fn(function (name: string, value: any) { this.headers[name] = value; })
|
|
330
|
+
};
|
|
331
|
+
await new Promise<void>((resolve) => mw({ ...req, requestId: 'rid-2' }, resB, resolve));
|
|
332
|
+
await resB.send({ ok: true });
|
|
333
|
+
|
|
334
|
+
// Cover dispatcher message-level logging branches installed by setupServerMessageDebugging
|
|
335
|
+
fakeServer.messageDispatcher.sendMessage({} as any, '*', 'ack', 'rid-1', { path: '/p' });
|
|
336
|
+
fakeServer.messageDispatcher.sendMessage({} as any, '*', 'async', 'rid-1', { path: '/p' });
|
|
337
|
+
fakeServer.messageDispatcher.sendMessage({} as any, '*', 'stream_start', 'rid-1', { body: { streamId: 's', type: 'file', chunked: true, autoResolve: true, metadata: { a: 1 } } });
|
|
338
|
+
fakeServer.messageDispatcher.sendMessage({} as any, '*', 'stream_data', 'rid-1', { body: { streamId: 's', done: false, data: 'xxx' } });
|
|
339
|
+
fakeServer.messageDispatcher.sendMessage({} as any, '*', 'stream_end', 'rid-1', { body: { streamId: 's' } });
|
|
340
|
+
fakeServer.messageDispatcher.sendMessage({} as any, '*', 'error', 'rid-1', { status: 500, statusText: 'ERR', error: { message: 'x' }, path: '/p' });
|
|
341
|
+
fakeServer.messageDispatcher.sendMessage({} as any, '*', 'response', 'rid-1', { status: 200, statusText: 'OK', requireAck: false, path: '/p' });
|
|
342
|
+
|
|
343
|
+
// Cover handleRequest wrapper branch
|
|
344
|
+
fakeServer.handleRequest({ requestId: 'rid-3', path: '/p', role: 'client', creatorId: 'c' }, { origin: 'o' });
|
|
345
|
+
// Cover runMiddlewares wrapper branch
|
|
346
|
+
fakeServer.runMiddlewares({ requestId: 'rid-4', path: '/p' }, {} as any, () => undefined);
|
|
347
|
+
|
|
348
|
+
expect(infoSpy).toHaveBeenCalled();
|
|
349
|
+
expect(errorSpy).toHaveBeenCalled();
|
|
350
|
+
|
|
351
|
+
infoSpy.mockRestore();
|
|
352
|
+
errorSpy.mockRestore();
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
@@ -101,6 +101,8 @@ describe('debug', () => {
|
|
|
101
101
|
|
|
102
102
|
expect(console.info).toHaveBeenCalledWith(
|
|
103
103
|
expect.stringContaining('[Client] Request Start'),
|
|
104
|
+
expect.any(String),
|
|
105
|
+
expect.any(String),
|
|
104
106
|
expect.objectContaining({
|
|
105
107
|
path: 'test',
|
|
106
108
|
body: { param: 'value' }
|
|
@@ -109,6 +111,8 @@ describe('debug', () => {
|
|
|
109
111
|
|
|
110
112
|
expect(console.info).toHaveBeenCalledWith(
|
|
111
113
|
expect.stringContaining('[Client] Request Success'),
|
|
114
|
+
expect.any(String),
|
|
115
|
+
expect.any(String),
|
|
112
116
|
expect.objectContaining({
|
|
113
117
|
requestId: expect.any(String),
|
|
114
118
|
status: 200
|
|
@@ -144,6 +148,8 @@ describe('debug', () => {
|
|
|
144
148
|
|
|
145
149
|
expect(console.error).toHaveBeenCalledWith(
|
|
146
150
|
expect.stringContaining('[Client] Request Failed'),
|
|
151
|
+
expect.any(String),
|
|
152
|
+
expect.any(String),
|
|
147
153
|
expect.objectContaining({
|
|
148
154
|
code: expect.any(String)
|
|
149
155
|
})
|
|
@@ -258,6 +264,8 @@ describe('debug', () => {
|
|
|
258
264
|
|
|
259
265
|
expect(console.info).toHaveBeenCalledWith(
|
|
260
266
|
expect.stringContaining('[Client] Request Success (File)'),
|
|
267
|
+
expect.any(String),
|
|
268
|
+
expect.any(String),
|
|
261
269
|
expect.objectContaining({
|
|
262
270
|
fileData: expect.objectContaining({
|
|
263
271
|
fileName: 'test.txt'
|
|
@@ -320,6 +328,8 @@ describe('debug', () => {
|
|
|
320
328
|
|
|
321
329
|
expect(console.info).toHaveBeenCalledWith(
|
|
322
330
|
expect.stringContaining('[Client] Received ACK'),
|
|
331
|
+
expect.any(String),
|
|
332
|
+
expect.any(String),
|
|
323
333
|
expect.objectContaining({
|
|
324
334
|
requestId: expect.any(String)
|
|
325
335
|
})
|
|
@@ -370,6 +380,8 @@ describe('debug', () => {
|
|
|
370
380
|
|
|
371
381
|
expect(console.info).toHaveBeenCalledWith(
|
|
372
382
|
expect.stringContaining('[Server] Received Request'),
|
|
383
|
+
expect.any(String),
|
|
384
|
+
expect.any(String),
|
|
373
385
|
expect.objectContaining({
|
|
374
386
|
path: 'test',
|
|
375
387
|
body: { param: 'value' }
|
|
@@ -378,6 +390,8 @@ describe('debug', () => {
|
|
|
378
390
|
|
|
379
391
|
expect(console.info).toHaveBeenCalledWith(
|
|
380
392
|
expect.stringContaining('[Server] Sending Response'),
|
|
393
|
+
expect.any(String),
|
|
394
|
+
expect.any(String),
|
|
381
395
|
expect.objectContaining({
|
|
382
396
|
status: 200
|
|
383
397
|
})
|
|
@@ -426,6 +440,8 @@ describe('debug', () => {
|
|
|
426
440
|
|
|
427
441
|
expect(console.info).toHaveBeenCalledWith(
|
|
428
442
|
expect.stringContaining('[Server] Setting Status Code'),
|
|
443
|
+
expect.any(String),
|
|
444
|
+
expect.any(String),
|
|
429
445
|
expect.objectContaining({
|
|
430
446
|
statusCode: 404
|
|
431
447
|
})
|
|
@@ -475,6 +491,8 @@ describe('debug', () => {
|
|
|
475
491
|
|
|
476
492
|
expect(console.info).toHaveBeenCalledWith(
|
|
477
493
|
expect.stringContaining('[Server] Setting Header'),
|
|
494
|
+
expect.any(String),
|
|
495
|
+
expect.any(String),
|
|
478
496
|
expect.objectContaining({
|
|
479
497
|
header: 'X-Custom',
|
|
480
498
|
value: 'value'
|
|
@@ -527,6 +545,8 @@ describe('debug', () => {
|
|
|
527
545
|
|
|
528
546
|
expect(console.info).toHaveBeenCalledWith(
|
|
529
547
|
expect.stringContaining('[Server] Sending File'),
|
|
548
|
+
expect.any(String),
|
|
549
|
+
expect.any(String),
|
|
530
550
|
expect.objectContaining({
|
|
531
551
|
fileName: 'test.txt',
|
|
532
552
|
mimeType: 'text/plain'
|
|
@@ -576,6 +596,8 @@ describe('debug', () => {
|
|
|
576
596
|
|
|
577
597
|
expect(console.info).toHaveBeenCalledWith(
|
|
578
598
|
expect.stringContaining('[Server] Sending JSON Response'),
|
|
599
|
+
expect.any(String),
|
|
600
|
+
expect.any(String),
|
|
579
601
|
expect.objectContaining({
|
|
580
602
|
status: 200
|
|
581
603
|
})
|
|
@@ -373,10 +373,11 @@ describe('MessageDispatcher', () => {
|
|
|
373
373
|
delete (message as any).role;
|
|
374
374
|
delete (message as any).creatorId;
|
|
375
375
|
|
|
376
|
-
dispatcher.send(targetWindow, message, 'https://example.com');
|
|
376
|
+
const ok = dispatcher.send(targetWindow, message, 'https://example.com');
|
|
377
377
|
|
|
378
378
|
expect(message.role).toBe(MessageRole.CLIENT);
|
|
379
379
|
expect(message.creatorId).toBe('instance-1');
|
|
380
|
+
expect(ok).toBe(true);
|
|
380
381
|
expect(targetWindow.postMessage).toHaveBeenCalled();
|
|
381
382
|
});
|
|
382
383
|
|
|
@@ -391,10 +392,11 @@ describe('MessageDispatcher', () => {
|
|
|
391
392
|
creatorId: 'custom-id'
|
|
392
393
|
});
|
|
393
394
|
|
|
394
|
-
dispatcher.send(targetWindow, message, 'https://example.com');
|
|
395
|
+
const ok = dispatcher.send(targetWindow, message, 'https://example.com');
|
|
395
396
|
|
|
396
397
|
expect(message.role).toBe(MessageRole.SERVER);
|
|
397
398
|
expect(message.creatorId).toBe('custom-id');
|
|
399
|
+
expect(ok).toBe(true);
|
|
398
400
|
});
|
|
399
401
|
|
|
400
402
|
it('should use default origin * when not specified', () => {
|
|
@@ -406,8 +408,9 @@ describe('MessageDispatcher', () => {
|
|
|
406
408
|
path: 'test'
|
|
407
409
|
});
|
|
408
410
|
|
|
409
|
-
dispatcher.send(targetWindow, message);
|
|
411
|
+
const ok = dispatcher.send(targetWindow, message);
|
|
410
412
|
|
|
413
|
+
expect(ok).toBe(true);
|
|
411
414
|
expect(targetWindow.postMessage).toHaveBeenCalledWith(
|
|
412
415
|
expect.any(Object),
|
|
413
416
|
'*'
|
|
@@ -421,7 +424,7 @@ describe('MessageDispatcher', () => {
|
|
|
421
424
|
postMessage: jest.fn()
|
|
422
425
|
} as any;
|
|
423
426
|
|
|
424
|
-
dispatcher.sendMessage(
|
|
427
|
+
const ok = dispatcher.sendMessage(
|
|
425
428
|
targetWindow,
|
|
426
429
|
'https://example.com',
|
|
427
430
|
MessageType.REQUEST,
|
|
@@ -432,6 +435,7 @@ describe('MessageDispatcher', () => {
|
|
|
432
435
|
}
|
|
433
436
|
);
|
|
434
437
|
|
|
438
|
+
expect(ok).toBe(true);
|
|
435
439
|
expect(targetWindow.postMessage).toHaveBeenCalledWith(
|
|
436
440
|
expect.objectContaining({
|
|
437
441
|
type: 'request',
|