cloudflare/cloudflare-typescript

Public

mirrored fromhttps://github.com/cloudflare/cloudflare-typescriptAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v6.0.0-beta.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

tests/qs/stringify.test.ts

2232lines · modecode

1import iconv from 'iconv-lite';
2import { stringify } from 'cloudflare/internal/qs';
3import { encode } from 'cloudflare/internal/qs/utils';
4import { StringifyOptions } from 'cloudflare/internal/qs/types';
5import { empty_test_cases } from './empty-keys-cases';
6import assert from 'assert';
7
8describe('stringify()', function () {
9 test('stringifies a querystring object', function () {
10 expect(stringify({ a: 'b' })).toBe('a=b');
11 expect(stringify({ a: 1 })).toBe('a=1');
12 expect(stringify({ a: 1, b: 2 })).toBe('a=1&b=2');
13 expect(stringify({ a: 'A_Z' })).toBe('a=A_Z');
14 expect(stringify({ a: '€' })).toBe('a=%E2%82%AC');
15 expect(stringify({ a: '' })).toBe('a=%EE%80%80');
16 expect(stringify({ a: 'א' })).toBe('a=%D7%90');
17 expect(stringify({ a: '𐐷' })).toBe('a=%F0%90%90%B7');
18 });
19
20 test('stringifies falsy values', function () {
21 expect(stringify(undefined)).toBe('');
22 expect(stringify(null)).toBe('');
23 expect(stringify(null, { strictNullHandling: true })).toBe('');
24 expect(stringify(false)).toBe('');
25 expect(stringify(0)).toBe('');
26 });
27
28 test('stringifies symbols', function () {
29 expect(stringify(Symbol.iterator)).toBe('');
30 expect(stringify([Symbol.iterator])).toBe('0=Symbol%28Symbol.iterator%29');
31 expect(stringify({ a: Symbol.iterator })).toBe('a=Symbol%28Symbol.iterator%29');
32 expect(stringify({ a: [Symbol.iterator] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
33 'a[]=Symbol%28Symbol.iterator%29',
34 );
35 });
36
37 test('stringifies bigints', function () {
38 var three = BigInt(3);
39 // @ts-expect-error
40 var encodeWithN = function (value, defaultEncoder, charset) {
41 var result = defaultEncoder(value, defaultEncoder, charset);
42 return typeof value === 'bigint' ? result + 'n' : result;
43 };
44
45 expect(stringify(three)).toBe('');
46 expect(stringify([three])).toBe('0=3');
47 expect(stringify([three], { encoder: encodeWithN })).toBe('0=3n');
48 expect(stringify({ a: three })).toBe('a=3');
49 expect(stringify({ a: three }, { encoder: encodeWithN })).toBe('a=3n');
50 expect(stringify({ a: [three] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a[]=3');
51 expect(
52 stringify({ a: [three] }, { encodeValuesOnly: true, encoder: encodeWithN, arrayFormat: 'brackets' }),
53 ).toBe('a[]=3n');
54 });
55
56 test('encodes dot in key of object when encodeDotInKeys and allowDots is provided', function () {
57 expect(
58 stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: false, encodeDotInKeys: false }),
59 ).toBe('name.obj%5Bfirst%5D=John&name.obj%5Blast%5D=Doe');
60 expect(
61 stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: false }),
62 ).toBe('name.obj.first=John&name.obj.last=Doe');
63 expect(
64 stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: false, encodeDotInKeys: true }),
65 ).toBe('name%252Eobj%5Bfirst%5D=John&name%252Eobj%5Blast%5D=Doe');
66 expect(
67 stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: true }),
68 ).toBe('name%252Eobj.first=John&name%252Eobj.last=Doe');
69
70 // st.equal(
71 // stringify(
72 // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
73 // { allowDots: false, encodeDotInKeys: false },
74 // ),
75 // 'name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe',
76 // 'with allowDots false and encodeDotInKeys false',
77 // );
78 // st.equal(
79 // stringify(
80 // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
81 // { allowDots: true, encodeDotInKeys: false },
82 // ),
83 // 'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe',
84 // 'with allowDots false and encodeDotInKeys false',
85 // );
86 // st.equal(
87 // stringify(
88 // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
89 // { allowDots: false, encodeDotInKeys: true },
90 // ),
91 // 'name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe',
92 // 'with allowDots false and encodeDotInKeys true',
93 // );
94 // st.equal(
95 // stringify(
96 // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
97 // { allowDots: true, encodeDotInKeys: true },
98 // ),
99 // 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
100 // 'with allowDots true and encodeDotInKeys true',
101 // );
102 expect(
103 stringify(
104 { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
105 { allowDots: false, encodeDotInKeys: false },
106 ),
107 ).toBe('name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe');
108 expect(
109 stringify(
110 { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
111 { allowDots: true, encodeDotInKeys: false },
112 ),
113 ).toBe('name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe');
114 expect(
115 stringify(
116 { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
117 { allowDots: false, encodeDotInKeys: true },
118 ),
119 ).toBe('name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe');
120 expect(
121 stringify(
122 { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
123 { allowDots: true, encodeDotInKeys: true },
124 ),
125 ).toBe('name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe');
126 });
127
128 test('should encode dot in key of object, and automatically set allowDots to `true` when encodeDotInKeys is true and allowDots in undefined', function () {
129 // st.equal(
130 // stringify(
131 // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
132 // { encodeDotInKeys: true },
133 // ),
134 // 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
135 // 'with allowDots undefined and encodeDotInKeys true',
136 // );
137 expect(
138 stringify(
139 { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
140 { encodeDotInKeys: true },
141 ),
142 ).toBe('name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe');
143 });
144
145 test('should encode dot in key of object when encodeDotInKeys and allowDots is provided, and nothing else when encodeValuesOnly is provided', function () {
146 // st.equal(
147 // stringify(
148 // { 'name.obj': { first: 'John', last: 'Doe' } },
149 // {
150 // encodeDotInKeys: true,
151 // allowDots: true,
152 // encodeValuesOnly: true,
153 // },
154 // ),
155 // 'name%2Eobj.first=John&name%2Eobj.last=Doe',
156 // );
157 expect(
158 stringify(
159 { 'name.obj': { first: 'John', last: 'Doe' } },
160 {
161 encodeDotInKeys: true,
162 allowDots: true,
163 encodeValuesOnly: true,
164 },
165 ),
166 ).toBe('name%2Eobj.first=John&name%2Eobj.last=Doe');
167
168 // st.equal(
169 // stringify(
170 // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
171 // { allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true },
172 // ),
173 // 'name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe',
174 // );
175 expect(
176 stringify(
177 { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
178 { allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true },
179 ),
180 ).toBe('name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe');
181 });
182
183 test('throws when `commaRoundTrip` is not a boolean', function () {
184 // st['throws'](
185 // function () {
186 // stringify({}, { commaRoundTrip: 'not a boolean' });
187 // },
188 // TypeError,
189 // 'throws when `commaRoundTrip` is not a boolean',
190 // );
191 expect(() => {
192 // @ts-expect-error
193 stringify({}, { commaRoundTrip: 'not a boolean' });
194 }).toThrow(TypeError);
195 });
196
197 test('throws when `encodeDotInKeys` is not a boolean', function () {
198 // st['throws'](function () {
199 // stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' });
200 // }, TypeError);
201 expect(() => {
202 // @ts-expect-error
203 stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' });
204 }).toThrow(TypeError);
205
206 // st['throws'](function () {
207 // stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 });
208 // }, TypeError);
209 expect(() => {
210 // @ts-expect-error
211 stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 });
212 }).toThrow(TypeError);
213
214 // st['throws'](function () {
215 // stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN });
216 // }, TypeError);
217 expect(() => {
218 // @ts-expect-error
219 stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN });
220 }).toThrow(TypeError);
221
222 // st['throws'](function () {
223 // stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null });
224 // }, TypeError);
225 expect(() => {
226 // @ts-expect-error
227 stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null });
228 }).toThrow(TypeError);
229 });
230
231 test('adds query prefix', function () {
232 // st.equal(stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
233 expect(stringify({ a: 'b' }, { addQueryPrefix: true })).toBe('?a=b');
234 });
235
236 test('with query prefix, outputs blank string given an empty object', function () {
237 // st.equal(stringify({}, { addQueryPrefix: true }), '');
238 expect(stringify({}, { addQueryPrefix: true })).toBe('');
239 });
240
241 test('stringifies nested falsy values', function () {
242 // st.equal(stringify({ a: { b: { c: null } } }), 'a%5Bb%5D%5Bc%5D=');
243 // st.equal(
244 // stringify({ a: { b: { c: null } } }, { strictNullHandling: true }),
245 // 'a%5Bb%5D%5Bc%5D',
246 // );
247 // st.equal(stringify({ a: { b: { c: false } } }), 'a%5Bb%5D%5Bc%5D=false');
248 expect(stringify({ a: { b: { c: null } } })).toBe('a%5Bb%5D%5Bc%5D=');
249 expect(stringify({ a: { b: { c: null } } }, { strictNullHandling: true })).toBe('a%5Bb%5D%5Bc%5D');
250 expect(stringify({ a: { b: { c: false } } })).toBe('a%5Bb%5D%5Bc%5D=false');
251 });
252
253 test('stringifies a nested object', function () {
254 // st.equal(stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
255 // st.equal(stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e');
256 expect(stringify({ a: { b: 'c' } })).toBe('a%5Bb%5D=c');
257 expect(stringify({ a: { b: { c: { d: 'e' } } } })).toBe('a%5Bb%5D%5Bc%5D%5Bd%5D=e');
258 });
259
260 test('`allowDots` option: stringifies a nested object with dots notation', function () {
261 // st.equal(stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c');
262 // st.equal(stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e');
263 expect(stringify({ a: { b: 'c' } }, { allowDots: true })).toBe('a.b=c');
264 expect(stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true })).toBe('a.b.c.d=e');
265 });
266
267 test('stringifies an array value', function () {
268 // st.equal(
269 // stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' }),
270 // 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
271 // 'indices => indices',
272 // );
273 // st.equal(
274 // stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' }),
275 // 'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d',
276 // 'brackets => brackets',
277 // );
278 // st.equal(
279 // stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma' }),
280 // 'a=b%2Cc%2Cd',
281 // 'comma => comma',
282 // );
283 // st.equal(
284 // stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true }),
285 // 'a=b%2Cc%2Cd',
286 // 'comma round trip => comma',
287 // );
288 // st.equal(
289 // stringify({ a: ['b', 'c', 'd'] }),
290 // 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
291 // 'default => indices',
292 // );
293 expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' })).toBe(
294 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
295 );
296 expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' })).toBe(
297 'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d',
298 );
299 expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma' })).toBe('a=b%2Cc%2Cd');
300 expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true })).toBe(
301 'a=b%2Cc%2Cd',
302 );
303 expect(stringify({ a: ['b', 'c', 'd'] })).toBe('a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d');
304 });
305
306 test('`skipNulls` option', function () {
307 // st.equal(
308 // stringify({ a: 'b', c: null }, { skipNulls: true }),
309 // 'a=b',
310 // 'omits nulls when asked',
311 // );
312 expect(stringify({ a: 'b', c: null }, { skipNulls: true })).toBe('a=b');
313
314 // st.equal(
315 // stringify({ a: { b: 'c', d: null } }, { skipNulls: true }),
316 // 'a%5Bb%5D=c',
317 // 'omits nested nulls when asked',
318 // );
319 expect(stringify({ a: { b: 'c', d: null } }, { skipNulls: true })).toBe('a%5Bb%5D=c');
320 });
321
322 test('omits array indices when asked', function () {
323 // st.equal(stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d');
324 expect(stringify({ a: ['b', 'c', 'd'] }, { indices: false })).toBe('a=b&a=c&a=d');
325 });
326
327 test('omits object key/value pair when value is empty array', function () {
328 // st.equal(stringify({ a: [], b: 'zz' }), 'b=zz');
329 expect(stringify({ a: [], b: 'zz' })).toBe('b=zz');
330 });
331
332 test('should not omit object key/value pair when value is empty array and when asked', function () {
333 // st.equal(stringify({ a: [], b: 'zz' }), 'b=zz');
334 // st.equal(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false }), 'b=zz');
335 // st.equal(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true }), 'a[]&b=zz');
336 expect(stringify({ a: [], b: 'zz' })).toBe('b=zz');
337 expect(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false })).toBe('b=zz');
338 expect(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true })).toBe('a[]&b=zz');
339 });
340
341 test('should throw when allowEmptyArrays is not of type boolean', function () {
342 // st['throws'](function () {
343 // stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' });
344 // }, TypeError);
345 expect(() => {
346 // @ts-expect-error
347 stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' });
348 }).toThrow(TypeError);
349
350 // st['throws'](function () {
351 // stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 });
352 // }, TypeError);
353 expect(() => {
354 // @ts-expect-error
355 stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 });
356 }).toThrow(TypeError);
357
358 // st['throws'](function () {
359 // stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN });
360 // }, TypeError);
361 expect(() => {
362 // @ts-expect-error
363 stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN });
364 }).toThrow(TypeError);
365
366 // st['throws'](function () {
367 // stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null });
368 // }, TypeError);
369 expect(() => {
370 // @ts-expect-error
371 stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null });
372 }).toThrow(TypeError);
373 });
374
375 test('allowEmptyArrays + strictNullHandling', function () {
376 // st.equal(
377 // stringify({ testEmptyArray: [] }, { strictNullHandling: true, allowEmptyArrays: true }),
378 // 'testEmptyArray[]',
379 // );
380 expect(stringify({ testEmptyArray: [] }, { strictNullHandling: true, allowEmptyArrays: true })).toBe(
381 'testEmptyArray[]',
382 );
383 });
384
385 describe('stringifies an array value with one item vs multiple items', function () {
386 test('non-array item', function () {
387 // s2t.equal(
388 // stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
389 // 'a=c',
390 // );
391 // s2t.equal(
392 // stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
393 // 'a=c',
394 // );
395 // s2t.equal(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c');
396 // s2t.equal(stringify({ a: 'c' }, { encodeValuesOnly: true }), 'a=c');
397 expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe('a=c');
398 expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a=c');
399 expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c');
400 expect(stringify({ a: 'c' }, { encodeValuesOnly: true })).toBe('a=c');
401 });
402
403 test('array with a single item', function () {
404 // s2t.equal(
405 // stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
406 // 'a[0]=c',
407 // );
408 // s2t.equal(
409 // stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
410 // 'a[]=c',
411 // );
412 // s2t.equal(
413 // stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
414 // 'a=c',
415 // );
416 // s2t.equal(
417 // stringify(
418 // { a: ['c'] },
419 // { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true },
420 // ),
421 // 'a[]=c',
422 // ); // so it parses back as an array
423 // s2t.equal(stringify({ a: ['c'] }, { encodeValuesOnly: true }), 'a[0]=c');
424 expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe('a[0]=c');
425 expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a[]=c');
426 expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c');
427 expect(
428 stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }),
429 ).toBe('a[]=c');
430 expect(stringify({ a: ['c'] }, { encodeValuesOnly: true })).toBe('a[0]=c');
431 });
432
433 test('array with multiple items', function () {
434 // s2t.equal(
435 // stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
436 // 'a[0]=c&a[1]=d',
437 // );
438 // s2t.equal(
439 // stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
440 // 'a[]=c&a[]=d',
441 // );
442 // s2t.equal(
443 // stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
444 // 'a=c,d',
445 // );
446 // s2t.equal(
447 // stringify(
448 // { a: ['c', 'd'] },
449 // { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true },
450 // ),
451 // 'a=c,d',
452 // );
453 // s2t.equal(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true }), 'a[0]=c&a[1]=d');
454 expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe(
455 'a[0]=c&a[1]=d',
456 );
457 expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
458 'a[]=c&a[]=d',
459 );
460 expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c,d');
461 expect(
462 stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }),
463 ).toBe('a=c,d');
464 expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true })).toBe('a[0]=c&a[1]=d');
465 });
466
467 test('array with multiple items with a comma inside', function () {
468 // s2t.equal(
469 // stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
470 // 'a=c%2Cd,e',
471 // );
472 // s2t.equal(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' }), 'a=c%2Cd%2Ce');
473 expect(stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe(
474 'a=c%2Cd,e',
475 );
476 expect(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' })).toBe('a=c%2Cd%2Ce');
477
478 // s2t.equal(
479 // stringify(
480 // { a: ['c,d', 'e'] },
481 // { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true },
482 // ),
483 // 'a=c%2Cd,e',
484 // );
485 // s2t.equal(
486 // stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true }),
487 // 'a=c%2Cd%2Ce',
488 // );
489 expect(
490 stringify(
491 { a: ['c,d', 'e'] },
492 { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true },
493 ),
494 ).toBe('a=c%2Cd,e');
495 expect(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true })).toBe(
496 'a=c%2Cd%2Ce',
497 );
498 });
499 });
500
501 test('stringifies a nested array value', function () {
502 expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe(
503 'a[b][0]=c&a[b][1]=d',
504 );
505 expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
506 'a[b][]=c&a[b][]=d',
507 );
508 expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe(
509 'a[b]=c,d',
510 );
511 expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true })).toBe('a[b][0]=c&a[b][1]=d');
512 });
513
514 test('stringifies comma and empty array values', function () {
515 // st.equal(
516 // stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' }),
517 // 'a[0]=,&a[1]=&a[2]=c,d%',
518 // );
519 // st.equal(
520 // stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' }),
521 // 'a[]=,&a[]=&a[]=c,d%',
522 // );
523 // st.equal(
524 // stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' }),
525 // 'a=,,,c,d%',
526 // );
527 // st.equal(
528 // stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' }),
529 // 'a=,&a=&a=c,d%',
530 // );
531 expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' })).toBe(
532 'a[0]=,&a[1]=&a[2]=c,d%',
533 );
534 expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' })).toBe(
535 'a[]=,&a[]=&a[]=c,d%',
536 );
537 expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' })).toBe('a=,,,c,d%');
538 expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' })).toBe(
539 'a=,&a=&a=c,d%',
540 );
541
542 // st.equal(
543 // stringify(
544 // { a: [',', '', 'c,d%'] },
545 // { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' },
546 // ),
547 // 'a[0]=%2C&a[1]=&a[2]=c%2Cd%25',
548 // );
549 // st.equal(
550 // stringify(
551 // { a: [',', '', 'c,d%'] },
552 // { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
553 // ),
554 // 'a[]=%2C&a[]=&a[]=c%2Cd%25',
555 // );
556 // st.equal(
557 // stringify(
558 // { a: [',', '', 'c,d%'] },
559 // { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' },
560 // ),
561 // 'a=%2C,,c%2Cd%25',
562 // );
563 // st.equal(
564 // stringify(
565 // { a: [',', '', 'c,d%'] },
566 // { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' },
567 // ),
568 // 'a=%2C&a=&a=c%2Cd%25',
569 // );
570 expect(
571 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }),
572 ).toBe('a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25');
573 expect(
574 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }),
575 ).toBe('a[]=%2C&a[]=&a[]=c%2Cd%25');
576 expect(
577 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }),
578 ).toBe('a=%2C%2C%2Cc%2Cd%25');
579 expect(
580 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }),
581 ).toBe('a=%2C&a=&a=c%2Cd%25');
582
583 // st.equal(
584 // stringify(
585 // { a: [',', '', 'c,d%'] },
586 // { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' },
587 // ),
588 // 'a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25',
589 // );
590 // st.equal(
591 // stringify(
592 // { a: [',', '', 'c,d%'] },
593 // { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' },
594 // ),
595 // 'a%5B%5D=%2C&a%5B%5D=&a%5B%5D=c%2Cd%25',
596 // );
597 // st.equal(
598 // stringify(
599 // { a: [',', '', 'c,d%'] },
600 // { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' },
601 // ),
602 // 'a=%2C%2C%2Cc%2Cd%25',
603 // );
604 // st.equal(
605 // stringify(
606 // { a: [',', '', 'c,d%'] },
607 // { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' },
608 // ),
609 // 'a=%2C&a=&a=c%2Cd%25',
610 // );
611 expect(
612 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }),
613 ).toBe('a=%2C&a=&a=c%2Cd%25');
614 expect(
615 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }),
616 ).toBe('a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25');
617 expect(
618 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }),
619 ).toBe('a[]=%2C&a[]=&a[]=c%2Cd%25');
620 expect(
621 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }),
622 ).toBe('a=%2C%2C%2Cc%2Cd%25');
623 expect(
624 stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }),
625 ).toBe('a=%2C&a=&a=c%2Cd%25');
626 });
627
628 test('stringifies comma and empty non-array values', function () {
629 // st.equal(
630 // stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' }),
631 // 'a=,&b=&c=c,d%',
632 // );
633 // st.equal(
634 // stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' }),
635 // 'a=,&b=&c=c,d%',
636 // );
637 // st.equal(
638 // stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'comma' }),
639 // 'a=,&b=&c=c,d%',
640 // );
641 // st.equal(
642 // stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'repeat' }),
643 // 'a=,&b=&c=c,d%',
644 // );
645 expect(stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' })).toBe(
646 'a=,&b=&c=c,d%',
647 );
648 expect(stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' })).toBe(
649 'a=,&b=&c=c,d%',
650 );
651
652 // st.equal(
653 // stringify(
654 // { a: ',', b: '', c: 'c,d%' },
655 // { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' },
656 // ),
657 // 'a=%2C&b=&c=c%2Cd%25',
658 // );
659 // st.equal(
660 // stringify(
661 // { a: ',', b: '', c: 'c,d%' },
662 // { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
663 // ),
664 // 'a=%2C&b=&c=c%2Cd%25',
665 // );
666 // st.equal(
667 // stringify(
668 // { a: ',', b: '', c: 'c,d%' },
669 // { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' },
670 // ),
671 // 'a=%2C&b=&c=c%2Cd%25',
672 // );
673 // st.equal(
674 // stringify(
675 // { a: ',', b: '', c: 'c,d%' },
676 // { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' },
677 // ),
678 // 'a=%2C&b=&c=c%2Cd%25',
679 // );
680 expect(
681 stringify(
682 { a: ',', b: '', c: 'c,d%' },
683 { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' },
684 ),
685 ).toBe('a=%2C&b=&c=c%2Cd%25');
686 expect(
687 stringify(
688 { a: ',', b: '', c: 'c,d%' },
689 { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
690 ),
691 ).toBe('a=%2C&b=&c=c%2Cd%25');
692 expect(
693 stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }),
694 ).toBe('a=%2C&b=&c=c%2Cd%25');
695 expect(
696 stringify(
697 { a: ',', b: '', c: 'c,d%' },
698 { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' },
699 ),
700 ).toBe('a=%2C&b=&c=c%2Cd%25');
701
702 // st.equal(
703 // stringify(
704 // { a: ',', b: '', c: 'c,d%' },
705 // { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' },
706 // ),
707 // 'a=%2C&b=&c=c%2Cd%25',
708 // );
709 // st.equal(
710 // stringify(
711 // { a: ',', b: '', c: 'c,d%' },
712 // { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' },
713 // ),
714 // 'a=%2C&b=&c=c%2Cd%25',
715 // );
716 // st.equal(
717 // stringify(
718 // { a: ',', b: '', c: 'c,d%' },
719 // { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' },
720 // ),
721 // 'a=%2C&b=&c=c%2Cd%25',
722 // );
723 // st.equal(
724 // stringify(
725 // { a: ',', b: '', c: 'c,d%' },
726 // { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' },
727 // ),
728 // 'a=%2C&b=&c=c%2Cd%25',
729 // );
730 expect(
731 stringify(
732 { a: ',', b: '', c: 'c,d%' },
733 { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' },
734 ),
735 ).toBe('a=%2C&b=&c=c%2Cd%25');
736 expect(
737 stringify(
738 { a: ',', b: '', c: 'c,d%' },
739 { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' },
740 ),
741 ).toBe('a=%2C&b=&c=c%2Cd%25');
742 expect(
743 stringify(
744 { a: ',', b: '', c: 'c,d%' },
745 { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' },
746 ),
747 ).toBe('a=%2C&b=&c=c%2Cd%25');
748 expect(
749 stringify(
750 { a: ',', b: '', c: 'c,d%' },
751 { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' },
752 ),
753 ).toBe('a=%2C&b=&c=c%2Cd%25');
754 });
755
756 test('stringifies a nested array value with dots notation', function () {
757 // st.equal(
758 // stringify(
759 // { a: { b: ['c', 'd'] } },
760 // { allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' },
761 // ),
762 // 'a.b[0]=c&a.b[1]=d',
763 // 'indices: stringifies with dots + indices',
764 // );
765 // st.equal(
766 // stringify(
767 // { a: { b: ['c', 'd'] } },
768 // { allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
769 // ),
770 // 'a.b[]=c&a.b[]=d',
771 // 'brackets: stringifies with dots + brackets',
772 // );
773 // st.equal(
774 // stringify(
775 // { a: { b: ['c', 'd'] } },
776 // { allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' },
777 // ),
778 // 'a.b=c,d',
779 // 'comma: stringifies with dots + comma',
780 // );
781 // st.equal(
782 // stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true }),
783 // 'a.b[0]=c&a.b[1]=d',
784 // 'default: stringifies with dots + indices',
785 // );
786 expect(
787 stringify(
788 { a: { b: ['c', 'd'] } },
789 { allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' },
790 ),
791 ).toBe('a.b[0]=c&a.b[1]=d');
792 expect(
793 stringify(
794 { a: { b: ['c', 'd'] } },
795 { allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' },
796 ),
797 ).toBe('a.b[]=c&a.b[]=d');
798 expect(
799 stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' }),
800 ).toBe('a.b=c,d');
801 expect(stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true })).toBe(
802 'a.b[0]=c&a.b[1]=d',
803 );
804 });
805
806 test('stringifies an object inside an array', function () {
807 // st.equal(
808 // stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
809 // 'a[0][b]=c',
810 // 'indices => indices',
811 // );
812 // st.equal(
813 // stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
814 // 'a[b]=c',
815 // 'repeat => repeat',
816 // );
817 // st.equal(
818 // stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
819 // 'a[][b]=c',
820 // 'brackets => brackets',
821 // );
822 // st.equal(
823 // stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true }),
824 // 'a[0][b]=c',
825 // 'default => indices',
826 // );
827 expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true })).toBe(
828 'a[0][b]=c',
829 );
830 expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true })).toBe('a[b]=c');
831 expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true })).toBe(
832 'a[][b]=c',
833 );
834 expect(stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true })).toBe('a[0][b]=c');
835
836 // st.equal(
837 // stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
838 // 'a[0][b][c][0]=1',
839 // 'indices => indices',
840 // );
841 // st.equal(
842 // stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
843 // 'a[b][c]=1',
844 // 'repeat => repeat',
845 // );
846 // st.equal(
847 // stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
848 // 'a[][b][c][]=1',
849 // 'brackets => brackets',
850 // );
851 // st.equal(
852 // stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true }),
853 // 'a[0][b][c][0]=1',
854 // 'default => indices',
855 // );
856 expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true })).toBe(
857 'a[0][b][c][0]=1',
858 );
859 expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true })).toBe(
860 'a[b][c]=1',
861 );
862 expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true })).toBe(
863 'a[][b][c][]=1',
864 );
865 expect(stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true })).toBe('a[0][b][c][0]=1');
866 });
867
868 test('stringifies an array with mixed objects and primitives', function () {
869 // st.equal(
870 // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
871 // 'a[0][b]=1&a[1]=2&a[2]=3',
872 // 'indices => indices',
873 // );
874 // st.equal(
875 // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
876 // 'a[][b]=1&a[]=2&a[]=3',
877 // 'brackets => brackets',
878 // );
879 // st.equal(
880 // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
881 // '???',
882 // 'brackets => brackets',
883 // { skip: 'TODO: figure out what this should do' },
884 // );
885 // st.equal(
886 // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true }),
887 // 'a[0][b]=1&a[1]=2&a[2]=3',
888 // 'default => indices',
889 // );
890 expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe(
891 'a[0][b]=1&a[1]=2&a[2]=3',
892 );
893 expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
894 'a[][b]=1&a[]=2&a[]=3',
895 );
896 // !Skipped: Figure out what this should do
897 // expect(
898 // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }),
899 // ).toBe('???');
900 expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true })).toBe('a[0][b]=1&a[1]=2&a[2]=3');
901 });
902
903 test('stringifies an object inside an array with dots notation', function () {
904 // st.equal(
905 // stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'indices' }),
906 // 'a[0].b=c',
907 // 'indices => indices',
908 // );
909 // st.equal(
910 // stringify(
911 // { a: [{ b: 'c' }] },
912 // { allowDots: true, encode: false, arrayFormat: 'brackets' },
913 // ),
914 // 'a[].b=c',
915 // 'brackets => brackets',
916 // );
917 // st.equal(
918 // stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false }),
919 // 'a[0].b=c',
920 // 'default => indices',
921 // );
922 expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'indices' })).toBe(
923 'a[0].b=c',
924 );
925 expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'brackets' })).toBe(
926 'a[].b=c',
927 );
928 expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false })).toBe('a[0].b=c');
929
930 // st.equal(
931 // stringify(
932 // { a: [{ b: { c: [1] } }] },
933 // { allowDots: true, encode: false, arrayFormat: 'indices' },
934 // ),
935 // 'a[0].b.c[0]=1',
936 // 'indices => indices',
937 // );
938 // st.equal(
939 // stringify(
940 // { a: [{ b: { c: [1] } }] },
941 // { allowDots: true, encode: false, arrayFormat: 'brackets' },
942 // ),
943 // 'a[].b.c[]=1',
944 // 'brackets => brackets',
945 // );
946 // st.equal(
947 // stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false }),
948 // 'a[0].b.c[0]=1',
949 // 'default => indices',
950 // );
951 expect(
952 stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false, arrayFormat: 'indices' }),
953 ).toBe('a[0].b.c[0]=1');
954 expect(
955 stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false, arrayFormat: 'brackets' }),
956 ).toBe('a[].b.c[]=1');
957 expect(stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false })).toBe('a[0].b.c[0]=1');
958 });
959
960 test('does not omit object keys when indices = false', function () {
961 // st.equal(stringify({ a: [{ b: 'c' }] }, { indices: false }), 'a%5Bb%5D=c');
962 expect(stringify({ a: [{ b: 'c' }] }, { indices: false })).toBe('a%5Bb%5D=c');
963 });
964
965 test('uses indices notation for arrays when indices=true', function () {
966 // st.equal(stringify({ a: ['b', 'c'] }, { indices: true }), 'a%5B0%5D=b&a%5B1%5D=c');
967 expect(stringify({ a: ['b', 'c'] }, { indices: true })).toBe('a%5B0%5D=b&a%5B1%5D=c');
968 });
969
970 test('uses indices notation for arrays when no arrayFormat is specified', function () {
971 // st.equal(stringify({ a: ['b', 'c'] }), 'a%5B0%5D=b&a%5B1%5D=c');
972 expect(stringify({ a: ['b', 'c'] })).toBe('a%5B0%5D=b&a%5B1%5D=c');
973 });
974
975 test('uses indices notation for arrays when arrayFormat=indices', function () {
976 // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c');
977 expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })).toBe('a%5B0%5D=b&a%5B1%5D=c');
978 });
979
980 test('uses repeat notation for arrays when arrayFormat=repeat', function () {
981 // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c');
982 expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })).toBe('a=b&a=c');
983 });
984
985 test('uses brackets notation for arrays when arrayFormat=brackets', function () {
986 // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c');
987 expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })).toBe('a%5B%5D=b&a%5B%5D=c');
988 });
989
990 test('stringifies a complicated object', function () {
991 // st.equal(stringify({ a: { b: 'c', d: 'e' } }), 'a%5Bb%5D=c&a%5Bd%5D=e');
992 expect(stringify({ a: { b: 'c', d: 'e' } })).toBe('a%5Bb%5D=c&a%5Bd%5D=e');
993 });
994
995 test('stringifies an empty value', function () {
996 // st.equal(stringify({ a: '' }), 'a=');
997 // st.equal(stringify({ a: null }, { strictNullHandling: true }), 'a');
998 expect(stringify({ a: '' })).toBe('a=');
999 expect(stringify({ a: null }, { strictNullHandling: true })).toBe('a');
1000
1001 // st.equal(stringify({ a: '', b: '' }), 'a=&b=');
1002 // st.equal(stringify({ a: null, b: '' }, { strictNullHandling: true }), 'a&b=');
1003 expect(stringify({ a: '', b: '' })).toBe('a=&b=');
1004 expect(stringify({ a: null, b: '' }, { strictNullHandling: true })).toBe('a&b=');
1005
1006 // st.equal(stringify({ a: { b: '' } }), 'a%5Bb%5D=');
1007 // st.equal(stringify({ a: { b: null } }, { strictNullHandling: true }), 'a%5Bb%5D');
1008 // st.equal(stringify({ a: { b: null } }, { strictNullHandling: false }), 'a%5Bb%5D=');
1009 expect(stringify({ a: { b: '' } })).toBe('a%5Bb%5D=');
1010 expect(stringify({ a: { b: null } }, { strictNullHandling: true })).toBe('a%5Bb%5D');
1011 expect(stringify({ a: { b: null } }, { strictNullHandling: false })).toBe('a%5Bb%5D=');
1012 });
1013
1014 test('stringifies an empty array in different arrayFormat', function () {
1015 // st.equal(stringify({ a: [], b: [null], c: 'c' }, { encode: false }), 'b[0]=&c=c');
1016 expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false })).toBe('b[0]=&c=c');
1017 // arrayFormat default
1018 // st.equal(
1019 // stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices' }),
1020 // 'b[0]=&c=c',
1021 // );
1022 // st.equal(
1023 // stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' }),
1024 // 'b[]=&c=c',
1025 // );
1026 // st.equal(
1027 // stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' }),
1028 // 'b=&c=c',
1029 // );
1030 // st.equal(
1031 // stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' }),
1032 // 'b=&c=c',
1033 // );
1034 // st.equal(
1035 // stringify(
1036 // { a: [], b: [null], c: 'c' },
1037 // { encode: false, arrayFormat: 'comma', commaRoundTrip: true },
1038 // ),
1039 // 'b[]=&c=c',
1040 // );
1041 expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices' })).toBe(
1042 'b[0]=&c=c',
1043 );
1044 expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' })).toBe(
1045 'b[]=&c=c',
1046 );
1047 expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' })).toBe('b=&c=c');
1048 expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' })).toBe('b=&c=c');
1049 expect(
1050 stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', commaRoundTrip: true }),
1051 ).toBe('b[]=&c=c');
1052
1053 // with strictNullHandling
1054 // st.equal(
1055 // stringify(
1056 // { a: [], b: [null], c: 'c' },
1057 // { encode: false, arrayFormat: 'indices', strictNullHandling: true },
1058 // ),
1059 // 'b[0]&c=c',
1060 // );
1061 // st.equal(
1062 // stringify(
1063 // { a: [], b: [null], c: 'c' },
1064 // { encode: false, arrayFormat: 'brackets', strictNullHandling: true },
1065 // ),
1066 // 'b[]&c=c',
1067 // );
1068 // st.equal(
1069 // stringify(
1070 // { a: [], b: [null], c: 'c' },
1071 // { encode: false, arrayFormat: 'repeat', strictNullHandling: true },
1072 // ),
1073 // 'b&c=c',
1074 // );
1075 // st.equal(
1076 // stringify(
1077 // { a: [], b: [null], c: 'c' },
1078 // { encode: false, arrayFormat: 'comma', strictNullHandling: true },
1079 // ),
1080 // 'b&c=c',
1081 // );
1082 // st.equal(
1083 // stringify(
1084 // { a: [], b: [null], c: 'c' },
1085 // { encode: false, arrayFormat: 'comma', strictNullHandling: true, commaRoundTrip: true },
1086 // ),
1087 // 'b[]&c=c',
1088 // );
1089
1090 expect(
1091 stringify(
1092 { a: [], b: [null], c: 'c' },
1093 { encode: false, arrayFormat: 'indices', strictNullHandling: true },
1094 ),
1095 ).toBe('b[0]&c=c');
1096 expect(
1097 stringify(
1098 { a: [], b: [null], c: 'c' },
1099 { encode: false, arrayFormat: 'brackets', strictNullHandling: true },
1100 ),
1101 ).toBe('b[]&c=c');
1102 expect(
1103 stringify(
1104 { a: [], b: [null], c: 'c' },
1105 { encode: false, arrayFormat: 'repeat', strictNullHandling: true },
1106 ),
1107 ).toBe('b&c=c');
1108 expect(
1109 stringify(
1110 { a: [], b: [null], c: 'c' },
1111 { encode: false, arrayFormat: 'comma', strictNullHandling: true },
1112 ),
1113 ).toBe('b&c=c');
1114 expect(
1115 stringify(
1116 { a: [], b: [null], c: 'c' },
1117 { encode: false, arrayFormat: 'comma', strictNullHandling: true, commaRoundTrip: true },
1118 ),
1119 ).toBe('b[]&c=c');
1120
1121 // with skipNulls
1122 // st.equal(
1123 // stringify(
1124 // { a: [], b: [null], c: 'c' },
1125 // { encode: false, arrayFormat: 'indices', skipNulls: true },
1126 // ),
1127 // 'c=c',
1128 // );
1129 // st.equal(
1130 // stringify(
1131 // { a: [], b: [null], c: 'c' },
1132 // { encode: false, arrayFormat: 'brackets', skipNulls: true },
1133 // ),
1134 // 'c=c',
1135 // );
1136 // st.equal(
1137 // stringify(
1138 // { a: [], b: [null], c: 'c' },
1139 // { encode: false, arrayFormat: 'repeat', skipNulls: true },
1140 // ),
1141 // 'c=c',
1142 // );
1143 // st.equal(
1144 // stringify(
1145 // { a: [], b: [null], c: 'c' },
1146 // { encode: false, arrayFormat: 'comma', skipNulls: true },
1147 // ),
1148 // 'c=c',
1149 // );
1150 expect(
1151 stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', skipNulls: true }),
1152 ).toBe('c=c');
1153 expect(
1154 stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', skipNulls: true }),
1155 ).toBe('c=c');
1156 expect(
1157 stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat', skipNulls: true }),
1158 ).toBe('c=c');
1159 expect(
1160 stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', skipNulls: true }),
1161 ).toBe('c=c');
1162 });
1163
1164 test('stringifies a null object', function () {
1165 var obj = Object.create(null);
1166 obj.a = 'b';
1167 // st.equal(stringify(obj), 'a=b');
1168 expect(stringify(obj)).toBe('a=b');
1169 });
1170
1171 test('returns an empty string for invalid input', function () {
1172 // st.equal(stringify(undefined), '');
1173 // st.equal(stringify(false), '');
1174 // st.equal(stringify(null), '');
1175 // st.equal(stringify(''), '');
1176 expect(stringify(undefined)).toBe('');
1177 expect(stringify(false)).toBe('');
1178 expect(stringify(null)).toBe('');
1179 expect(stringify('')).toBe('');
1180 });
1181
1182 test('stringifies an object with a null object as a child', function () {
1183 var obj = { a: Object.create(null) };
1184
1185 obj.a.b = 'c';
1186 // st.equal(stringify(obj), 'a%5Bb%5D=c');
1187 expect(stringify(obj)).toBe('a%5Bb%5D=c');
1188 });
1189
1190 test('drops keys with a value of undefined', function () {
1191 // st.equal(stringify({ a: undefined }), '');
1192 expect(stringify({ a: undefined })).toBe('');
1193
1194 // st.equal(
1195 // stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true }),
1196 // 'a%5Bc%5D',
1197 // );
1198 // st.equal(
1199 // stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false }),
1200 // 'a%5Bc%5D=',
1201 // );
1202 // st.equal(stringify({ a: { b: undefined, c: '' } }), 'a%5Bc%5D=');
1203 expect(stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true })).toBe('a%5Bc%5D');
1204 expect(stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false })).toBe('a%5Bc%5D=');
1205 expect(stringify({ a: { b: undefined, c: '' } })).toBe('a%5Bc%5D=');
1206 });
1207
1208 test('url encodes values', function () {
1209 // st.equal(stringify({ a: 'b c' }), 'a=b%20c');
1210 expect(stringify({ a: 'b c' })).toBe('a=b%20c');
1211 });
1212
1213 test('stringifies a date', function () {
1214 var now = new Date();
1215 var str = 'a=' + encodeURIComponent(now.toISOString());
1216 // st.equal(stringify({ a: now }), str);
1217 expect(stringify({ a: now })).toBe(str);
1218 });
1219
1220 test('stringifies the weird object from qs', function () {
1221 // st.equal(
1222 // stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' }),
1223 // 'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F',
1224 // );
1225 expect(stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' })).toBe(
1226 'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F',
1227 );
1228 });
1229
1230 // TODO: Investigate how to to intercept in vitest
1231 // TODO(rob)
1232 test('skips properties that are part of the object prototype', function () {
1233 // st.intercept(Object.prototype, 'crash', { value: 'test' });
1234 // @ts-expect-error
1235 Object.prototype.crash = 'test';
1236
1237 // st.equal(stringify({ a: 'b' }), 'a=b');
1238 // st.equal(stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
1239 expect(stringify({ a: 'b' })).toBe('a=b');
1240 expect(stringify({ a: { b: 'c' } })).toBe('a%5Bb%5D=c');
1241 });
1242
1243 test('stringifies boolean values', function () {
1244 // st.equal(stringify({ a: true }), 'a=true');
1245 // st.equal(stringify({ a: { b: true } }), 'a%5Bb%5D=true');
1246 // st.equal(stringify({ b: false }), 'b=false');
1247 // st.equal(stringify({ b: { c: false } }), 'b%5Bc%5D=false');
1248 expect(stringify({ a: true })).toBe('a=true');
1249 expect(stringify({ a: { b: true } })).toBe('a%5Bb%5D=true');
1250 expect(stringify({ b: false })).toBe('b=false');
1251 expect(stringify({ b: { c: false } })).toBe('b%5Bc%5D=false');
1252 });
1253
1254 test('stringifies buffer values', function () {
1255 // st.equal(stringify({ a: Buffer.from('test') }), 'a=test');
1256 // st.equal(stringify({ a: { b: Buffer.from('test') } }), 'a%5Bb%5D=test');
1257 });
1258
1259 test('stringifies an object using an alternative delimiter', function () {
1260 // st.equal(stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d');
1261 expect(stringify({ a: 'b', c: 'd' }, { delimiter: ';' })).toBe('a=b;c=d');
1262 });
1263
1264 // We dont target environments which dont even have Buffer
1265 // test('does not blow up when Buffer global is missing', function () {
1266 // var restore = mockProperty(global, 'Buffer', { delete: true });
1267
1268 // var result = stringify({ a: 'b', c: 'd' });
1269
1270 // restore();
1271
1272 // st.equal(result, 'a=b&c=d');
1273 // st.end();
1274 // });
1275
1276 test('does not crash when parsing circular references', function () {
1277 var a: any = {};
1278 a.b = a;
1279
1280 // st['throws'](
1281 // function () {
1282 // stringify({ 'foo[bar]': 'baz', 'foo[baz]': a });
1283 // },
1284 // /RangeError: Cyclic object value/,
1285 // 'cyclic values throw',
1286 // );
1287 expect(() => {
1288 stringify({ 'foo[bar]': 'baz', 'foo[baz]': a });
1289 }).toThrow('Cyclic object value');
1290
1291 var circular: any = {
1292 a: 'value',
1293 };
1294 circular.a = circular;
1295 // st['throws'](
1296 // function () {
1297 // stringify(circular);
1298 // },
1299 // /RangeError: Cyclic object value/,
1300 // 'cyclic values throw',
1301 // );
1302 expect(() => {
1303 stringify(circular);
1304 }).toThrow('Cyclic object value');
1305
1306 var arr = ['a'];
1307 // st.doesNotThrow(function () {
1308 // stringify({ x: arr, y: arr });
1309 // }, 'non-cyclic values do not throw');
1310 expect(() => {
1311 stringify({ x: arr, y: arr });
1312 }).not.toThrow();
1313 });
1314
1315 test('non-circular duplicated references can still work', function () {
1316 var hourOfDay = {
1317 function: 'hour_of_day',
1318 };
1319
1320 var p1 = {
1321 function: 'gte',
1322 arguments: [hourOfDay, 0],
1323 };
1324 var p2 = {
1325 function: 'lte',
1326 arguments: [hourOfDay, 23],
1327 };
1328
1329 // st.equal(
1330 // stringify(
1331 // { filters: { $and: [p1, p2] } },
1332 // { encodeValuesOnly: true, arrayFormat: 'indices' },
1333 // ),
1334 // 'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23',
1335 // );
1336 // st.equal(
1337 // stringify(
1338 // { filters: { $and: [p1, p2] } },
1339 // { encodeValuesOnly: true, arrayFormat: 'brackets' },
1340 // ),
1341 // 'filters[$and][][function]=gte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=0&filters[$and][][function]=lte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=23',
1342 // );
1343 // st.equal(
1344 // stringify(
1345 // { filters: { $and: [p1, p2] } },
1346 // { encodeValuesOnly: true, arrayFormat: 'repeat' },
1347 // ),
1348 // 'filters[$and][function]=gte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=0&filters[$and][function]=lte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=23',
1349 // );
1350 expect(
1351 stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
1352 ).toBe(
1353 'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23',
1354 );
1355 expect(
1356 stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
1357 ).toBe(
1358 'filters[$and][][function]=gte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=0&filters[$and][][function]=lte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=23',
1359 );
1360 expect(
1361 stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
1362 ).toBe(
1363 'filters[$and][function]=gte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=0&filters[$and][function]=lte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=23',
1364 );
1365 });
1366
1367 test('selects properties when filter=array', function () {
1368 // st.equal(stringify({ a: 'b' }, { filter: ['a'] }), 'a=b');
1369 // st.equal(stringify({ a: 1 }, { filter: [] }), '');
1370 expect(stringify({ a: 'b' }, { filter: ['a'] })).toBe('a=b');
1371 expect(stringify({ a: 1 }, { filter: [] })).toBe('');
1372
1373 // st.equal(
1374 // stringify(
1375 // { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
1376 // { filter: ['a', 'b', 0, 2], arrayFormat: 'indices' },
1377 // ),
1378 // 'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
1379 // 'indices => indices',
1380 // );
1381 // st.equal(
1382 // stringify(
1383 // { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
1384 // { filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' },
1385 // ),
1386 // 'a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3',
1387 // 'brackets => brackets',
1388 // );
1389 // st.equal(
1390 // stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] }),
1391 // 'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
1392 // 'default => indices',
1393 // );
1394 expect(stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] })).toBe(
1395 'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3',
1396 );
1397 expect(
1398 stringify(
1399 { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
1400 { filter: ['a', 'b', 0, 2], arrayFormat: 'indices' },
1401 ),
1402 ).toBe('a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3');
1403 expect(
1404 stringify(
1405 { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' },
1406 { filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' },
1407 ),
1408 ).toBe('a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3');
1409 });
1410
1411 test('supports custom representations when filter=function', function () {
1412 var calls = 0;
1413 var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } };
1414 var filterFunc: StringifyOptions['filter'] = function (prefix, value) {
1415 calls += 1;
1416 if (calls === 1) {
1417 // st.equal(prefix, '', 'prefix is empty');
1418 // st.equal(value, obj);
1419 expect(prefix).toBe('');
1420 expect(value).toBe(obj);
1421 } else if (prefix === 'c') {
1422 return void 0;
1423 } else if (value instanceof Date) {
1424 // st.equal(prefix, 'e[f]');
1425 expect(prefix).toBe('e[f]');
1426 return value.getTime();
1427 }
1428 return value;
1429 };
1430
1431 // st.equal(stringify(obj, { filter: filterFunc }), 'a=b&e%5Bf%5D=1257894000000');
1432 // st.equal(calls, 5);
1433 expect(stringify(obj, { filter: filterFunc })).toBe('a=b&e%5Bf%5D=1257894000000');
1434 expect(calls).toBe(5);
1435 });
1436
1437 test('can disable uri encoding', function () {
1438 // st.equal(stringify({ a: 'b' }, { encode: false }), 'a=b');
1439 // st.equal(stringify({ a: { b: 'c' } }, { encode: false }), 'a[b]=c');
1440 // st.equal(
1441 // stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false }),
1442 // 'a=b&c',
1443 // );
1444 expect(stringify({ a: 'b' }, { encode: false })).toBe('a=b');
1445 expect(stringify({ a: { b: 'c' } }, { encode: false })).toBe('a[b]=c');
1446 expect(stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false })).toBe('a=b&c');
1447 });
1448
1449 test('can sort the keys', function () {
1450 // @ts-expect-error
1451 var sort: NonNullable<StringifyOptions['sort']> = function (a: string, b: string) {
1452 return a.localeCompare(b);
1453 };
1454 // st.equal(stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort }), 'a=c&b=f&z=y');
1455 // st.equal(
1456 // stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort }),
1457 // 'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a',
1458 // );
1459 expect(stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort })).toBe('a=c&b=f&z=y');
1460 expect(stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort })).toBe(
1461 'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a',
1462 );
1463 });
1464
1465 test('can sort the keys at depth 3 or more too', function () {
1466 // @ts-expect-error
1467 var sort: NonNullable<StringifyOptions['sort']> = function (a: string, b: string) {
1468 return a.localeCompare(b);
1469 };
1470 // st.equal(
1471 // stringify(
1472 // { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
1473 // { sort: sort, encode: false },
1474 // ),
1475 // 'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb',
1476 // );
1477 // st.equal(
1478 // stringify(
1479 // { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
1480 // { sort: null, encode: false },
1481 // ),
1482 // 'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b',
1483 // );
1484 expect(
1485 stringify(
1486 { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
1487 { sort: sort, encode: false },
1488 ),
1489 ).toBe('a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb');
1490 expect(
1491 stringify(
1492 { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' },
1493 { sort: null, encode: false },
1494 ),
1495 ).toBe('a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b');
1496 });
1497
1498 test('can stringify with custom encoding', function () {
1499 // st.equal(
1500 // stringify(
1501 // { 県: '大阪府', '': '' },
1502 // {
1503 // encoder: function (str) {
1504 // if (str.length === 0) {
1505 // return '';
1506 // }
1507 // var buf = iconv.encode(str, 'shiftjis');
1508 // var result = [];
1509 // for (var i = 0; i < buf.length; ++i) {
1510 // result.push(buf.readUInt8(i).toString(16));
1511 // }
1512 // return '%' + result.join('%');
1513 // },
1514 // },
1515 // ),
1516 // '%8c%a7=%91%e5%8d%e3%95%7b&=',
1517 // );
1518 expect(
1519 stringify(
1520 { 県: '大阪府', '': '' },
1521 {
1522 encoder: function (str) {
1523 if (str.length === 0) {
1524 return '';
1525 }
1526 var buf = iconv.encode(str, 'shiftjis');
1527 var result = [];
1528 for (var i = 0; i < buf.length; ++i) {
1529 result.push(buf.readUInt8(i).toString(16));
1530 }
1531 return '%' + result.join('%');
1532 },
1533 },
1534 ),
1535 ).toBe('%8c%a7=%91%e5%8d%e3%95%7b&=');
1536 });
1537
1538 test('receives the default encoder as a second argument', function () {
1539 // stringify(
1540 // { a: 1, b: new Date(), c: true, d: [1] },
1541 // {
1542 // encoder: function (str) {
1543 // st.match(typeof str, /^(?:string|number|boolean)$/);
1544 // return '';
1545 // },
1546 // },
1547 // );
1548
1549 stringify(
1550 { a: 1, b: new Date(), c: true, d: [1] },
1551 {
1552 encoder: function (str) {
1553 // st.match(typeof str, /^(?:string|number|boolean)$/);
1554 assert.match(typeof str, /^(?:string|number|boolean)$/);
1555 return '';
1556 },
1557 },
1558 );
1559 });
1560
1561 test('receives the default encoder as a second argument', function () {
1562 // stringify(
1563 // { a: 1 },
1564 // {
1565 // encoder: function (str, defaultEncoder) {
1566 // st.equal(defaultEncoder, utils.encode);
1567 // },
1568 // },
1569 // );
1570
1571 stringify(
1572 { a: 1 },
1573 {
1574 // @ts-ignore
1575 encoder: function (_str, defaultEncoder) {
1576 expect(defaultEncoder).toBe(encode);
1577 },
1578 },
1579 );
1580 });
1581
1582 test('throws error with wrong encoder', function () {
1583 // st['throws'](function () {
1584 // stringify({}, { encoder: 'string' });
1585 // }, new TypeError('Encoder has to be a function.'));
1586 // st.end();
1587 expect(() => {
1588 // @ts-expect-error
1589 stringify({}, { encoder: 'string' });
1590 }).toThrow(TypeError);
1591 });
1592
1593 (typeof Buffer === 'undefined' ? test.skip : test)(
1594 'can use custom encoder for a buffer object',
1595 function () {
1596 // st.equal(
1597 // stringify(
1598 // { a: Buffer.from([1]) },
1599 // {
1600 // encoder: function (buffer) {
1601 // if (typeof buffer === 'string') {
1602 // return buffer;
1603 // }
1604 // return String.fromCharCode(buffer.readUInt8(0) + 97);
1605 // },
1606 // },
1607 // ),
1608 // 'a=b',
1609 // );
1610 expect(
1611 stringify(
1612 { a: Buffer.from([1]) },
1613 {
1614 encoder: function (buffer) {
1615 if (typeof buffer === 'string') {
1616 return buffer;
1617 }
1618 return String.fromCharCode(buffer.readUInt8(0) + 97);
1619 },
1620 },
1621 ),
1622 ).toBe('a=b');
1623
1624 // st.equal(
1625 // stringify(
1626 // { a: Buffer.from('a b') },
1627 // {
1628 // encoder: function (buffer) {
1629 // return buffer;
1630 // },
1631 // },
1632 // ),
1633 // 'a=a b',
1634 // );
1635 expect(
1636 stringify(
1637 { a: Buffer.from('a b') },
1638 {
1639 encoder: function (buffer) {
1640 return buffer;
1641 },
1642 },
1643 ),
1644 ).toBe('a=a b');
1645 },
1646 );
1647
1648 test('serializeDate option', function () {
1649 var date = new Date();
1650 // st.equal(
1651 // stringify({ a: date }),
1652 // 'a=' + date.toISOString().replace(/:/g, '%3A'),
1653 // 'default is toISOString',
1654 // );
1655 expect(stringify({ a: date })).toBe('a=' + date.toISOString().replace(/:/g, '%3A'));
1656
1657 var mutatedDate = new Date();
1658 mutatedDate.toISOString = function () {
1659 throw new SyntaxError();
1660 };
1661 // st['throws'](function () {
1662 // mutatedDate.toISOString();
1663 // }, SyntaxError);
1664 expect(() => {
1665 mutatedDate.toISOString();
1666 }).toThrow(SyntaxError);
1667 // st.equal(
1668 // stringify({ a: mutatedDate }),
1669 // 'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'),
1670 // 'toISOString works even when method is not locally present',
1671 // );
1672 expect(stringify({ a: mutatedDate })).toBe(
1673 'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'),
1674 );
1675
1676 var specificDate = new Date(6);
1677 // st.equal(
1678 // stringify(
1679 // { a: specificDate },
1680 // {
1681 // serializeDate: function (d) {
1682 // return d.getTime() * 7;
1683 // },
1684 // },
1685 // ),
1686 // 'a=42',
1687 // 'custom serializeDate function called',
1688 // );
1689 expect(
1690 stringify(
1691 { a: specificDate },
1692 {
1693 // @ts-ignore
1694 serializeDate: function (d) {
1695 return d.getTime() * 7;
1696 },
1697 },
1698 ),
1699 ).toBe('a=42');
1700
1701 // st.equal(
1702 // stringify(
1703 // { a: [date] },
1704 // {
1705 // serializeDate: function (d) {
1706 // return d.getTime();
1707 // },
1708 // arrayFormat: 'comma',
1709 // },
1710 // ),
1711 // 'a=' + date.getTime(),
1712 // 'works with arrayFormat comma',
1713 // );
1714 // st.equal(
1715 // stringify(
1716 // { a: [date] },
1717 // {
1718 // serializeDate: function (d) {
1719 // return d.getTime();
1720 // },
1721 // arrayFormat: 'comma',
1722 // commaRoundTrip: true,
1723 // },
1724 // ),
1725 // 'a%5B%5D=' + date.getTime(),
1726 // 'works with arrayFormat comma',
1727 // );
1728 expect(
1729 stringify(
1730 { a: [date] },
1731 {
1732 // @ts-expect-error
1733 serializeDate: function (d) {
1734 return d.getTime();
1735 },
1736 arrayFormat: 'comma',
1737 },
1738 ),
1739 ).toBe('a=' + date.getTime());
1740 expect(
1741 stringify(
1742 { a: [date] },
1743 {
1744 // @ts-expect-error
1745 serializeDate: function (d) {
1746 return d.getTime();
1747 },
1748 arrayFormat: 'comma',
1749 commaRoundTrip: true,
1750 },
1751 ),
1752 ).toBe('a%5B%5D=' + date.getTime());
1753 });
1754
1755 test('RFC 1738 serialization', function () {
1756 // st.equal(stringify({ a: 'b c' }, { format: formats.RFC1738 }), 'a=b+c');
1757 // st.equal(stringify({ 'a b': 'c d' }, { format: formats.RFC1738 }), 'a+b=c+d');
1758 // st.equal(
1759 // stringify({ 'a b': Buffer.from('a b') }, { format: formats.RFC1738 }),
1760 // 'a+b=a+b',
1761 // );
1762 expect(stringify({ a: 'b c' }, { format: 'RFC1738' })).toBe('a=b+c');
1763 expect(stringify({ 'a b': 'c d' }, { format: 'RFC1738' })).toBe('a+b=c+d');
1764 expect(stringify({ 'a b': Buffer.from('a b') }, { format: 'RFC1738' })).toBe('a+b=a+b');
1765
1766 // st.equal(stringify({ 'foo(ref)': 'bar' }, { format: formats.RFC1738 }), 'foo(ref)=bar');
1767 expect(stringify({ 'foo(ref)': 'bar' }, { format: 'RFC1738' })).toBe('foo(ref)=bar');
1768 });
1769
1770 test('RFC 3986 spaces serialization', function () {
1771 // st.equal(stringify({ a: 'b c' }, { format: formats.RFC3986 }), 'a=b%20c');
1772 // st.equal(stringify({ 'a b': 'c d' }, { format: formats.RFC3986 }), 'a%20b=c%20d');
1773 // st.equal(
1774 // stringify({ 'a b': Buffer.from('a b') }, { format: formats.RFC3986 }),
1775 // 'a%20b=a%20b',
1776 // );
1777 expect(stringify({ a: 'b c' }, { format: 'RFC3986' })).toBe('a=b%20c');
1778 expect(stringify({ 'a b': 'c d' }, { format: 'RFC3986' })).toBe('a%20b=c%20d');
1779 expect(stringify({ 'a b': Buffer.from('a b') }, { format: 'RFC3986' })).toBe('a%20b=a%20b');
1780 });
1781
1782 test('Backward compatibility to RFC 3986', function () {
1783 // st.equal(stringify({ a: 'b c' }), 'a=b%20c');
1784 // st.equal(stringify({ 'a b': Buffer.from('a b') }), 'a%20b=a%20b');
1785 expect(stringify({ a: 'b c' })).toBe('a=b%20c');
1786 expect(stringify({ 'a b': Buffer.from('a b') })).toBe('a%20b=a%20b');
1787 });
1788
1789 test('Edge cases and unknown formats', function () {
1790 ['UFO1234', false, 1234, null, {}, []].forEach(function (format) {
1791 // st['throws'](function () {
1792 // stringify({ a: 'b c' }, { format: format });
1793 // }, new TypeError('Unknown format option provided.'));
1794 expect(() => {
1795 // @ts-expect-error
1796 stringify({ a: 'b c' }, { format: format });
1797 }).toThrow(TypeError);
1798 });
1799 });
1800
1801 test('encodeValuesOnly', function () {
1802 // st.equal(
1803 // stringify(
1804 // { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
1805 // { encodeValuesOnly: true, arrayFormat: 'indices' },
1806 // ),
1807 // 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h',
1808 // 'encodeValuesOnly + indices',
1809 // );
1810 // st.equal(
1811 // stringify(
1812 // { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
1813 // { encodeValuesOnly: true, arrayFormat: 'brackets' },
1814 // ),
1815 // 'a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h',
1816 // 'encodeValuesOnly + brackets',
1817 // );
1818 // st.equal(
1819 // stringify(
1820 // { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
1821 // { encodeValuesOnly: true, arrayFormat: 'repeat' },
1822 // ),
1823 // 'a=b&c=d&c=e%3Df&f=g&f=h',
1824 // 'encodeValuesOnly + repeat',
1825 // );
1826 expect(
1827 stringify(
1828 { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
1829 { encodeValuesOnly: true, arrayFormat: 'indices' },
1830 ),
1831 ).toBe('a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h');
1832 expect(
1833 stringify(
1834 { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
1835 { encodeValuesOnly: true, arrayFormat: 'brackets' },
1836 ),
1837 ).toBe('a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h');
1838 expect(
1839 stringify(
1840 { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
1841 { encodeValuesOnly: true, arrayFormat: 'repeat' },
1842 ),
1843 ).toBe('a=b&c=d&c=e%3Df&f=g&f=h');
1844
1845 // st.equal(
1846 // stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'indices' }),
1847 // 'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h',
1848 // 'no encodeValuesOnly + indices',
1849 // );
1850 // st.equal(
1851 // stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'brackets' }),
1852 // 'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h',
1853 // 'no encodeValuesOnly + brackets',
1854 // );
1855 // st.equal(
1856 // stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'repeat' }),
1857 // 'a=b&c=d&c=e&f=g&f=h',
1858 // 'no encodeValuesOnly + repeat',
1859 // );
1860 expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'indices' })).toBe(
1861 'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h',
1862 );
1863 expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'brackets' })).toBe(
1864 'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h',
1865 );
1866 expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'repeat' })).toBe(
1867 'a=b&c=d&c=e&f=g&f=h',
1868 );
1869 });
1870
1871 test('encodeValuesOnly - strictNullHandling', function () {
1872 // st.equal(
1873 // stringify({ a: { b: null } }, { encodeValuesOnly: true, strictNullHandling: true }),
1874 // 'a[b]',
1875 // );
1876 expect(stringify({ a: { b: null } }, { encodeValuesOnly: true, strictNullHandling: true })).toBe('a[b]');
1877 });
1878
1879 test('throws if an invalid charset is specified', function () {
1880 // st['throws'](function () {
1881 // stringify({ a: 'b' }, { charset: 'foobar' });
1882 // }, new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'));
1883 expect(() => {
1884 // @ts-expect-error
1885 stringify({ a: 'b' }, { charset: 'foobar' });
1886 }).toThrow(TypeError);
1887 });
1888
1889 test('respects a charset of iso-8859-1', function () {
1890 // st.equal(stringify({ æ: 'æ' }, { charset: 'iso-8859-1' }), '%E6=%E6');
1891 expect(stringify({ æ: 'æ' }, { charset: 'iso-8859-1' })).toBe('%E6=%E6');
1892 });
1893
1894 test('encodes unrepresentable chars as numeric entities in iso-8859-1 mode', function () {
1895 // st.equal(stringify({ a: '☺' }, { charset: 'iso-8859-1' }), 'a=%26%239786%3B');
1896 expect(stringify({ a: '☺' }, { charset: 'iso-8859-1' })).toBe('a=%26%239786%3B');
1897 });
1898
1899 test('respects an explicit charset of utf-8 (the default)', function () {
1900 // st.equal(stringify({ a: 'æ' }, { charset: 'utf-8' }), 'a=%C3%A6');
1901 expect(stringify({ a: 'æ' }, { charset: 'utf-8' })).toBe('a=%C3%A6');
1902 });
1903
1904 test('`charsetSentinel` option', function () {
1905 // st.equal(
1906 // stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }),
1907 // 'utf8=%E2%9C%93&a=%C3%A6',
1908 // 'adds the right sentinel when instructed to and the charset is utf-8',
1909 // );
1910 expect(stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' })).toBe(
1911 'utf8=%E2%9C%93&a=%C3%A6',
1912 );
1913
1914 // st.equal(
1915 // stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }),
1916 // 'utf8=%26%2310003%3B&a=%E6',
1917 // 'adds the right sentinel when instructed to and the charset is iso-8859-1',
1918 // );
1919 expect(stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' })).toBe(
1920 'utf8=%26%2310003%3B&a=%E6',
1921 );
1922 });
1923
1924 test('does not mutate the options argument', function () {
1925 var options = {};
1926 stringify({}, options);
1927 // st.deepEqual(options, {});
1928 expect(options).toEqual({});
1929 });
1930
1931 test('strictNullHandling works with custom filter', function () {
1932 // @ts-expect-error
1933 var filter = function (_prefix, value) {
1934 return value;
1935 };
1936
1937 var options = { strictNullHandling: true, filter: filter };
1938 // st.equal(stringify({ key: null }, options), 'key');
1939 expect(stringify({ key: null }, options)).toBe('key');
1940 });
1941
1942 test('strictNullHandling works with null serializeDate', function () {
1943 var serializeDate = function () {
1944 return null;
1945 };
1946 var options = { strictNullHandling: true, serializeDate: serializeDate };
1947 var date = new Date();
1948 // st.equal(stringify({ key: date }, options), 'key');
1949 // @ts-expect-error
1950 expect(stringify({ key: date }, options)).toBe('key');
1951 });
1952
1953 test('allows for encoding keys and values differently', function () {
1954 // @ts-expect-error
1955 var encoder = function (str, defaultEncoder, charset, type) {
1956 if (type === 'key') {
1957 return defaultEncoder(str, defaultEncoder, charset, type).toLowerCase();
1958 }
1959 if (type === 'value') {
1960 return defaultEncoder(str, defaultEncoder, charset, type).toUpperCase();
1961 }
1962 throw 'this should never happen! type: ' + type;
1963 };
1964
1965 // st.deepEqual(stringify({ KeY: 'vAlUe' }, { encoder: encoder }), 'key=VALUE');
1966 expect(stringify({ KeY: 'vAlUe' }, { encoder: encoder })).toBe('key=VALUE');
1967 });
1968
1969 test('objects inside arrays', function () {
1970 var obj = { a: { b: { c: 'd', e: 'f' } } };
1971 var withArray = { a: { b: [{ c: 'd', e: 'f' }] } };
1972
1973 // st.equal(
1974 // stringify(obj, { encode: false }),
1975 // 'a[b][c]=d&a[b][e]=f',
1976 // 'no array, no arrayFormat',
1977 // );
1978 // st.equal(
1979 // stringify(obj, { encode: false, arrayFormat: 'brackets' }),
1980 // 'a[b][c]=d&a[b][e]=f',
1981 // 'no array, bracket',
1982 // );
1983 // st.equal(
1984 // stringify(obj, { encode: false, arrayFormat: 'indices' }),
1985 // 'a[b][c]=d&a[b][e]=f',
1986 // 'no array, indices',
1987 // );
1988 // st.equal(
1989 // stringify(obj, { encode: false, arrayFormat: 'repeat' }),
1990 // 'a[b][c]=d&a[b][e]=f',
1991 // 'no array, repeat',
1992 // );
1993 // st.equal(
1994 // stringify(obj, { encode: false, arrayFormat: 'comma' }),
1995 // 'a[b][c]=d&a[b][e]=f',
1996 // 'no array, comma',
1997 // );
1998 expect(stringify(obj, { encode: false })).toBe('a[b][c]=d&a[b][e]=f');
1999 expect(stringify(obj, { encode: false, arrayFormat: 'brackets' })).toBe('a[b][c]=d&a[b][e]=f');
2000 expect(stringify(obj, { encode: false, arrayFormat: 'indices' })).toBe('a[b][c]=d&a[b][e]=f');
2001 expect(stringify(obj, { encode: false, arrayFormat: 'repeat' })).toBe('a[b][c]=d&a[b][e]=f');
2002 expect(stringify(obj, { encode: false, arrayFormat: 'comma' })).toBe('a[b][c]=d&a[b][e]=f');
2003
2004 // st.equal(
2005 // stringify(withArray, { encode: false }),
2006 // 'a[b][0][c]=d&a[b][0][e]=f',
2007 // 'array, no arrayFormat',
2008 // );
2009 // st.equal(
2010 // stringify(withArray, { encode: false, arrayFormat: 'brackets' }),
2011 // 'a[b][][c]=d&a[b][][e]=f',
2012 // 'array, bracket',
2013 // );
2014 // st.equal(
2015 // stringify(withArray, { encode: false, arrayFormat: 'indices' }),
2016 // 'a[b][0][c]=d&a[b][0][e]=f',
2017 // 'array, indices',
2018 // );
2019 // st.equal(
2020 // stringify(withArray, { encode: false, arrayFormat: 'repeat' }),
2021 // 'a[b][c]=d&a[b][e]=f',
2022 // 'array, repeat',
2023 // );
2024 // st.equal(
2025 // stringify(withArray, { encode: false, arrayFormat: 'comma' }),
2026 // '???',
2027 // 'array, comma',
2028 // { skip: 'TODO: figure out what this should do' },
2029 // );
2030 expect(stringify(withArray, { encode: false })).toBe('a[b][0][c]=d&a[b][0][e]=f');
2031 expect(stringify(withArray, { encode: false, arrayFormat: 'brackets' })).toBe('a[b][][c]=d&a[b][][e]=f');
2032 expect(stringify(withArray, { encode: false, arrayFormat: 'indices' })).toBe('a[b][0][c]=d&a[b][0][e]=f');
2033 expect(stringify(withArray, { encode: false, arrayFormat: 'repeat' })).toBe('a[b][c]=d&a[b][e]=f');
2034 // !TODo: Figure out what this should do
2035 // expect(stringify(withArray, { encode: false, arrayFormat: 'comma' })).toBe(
2036 // 'a[b][c]=d&a[b][e]=f',
2037 // );
2038 });
2039
2040 test('stringifies sparse arrays', function () {
2041 // st.equal(
2042 // stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
2043 // 'a[1]=2&a[4]=1',
2044 // );
2045 // st.equal(
2046 // stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
2047 // 'a[]=2&a[]=1',
2048 // );
2049 // st.equal(
2050 // stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
2051 // 'a=2&a=1',
2052 // );
2053 expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe(
2054 'a[1]=2&a[4]=1',
2055 );
2056 expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe(
2057 'a[]=2&a[]=1',
2058 );
2059 expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' })).toBe(
2060 'a=2&a=1',
2061 );
2062
2063 // st.equal(
2064 // stringify(
2065 // { a: [, { b: [, , { c: '1' }] }] },
2066 // { encodeValuesOnly: true, arrayFormat: 'indices' },
2067 // ),
2068 // 'a[1][b][2][c]=1',
2069 // );
2070 // st.equal(
2071 // stringify(
2072 // { a: [, { b: [, , { c: '1' }] }] },
2073 // { encodeValuesOnly: true, arrayFormat: 'brackets' },
2074 // ),
2075 // 'a[][b][][c]=1',
2076 // );
2077 // st.equal(
2078 // stringify(
2079 // { a: [, { b: [, , { c: '1' }] }] },
2080 // { encodeValuesOnly: true, arrayFormat: 'repeat' },
2081 // ),
2082 // 'a[b][c]=1',
2083 // );
2084 expect(
2085 stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
2086 ).toBe('a[1][b][2][c]=1');
2087 expect(
2088 stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
2089 ).toBe('a[][b][][c]=1');
2090 expect(
2091 stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
2092 ).toBe('a[b][c]=1');
2093
2094 // st.equal(
2095 // stringify(
2096 // { a: [, [, , [, , , { c: '1' }]]] },
2097 // { encodeValuesOnly: true, arrayFormat: 'indices' },
2098 // ),
2099 // 'a[1][2][3][c]=1',
2100 // );
2101 // st.equal(
2102 // stringify(
2103 // { a: [, [, , [, , , { c: '1' }]]] },
2104 // { encodeValuesOnly: true, arrayFormat: 'brackets' },
2105 // ),
2106 // 'a[][][][c]=1',
2107 // );
2108 // st.equal(
2109 // stringify(
2110 // { a: [, [, , [, , , { c: '1' }]]] },
2111 // { encodeValuesOnly: true, arrayFormat: 'repeat' },
2112 // ),
2113 // 'a[c]=1',
2114 // );
2115 expect(
2116 stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
2117 ).toBe('a[1][2][3][c]=1');
2118 expect(
2119 stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
2120 ).toBe('a[][][][c]=1');
2121 expect(
2122 stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
2123 ).toBe('a[c]=1');
2124
2125 // st.equal(
2126 // stringify(
2127 // { a: [, [, , [, , , { c: [, '1'] }]]] },
2128 // { encodeValuesOnly: true, arrayFormat: 'indices' },
2129 // ),
2130 // 'a[1][2][3][c][1]=1',
2131 // );
2132 // st.equal(
2133 // stringify(
2134 // { a: [, [, , [, , , { c: [, '1'] }]]] },
2135 // { encodeValuesOnly: true, arrayFormat: 'brackets' },
2136 // ),
2137 // 'a[][][][c][]=1',
2138 // );
2139 // st.equal(
2140 // stringify(
2141 // { a: [, [, , [, , , { c: [, '1'] }]]] },
2142 // { encodeValuesOnly: true, arrayFormat: 'repeat' },
2143 // ),
2144 // 'a[c]=1',
2145 // );
2146 expect(
2147 stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
2148 ).toBe('a[1][2][3][c][1]=1');
2149 expect(
2150 stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
2151 ).toBe('a[][][][c][]=1');
2152 expect(
2153 stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
2154 ).toBe('a[c]=1');
2155 });
2156
2157 test('encodes a very long string', function () {
2158 var chars = [];
2159 var expected = [];
2160 for (var i = 0; i < 5e3; i++) {
2161 chars.push(' ' + i);
2162
2163 expected.push('%20' + i);
2164 }
2165
2166 var obj = {
2167 foo: chars.join(''),
2168 };
2169
2170 // st.equal(
2171 // stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' }),
2172 // 'foo=' + expected.join(''),
2173 // );
2174 // @ts-expect-error
2175 expect(stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' })).toBe('foo=' + expected.join(''));
2176 });
2177});
2178
2179describe('stringifies empty keys', function () {
2180 empty_test_cases.forEach(function (testCase) {
2181 test('stringifies an object with empty string key with ' + testCase.input, function () {
2182 // st.deepEqual(
2183 // stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'indices' }),
2184 // testCase.stringifyOutput.indices,
2185 // 'test case: ' + testCase.input + ', indices',
2186 // );
2187 // st.deepEqual(
2188 // stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'brackets' }),
2189 // testCase.stringifyOutput.brackets,
2190 // 'test case: ' + testCase.input + ', brackets',
2191 // );
2192 // st.deepEqual(
2193 // stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'repeat' }),
2194 // testCase.stringifyOutput.repeat,
2195 // 'test case: ' + testCase.input + ', repeat',
2196 // );
2197 expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'indices' })).toBe(
2198 testCase.stringify_output.indices,
2199 );
2200 expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'brackets' })).toBe(
2201 testCase.stringify_output.brackets,
2202 );
2203 expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'repeat' })).toBe(
2204 testCase.stringify_output.repeat,
2205 );
2206 });
2207 });
2208
2209 test('edge case with object/arrays', function () {
2210 // st.deepEqual(stringify({ '': { '': [2, 3] } }, { encode: false }), '[][0]=2&[][1]=3');
2211 // st.deepEqual(
2212 // stringify({ '': { '': [2, 3], a: 2 } }, { encode: false }),
2213 // '[][0]=2&[][1]=3&[a]=2',
2214 // );
2215 // st.deepEqual(
2216 // stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' }),
2217 // '[][0]=2&[][1]=3',
2218 // );
2219 // st.deepEqual(
2220 // stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' }),
2221 // '[][0]=2&[][1]=3&[a]=2',
2222 // );
2223 expect(stringify({ '': { '': [2, 3] } }, { encode: false })).toBe('[][0]=2&[][1]=3');
2224 expect(stringify({ '': { '': [2, 3], a: 2 } }, { encode: false })).toBe('[][0]=2&[][1]=3&[a]=2');
2225 expect(stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' })).toBe(
2226 '[][0]=2&[][1]=3',
2227 );
2228 expect(stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' })).toBe(
2229 '[][0]=2&[][1]=3&[a]=2',
2230 );
2231 });
2232});
2233