qs 6.11.2 → 6.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/test/stringify.js CHANGED
@@ -6,6 +6,7 @@ var utils = require('../lib/utils');
6
6
  var iconv = require('iconv-lite');
7
7
  var SaferBuffer = require('safer-buffer').Buffer;
8
8
  var hasSymbols = require('has-symbols');
9
+ var mockProperty = require('mock-property');
9
10
  var emptyTestCases = require('./empty-keys-cases').emptyTestCases;
10
11
  var hasBigInt = typeof BigInt === 'function';
11
12
 
@@ -64,6 +65,138 @@ test('stringify()', function (t) {
64
65
  st.end();
65
66
  });
66
67
 
68
+ t.test('encodes dot in key of object when encodeDotInKeys and allowDots is provided', function (st) {
69
+ st.equal(
70
+ qs.stringify(
71
+ { 'name.obj': { first: 'John', last: 'Doe' } },
72
+ { allowDots: false, encodeDotInKeys: false }
73
+ ),
74
+ 'name.obj%5Bfirst%5D=John&name.obj%5Blast%5D=Doe',
75
+ 'with allowDots false and encodeDotInKeys false'
76
+ );
77
+ st.equal(
78
+ qs.stringify(
79
+ { 'name.obj': { first: 'John', last: 'Doe' } },
80
+ { allowDots: true, encodeDotInKeys: false }
81
+ ),
82
+ 'name.obj.first=John&name.obj.last=Doe',
83
+ 'with allowDots true and encodeDotInKeys false'
84
+ );
85
+ st.equal(
86
+ qs.stringify(
87
+ { 'name.obj': { first: 'John', last: 'Doe' } },
88
+ { allowDots: false, encodeDotInKeys: true }
89
+ ),
90
+ 'name%252Eobj%5Bfirst%5D=John&name%252Eobj%5Blast%5D=Doe',
91
+ 'with allowDots false and encodeDotInKeys true'
92
+ );
93
+ st.equal(
94
+ qs.stringify(
95
+ { 'name.obj': { first: 'John', last: 'Doe' } },
96
+ { allowDots: true, encodeDotInKeys: true }
97
+ ),
98
+ 'name%252Eobj.first=John&name%252Eobj.last=Doe',
99
+ 'with allowDots true and encodeDotInKeys true'
100
+ );
101
+
102
+ st.equal(
103
+ qs.stringify(
104
+ { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
105
+ { allowDots: false, encodeDotInKeys: false }
106
+ ),
107
+ 'name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe',
108
+ 'with allowDots false and encodeDotInKeys false'
109
+ );
110
+ st.equal(
111
+ qs.stringify(
112
+ { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
113
+ { allowDots: true, encodeDotInKeys: false }
114
+ ),
115
+ 'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe',
116
+ 'with allowDots false and encodeDotInKeys false'
117
+ );
118
+ st.equal(
119
+ qs.stringify(
120
+ { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
121
+ { allowDots: false, encodeDotInKeys: true }
122
+ ),
123
+ 'name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe',
124
+ 'with allowDots false and encodeDotInKeys true'
125
+ );
126
+ st.equal(
127
+ qs.stringify(
128
+ { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
129
+ { allowDots: true, encodeDotInKeys: true }
130
+ ),
131
+ 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
132
+ 'with allowDots true and encodeDotInKeys true'
133
+ );
134
+
135
+ st.end();
136
+ });
137
+
138
+ t.test('should encode dot in key of object, and automatically set allowDots to `true` when encodeDotInKeys is true and allowDots in undefined', function (st) {
139
+ st.equal(
140
+ qs.stringify(
141
+ { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } },
142
+ { encodeDotInKeys: true }
143
+ ),
144
+ 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe',
145
+ 'with allowDots undefined and encodeDotInKeys true'
146
+ );
147
+ st.end();
148
+ });
149
+
150
+ t.test('should encode dot in key of object when encodeDotInKeys and allowDots is provided, and nothing else when encodeValuesOnly is provided', function (st) {
151
+ st.equal(
152
+ qs.stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, {
153
+ encodeDotInKeys: true, allowDots: true, encodeValuesOnly: true
154
+ }),
155
+ 'name%2Eobj.first=John&name%2Eobj.last=Doe'
156
+ );
157
+
158
+ st.equal(
159
+ qs.stringify({ 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true }),
160
+ 'name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe'
161
+ );
162
+
163
+ st.end();
164
+ });
165
+
166
+ t.test('throws when `commaRoundTrip` is not a boolean', function (st) {
167
+ st['throws'](
168
+ function () { qs.stringify({}, { commaRoundTrip: 'not a boolean' }); },
169
+ TypeError,
170
+ 'throws when `commaRoundTrip` is not a boolean'
171
+ );
172
+
173
+ st.end();
174
+ });
175
+
176
+ t.test('throws when `encodeDotInKeys` is not a boolean', function (st) {
177
+ st['throws'](
178
+ function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' }); },
179
+ TypeError
180
+ );
181
+
182
+ st['throws'](
183
+ function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 }); },
184
+ TypeError
185
+ );
186
+
187
+ st['throws'](
188
+ function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN }); },
189
+ TypeError
190
+ );
191
+
192
+ st['throws'](
193
+ function () { qs.stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null }); },
194
+ TypeError
195
+ );
196
+
197
+ st.end();
198
+ });
199
+
67
200
  t.test('adds query prefix', function (st) {
68
201
  st.equal(qs.stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b');
69
202
  st.end();
@@ -87,7 +220,7 @@ test('stringify()', function (t) {
87
220
  st.end();
88
221
  });
89
222
 
90
- t.test('stringifies a nested object with dots notation', function (st) {
223
+ t.test('`allowDots` option: stringifies a nested object with dots notation', function (st) {
91
224
  st.equal(qs.stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c');
92
225
  st.equal(qs.stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e');
93
226
  st.end();
@@ -109,6 +242,11 @@ test('stringify()', function (t) {
109
242
  'a=b%2Cc%2Cd',
110
243
  'comma => comma'
111
244
  );
245
+ st.equal(
246
+ qs.stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true }),
247
+ 'a=b%2Cc%2Cd',
248
+ 'comma round trip => comma'
249
+ );
112
250
  st.equal(
113
251
  qs.stringify({ a: ['b', 'c', 'd'] }),
114
252
  'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d',
@@ -117,18 +255,63 @@ test('stringify()', function (t) {
117
255
  st.end();
118
256
  });
119
257
 
120
- t.test('omits nulls when asked', function (st) {
121
- st.equal(qs.stringify({ a: 'b', c: null }, { skipNulls: true }), 'a=b');
122
- st.end();
123
- });
258
+ t.test('`skipNulls` option', function (st) {
259
+ st.equal(
260
+ qs.stringify({ a: 'b', c: null }, { skipNulls: true }),
261
+ 'a=b',
262
+ 'omits nulls when asked'
263
+ );
264
+
265
+ st.equal(
266
+ qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }),
267
+ 'a%5Bb%5D=c',
268
+ 'omits nested nulls when asked'
269
+ );
124
270
 
125
- t.test('omits nested nulls when asked', function (st) {
126
- st.equal(qs.stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), 'a%5Bb%5D=c');
127
271
  st.end();
128
272
  });
129
273
 
130
274
  t.test('omits array indices when asked', function (st) {
131
275
  st.equal(qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d');
276
+
277
+ st.end();
278
+ });
279
+
280
+ t.test('omits object key/value pair when value is empty array', function (st) {
281
+ st.equal(qs.stringify({ a: [], b: 'zz' }), 'b=zz');
282
+
283
+ st.end();
284
+ });
285
+
286
+ t.test('should not omit object key/value pair when value is empty array and when asked', function (st) {
287
+ st.equal(qs.stringify({ a: [], b: 'zz' }), 'b=zz');
288
+ st.equal(qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false }), 'b=zz');
289
+ st.equal(qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true }), 'a[]&b=zz');
290
+
291
+ st.end();
292
+ });
293
+
294
+ t.test('should throw when allowEmptyArrays is not of type boolean', function (st) {
295
+ st['throws'](
296
+ function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' }); },
297
+ TypeError
298
+ );
299
+
300
+ st['throws'](
301
+ function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 }); },
302
+ TypeError
303
+ );
304
+
305
+ st['throws'](
306
+ function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN }); },
307
+ TypeError
308
+ );
309
+
310
+ st['throws'](
311
+ function () { qs.stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null }); },
312
+ TypeError
313
+ );
314
+
132
315
  st.end();
