MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1import { test, testThrows, testDeep, summary } from './helpers.js';
2
3console.log('FormData constructor\n');
4
5const fd0 = new FormData();
6test('empty constructor', fd0.has('x'), false);
7
8testThrows('requires new', () => FormData());
9testThrows('rejects form element', () => new FormData(document));
10
11console.log('\nappend / get / has / delete / set\n');
12
13const fd = new FormData();
14
15fd.append('name', 'Alice');
16test('append then get', fd.get('name'), 'Alice');
17test('has returns true', fd.has('name'), true);
18test('has missing returns false', fd.has('other'), false);
19
20fd.append('name', 'Bob');
21const all = fd.getAll('name');
22test('getAll length after two appends', all.length, 2);
23test('getAll first', all[0], 'Alice');
24test('getAll second', all[1], 'Bob');
25
26fd.set('name', 'Carol');
27test('set replaces all', fd.getAll('name').length, 1);
28test('set value', fd.get('name'), 'Carol');
29
30fd.delete('name');
31test('delete removes all', fd.has('name'), false);
32test('get after delete returns null', fd.get('name'), null);
33
34console.log('\nBlob values\n');
35
36const blob = new Blob(['hello'], { type: 'text/plain' });
37const fdb = new FormData();
38fdb.append('file', blob);
39
40const got = fdb.get('file');
41test('blob entry is File instance', got instanceof File, true);
42test('blob entry filename default', got.name, 'blob');
43test('blob entry type', got.type, 'text/plain');
44
45fdb.append('file2', blob, 'custom.txt');
46const got2 = fdb.get('file2');
47test('blob with filename', got2.name, 'custom.txt');
48
49console.log('\nFile values\n');
50
51const file = new File(['world'], 'test.txt', { type: 'text/html' });
52const fdf = new FormData();
53fdf.append('upload', file);
54
55const gotf = fdf.get('upload');
56test('file entry is File instance', gotf instanceof File, true);
57test('file entry name from File', gotf.name, 'test.txt');
58test('file entry type', gotf.type, 'text/html');
59
60fdf.append('upload2', file, 'override.txt');
61test('file entry name overridden', fdf.get('upload2').name, 'override.txt');
62
63console.log('\ngetAll with mixed types\n');
64
65const fdm = new FormData();
66fdm.append('x', 'str');
67fdm.append('x', new Blob(['data']));
68const mixed = fdm.getAll('x');
69test('mixed getAll length', mixed.length, 2);
70test('mixed first is string', mixed[0], 'str');
71test('mixed second is File', mixed[1] instanceof File, true);
72
73console.log('\nforEach\n');
74
75const fdfe = new FormData();
76fdfe.append('b', '2');
77fdfe.append('a', '1');
78const seen = [];
79fdfe.forEach((val, name) => seen.push(`${name}=${val}`));
80test('forEach visits all entries', seen.length, 2);
81test('forEach insertion order first', seen[0], 'b=2');
82test('forEach insertion order second', seen[1], 'a=1');
83
84console.log('\nentries / keys / values\n');
85
86const fdi = new FormData();
87fdi.append('x', '1');
88fdi.append('y', '2');
89fdi.append('x', '3');
90
91const keys = [...fdi.keys()];
92test('keys length', keys.length, 3);
93test('keys first', keys[0], 'x');
94test('keys second', keys[1], 'y');
95test('keys third', keys[2], 'x');
96
97const vals = [...fdi.values()];
98test('values first', vals[0], '1');
99test('values second', vals[1], '2');
100test('values third', vals[2], '3');
101
102const entries = [...fdi.entries()];
103test('entries length', entries.length, 3);
104test('entries first name', entries[0][0], 'x');
105test('entries first value', entries[0][1], '1');
106
107console.log('\nSymbol.iterator\n');
108
109const fds = new FormData();
110fds.append('k', 'v');
111const iter_result = [...fds];
112test('Symbol.iterator yields entries', iter_result.length, 1);
113test('Symbol.iterator entry name', iter_result[0][0], 'k');
114test('Symbol.iterator entry value', iter_result[0][1], 'v');
115
116console.log('\ntoStringTag\n');
117
118test('toStringTag', Object.prototype.toString.call(new FormData()), '[object FormData]');
119
120console.log('\nmultipart parameter parsing\n');
121
122const boundary = 'spec-boundary';
123const multipartBody =
124 `--${boundary}\r\n` +
125 `Content-Disposition: form-data; name="field"\r\n\r\n` +
126 `value\r\n` +
127 `--${boundary}--\r\n`;
128
129const multipartReq = new Request('https://example.com/', {
130 method: 'POST',
131 headers: {
132 'Content-Type': `multipart/form-data; boundaryx=wrong; boundary="${boundary}"`,
133 },
134 body: multipartBody,
135});
136
137const multipartFd = await multipartReq.formData();
138test('multipart boundary lookup skips longer prefix match', multipartFd.get('field'), 'value');
139
140summary();