Skip to content

Commit 74b9a70

Browse files
authored
fix : invalid query string when duplicate query param keys are provided (#5)
* fix : invalid query string when duplicate query param keys are provided * added relevant test cases
1 parent 2676dac commit 74b9a70

File tree

3 files changed

+49
-1
lines changed

3 files changed

+49
-1
lines changed

src/helpers/query-params.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ReducedHelperObject } from './reducer';
2+
3+
/**
4+
* Given a query params object return a flattened query string.
5+
*/
6+
export const getQueryString = (queryObj: ReducedHelperObject): string => {
7+
const params = new URLSearchParams();
8+
9+
Object.entries(queryObj).forEach(([key, value]) => {
10+
if (Array.isArray(value)) {
11+
value.forEach(v => params.append(key, v));
12+
} else {
13+
params.append(key, value);
14+
}
15+
});
16+
17+
return params.toString();
18+
};

src/httpsnippet.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { mimetypes } from './fixtures/mimetypes';
2+
import full from './fixtures/requests/full.json';
23
import headers from './fixtures/requests/headers.json';
34
import query from './fixtures/requests/query.json';
45
import short from './fixtures/requests/short.json';
@@ -217,4 +218,32 @@ describe('hTTPSnippet', () => {
217218
});
218219
});
219220
});
221+
222+
describe('queryObj', () => {
223+
it('should build queryObj with arrays for duplicate keys', () => {
224+
const snippet = new HTTPSnippet(full as Request);
225+
const request = snippet.requests[0];
226+
227+
expect(request.queryObj).toMatchObject({
228+
key: 'value',
229+
foo: ['bar', 'baz'],
230+
baz: 'abc',
231+
});
232+
});
233+
234+
it('should not include array-indexed query keys like foo[0]', () => {
235+
const snippet = new HTTPSnippet(full as Request);
236+
const curl = snippet.convert('shell', 'curl');
237+
238+
expect(curl).not.toMatch(/foo\[\d+\]=/);
239+
});
240+
241+
it('should handle empty queryString array gracefully', () => {
242+
const snippet = new HTTPSnippet(short as Request);
243+
244+
const curl = snippet.convert('shell', 'curl');
245+
246+
expect(curl).toContain('--url http://mockbin.com/har');
247+
});
248+
});
220249
});

src/httpsnippet.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { format as urlFormat, parse as urlParse, UrlWithParsedQuery } from 'url'
66

77
import { formDataIterator, isBlob } from './helpers/form-data';
88
import { getHeaderName } from './helpers/headers';
9+
import { getQueryString } from './helpers/query-params';
910
import { ReducedHelperObject, reducer } from './helpers/reducer';
1011
import { ClientId, TargetId, targets } from './targets/targets';
1112

@@ -308,7 +309,7 @@ export class HTTPSnippet {
308309
}; //?
309310

310311
// reset uriObj values for a clean url
311-
const search = queryStringify(request.queryObj);
312+
const search = getQueryString(request.queryObj);
312313

313314
const uriObj = {
314315
...urlWithParsedQuery,

0 commit comments

Comments
 (0)