133
316
  });
134
317
 
@@ -156,6 +339,7 @@ test('stringify()', function (t) {
156
339
  s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[0]=c&a[1]=d');
157
340
  s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=c&a[]=d');
158
341
  s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c,d');
342
+ s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), 'a=c,d');
159
343
  s2t.equal(qs.stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true }), 'a[0]=c&a[1]=d');
160
344
 
161
345
  s2t.end();
@@ -165,6 +349,9 @@ test('stringify()', function (t) {
165
349
  s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c%2Cd,e');
166
350
  s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' }), 'a=c%2Cd%2Ce');
167
351
 
352
+ s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), 'a=c%2Cd,e');
353
+ s2t.equal(qs.stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true }), 'a=c%2Cd%2Ce');
354
+
168
355
  s2t.end();
169
356
  });
170
357
 
@@ -255,36 +442,44 @@ test('stringify()', function (t) {
255
442
 
256
443
  t.test('stringifies an object inside an array', function (st) {
257
444
  st.equal(
258
- qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices' }),
259
- 'a%5B0%5D%5Bb%5D=c', // a[0][b]=c
260
- 'indices => brackets'
445
+ qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
446
+ 'a[0][b]=c',
447
+ 'indices => indices'
261
448
  );
262
449
  st.equal(
263
- qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets' }),
264
- 'a%5B%5D%5Bb%5D=c', // a[][b]=c
450
+ qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
451
+ 'a[b]=c',
452
+ 'repeat => repeat'
453
+ );
454
+ st.equal(
455
+ qs.stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
456
+ 'a[][b]=c',
265
457
  'brackets => brackets'
266
458
  );
267
459
  st.equal(
268
- qs.stringify({ a: [{ b: 'c' }] }),
269
- 'a%5B0%5D%5Bb%5D=c',
460
+ qs.stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true }),
461
+ 'a[0][b]=c',
270
462
  'default => indices'
271
463
  );
272
464
 
273
465
  st.equal(
274
- qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices' }),
275
- 'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1',
466
+ qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true }),
467
+ 'a[0][b][c][0]=1',
276
468
  'indices => indices'
277
469
  );
