MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1import { test, testThrows, testDeep, summary } from './helpers.js';
2
3console.log('Headers constructor\n');
4
5const h0 = new Headers();
6test('empty constructor', h0.has('x-foo'), false);
7
8const h1 = new Headers({ 'Content-Type': 'text/html', 'x-custom': 'val' });
9test('init from record', h1.get('content-type'), 'text/html');
10test('record key case-folded', h1.get('Content-Type'), 'text/html');
11
12const h2 = new Headers([['x-a', '1'], ['x-b', '2']]);
13test('init from sequence', h2.get('x-a'), '1');
14test('init from sequence second', h2.get('x-b'), '2');
15
16const h3 = new Headers(new Headers({ 'x-copy': 'yes' }));
17test('init from another Headers', h3.get('x-copy'), 'yes');
18
19testThrows('requires new', () => Headers());
20testThrows('null init throws', () => new Headers(null));
21testThrows('string init throws', () => new Headers('bad'));
22testThrows('number init throws', () => new Headers(42));
23
24console.log('\nappend / get / has / delete / set\n');
25
26const h = new Headers();
27
28h.append('x-foo', 'one');
29test('append then get', h.get('x-foo'), 'one');
30
31h.append('x-foo', 'two');
32test('append combines values', h.get('x-foo'), 'one, two');
33
34test('has returns true', h.has('x-foo'), true);
35test('has case-insensitive', h.has('X-FOO'), true);
36test('has missing returns false', h.has('x-bar'), false);
37
38h.set('x-foo', 'replaced');
39test('set replaces combined value', h.get('x-foo'), 'replaced');
40
41h.delete('x-foo');
42test('delete removes header', h.has('x-foo'), false);
43test('get deleted returns null', h.get('x-foo'), null);
44
45console.log('\nset-cookie special case\n');
46
47const hc = new Headers();
48hc.append('set-cookie', 'a=1');
49hc.append('set-cookie', 'b=2');
50test('set-cookie not combined', hc.get('set-cookie'), 'a=1');
51
52const cookies = hc.getSetCookie ? hc.getSetCookie() : null;
53if (cookies) {
54 test('getSetCookie length', cookies.length, 2);
55 test('getSetCookie first', cookies[0], 'a=1');
56 test('getSetCookie second', cookies[1], 'b=2');
57}
58
59console.log('\nvalue normalization\n');
60
61const hn = new Headers();
62hn.set('x-trim', ' hello ');
63test('leading/trailing whitespace stripped', hn.get('x-trim'), 'hello');
64
65hn.set('x-tab', '\thello\t');
66test('leading/trailing tab stripped', hn.get('x-tab'), 'hello');
67
68console.log('\ninvalid name / value\n');
69
70testThrows('empty name throws', () => h.set('', 'val'));
71testThrows('name with space throws', () => h.set('x bad', 'val'));
72testThrows('name with colon throws', () => h.set('x:bad', 'val'));
73
74console.log('\nforEach\n');
75
76const hf = new Headers({ 'b-key': 'bval', 'a-key': 'aval' });
77const seen = [];
78hf.forEach((val, name) => seen.push(`${name}:${val}`));
79test('forEach visits all entries', seen.length, 2);
80test('forEach sorted order', seen[0], 'a-key:aval');
81test('forEach sorted order 2', seen[1], 'b-key:bval');
82
83console.log('\nentries / keys / values iteration\n');
84
85const hi = new Headers({ 'b-hdr': '2', 'a-hdr': '1' });
86
87const entries = [...hi.entries()];
88test('entries sorted', entries[0][0], 'a-hdr');
89test('entries value', entries[0][1], '1');
90test('entries length', entries.length, 2);
91
92const keys = [...hi.keys()];
93test('keys sorted', keys[0], 'a-hdr');
94test('keys length', keys.length, 2);
95
96const vals = [...hi.values()];
97test('values order matches keys', vals[0], '1');
98
99console.log('\nlive iteration\n');
100
101const hl = new Headers({ 'x-a': '1' });
102const iter = hl.entries();
103hl.set('x-b', '2');
104const all = [];
105for (const e of { [Symbol.iterator]: () => iter }) all.push(e[0]);
106test('live iterator sees added key', all.includes('x-b'), true);
107
108console.log('\niterator prototype chain\n');
109
110const it = new Headers().entries();
111const iterProto = Object.getPrototypeOf(Object.getPrototypeOf(it));
112test('iterator proto chain has Symbol.iterator', typeof iterProto[Symbol.iterator], 'function');
113
114summary();