diff --git a/test/empty-keys-cases.js b/test/empty-keys-cases.js new file mode 100644 index 00000000..e41d1819 --- /dev/null +++ b/test/empty-keys-cases.js @@ -0,0 +1,37 @@ +'use strict'; + +module.exports = { + emptyTestCases: [ + { input: '&', withEmptyKeys: {}, stringifyOutput: '', noEmptyKeys: {} }, + { input: '&&', withEmptyKeys: {}, stringifyOutput: '', noEmptyKeys: {} }, + { input: '&=', withEmptyKeys: { '': '' }, stringifyOutput: '=', noEmptyKeys: {} }, + { input: '&=&', withEmptyKeys: { '': '' }, stringifyOutput: '=', noEmptyKeys: {} }, + { input: '&=&=', withEmptyKeys: { '': ['', ''] }, stringifyOutput: '[0]=&[1]=', noEmptyKeys: {} }, + { input: '&=&=&', withEmptyKeys: { '': ['', ''] }, stringifyOutput: '[0]=&[1]=', noEmptyKeys: {} }, + + { input: '=', withEmptyKeys: { '': '' }, noEmptyKeys: {}, stringifyOutput: '=' }, + { input: '=&', withEmptyKeys: { '': '' }, stringifyOutput: '=', noEmptyKeys: {} }, + { input: '=&&&', withEmptyKeys: { '': '' }, stringifyOutput: '=', noEmptyKeys: {} }, + { input: '=&=&=&', withEmptyKeys: { '': ['', '', ''] }, stringifyOutput: '[0]=&[1]=&[2]=', noEmptyKeys: {} }, + { input: '=&a[]=b&a[1]=c', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } }, + { input: '=a', withEmptyKeys: { '': 'a' }, noEmptyKeys: {}, stringifyOutput: '=a' }, + { input: '=a', withEmptyKeys: { '': 'a' }, noEmptyKeys: {}, stringifyOutput: '=a' }, + { input: 'a==a', withEmptyKeys: { a: '=a' }, noEmptyKeys: { a: '=a' }, stringifyOutput: 'a==a' }, + + { input: '=&a[]=b', withEmptyKeys: { '': '', a: ['b'] }, stringifyOutput: '=&a[0]=b', noEmptyKeys: { a: ['b'] } }, + { input: '=&a[]=b&a[]=c&a[2]=d', withEmptyKeys: { '': '', a: ['b', 'c', 'd'] }, stringifyOutput: '=&a[0]=b&a[1]=c&a[2]=d', noEmptyKeys: { a: ['b', 'c', 'd'] } }, + { input: '=a&=b', withEmptyKeys: { '': ['a', 'b'] }, stringifyOutput: '[0]=a&[1]=b', noEmptyKeys: {} }, + { input: '=a&foo=b', withEmptyKeys: { '': 'a', foo: 'b' }, noEmptyKeys: { foo: 'b' }, stringifyOutput: '=a&foo=b' }, + + { input: 'a[]=b&a=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } }, + { input: 'a[]=b&a=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } }, + { input: 'a[0]=b&a=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } }, + { input: 'a=b&a[]=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } }, + { input: 'a=b&a[0]=c&=', withEmptyKeys: { '': '', a: ['b', 'c'] }, stringifyOutput: '=&a[0]=b&a[1]=c', noEmptyKeys: { a: ['b', 'c'] } }, + + { input: '[]=a&[]=b& []=1', withEmptyKeys: { '': ['a', 'b'], ' ': ['1'] }, stringifyOutput: '[0]=a&[1]=b& [0]=1', noEmptyKeys: { 0: 'a', 1: 'b', ' ': ['1'] } }, + { input: '[0]=a&[1]=b&a[0]=1&a[1]=2', withEmptyKeys: { '': ['a', 'b'], a: ['1', '2'] }, noEmptyKeys: { 0: 'a', 1: 'b', a: ['1', '2'] }, stringifyOutput: '[0]=a&[1]=b&a[0]=1&a[1]=2' }, + { input: '[deep]=a&[deep]=2', withEmptyKeys: { '': { deep: ['a', '2'] } }, stringifyOutput: '[deep][0]=a&[deep][1]=2', noEmptyKeys: { deep: ['a', '2'] } }, + { input: '%5B0%5D=a&%5B1%5D=b', withEmptyKeys: { '': ['a', 'b'] }, stringifyOutput: '[0]=a&[1]=b', noEmptyKeys: { 0: 'a', 1: 'b' } } + ] +}; diff --git a/test/parse.js b/test/parse.js index ca9ca730..d4a213a2 100644 --- a/test/parse.js +++ b/test/parse.js @@ -6,6 +6,7 @@ var iconv = require('iconv-lite'); var mockProperty = require('mock-property'); var hasOverrideMistake = require('has-override-mistake')(); var SaferBuffer = require('safer-buffer').Buffer; +var emptyTestCases = require('./empty-keys-cases').emptyTestCases; var qs = require('../'); var utils = require('../lib/utils'); @@ -885,3 +886,13 @@ test('parse()', function (t) { t.end(); }); + +test('parses empty keys', function (t) { + emptyTestCases.forEach(function (testCase) { + t.test('skips empty string key with ' + testCase.input, function (st) { + st.deepEqual(qs.parse(testCase.input), testCase.noEmptyKeys); + + st.end(); + }); + }); +}); diff --git a/test/stringify.js b/test/stringify.js index 32272730..a49e4f16 100644 --- a/test/stringify.js +++ b/test/stringify.js @@ -6,6 +6,7 @@ var utils = require('../lib/utils'); var iconv = require('iconv-lite'); var SaferBuffer = require('safer-buffer').Buffer; var hasSymbols = require('has-symbols'); +var emptyTestCases = require('./empty-keys-cases').emptyTestCases; var hasBigInt = typeof BigInt === 'function'; test('stringify()', function (t) { @@ -952,3 +953,20 @@ test('stringify()', function (t) { t.end(); }); + +test('stringifies empty keys', function (t) { + emptyTestCases.forEach(function (testCase) { + t.test('stringifies an object with empty string key with ' + testCase.input, function (st) { + st.deepEqual(qs.stringify(testCase.withEmptyKeys, { encode: false }), testCase.stringifyOutput); + + st.end(); + }); + }); + + t.test('edge case with object/arrays', function (st) { + st.deepEqual(qs.stringify({ '': { '': [2, 3] } }, { encode: false }), '[][0]=2&[][1]=3'); + st.deepEqual(qs.stringify({ '': { '': [2, 3], a: 2 } }, { encode: false }), '[][0]=2&[][1]=3&[a]=2'); + + st.end(); + }); +});