278
-
279
470
  st.equal(
280
- qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets' }),
281
- 'a%5B%5D%5Bb%5D%5Bc%5D%5B%5D=1',
471
+ qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }),
472
+ 'a[b][c]=1',
473
+ 'repeat => repeat'
474
+ );
475
+ st.equal(
476
+ qs.stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }),
477
+ 'a[][b][c][]=1',
282
478
  'brackets => brackets'
283
479
  );
284
-
285
480
  st.equal(
286
- qs.stringify({ a: [{ b: { c: [1] } }] }),
287
- 'a%5B0%5D%5Bb%5D%5Bc%5D%5B0%5D=1',
481
+ qs.stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true }),
482
+ 'a[0][b][c][0]=1',
288
483
  'default => indices'
289
484
  );
290
485
 
@@ -386,17 +581,17 @@ test('stringify()', function (t) {
386
581
  st.end();
387
582
  });
388
583
 
389
- t.test('uses indices notation for arrays when no arrayFormat=indices', function (st) {
584
+ t.test('uses indices notation for arrays when arrayFormat=indices', function (st) {
390
585
  st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c');
391
586
  st.end();
392
587
  });
393
588
 
394
- t.test('uses repeat notation for arrays when no arrayFormat=repeat', function (st) {
589
+ t.test('uses repeat notation for arrays when arrayFormat=repeat', function (st) {
395
590
  st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c');
396
591
  st.end();
397
592
  });
398
593
 
399
- t.test('uses brackets notation for arrays when no arrayFormat=brackets', function (st) {
594
+ t.test('uses brackets notation for arrays when arrayFormat=brackets', function (st) {
400
595
  st.equal(qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c');
401
596
  st.end();
402
597
  });
@@ -493,10 +688,11 @@ test('stringify()', function (t) {
493
688
  });
494
689
 
495
690
  t.test('skips properties that are part of the object prototype', function (st) {
496
- Object.prototype.crash = 'test';
691
+ st.intercept(Object.prototype, 'crash', { value: 'test' });
692
+
497
693
  st.equal(qs.stringify({ a: 'b' }), 'a=b');
498
694
  st.equal(qs.stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c');
499
- delete Object.prototype.crash;
695
+
500
696
  st.end();
501
697
  });
502
698
 
@@ -520,10 +716,12 @@ test('stringify()', function (t) {
520
716
  });
521
717
 
522
718
  t.test('does not blow up when Buffer global is missing', function (st) {
523
- var tempBuffer = global.Buffer;
524
- delete global.Buffer;
719
+ var restore = mockProperty(global, 'Buffer', { 'delete': true });
720
+
525
721
  var result = qs.stringify({ a: 'b', c: 'd' });
526
- global.Buffer = tempBuffer;
722
+
723
+ restore();
724
+
527
725
  st.equal(result, 'a=b&c=d');
528
726
  st.end();
529
727
  });
@@ -572,9 +770,17 @@ test('stringify()', function (t) {
572
770
  };
573
771
 
574
772
  st.equal(
575
- qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true }),
773
+ qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }),
576
774
  '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'
577
775
  );
776
+ st.equal(
777
+ qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }),
778
+ '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'
779
+ );
780
+ st.equal(
781
+ qs.stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'repeat' }),
782
+ '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'
783
+ );
578
784
 
579
785
  st.end();
580
786
  });
