request-iframe 0.0.2 → 0.0.4
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 +439 -36
- package/README.md +496 -30
- package/library/__tests__/channel.test.ts +420 -0
- package/library/__tests__/coverage-branches.test.ts +356 -0
- package/library/__tests__/debug.test.ts +588 -0
- package/library/__tests__/dispatcher.test.ts +481 -0
- package/library/__tests__/requestIframe.test.ts +3163 -185
- package/library/__tests__/server.test.ts +738 -0
- package/library/__tests__/stream.test.ts +46 -15
- package/library/api/client.d.ts.map +1 -1
- package/library/api/client.js +12 -6
- package/library/api/server.d.ts +4 -3
- package/library/api/server.d.ts.map +1 -1
- package/library/api/server.js +25 -7
- package/library/constants/index.d.ts +14 -4
- package/library/constants/index.d.ts.map +1 -1
- package/library/constants/index.js +15 -7
- package/library/constants/messages.d.ts +37 -0
- package/library/constants/messages.d.ts.map +1 -1
- package/library/constants/messages.js +38 -1
- package/library/core/client-server.d.ts +105 -0
- package/library/core/client-server.d.ts.map +1 -0
- package/library/core/client-server.js +289 -0
- package/library/core/client.d.ts +53 -10
- package/library/core/client.d.ts.map +1 -1
- package/library/core/client.js +529 -207
- 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 +30 -4
- package/library/core/response.d.ts.map +1 -1
- package/library/core/response.js +176 -100
- package/library/core/server-client.d.ts +3 -1
- package/library/core/server-client.d.ts.map +1 -1
- package/library/core/server-client.js +19 -9
- package/library/core/server.d.ts +22 -1
- package/library/core/server.d.ts.map +1 -1
- package/library/core/server.js +304 -55
- package/library/index.d.ts +3 -2
- package/library/index.d.ts.map +1 -1
- package/library/index.js +34 -5
- package/library/interceptors/index.d.ts.map +1 -1
- package/library/message/channel.d.ts +3 -1
- package/library/message/channel.d.ts.map +1 -1
- package/library/message/dispatcher.d.ts +7 -2
- package/library/message/dispatcher.d.ts.map +1 -1
- package/library/message/dispatcher.js +48 -2
- package/library/message/index.d.ts.map +1 -1
- package/library/stream/file-stream.d.ts +5 -0
- package/library/stream/file-stream.d.ts.map +1 -1
- package/library/stream/file-stream.js +41 -12
- 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/readable-stream.d.ts.map +1 -1
- package/library/stream/readable-stream.js +32 -30
- package/library/stream/types.d.ts +20 -2
- package/library/stream/types.d.ts.map +1 -1
- package/library/stream/writable-stream.d.ts +2 -1
- package/library/stream/writable-stream.d.ts.map +1 -1
- package/library/stream/writable-stream.js +13 -10
- package/library/types/index.d.ts +106 -32
- package/library/types/index.d.ts.map +1 -1
- package/library/utils/cache.d.ts +24 -0
- package/library/utils/cache.d.ts.map +1 -1
- package/library/utils/cache.js +76 -0
- package/library/utils/cookie.d.ts.map +1 -1
- package/library/utils/debug.d.ts.map +1 -1
- package/library/utils/debug.js +382 -20
- package/library/utils/index.d.ts +19 -0
- package/library/utils/index.d.ts.map +1 -1
- package/library/utils/index.js +113 -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/library/utils/protocol.d.ts.map +1 -1
- package/package.json +4 -1
- package/react/library/__tests__/index.test.tsx +274 -281
- package/react/library/index.d.ts +4 -3
- package/react/library/index.d.ts.map +1 -1
- package/react/library/index.js +225 -158
- package/react/package.json +7 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
import { MessageDispatcher } from '../message/dispatcher';
|
|
2
|
+
import { MessageChannel } from '../message/channel';
|
|
3
|
+
import { MessageRole, MessageType, ProtocolVersion } from '../constants';
|
|
4
|
+
import { createPostMessage } from '../utils';
|
|
5
|
+
import { MessageContext } from '../message/channel';
|
|
6
|
+
|
|
7
|
+
describe('MessageDispatcher', () => {
|
|
8
|
+
let channel: MessageChannel;
|
|
9
|
+
let dispatcher: MessageDispatcher;
|
|
10
|
+
let mockHandler: jest.Mock;
|
|
11
|
+
let mockContext: MessageContext;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
channel = new MessageChannel();
|
|
15
|
+
dispatcher = new MessageDispatcher(channel, MessageRole.CLIENT, 'instance-1');
|
|
16
|
+
mockHandler = jest.fn();
|
|
17
|
+
mockContext = {
|
|
18
|
+
source: window,
|
|
19
|
+
origin: 'https://example.com'
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
dispatcher.destroy();
|
|
25
|
+
channel.destroy();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('constructor', () => {
|
|
29
|
+
it('should create dispatcher with channel and role', () => {
|
|
30
|
+
expect(dispatcher.secretKey).toBeUndefined();
|
|
31
|
+
expect(dispatcher.type).toBe('postMessage');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should create dispatcher with secretKey from channel', () => {
|
|
35
|
+
const channelWithKey = new MessageChannel('test-key');
|
|
36
|
+
const dispatcherWithKey = new MessageDispatcher(channelWithKey, MessageRole.SERVER);
|
|
37
|
+
expect(dispatcherWithKey.secretKey).toBe('test-key');
|
|
38
|
+
dispatcherWithKey.destroy();
|
|
39
|
+
channelWithKey.destroy();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should create dispatcher with instanceId', () => {
|
|
43
|
+
const dispatcherWithId = new MessageDispatcher(channel, MessageRole.CLIENT, 'custom-id');
|
|
44
|
+
expect(dispatcherWithId).toBeDefined();
|
|
45
|
+
dispatcherWithId.destroy();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('reference counting', () => {
|
|
50
|
+
it('should increment reference count', () => {
|
|
51
|
+
expect(dispatcher.getRefCount()).toBe(0);
|
|
52
|
+
dispatcher.addRef();
|
|
53
|
+
expect(dispatcher.getRefCount()).toBe(1);
|
|
54
|
+
dispatcher.addRef();
|
|
55
|
+
expect(dispatcher.getRefCount()).toBe(2);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should decrement reference count', () => {
|
|
59
|
+
dispatcher.addRef();
|
|
60
|
+
dispatcher.addRef();
|
|
61
|
+
expect(dispatcher.release()).toBe(1);
|
|
62
|
+
expect(dispatcher.release()).toBe(0);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('registerHandler', () => {
|
|
67
|
+
it('should register handler with string matcher', () => {
|
|
68
|
+
const unregister = dispatcher.registerHandler(MessageType.REQUEST, mockHandler);
|
|
69
|
+
|
|
70
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
71
|
+
path: 'test',
|
|
72
|
+
role: MessageRole.SERVER
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
76
|
+
|
|
77
|
+
expect(mockHandler).toHaveBeenCalledWith(message, mockContext);
|
|
78
|
+
unregister();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should register handler with regex matcher', () => {
|
|
82
|
+
const unregister = dispatcher.registerHandler(/^stream_/, mockHandler);
|
|
83
|
+
|
|
84
|
+
const message = createPostMessage(MessageType.STREAM_START, 'req123', {
|
|
85
|
+
body: { streamId: 'stream-1' },
|
|
86
|
+
role: MessageRole.SERVER
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
90
|
+
|
|
91
|
+
expect(mockHandler).toHaveBeenCalledWith(message, mockContext);
|
|
92
|
+
unregister();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should register handler with function matcher', () => {
|
|
96
|
+
const matcher = (type: string) => type.startsWith('stream_');
|
|
97
|
+
const unregister = dispatcher.registerHandler(matcher, mockHandler);
|
|
98
|
+
|
|
99
|
+
const message = createPostMessage(MessageType.STREAM_DATA, 'req123', {
|
|
100
|
+
body: { streamId: 'stream-1' },
|
|
101
|
+
role: MessageRole.SERVER
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
105
|
+
|
|
106
|
+
expect(mockHandler).toHaveBeenCalledWith(message, mockContext);
|
|
107
|
+
unregister();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should support priority ordering', () => {
|
|
111
|
+
const handler1 = jest.fn();
|
|
112
|
+
const handler2 = jest.fn();
|
|
113
|
+
|
|
114
|
+
dispatcher.registerHandler(MessageType.REQUEST, handler1, { priority: 1 });
|
|
115
|
+
dispatcher.registerHandler(MessageType.REQUEST, handler2, { priority: 2 });
|
|
116
|
+
|
|
117
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
118
|
+
path: 'test',
|
|
119
|
+
role: MessageRole.SERVER
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
123
|
+
|
|
124
|
+
// Higher priority handler should be called first
|
|
125
|
+
expect(handler2.mock.invocationCallOrder[0]).toBeLessThan(handler1.mock.invocationCallOrder[0]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should support legacy priority API (number)', () => {
|
|
129
|
+
const handler1 = jest.fn();
|
|
130
|
+
const handler2 = jest.fn();
|
|
131
|
+
|
|
132
|
+
dispatcher.registerHandler(MessageType.REQUEST, handler1, 1);
|
|
133
|
+
dispatcher.registerHandler(MessageType.REQUEST, handler2, 2);
|
|
134
|
+
|
|
135
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
136
|
+
path: 'test',
|
|
137
|
+
role: MessageRole.SERVER
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
141
|
+
|
|
142
|
+
expect(handler2.mock.invocationCallOrder[0]).toBeLessThan(handler1.mock.invocationCallOrder[0]);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should return unregister function', () => {
|
|
146
|
+
const unregister = dispatcher.registerHandler(MessageType.REQUEST, mockHandler);
|
|
147
|
+
|
|
148
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
149
|
+
path: 'test',
|
|
150
|
+
role: MessageRole.SERVER
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
unregister();
|
|
154
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
155
|
+
|
|
156
|
+
expect(mockHandler).not.toHaveBeenCalled();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe('unregisterHandler', () => {
|
|
161
|
+
it('should unregister handler by function reference', () => {
|
|
162
|
+
dispatcher.registerHandler(MessageType.REQUEST, mockHandler);
|
|
163
|
+
dispatcher.unregisterHandler(mockHandler);
|
|
164
|
+
|
|
165
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
166
|
+
path: 'test',
|
|
167
|
+
role: MessageRole.SERVER
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
171
|
+
|
|
172
|
+
expect(mockHandler).not.toHaveBeenCalled();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe('role-based filtering', () => {
|
|
177
|
+
it('should only process messages from opposite role (client receives from server)', () => {
|
|
178
|
+
const clientDispatcher = new MessageDispatcher(channel, MessageRole.CLIENT);
|
|
179
|
+
clientDispatcher.registerHandler(MessageType.RESPONSE, mockHandler);
|
|
180
|
+
|
|
181
|
+
// Message from server (should be processed)
|
|
182
|
+
const serverMessage = createPostMessage(MessageType.RESPONSE, 'req123', {
|
|
183
|
+
role: MessageRole.SERVER
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
clientDispatcher['dispatchMessage'](serverMessage, mockContext);
|
|
187
|
+
expect(mockHandler).toHaveBeenCalled();
|
|
188
|
+
|
|
189
|
+
// Message from client (should be ignored)
|
|
190
|
+
const clientMessage = createPostMessage(MessageType.RESPONSE, 'req124', {
|
|
191
|
+
role: MessageRole.CLIENT
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
mockHandler.mockClear();
|
|
195
|
+
clientDispatcher['dispatchMessage'](clientMessage, mockContext);
|
|
196
|
+
expect(mockHandler).not.toHaveBeenCalled();
|
|
197
|
+
|
|
198
|
+
clientDispatcher.destroy();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should only process messages from opposite role (server receives from client)', () => {
|
|
202
|
+
const serverDispatcher = new MessageDispatcher(channel, MessageRole.SERVER);
|
|
203
|
+
serverDispatcher.registerHandler(MessageType.REQUEST, mockHandler);
|
|
204
|
+
|
|
205
|
+
// Message from client (should be processed)
|
|
206
|
+
const clientMessage = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
207
|
+
role: MessageRole.CLIENT
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
serverDispatcher['dispatchMessage'](clientMessage, mockContext);
|
|
211
|
+
expect(mockHandler).toHaveBeenCalled();
|
|
212
|
+
|
|
213
|
+
// Message from server (should be ignored)
|
|
214
|
+
const serverMessage = createPostMessage(MessageType.REQUEST, 'req124', {
|
|
215
|
+
role: MessageRole.SERVER
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
mockHandler.mockClear();
|
|
219
|
+
serverDispatcher['dispatchMessage'](serverMessage, mockContext);
|
|
220
|
+
expect(mockHandler).not.toHaveBeenCalled();
|
|
221
|
+
|
|
222
|
+
serverDispatcher.destroy();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should process messages without role (backward compatibility)', () => {
|
|
226
|
+
dispatcher.registerHandler(MessageType.REQUEST, mockHandler);
|
|
227
|
+
|
|
228
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
229
|
+
path: 'test'
|
|
230
|
+
});
|
|
231
|
+
delete (message as any).role;
|
|
232
|
+
|
|
233
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
234
|
+
expect(mockHandler).toHaveBeenCalled();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe('version validation', () => {
|
|
239
|
+
it('should validate protocol version', () => {
|
|
240
|
+
const versionValidator = jest.fn((version: number) => version >= ProtocolVersion.MIN_SUPPORTED);
|
|
241
|
+
const onVersionError = jest.fn();
|
|
242
|
+
|
|
243
|
+
dispatcher.registerHandler(MessageType.REQUEST, mockHandler, {
|
|
244
|
+
versionValidator,
|
|
245
|
+
onVersionError
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Valid version
|
|
249
|
+
const validMessage = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
250
|
+
path: 'test',
|
|
251
|
+
role: MessageRole.SERVER
|
|
252
|
+
});
|
|
253
|
+
(validMessage as any).__requestIframe__ = ProtocolVersion.CURRENT;
|
|
254
|
+
|
|
255
|
+
dispatcher['dispatchMessage'](validMessage, mockContext);
|
|
256
|
+
expect(mockHandler).toHaveBeenCalled();
|
|
257
|
+
expect(onVersionError).not.toHaveBeenCalled();
|
|
258
|
+
|
|
259
|
+
// Invalid version
|
|
260
|
+
const invalidMessage = createPostMessage(MessageType.REQUEST, 'req124', {
|
|
261
|
+
path: 'test',
|
|
262
|
+
role: MessageRole.SERVER
|
|
263
|
+
});
|
|
264
|
+
(invalidMessage as any).__requestIframe__ = 0; // Invalid version
|
|
265
|
+
|
|
266
|
+
mockHandler.mockClear();
|
|
267
|
+
dispatcher['dispatchMessage'](invalidMessage, mockContext);
|
|
268
|
+
expect(mockHandler).not.toHaveBeenCalled();
|
|
269
|
+
expect(onVersionError).toHaveBeenCalledWith(
|
|
270
|
+
invalidMessage,
|
|
271
|
+
mockContext,
|
|
272
|
+
0
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('should continue to other handlers when version validation fails', () => {
|
|
277
|
+
const handler1 = jest.fn();
|
|
278
|
+
const handler2 = jest.fn();
|
|
279
|
+
|
|
280
|
+
dispatcher.registerHandler(MessageType.REQUEST, handler1, {
|
|
281
|
+
versionValidator: () => false
|
|
282
|
+
});
|
|
283
|
+
dispatcher.registerHandler(MessageType.REQUEST, handler2);
|
|
284
|
+
|
|
285
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
286
|
+
path: 'test',
|
|
287
|
+
role: MessageRole.SERVER
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
291
|
+
|
|
292
|
+
expect(handler1).not.toHaveBeenCalled();
|
|
293
|
+
expect(handler2).toHaveBeenCalled();
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
describe('handledBy context', () => {
|
|
298
|
+
it('should skip processing if message already handled', () => {
|
|
299
|
+
dispatcher.registerHandler(MessageType.REQUEST, mockHandler);
|
|
300
|
+
|
|
301
|
+
const context: MessageContext = {
|
|
302
|
+
...mockContext,
|
|
303
|
+
handledBy: 'other-instance'
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
307
|
+
path: 'test',
|
|
308
|
+
role: MessageRole.SERVER
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
dispatcher['dispatchMessage'](message, context);
|
|
312
|
+
expect(mockHandler).not.toHaveBeenCalled();
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('should stop processing after handler sets handledBy', () => {
|
|
316
|
+
const handler1 = jest.fn((data, context) => {
|
|
317
|
+
context.handledBy = 'instance-1';
|
|
318
|
+
});
|
|
319
|
+
const handler2 = jest.fn();
|
|
320
|
+
|
|
321
|
+
dispatcher.registerHandler(MessageType.REQUEST, handler1);
|
|
322
|
+
dispatcher.registerHandler(MessageType.REQUEST, handler2);
|
|
323
|
+
|
|
324
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
325
|
+
path: 'test',
|
|
326
|
+
role: MessageRole.SERVER
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
330
|
+
|
|
331
|
+
expect(handler1).toHaveBeenCalled();
|
|
332
|
+
expect(handler2).not.toHaveBeenCalled();
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
describe('error handling', () => {
|
|
337
|
+
it('should handle handler errors gracefully', () => {
|
|
338
|
+
const errorHandler = jest.fn(() => {
|
|
339
|
+
throw new Error('Handler error');
|
|
340
|
+
});
|
|
341
|
+
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
342
|
+
|
|
343
|
+
dispatcher.registerHandler(MessageType.REQUEST, errorHandler);
|
|
344
|
+
dispatcher.registerHandler(MessageType.REQUEST, mockHandler);
|
|
345
|
+
|
|
346
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
347
|
+
path: 'test',
|
|
348
|
+
role: MessageRole.SERVER
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
352
|
+
|
|
353
|
+
expect(errorHandler).toHaveBeenCalled();
|
|
354
|
+
expect(mockHandler).toHaveBeenCalled(); // Other handlers should still be called
|
|
355
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
356
|
+
'[request-iframe] Handler error:',
|
|
357
|
+
expect.any(Error)
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
consoleErrorSpy.mockRestore();
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
describe('send', () => {
|
|
365
|
+
it('should send message with role and creatorId', () => {
|
|
366
|
+
const targetWindow = {
|
|
367
|
+
postMessage: jest.fn()
|
|
368
|
+
} as any;
|
|
369
|
+
|
|
370
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
371
|
+
path: 'test'
|
|
372
|
+
});
|
|
373
|
+
delete (message as any).role;
|
|
374
|
+
delete (message as any).creatorId;
|
|
375
|
+
|
|
376
|
+
dispatcher.send(targetWindow, message, 'https://example.com');
|
|
377
|
+
|
|
378
|
+
expect(message.role).toBe(MessageRole.CLIENT);
|
|
379
|
+
expect(message.creatorId).toBe('instance-1');
|
|
380
|
+
expect(targetWindow.postMessage).toHaveBeenCalled();
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('should not override existing role and creatorId', () => {
|
|
384
|
+
const targetWindow = {
|
|
385
|
+
postMessage: jest.fn()
|
|
386
|
+
} as any;
|
|
387
|
+
|
|
388
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
389
|
+
path: 'test',
|
|
390
|
+
role: MessageRole.SERVER,
|
|
391
|
+
creatorId: 'custom-id'
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
dispatcher.send(targetWindow, message, 'https://example.com');
|
|
395
|
+
|
|
396
|
+
expect(message.role).toBe(MessageRole.SERVER);
|
|
397
|
+
expect(message.creatorId).toBe('custom-id');
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('should use default origin * when not specified', () => {
|
|
401
|
+
const targetWindow = {
|
|
402
|
+
postMessage: jest.fn()
|
|
403
|
+
} as any;
|
|
404
|
+
|
|
405
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
406
|
+
path: 'test'
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
dispatcher.send(targetWindow, message);
|
|
410
|
+
|
|
411
|
+
expect(targetWindow.postMessage).toHaveBeenCalledWith(
|
|
412
|
+
expect.any(Object),
|
|
413
|
+
'*'
|
|
414
|
+
);
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
describe('sendMessage', () => {
|
|
419
|
+
it('should create and send message with role and creatorId', () => {
|
|
420
|
+
const targetWindow = {
|
|
421
|
+
postMessage: jest.fn()
|
|
422
|
+
} as any;
|
|
423
|
+
|
|
424
|
+
dispatcher.sendMessage(
|
|
425
|
+
targetWindow,
|
|
426
|
+
'https://example.com',
|
|
427
|
+
MessageType.REQUEST,
|
|
428
|
+
'req123',
|
|
429
|
+
{
|
|
430
|
+
path: 'test',
|
|
431
|
+
body: { param: 'value' }
|
|
432
|
+
}
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
expect(targetWindow.postMessage).toHaveBeenCalledWith(
|
|
436
|
+
expect.objectContaining({
|
|
437
|
+
type: 'request',
|
|
438
|
+
requestId: 'req123',
|
|
439
|
+
path: 'test',
|
|
440
|
+
body: { param: 'value' },
|
|
441
|
+
role: MessageRole.CLIENT,
|
|
442
|
+
creatorId: 'instance-1'
|
|
443
|
+
}),
|
|
444
|
+
'https://example.com'
|
|
445
|
+
);
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
describe('prefixPath', () => {
|
|
450
|
+
it('should delegate to channel prefixPath', () => {
|
|
451
|
+
const channelWithKey = new MessageChannel('test-key');
|
|
452
|
+
const dispatcherWithKey = new MessageDispatcher(channelWithKey, MessageRole.CLIENT);
|
|
453
|
+
|
|
454
|
+
expect(dispatcherWithKey.prefixPath('test')).toBe('test-key:test');
|
|
455
|
+
|
|
456
|
+
dispatcherWithKey.destroy();
|
|
457
|
+
channelWithKey.destroy();
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
describe('getChannel', () => {
|
|
462
|
+
it('should return underlying channel', () => {
|
|
463
|
+
expect(dispatcher.getChannel()).toBe(channel);
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
describe('destroy', () => {
|
|
468
|
+
it('should clear handlers and remove receiver', () => {
|
|
469
|
+
dispatcher.registerHandler(MessageType.REQUEST, mockHandler);
|
|
470
|
+
dispatcher.destroy();
|
|
471
|
+
|
|
472
|
+
const message = createPostMessage(MessageType.REQUEST, 'req123', {
|
|
473
|
+
path: 'test',
|
|
474
|
+
role: MessageRole.SERVER
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
dispatcher['dispatchMessage'](message, mockContext);
|
|
478
|
+
expect(mockHandler).not.toHaveBeenCalled();
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
});
|