request-iframe 0.0.5 → 0.0.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.
Files changed (54) hide show
  1. package/README.CN.md +1 -1
  2. package/README.md +1 -1
  3. package/package.json +5 -4
  4. package/react/library/index.d.ts.map +1 -1
  5. package/react/library/index.js +4 -1
  6. package/library/__tests__/channel.test.ts +0 -432
  7. package/library/__tests__/coverage-branches.test.ts +0 -356
  8. package/library/__tests__/debug.test.ts +0 -610
  9. package/library/__tests__/dispatcher.test.ts +0 -485
  10. package/library/__tests__/interceptors.test.ts +0 -146
  11. package/library/__tests__/requestIframe.test.ts +0 -5590
  12. package/library/__tests__/server.test.ts +0 -738
  13. package/library/__tests__/stream.test.ts +0 -726
  14. package/library/__tests__/utils.test.ts +0 -473
  15. package/library/api/client.d.js +0 -5
  16. package/library/api/server.d.js +0 -5
  17. package/library/constants/index.d.js +0 -36
  18. package/library/constants/messages.d.js +0 -5
  19. package/library/core/client.d.js +0 -5
  20. package/library/core/message-handler.d.ts +0 -110
  21. package/library/core/message-handler.d.ts.map +0 -1
  22. package/library/core/message-handler.js +0 -320
  23. package/library/core/request-response.d.ts +0 -59
  24. package/library/core/request-response.d.ts.map +0 -1
  25. package/library/core/request-response.js +0 -337
  26. package/library/core/request.d.js +0 -5
  27. package/library/core/response.d.js +0 -5
  28. package/library/core/server-base.d.ts +0 -86
  29. package/library/core/server-base.d.ts.map +0 -1
  30. package/library/core/server-base.js +0 -257
  31. package/library/core/server-client.d.js +0 -5
  32. package/library/core/server-client.d.ts +0 -101
  33. package/library/core/server-client.d.ts.map +0 -1
  34. package/library/core/server-client.js +0 -266
  35. package/library/core/server.d.js +0 -5
  36. package/library/interceptors/index.d.js +0 -5
  37. package/library/message/channel.d.js +0 -5
  38. package/library/message/dispatcher.d.js +0 -5
  39. package/library/message/index.d.js +0 -25
  40. package/library/stream/file-stream.d.js +0 -4
  41. package/library/stream/index.d.js +0 -58
  42. package/library/stream/readable-stream.d.js +0 -5
  43. package/library/stream/types.d.js +0 -5
  44. package/library/stream/writable-stream.d.js +0 -5
  45. package/library/types/index.d.js +0 -5
  46. package/library/utils/cache.d.js +0 -5
  47. package/library/utils/cookie.d.js +0 -5
  48. package/library/utils/debug.d.js +0 -5
  49. package/library/utils/index.d.js +0 -94
  50. package/library/utils/path-match.d.js +0 -5
  51. package/library/utils/protocol.d.js +0 -5
  52. package/react/library/__tests__/index.test.d.ts +0 -2
  53. package/react/library/__tests__/index.test.d.ts.map +0 -1
  54. package/react/library/__tests__/index.test.tsx +0 -792