@@ -687,13 +893,28 @@ test('stringify()', function (t) {
687
893
  st.end();
688
894
  });
689
895
 
896
+ t.test('receives the default encoder as a second argument', function (st) {
897
+ st.plan(8);
898
+
899
+ qs.stringify({ a: 1, b: new Date(), c: true, d: [1] }, {
900
+ encoder: function (str) {
901
+ st.match(typeof str, /^(?:string|number|boolean)$/);
902
+ return '';
903
+ }
904
+ });
905
+
906
+ st.end();
907
+ });
908
+
690
909
  t.test('receives the default encoder as a second argument', function (st) {
691
910
  st.plan(2);
911
+
692
912
  qs.stringify({ a: 1 }, {
693
913
  encoder: function (str, defaultEncoder) {
694
914
  st.equal(defaultEncoder, utils.encode);
695
915
  }
696
916
  });
917
+
697
918
  st.end();
698
919
  });
699
920
 
@@ -821,16 +1042,53 @@ test('stringify()', function (t) {
821
1042
  st.equal(
822
1043
  qs.stringify(
823
1044
  { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
824
- { encodeValuesOnly: true }
1045
+ { encodeValuesOnly: true, arrayFormat: 'indices' }
1046
+ ),
1047
+ 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h',
1048
+ 'encodeValuesOnly + indices'
1049
+ );
1050
+ st.equal(
1051
+ qs.stringify(
1052
+ { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
1053
+ { encodeValuesOnly: true, arrayFormat: 'brackets' }
1054
+ ),
1055
+ 'a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h',
1056
+ 'encodeValuesOnly + brackets'
1057
+ );
1058
+ st.equal(
1059
+ qs.stringify(
1060
+ { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] },
1061
+ { encodeValuesOnly: true, arrayFormat: 'repeat' }
825
1062
  ),
826
- 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'
1063
+ 'a=b&c=d&c=e%3Df&f=g&f=h',
1064
+ 'encodeValuesOnly + repeat'
1065
+ );
1066
+
1067
+ st.equal(
1068
+ qs.stringify(
1069
+ { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
1070
+ { arrayFormat: 'indices' }
1071
+ ),
1072
+ 'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h',
1073
+ 'no encodeValuesOnly + indices'
827
1074
  );
828
1075
  st.equal(
829
1076
  qs.stringify(
830
- { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }
1077
+ { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
1078
+ { arrayFormat: 'brackets' }
831
1079
  ),
832
- 'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h'
1080
+ 'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h',
1081
+ 'no encodeValuesOnly + brackets'
833
1082
  );
1083
+ st.equal(
1084
+ qs.stringify(
1085
+ { a: 'b', c: ['d', 'e'], f: [['g'], ['h']] },
1086
+ { arrayFormat: 'repeat' }
1087
+ ),
1088
+ 'a=b&c=d&c=e&f=g&f=h',
1089
+ 'no encodeValuesOnly + repeat'
1090
+ );
1091
+
834
1092
  st.end();
835
1093
  });
836
1094
 
@@ -867,13 +1125,19 @@ test('stringify()', function (t) {
867
1125
  st.end();
868
1126
  });
869
1127
 
870
- t.test('adds the right sentinel when instructed to and the charset is utf-8', function (st) {
871
- st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }), 'utf8=%E2%9C%93&a=%C3%A6');
872
- st.end();
873
- });
1128
+ t.test('`charsetSentinel` option', function (st) {
1129
+ st.equal(
1130
+ qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }),
1131
+ 'utf8=%E2%9C%93&a=%C3%A6',
1132
+ 'adds the right sentinel when instructed to and the charset is utf-8'
1133
+ );
1134
+
1135
+ st.equal(
1136
+ qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }),
1137
+ 'utf8=%26%2310003%3B&a=%E6',
1138
+ 'adds the right sentinel when instructed to and the charset is iso-8859-1'
1139
+ );
874
1140
 
