๐Ÿ“ฆ kitten / multitars

๐Ÿ“„ multipartOutput.test.ts ยท 130 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130import { describe, it, expect, vi } from 'vitest';
import { streamMultipart } from '../multipartOutput';
import { iterableToStream, streamToText } from './utils';
import { MultipartPart } from '../multipartShared';

vi.mock('../multipartEncoding', async importOriginal => ({
  ...(await importOriginal()),
  BOUNDARY_ID: '----formdata-multitars',
}));

describe('streamMultipart', () => {
  it('creates a multipart stream of strings', async () => {
    const data = streamMultipart(
      (async function* () {
        yield ['a', '1'];
        yield ['b', '2'];
      })()
    );

    expect(await streamToText(iterableToStream(data))).toMatchInlineSnapshot(`
      "------formdata-multitars
      Content-Disposition: form-data; name="a"

      1
      ------formdata-multitars
      Content-Disposition: form-data; name="b"

      2
      ------formdata-multitars--

      "
    `);
  });

  it('creates a multipart stream of files', async () => {
    const data = streamMultipart(
      (async function* () {
        yield ['a', new File(['1'], '1.txt')];
        yield ['b', new File(['2'], '2.txt')];
      })()
    );

    expect(await streamToText(iterableToStream(data))).toMatchInlineSnapshot(`
      "------formdata-multitars
      Content-Disposition: form-data; name="a"; filename="1.txt"
      Content-Length: 1

      1
      ------formdata-multitars
      Content-Disposition: form-data; name="b"; filename="2.txt"
      Content-Length: 1

      2
      ------formdata-multitars--

      "
    `);
  });

  it('creates a multipart stream of files with content types', async () => {
    const data = streamMultipart(
      (async function* () {
        yield ['a', new File(['1'], '1.txt', { type: 'text/plain' })];
        yield ['b', new File(['2'], '2.txt', { type: 'test/plain' })];
      })()
    );

    expect(await streamToText(iterableToStream(data))).toMatchInlineSnapshot(`
      "------formdata-multitars
      Content-Disposition: form-data; name="a"; filename="1.txt"
      Content-Type: text/plain
      Content-Length: 1

      1
      ------formdata-multitars
      Content-Disposition: form-data; name="b"; filename="2.txt"
      Content-Type: test/plain
      Content-Length: 1

      2
      ------formdata-multitars--

      "
    `);
  });

  it('encodes special filenames', async () => {
    const filename = 'newline\nfi+l en"am๐Ÿ‘e.txt';
    const data = streamMultipart(
      (async function* () {
        yield [filename, new File(['1'], filename)];
      })()
    );

    expect(await streamToText(iterableToStream(data))).toMatchInlineSnapshot(`
      "------formdata-multitars
      Content-Disposition: form-data; name="newline%0Afi+l en%22am๐Ÿ‘e.txt"; filename="newline%0Afi+l en%22am๐Ÿ‘e.txt"
      Content-Length: 1

      1
      ------formdata-multitars--

      "
    `);
  });

  it('adds custom header entries', async () => {
    const data = streamMultipart(
      (async function* () {
        const file = new MultipartPart(['1'], '1', {
          headers: { 'custom-signature': '123' },
        });
        yield ['1', file];
      })()
    );

    expect(await streamToText(iterableToStream(data))).toMatchInlineSnapshot(`
      "------formdata-multitars
      Content-Disposition: form-data; name="1"; filename="1"
      Content-Type: application/octet-stream
      custom-signature: 123

      1
      ------formdata-multitars--

      "
    `);
  });
});