@@ -1,726 +0,0 @@
1
- /**
2
- * Stream functionality tests
3
- */
4
- import type { MessageChannel } from '../message';
5
- import {
6
- IframeWritableStream,
7
- IframeReadableStream,
8
- IframeFileWritableStream,
9
- IframeFileReadableStream,
10
- isIframeReadableStream,
11
- isIframeFileReadableStream,
12
- isIframeFileWritableStream,
13
- StreamMessageHandler
14
- } from '../stream';
15
-
16
- describe('Stream', () => {
17
- describe('IframeWritableStream', () => {
18
- let mockTargetWindow: Window;
19
- let mockPostMessage: jest.Mock;
20
- /** Mock channel: only send() is used by WritableStream */
21
- let mockChannel: MessageChannel;
22
-
23
- beforeEach(() => {
24
- mockPostMessage = jest.fn();
25
- mockTargetWindow = {
26
- postMessage: mockPostMessage
27
- } as any;
28
- mockChannel = {
29
- send: (target: Window, message: any, origin: string) => {
30
- target.postMessage(message, origin);
31
- return true;
32
- }
33
- } as unknown as MessageChannel;
34
- });
35
-
36
- it('should create stream with default options', () => {
37
- const stream = new IframeWritableStream();
38
-
39
- expect(stream.streamId).toBeDefined();
40
- expect(stream.type).toBe('data');
41
- expect(stream.chunked).toBe(true);
42
- expect(stream.state).toBe('pending');
43
- });
44
-
45
- it('should create stream with custom options', () => {
46
- const stream = new IframeWritableStream({
47
- type: 'file',
48
- chunked: false,
49
- metadata: { foo: 'bar' }
50
- });
51
-
52
- expect(stream.type).toBe('file');
53
- expect(stream.chunked).toBe(false);
54
- });
55
-
56
- it('should throw error when starting without binding', async () => {
57
- const stream = new IframeWritableStream();
58
-
59
- await expect(stream.start()).rejects.toThrow();
60
- });
61
-
62
- it('should generate unique stream IDs', () => {
63
- const stream1 = new IframeWritableStream();
64
- const stream2 = new IframeWritableStream();
65
-
66
- expect(stream1.streamId).not.toBe(stream2.streamId);
67
- });
68
-
69
- it('should start stream with iterator', async () => {
70
- const stream = new IframeWritableStream({
71
- iterator: async function* () {
72
- yield 'chunk1';
73
- yield 'chunk2';
74
- yield 'chunk3';
75
- }
76
- });
77
-
78
- stream._bind({
79
- requestId: 'req-123',
80
- targetWindow: mockTargetWindow,
81
- targetOrigin: 'https://example.com',
82
- secretKey: 'test',
83
- channel: mockChannel
84
- });
85
-
86
- await stream.start();
87
-
88
- expect(stream.state).toBe('ended');
89
- // start + 3 data chunks + end = 5 calls
90
- expect(mockPostMessage).toHaveBeenCalledTimes(5);
91
- });
92
-
93
- it('should stop streaming when target window is closed', async () => {
94
- let streamDataCount = 0;
95
- mockPostMessage.mockImplementation((msg: any) => {
96
- if (msg?.type === 'stream_data') {
97
- streamDataCount += 1;
98
- // After first chunk, simulate target window closed
99
- (mockTargetWindow as any).closed = true;
100
- }
101
- });
102
-
103
- // Make mockChannel respect closed flag
104
- (mockChannel as any).send = (target: any, message: any, origin: string) => {
105
- if (target?.closed === true) return false;
106
- target.postMessage(message, origin);
107
- return true;
108
- };
109
-
110
- const stream = new IframeWritableStream({
111
- iterator: async function* () {
112
- yield 'chunk1';
113
- yield 'chunk2';
114
- yield 'chunk3';
115
- }
116
- });
117
-
118
- // mockTargetWindow now supports closed/document checks in isWindowAvailable
119
- (mockTargetWindow as any).closed = false;
120
- (mockTargetWindow as any).document = {};
121
-
122
- stream._bind({
123
- requestId: 'req-123',
124
- targetWindow: mockTargetWindow,
125
- targetOrigin: 'https://example.com',
126
- secretKey: 'test',
127
- channel: mockChannel
128
- });
129
-
130
- await expect(stream.start()).rejects.toThrow('Stream was cancelled');
131
- expect(stream.state).toBe('cancelled');
132
- expect(streamDataCount).toBe(1);
133
- });
134
-
135
- it('should start stream with next function', async () => {
136
- let callCount = 0;
137
- const stream = new IframeWritableStream({
138
- next: () => {
139
- callCount++;
140
- if (callCount === 1) {
141
- return { data: 'chunk1', done: false };
142
- } else if (callCount === 2) {
143
- return { data: 'chunk2', done: false };
144
- } else {
145
- return { data: 'chunk3', done: true };
146
- }
147
- }
148
- });
149
-
150
- stream._bind({
151
- requestId: 'req-123',
152
- targetWindow: mockTargetWindow,
153
- targetOrigin: 'https://example.com',
154
- secretKey: 'test',
155
- channel: mockChannel
156
- });
157
-
158
- await stream.start();
159
-
160
- expect(stream.state).toBe('ended');
161
- // start + 3 data chunks + end = 5 calls
162
- expect(mockPostMessage).toHaveBeenCalledTimes(5);
163
- });
164
-
165
- it('should start stream without data source', async () => {
166
- const stream = new IframeWritableStream();
167
-
168
- stream._bind({
169
- requestId: 'req-123',
170
- targetWindow: mockTargetWindow,
171
- targetOrigin: 'https://example.com',
172
- secretKey: 'test',
173
- channel: mockChannel
174
- });
175
-
176
- await stream.start();
177
-
178
- expect(stream.state).toBe('ended');
179
- expect(mockPostMessage).toHaveBeenCalledTimes(2); // start + end
180
- });
181
-
182
- it('should handle iterator error', async () => {
183
- const stream = new IframeWritableStream({
184
- iterator: async function* () {
185
- yield 'chunk1';
186
- throw new Error('Iterator error');
187
- }
188
- });
189
-
190
- stream._bind({
191
- requestId: 'req-123',
192
- targetWindow: mockTargetWindow,
193
- targetOrigin: 'https://example.com',
194
- secretKey: 'test',
195
- channel: mockChannel
196
- });
197
-
198
- await stream.start();
199
-
200
- expect(stream.state).toBe('error');
201
- const errorCall = mockPostMessage.mock.calls.find((call: any[]) =>
202
- call[0]?.type === 'stream_error'
203
- );
204
- expect(errorCall).toBeDefined();
205
- });
206
-
207
- it('should handle next function error', async () => {
208
- const stream = new IframeWritableStream({
209
- next: () => {
210
- throw new Error('Next error');
211
- }
212
- });
213
-
214
- stream._bind({
215
- requestId: 'req-123',
216
- targetWindow: mockTargetWindow,
217
- targetOrigin: 'https://example.com',
218
- secretKey: 'test',
219
- channel: mockChannel
220
- });
221
-
222
- await stream.start();
223
-
224
- expect(stream.state).toBe('error');
225
- });
226
-
227
- it('should cancel stream', () => {
228
- const stream = new IframeWritableStream();
229
-
230
- stream._bind({
231
- requestId: 'req-123',
232
- targetWindow: mockTargetWindow,
233
- targetOrigin: 'https://example.com',
234
- secretKey: 'test',
235
- channel: mockChannel
236
- });
237
-
238
- stream.cancel('User cancelled');
239
-
240
- expect(stream.state).toBe('cancelled');
241
- const cancelCall = mockPostMessage.mock.calls.find((call: any[]) =>
242
- call[0]?.type === 'stream_cancel'
243
- );
244
- expect(cancelCall).toBeDefined();
245
- });
246
-
247
- it('should not cancel if already ended', () => {
248
- const stream = new IframeWritableStream();
249
- stream._bind({
250
- requestId: 'req-123',
251
- targetWindow: mockTargetWindow,
252
- targetOrigin: 'https://example.com',
253
- secretKey: 'test',
254
- channel: mockChannel
255
- });
256
-
257
- // Manually set state to ended (simulating already ended)
258
- (stream as any)._state = 'ended';
259
- mockPostMessage.mockClear();
260
-
261
- stream.cancel('User cancelled');
262
-
263
- expect(stream.state).toBe('ended');
264
- expect(mockPostMessage).not.toHaveBeenCalled();
265
- });
266
-
267
- it('should use channel if provided', async () => {
268
- const mockChannel = {
269
- send: jest.fn(() => true)
270
- } as any;
271
-
272
- const stream = new IframeWritableStream();
273
-
274
- stream._bind({
275
- requestId: 'req-123',
276
- targetWindow: mockTargetWindow,
277
- targetOrigin: 'https://example.com',
278
- secretKey: 'test',
279
- channel: mockChannel
280
- });
281
-
282
- await stream.start();
283
-
284
- expect(mockChannel.send).toHaveBeenCalled();
285
- expect(mockPostMessage).not.toHaveBeenCalled();
286
- });
287
-
288
- it('should handle stream cancellation before start', () => {
289
- const stream = new IframeWritableStream({
290
- iterator: async function* () {
291
- yield 'chunk1';
292
- }
293
- });
294
-
295
- stream._bind({
296
- requestId: 'req-123',
297
- targetWindow: mockTargetWindow,
298
- targetOrigin: 'https://example.com',
299
- secretKey: 'test',
300
- channel: mockChannel
301
- });
302
-
303
- stream.cancel('User cancelled');
304
-
305
- expect(stream.state).toBe('cancelled');
306
- const cancelCall = mockPostMessage.mock.calls.find(
307
- (call: any[]) => call[0]?.type === 'stream_cancel'
308
- );
309
- expect(cancelCall).toBeDefined();
310
- });
311
-
312
- it('should handle stream error during iteration', async () => {
313
- const stream = new IframeWritableStream({
314
- iterator: async function* () {
315
- yield 'chunk1';
316
- throw new Error('Stream error');
317
- }
318
- });
319
-
320
- stream._bind({
321
- requestId: 'req-123',
322
- targetWindow: mockTargetWindow,
323
- targetOrigin: 'https://example.com',
324
- secretKey: 'test',
325
- channel: mockChannel
326
- });
327
-
328
- await stream.start();
329
-
330
- expect(stream.state).toBe('error');
331
- const errorCall = mockPostMessage.mock.calls.find(
332
- (call: any[]) => call[0]?.type === 'stream_error'
333
- );
334
- expect(errorCall).toBeDefined();
335
- });
336
-
337
- it('should not end if already cancelled', async () => {
338
- const stream = new IframeWritableStream({
339
- iterator: async function* () {
340
- yield 'chunk1';
341
- }
342
- });
343
-
344
- stream._bind({
345
- requestId: 'req-123',
346
- targetWindow: mockTargetWindow,
347
- targetOrigin: 'https://example.com',
348
- secretKey: 'test',
349
- channel: mockChannel
350
- });
351
-
352
- const startPromise = stream.start();
353
- stream.cancel('Cancelled');
354
- await startPromise;
355
-
356
- expect(stream.state).toBe('cancelled');
357
- });
358
- });
359
-
360
- describe('IframeReadableStream', () => {
361
- let mockHandler: StreamMessageHandler;
362
- let registeredHandlers: Map<string, (data: any) => void>;
363
-
364
- beforeEach(() => {
365
- registeredHandlers = new Map();
366
- mockHandler = {
367
- registerStreamHandler: jest.fn((streamId, handler) => {
368
- registeredHandlers.set(streamId, handler);
369
- }),
370
- unregisterStreamHandler: jest.fn((streamId) => {
371
- registeredHandlers.delete(streamId);
372
- }),
373
- postMessage: jest.fn()
374
- };
375
- });
376
-
377
- it('should create readable stream', () => {
378
- const stream = new IframeReadableStream(
379
- 'test-stream-id',
380
- 'test-request-id',
381
- mockHandler,
382
- { type: 'data', chunked: true }
383
- );
384
-
385
- expect(stream.streamId).toBe('test-stream-id');
386
- expect(stream.type).toBe('data');
387
- expect(stream.chunked).toBe(true);
388
- expect(stream.state).toBe('pending');
389
- expect(mockHandler.registerStreamHandler).toHaveBeenCalledWith(
390
- 'test-stream-id',
391
- expect.any(Function)
392
- );
393
- });
394
-
395
- it('should handle stream data', async () => {
396
- const stream = new IframeReadableStream<string>(
397
- 'test-stream-id',
398
- 'test-request-id',
399
- mockHandler
400
- );
401
-
402
- const handler = registeredHandlers.get('test-stream-id');
403
- expect(handler).toBeDefined();
404
-
405
- // Send data
406
- handler!({ type: 'data', streamId: 'test-stream-id', data: 'chunk1' });
407
- handler!({ type: 'data', streamId: 'test-stream-id', data: 'chunk2', done: true });
408
-
409
- // Read data
410
- const result = await stream.read();
411
- expect(result).toEqual(['chunk1', 'chunk2']);
412
- expect(stream.state).toBe('ended');
413
- });
414
-
415
- it('should handle stream end', async () => {
416
- const stream = new IframeReadableStream<string>(
417
- 'test-stream-id',
418
- 'test-request-id',
419
- mockHandler
420
- );
421
-
422
- const handler = registeredHandlers.get('test-stream-id');
423
-
424
- const onEndCallback = jest.fn();
425
- stream.onEnd(onEndCallback);
426
-
427
- handler!({ type: 'data', streamId: 'test-stream-id', data: 'test' });
428
- handler!({ type: 'end', streamId: 'test-stream-id' });
429
-
430
- await stream.read();
431
- expect(onEndCallback).toHaveBeenCalled();
432
- });
433
-
434
- it('should handle stream error', async () => {
435
- const stream = new IframeReadableStream<string>(
436
- 'test-stream-id',
437
- 'test-request-id',
438
- mockHandler
439
- );
440
-
441
- const handler = registeredHandlers.get('test-stream-id');
442
-
443
- const onErrorCallback = jest.fn();
444
- stream.onError(onErrorCallback);
445
-
446
- handler!({ type: 'error', streamId: 'test-stream-id', error: 'Test error' });
447
-
448
- await expect(stream.read()).rejects.toThrow();
449
- expect(onErrorCallback).toHaveBeenCalled();
450
- expect(stream.state).toBe('error');
451
- });
452
-
453
- it('should support async iterator', async () => {
454
- const stream = new IframeReadableStream<string>(
455
- 'test-stream-id',
456
- 'test-request-id',
457
- mockHandler
458
- );
459
-
460
- const handler = registeredHandlers.get('test-stream-id');
461
-
462
- // Simulate async data sending
463
- setTimeout(() => {
464
- handler!({ type: 'data', streamId: 'test-stream-id', data: 'a' });
465
- handler!({ type: 'data', streamId: 'test-stream-id', data: 'b' });
466
- handler!({ type: 'end', streamId: 'test-stream-id' });
467
- }, 10);
468
-
469
- const chunks: string[] = [];
470
- for await (const chunk of stream) {
471
- chunks.push(chunk);
472
- if (chunks.length >= 2) break; // Prevent infinite wait
473
- }
474
-
475
- expect(chunks).toEqual(['a', 'b']);
476
- });
477
-
478
- it('should cancel stream', () => {
479
- const stream = new IframeReadableStream<string>(
480
- 'test-stream-id',
481
- 'test-request-id',
482
- mockHandler
483
- );
484
-
485
- stream.cancel('User cancelled');
486
-
487
- expect(stream.state).toBe('cancelled');
488
- expect(mockHandler.postMessage).toHaveBeenCalled();
489
- expect(mockHandler.unregisterStreamHandler).toHaveBeenCalledWith('test-stream-id');
490
- });
491
-
492
- it('should not cancel if already ended', () => {
493
- const stream = new IframeReadableStream<string>(
494
- 'test-stream-id',
495
- 'test-request-id',
496
- mockHandler
497
- );
498
-
499
- const handler = registeredHandlers.get('test-stream-id');
500
- handler!({ type: 'end', streamId: 'test-stream-id' });
501
-
502
- jest.clearAllMocks();
503
- stream.cancel('User cancelled');
504
-
505
- expect(stream.state).toBe('ended');
506
- expect(mockHandler.postMessage).not.toHaveBeenCalled();
507
- });
508
-
509
- it('should not cancel if already in error state', () => {
510
- const stream = new IframeReadableStream<string>(
511
- 'test-stream-id',
512
- 'test-request-id',
513
- mockHandler
514
- );
515
-
516
- const handler = registeredHandlers.get('test-stream-id');
517
- handler!({ type: 'error', streamId: 'test-stream-id', error: 'Error' });
518
-
519
- jest.clearAllMocks();
520
- stream.cancel('User cancelled');
521
-
522
- expect(stream.state).toBe('error');
523
- expect(mockHandler.postMessage).not.toHaveBeenCalled();
524
- });
525
-
526
- it('should handle stream data with done flag', async () => {
527
- const stream = new IframeReadableStream<string>(
528
- 'test-stream-id',
529
- 'test-request-id',
530
- mockHandler
531
- );
532
-
533
- const handler = registeredHandlers.get('test-stream-id');
534
- handler!({ type: 'data', streamId: 'test-stream-id', data: 'chunk1', done: true });
535
-
536
- const result = await stream.read();
537
- expect(result).toBe('chunk1');
538
- expect(stream.state).toBe('ended');
539
- });
540
-
541
- it('should handle onEnd callback when stream already ended', () => {
542
- const stream = new IframeReadableStream<string>(
543
- 'test-stream-id',
544
- 'test-request-id',
545
- mockHandler
546
- );
547
-
548
- const handler = registeredHandlers.get('test-stream-id');
549
- handler!({ type: 'end', streamId: 'test-stream-id' });
550
-
551
- const callback = jest.fn();
552
- stream.onEnd(callback);
553
- expect(callback).toHaveBeenCalled();
554
- });
555
- });
556
-
557
- describe('IframeFileWritableStream', () => {
558
- it('should create file stream with filename', () => {
559
- const stream = new IframeFileWritableStream({
560
- filename: 'test.txt',
561
- mimeType: 'text/plain',
562
- size: 1024
563
- });
564
-
565
- expect(stream.type).toBe('file');
566
- expect(stream.filename).toBe('test.txt');
567
- expect(stream.mimeType).toBe('text/plain');
568
- expect(stream.size).toBe(1024);
569
- });
570
- });
571
-
572
- describe('IframeFileReadableStream', () => {
573
- let mockHandler: StreamMessageHandler;
574
- let registeredHandlers: Map<string, (data: any) => void>;
575
-
576
- beforeEach(() => {
577
- registeredHandlers = new Map();
578
- mockHandler = {
579
- registerStreamHandler: jest.fn((streamId, handler) => {
580
- registeredHandlers.set(streamId, handler);
581
- }),
582
- unregisterStreamHandler: jest.fn((streamId) => {
583
- registeredHandlers.delete(streamId);
584
- }),
585
- postMessage: jest.fn()
586
- };
587
- });
588
-
589
- it('should create file readable stream', () => {
590
- const stream = new IframeFileReadableStream(
591
- 'test-stream-id',
592
- 'test-request-id',
593
- mockHandler,
594
- {
595
- filename: 'test.txt',
596
- mimeType: 'text/plain',
597
- size: 100
598
- }
599
- );
600
-
601
- expect(stream.type).toBe('file');
602
- expect(stream.filename).toBe('test.txt');
603
- expect(stream.mimeType).toBe('text/plain');
604
- });
605
-
606
- it('should decode base64 data', async () => {
607
- const stream = new IframeFileReadableStream(
608
- 'test-stream-id',
609
- 'test-request-id',
610
- mockHandler
611
- );
612
-
613
- const handler = registeredHandlers.get('test-stream-id');
614
-
615
- // Send base64 encoded data
616
- const testData = 'Hello, World!';
617
- const base64Data = btoa(testData);
618
- handler!({ type: 'data', streamId: 'test-stream-id', data: base64Data, done: true });
619
-
620
- const result = await stream.read();
621
- expect(result).toBeInstanceOf(Uint8Array);
622
-
623
- // Decode to verify content (manually convert Uint8Array to string)
624
- let decoded = '';
625
- for (let i = 0; i < result.length; i++) {
626
- decoded += String.fromCharCode(result[i]);
627
- }
628
- expect(decoded).toBe(testData);
629
- });
630
-
631
- it('should read as Blob', async () => {
632
- const stream = new IframeFileReadableStream(
633
- 'test-stream-id',
634
- 'test-request-id',
635
- mockHandler,
636
- { mimeType: 'text/plain' }
637
- );
638
-
639
- const handler = registeredHandlers.get('test-stream-id');
640
- const base64Data = btoa('test');
641
- handler!({ type: 'data', streamId: 'test-stream-id', data: base64Data, done: true });
642
-
643
- const blob = await stream.readAsBlob();
644
- expect(blob).toBeInstanceOf(Blob);
645
- expect(blob.type).toBe('text/plain');
646
- });
647
-
648
- it('should read as ArrayBuffer', async () => {
649
- const stream = new IframeFileReadableStream(
650
- 'test-stream-id',
651
- 'test-request-id',
652
- mockHandler
653
- );
654
-
655
- const handler = registeredHandlers.get('test-stream-id');
656
- const base64Data = btoa('test');
657
- handler!({ type: 'data', streamId: 'test-stream-id', data: base64Data, done: true });
658
-
659
- const buffer = await stream.readAsArrayBuffer();
660
- expect(buffer).toBeInstanceOf(ArrayBuffer);
661
- });
662
-
663
- it('should read as Data URL', async () => {
664
- const stream = new IframeFileReadableStream(
665
- 'test-stream-id',
666
- 'test-request-id',
667
- mockHandler,
668
- { mimeType: 'text/plain' }
669
- );
670
-
671
- const handler = registeredHandlers.get('test-stream-id');
672
- const base64Data = btoa('test');
673
- handler!({ type: 'data', streamId: 'test-stream-id', data: base64Data, done: true });
674
-
675
- const dataUrl = await stream.readAsDataURL();
676
- expect(dataUrl).toMatch(/^data:text\/plain;base64,/);
677
- });
678
- });
679
-
680
- describe('Type guards', () => {
681
- let mockHandler: StreamMessageHandler;
682
-
683
- beforeEach(() => {
684
- mockHandler = {
685
- registerStreamHandler: jest.fn(),
686
- unregisterStreamHandler: jest.fn(),
687
- postMessage: jest.fn()
688
- };
689
- });
690
-
691
- it('isIframeReadableStream should return true for IframeReadableStream', () => {
692
- const stream = new IframeReadableStream('id', 'reqId', mockHandler);
693
- expect(isIframeReadableStream(stream)).toBe(true);
694
- });
695
-
696
- it('isIframeReadableStream should return false for non-stream objects', () => {
697
- expect(isIframeReadableStream({})).toBe(false);
698
- expect(isIframeReadableStream(null)).toBe(false);
699
- expect(isIframeReadableStream('string')).toBe(false);
700
- });
701
-
702
- it('isIframeFileReadableStream should return true for IframeFileReadableStream', () => {
703
- const stream = new IframeFileReadableStream('id', 'reqId', mockHandler);
704
- expect(isIframeFileReadableStream(stream)).toBe(true);
705
- });
706
-
707
- it('isIframeFileReadableStream should return false for regular IframeReadableStream', () => {
708
- const stream = new IframeReadableStream('id', 'reqId', mockHandler);
709
- expect(isIframeFileReadableStream(stream)).toBe(false);
710
- });
711
-
712
- it('isIframeFileWritableStream should return true for IframeFileWritableStream', () => {
713
- const stream = new IframeFileWritableStream({
714
- filename: 'test.txt',
715
- mimeType: 'text/plain',
716
- next: async () => ({ data: btoa('test'), done: true })
717
- });
718
- expect(isIframeFileWritableStream(stream)).toBe(true);
719
- });
720
-
721
- it('isIframeFileWritableStream should return false for regular IframeWritableStream', () => {
722
- const stream = new IframeWritableStream();
723
- expect(isIframeFileWritableStream(stream)).toBe(false);
724
- });
725
- });
726
- });