875
- t.test('adds the right sentinel when instructed to and the charset is iso-8859-1', function (st) {
876
- st.equal(qs.stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }), 'utf8=%26%2310003%3B&a=%E6');
877
1141
  st.end();
878
1142
  });
879
1143
 
@@ -924,13 +1188,15 @@ test('stringify()', function (t) {
924
1188
  var withArray = { a: { b: [{ c: 'd', e: 'f' }] } };
925
1189
 
926
1190
  st.equal(qs.stringify(obj, { encode: false }), 'a[b][c]=d&a[b][e]=f', 'no array, no arrayFormat');
927
- st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'bracket' }), 'a[b][c]=d&a[b][e]=f', 'no array, bracket');
1191
+ st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'brackets' }), 'a[b][c]=d&a[b][e]=f', 'no array, bracket');
928
1192
  st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'indices' }), 'a[b][c]=d&a[b][e]=f', 'no array, indices');
1193
+ st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'repeat' }), 'a[b][c]=d&a[b][e]=f', 'no array, repeat');
929
1194
  st.equal(qs.stringify(obj, { encode: false, arrayFormat: 'comma' }), 'a[b][c]=d&a[b][e]=f', 'no array, comma');
930
1195
 
931
1196
  st.equal(qs.stringify(withArray, { encode: false }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, no arrayFormat');
932
- st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'bracket' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, bracket');
1197
+ st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'brackets' }), 'a[b][][c]=d&a[b][][e]=f', 'array, bracket');
933
1198
  st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'indices' }), 'a[b][0][c]=d&a[b][0][e]=f', 'array, indices');
