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.
Files changed (69) hide show
  1. package/QUICKSTART.CN.md +35 -8
  2. package/QUICKSTART.md +35 -8
  3. package/README.CN.md +177 -24
  4. package/README.md +237 -19
  5. package/library/__tests__/channel.test.ts +16 -4
  6. package/library/__tests__/coverage-branches.test.ts +356 -0
  7. package/library/__tests__/debug.test.ts +22 -0
  8. package/library/__tests__/dispatcher.test.ts +8 -4
  9. package/library/__tests__/requestIframe.test.ts +1243 -87
  10. package/library/__tests__/stream.test.ts +92 -16
  11. package/library/__tests__/utils.test.ts +41 -1
  12. package/library/api/client.d.ts.map +1 -1
  13. package/library/api/client.js +1 -0
  14. package/library/constants/index.d.ts +2 -0
  15. package/library/constants/index.d.ts.map +1 -1
  16. package/library/constants/index.js +3 -1
  17. package/library/constants/messages.d.ts +3 -0
  18. package/library/constants/messages.d.ts.map +1 -1
  19. package/library/constants/messages.js +3 -0
  20. package/library/core/client-server.d.ts +4 -0
  21. package/library/core/client-server.d.ts.map +1 -1
  22. package/library/core/client-server.js +45 -22
  23. package/library/core/client.d.ts +36 -4
  24. package/library/core/client.d.ts.map +1 -1
  25. package/library/core/client.js +508 -285
  26. package/library/core/request.d.ts +3 -1
  27. package/library/core/request.d.ts.map +1 -1
  28. package/library/core/request.js +2 -1
  29. package/library/core/response.d.ts +26 -4
  30. package/library/core/response.d.ts.map +1 -1
  31. package/library/core/response.js +192 -112
  32. package/library/core/server.d.ts +13 -0
  33. package/library/core/server.d.ts.map +1 -1
  34. package/library/core/server.js +221 -6
  35. package/library/index.d.ts +2 -1
  36. package/library/index.d.ts.map +1 -1
  37. package/library/index.js +39 -3
  38. package/library/message/channel.d.ts +2 -2
  39. package/library/message/channel.d.ts.map +1 -1
  40. package/library/message/channel.js +5 -1
  41. package/library/message/dispatcher.d.ts +2 -2
  42. package/library/message/dispatcher.d.ts.map +1 -1
  43. package/library/message/dispatcher.js +6 -5
  44. package/library/stream/index.d.ts +11 -1
  45. package/library/stream/index.d.ts.map +1 -1
  46. package/library/stream/index.js +21 -3
  47. package/library/stream/types.d.ts +2 -2
  48. package/library/stream/types.d.ts.map +1 -1
  49. package/library/stream/writable-stream.d.ts +1 -1
  50. package/library/stream/writable-stream.d.ts.map +1 -1
  51. package/library/stream/writable-stream.js +87 -47
  52. package/library/types/index.d.ts +29 -5
  53. package/library/types/index.d.ts.map +1 -1
  54. package/library/utils/debug.d.ts.map +1 -1
  55. package/library/utils/debug.js +6 -2
  56. package/library/utils/error.d.ts +21 -0
  57. package/library/utils/error.d.ts.map +1 -0
  58. package/library/utils/error.js +34 -0
  59. package/library/utils/index.d.ts +21 -0
  60. package/library/utils/index.d.ts.map +1 -1
  61. package/library/utils/index.js +141 -2
  62. package/library/utils/path-match.d.ts +16 -0
  63. package/library/utils/path-match.d.ts.map +1 -1
  64. package/library/utils/path-match.js +65 -0
  65. package/package.json +2 -1
  66. package/react/library/__tests__/index.test.tsx +44 -22
  67. package/react/library/index.d.ts.map +1 -1
  68. package/react/library/index.js +81 -23
  69. 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',