Skip to content

Commit 6ddcfb6

Browse files
fix(routing): support parsing URLs with up to 100 refinements (#3671)
1 parent 2c9e38d commit 6ddcfb6

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

src/lib/__tests__/RoutingManager-test.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* globals jsdom */
2+
import qs from 'qs';
23
import instantsearch from '../main';
34
import RoutingManager from '../RoutingManager';
45
import historyRouter from '../routers/history';
@@ -585,4 +586,73 @@ describe('RoutingManager', () => {
585586
setWindowTitle.mockRestore();
586587
});
587588
});
589+
590+
describe('parseURL', () => {
591+
const createFakeUrlWithRefinements = ({ length }) =>
592+
[
593+
'https://website.com/',
594+
Array.from(
595+
{ length },
596+
(_v, i) => `refinementList[brand][${i}]=brand-${i}`
597+
).join('&'),
598+
].join('?');
599+
600+
test('should parse refinements with more than 20 filters per category as array', () => {
601+
jsdom.reconfigure({
602+
url: createFakeUrlWithRefinements({ length: 22 }),
603+
});
604+
605+
const router = historyRouter();
606+
const parsedUrl = router.parseURL({
607+
qsModule: qs,
608+
location: window.location,
609+
});
610+
611+
expect(parsedUrl.refinementList.brand).toBeInstanceOf(Array);
612+
expect(parsedUrl).toMatchInlineSnapshot(`
613+
Object {
614+
"refinementList": Object {
615+
"brand": Array [
616+
"brand-0",
617+
"brand-1",
618+
"brand-2",
619+
"brand-3",
620+
"brand-4",
621+
"brand-5",
622+
"brand-6",
623+
"brand-7",
624+
"brand-8",
625+
"brand-9",
626+
"brand-10",
627+
"brand-11",
628+
"brand-12",
629+
"brand-13",
630+
"brand-14",
631+
"brand-15",
632+
"brand-16",
633+
"brand-17",
634+
"brand-18",
635+
"brand-19",
636+
"brand-20",
637+
"brand-21",
638+
],
639+
},
640+
}
641+
`);
642+
});
643+
644+
test('should support returning 100 refinements as array', () => {
645+
jsdom.reconfigure({
646+
url: createFakeUrlWithRefinements({ length: 100 }),
647+
});
648+
649+
const router = historyRouter();
650+
const parsedUrl = router.parseURL({
651+
qsModule: qs,
652+
location: window.location,
653+
});
654+
655+
expect(parsedUrl.refinementList.brand).toBeInstanceOf(Array);
656+
});
657+
});
588658
});

src/lib/routers/history.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,17 @@ function defaultCreateURL({ qsModule, routeState, location }) {
1212
}
1313

1414
function defaultParseURL({ qsModule, location }) {
15-
return qsModule.parse(location.search.slice(1));
15+
// `qs` by default converts arrays with more than 20 items to an object.
16+
// We want to avoid this because the data structure manipulated can therefore vary.
17+
// Setting the limit to `100` seems a good number because the engine's default is 100
18+
// (it can go up to 1000 but it is very unlikely to select more than 100 items in the UI).
19+
//
20+
// Using an `arrayLimit` of `n` allows `n + 1` items.
21+
//
22+
// See:
23+
// - https://github.com/ljharb/qs#parsing-arrays
24+
// - https://www.algolia.com/doc/api-reference/api-parameters/maxValuesPerFacet/
25+
return qsModule.parse(location.search.slice(1), { arrayLimit: 99 });
1626
}
1727

1828
function setWindowTitle(title) {

0 commit comments

Comments
 (0)