From 1018c2029eea1f5b75b5120265996f1c0b3c12ae Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Fri, 30 Jul 2021 14:09:21 +0200 Subject: [PATCH] Fix merging `searchParams` Fixes #1814 --- documentation/2-options.md | 2 +- source/core/options.ts | 32 +++++++++++++++++++++----------- test/normalize-arguments.ts | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/documentation/2-options.md b/documentation/2-options.md index 989072daa..0ac3faacb 100644 --- a/documentation/2-options.md +++ b/documentation/2-options.md @@ -177,7 +177,7 @@ console.log(searchParams.toString()); #### **Note:** > - `null` values are not stringified, an empty string is used instead. -> - `undefined` values are skipped. +> - `undefined` values will clear the original keys. #### **Merge behavior:** > - Overrides existing properties. diff --git a/source/core/options.ts b/source/core/options.ts index a013d59d4..556744dc5 100644 --- a/source/core/options.ts +++ b/source/core/options.ts @@ -1325,6 +1325,10 @@ export default class Options { return (this._internals.url as URL).searchParams; } + if (this._internals.searchParams === undefined) { + this._internals.searchParams = new URLSearchParams(); + } + return this._internals.searchParams; } @@ -1343,11 +1347,13 @@ export default class Options { return; } - let searchParameters = (this.searchParams ?? new URLSearchParams()) as URLSearchParams; + const searchParameters = this.searchParams as URLSearchParams; let updated; - if (is.string(value) || (value instanceof URLSearchParams)) { + if (is.string(value)) { updated = new URLSearchParams(value); + } else if (value instanceof URLSearchParams) { + updated = value; } else { validateSearchParameters(value); @@ -1359,22 +1365,26 @@ export default class Options { if (entry === null) { updated.append(key, ''); - } else if (entry !== undefined) { + } else if (entry === undefined) { + searchParameters.delete(key); + } else { updated.append(key, entry as string); } } } if (this._merging) { - // eslint-disable-next-line unicorn/no-array-for-each - updated.forEach((value, key) => { - searchParameters.set(key, value); - }); - } else { - searchParameters = updated; - } + // These keys will be replaced + for (const key of updated.keys()) { + searchParameters.delete(key); + } - if (!url) { + for (const [key, value] of updated) { + searchParameters.append(key, value); + } + } else if (url) { + url.search = searchParameters.toString(); + } else { this._internals.searchParams = searchParameters; } } diff --git a/test/normalize-arguments.ts b/test/normalize-arguments.ts index 096d141b8..4930a0ec7 100644 --- a/test/normalize-arguments.ts +++ b/test/normalize-arguments.ts @@ -150,3 +150,20 @@ test('extending responseType', t => { t.is(merged.defaults.options.responseType, 'json'); }); + +test('searchParams - multiple values for one key', t => { + const searchParams = new URLSearchParams(); + + searchParams.append('a', '100'); + searchParams.append('a', '200'); + searchParams.append('a', '300'); + + const options = new Options({ + searchParams + }); + + t.deepEqual( + (options.searchParams as URLSearchParams).getAll('a'), + ['100', '200', '300'] + ); +});