1199
+ st.equal(qs.stringify(withArray, { encode: false, arrayFormat: 'repeat' }), 'a[b][c]=d&a[b][e]=f', 'array, repeat');
934
1200
  st.equal(
935
1201
  qs.stringify(withArray, { encode: false, arrayFormat: 'comma' }),
936
1202
  '???',
@@ -943,10 +1209,42 @@ test('stringify()', function (t) {
943
1209
 
944
1210
  t.test('stringifies sparse arrays', function (st) {
945
1211
  /* eslint no-sparse-arrays: 0 */
946
- st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true }), 'a[1]=2&a[4]=1');
947
- st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true }), 'a[1][b][2][c]=1');
948
- st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true }), 'a[1][2][3][c]=1');
949
- st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true }), 'a[1][2][3][c][1]=1');
1212
+ st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1]=2&a[4]=1');
1213
+ st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[]=2&a[]=1');
1214
+ st.equal(qs.stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a=2&a=1');
1215
+
1216
+ st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][b][2][c]=1');
1217
+ st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][b][][c]=1');
1218
+ st.equal(qs.stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[b][c]=1');
1219
+
1220
+ st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][2][3][c]=1');
1221
+ st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][][][c]=1');
1222
+ st.equal(qs.stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[c]=1');
1223
+
1224
+ st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), 'a[1][2][3][c][1]=1');
1225
+ st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), 'a[][][][c][]=1');
1226
+ st.equal(qs.stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), 'a[c]=1');
1227
+
1228
+ st.end();
1229
+ });
1230
+
1231
+ t.test('encodes a very long string', function (st) {
1232
+ var chars = [];
1233
+ var expected = [];
1234
+ for (var i = 0; i < 5e3; i++) {
1235
+ chars.push(' ' + i);
1236
+
1237
+ expected.push('%20' + i);
1238
+ }
1239
+
1240
+ var obj = {
1241
+ foo: chars.join('')
1242
+ };
1243
+
1244
+ st.equal(
1245
+ qs.stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' }),
1246
+ 'foo=' + expected.join('')
1247
+ );
950
1248
 
951
1249
  st.end();
952
1250
  });
@@ -957,7 +1255,21 @@ test('stringify()', function (t) {
957
1255
  test('stringifies empty keys', function (t) {
958
1256
  emptyTestCases.forEach(function (testCase) {
959
1257
  t.test('stringifies an object with empty string key with ' + testCase.input, function (st) {
960
- st.deepEqual(qs.stringify(testCase.withEmptyKeys, { encode: false }), testCase.stringifyOutput);
1258
+ st.deepEqual(
1259
+ qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'indices' }),
1260
+ testCase.stringifyOutput.indices,
1261
+ 'test case: ' + testCase.input + ', indices'
1262
+ );
1263
+ st.deepEqual(
1264
+ qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'brackets' }),
1265
+ testCase.stringifyOutput.brackets,
1266
+ 'test case: ' + testCase.input + ', brackets'
1267
+ );
1268
+ st.deepEqual(
1269
+ qs.stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'repeat' }),
1270
+ testCase.stringifyOutput.repeat,
1271
+ 'test case: ' + testCase.input + ', repeat'
1272
+ );
961
1273
 
962
1274
  st.end();
963
1275
  });
@@ -966,6 +1278,8 @@ test('stringifies empty keys', function (t) {
966
1278
  t.test('edge case with object/arrays', function (st) {
967
1279
  st.deepEqual(qs.stringify({ '': { '': [2, 3] } }, { encode: false }), '[][0]=2&[][1]=3');
968
1280
  st.deepEqual(qs.stringify({ '': { '': [2, 3], a: 2 } }, { encode: false }), '[][0]=2&[][1]=3&[a]=2');
1281
+ st.deepEqual(qs.stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' }), '[][0]=2&[][1]=3');
1282
+ st.deepEqual(qs.stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' }), '[][0]=2&[][1]=3&[a]=2');
969
1283
 
970
1284
  st.end();
971
1285
  });