diff --git a/packages/instantsearch.js/src/widgets/menu/__tests__/menu.test.tsx b/packages/instantsearch.js/src/widgets/menu/__tests__/menu.test.tsx
index 611eaa40f2..97a8137457 100644
--- a/packages/instantsearch.js/src/widgets/menu/__tests__/menu.test.tsx
+++ b/packages/instantsearch.js/src/widgets/menu/__tests__/menu.test.tsx
@@ -397,144 +397,6 @@ describe('menu', () => {
`);
});
- test('renders with templates show more count', async () => {
- const container = document.createElement('div');
- const searchClient = createMockedSearchClient();
-
- const search = instantsearch({
- indexName: 'indexName',
- searchClient,
- initialUiState: {
- indexName: {
- menu: {
- brand: 'Apple',
- },
- },
- },
- });
-
- search.addWidgets([
- menu({
- container,
- attribute: 'brand',
- limit: 3,
- showMore: true,
- showMoreLimit: 6,
- templates: {
- showMoreText({ isShowingMore, showMoreCount }) {
- return isShowingMore
- ? `Show top 3 items`
- : `Show ${showMoreCount} more`;
- },
- },
- }),
- ]);
-
- // @MAJOR Once Hogan.js and string-based templates are removed,
- // `search.start()` can be moved to the test body and the following
- // assertion can go away.
- expect(async () => {
- search.start();
-
- await wait(0);
- }).not.toWarnDev();
-
- await wait(0);
-
- expect(container).toMatchInlineSnapshot(`
-
-
-
-`);
-
- const toggleButton = within(container).getByRole('button');
-
- fireEvent.click(toggleButton);
-
- expect(toggleButton).toMatchInlineSnapshot(`
-
-`);
- });
-
function createMockedSearchClient() {
return createSearchClient({
search: jest.fn((requests) => {
diff --git a/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx b/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx
index 709b8d8d99..6790d1e0a6 100644
--- a/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx
+++ b/packages/instantsearch.js/src/widgets/refinement-list/__tests__/refinement-list.test.tsx
@@ -851,224 +851,6 @@ describe('refinementList', () => {
`);
});
- test('renders with templates show more count', async () => {
- const container = document.createElement('div');
- const searchClient = createMockedSearchClient();
-
- const search = instantsearch({
- indexName: 'indexName',
- searchClient,
- initialUiState: {
- indexName: {
- refinementList: {
- brand: ['Apple'],
- },
- },
- },
- });
-
- search.addWidgets([
- refinementList({
- container,
- attribute: 'brand',
- showMore: true,
- searchable: true,
- limit: 2,
- showMoreLimit: 6,
- templates: {
- showMoreText({ isShowingMore, showMoreCount }) {
- return isShowingMore
- ? `Show top 2 items`
- : `Show ${showMoreCount} more`;
- },
- },
- }),
- ]);
-
- search.start();
-
- await wait(0);
-
- expect(container).toMatchInlineSnapshot(`
-
-`);
-
- const showMoreButton = container.querySelector(
- '.ais-RefinementList-showMore'
- )!;
-
- fireEvent.click(showMoreButton);
-
- expect(showMoreButton).toHaveTextContent('Show top 2 items');
- });
-
function createMockedSearchClient() {
return createSearchClient({
search: jest.fn((requests) => {
@@ -1081,23 +863,6 @@ describe('refinementList', () => {
Apple: 746,
Samsung: 633,
Metra: 591,
- HP: 530,
- 'Insignia™': 442,
- GE: 394,
- Sony: 350,
- Incipio: 320,
- KitchenAid: 318,
- Whirlpool: 298,
- LG: 291,
- Canon: 287,
- Frigidaire: 275,
- Speck: 216,
- OtterBox: 214,
- Epson: 204,
- 'Dynex™': 184,
- Dell: 174,
- 'Hamilton Beach': 173,
- Platinum: 155,
},
},
})
diff --git a/packages/react-instantsearch-hooks-web/src/__tests__/common.test.tsx b/packages/react-instantsearch-hooks-web/src/__tests__/common.test.tsx
index fe3f930059..fac5c6a058 100644
--- a/packages/react-instantsearch-hooks-web/src/__tests__/common.test.tsx
+++ b/packages/react-instantsearch-hooks-web/src/__tests__/common.test.tsx
@@ -30,6 +30,27 @@ import {
import type { Hit } from 'instantsearch.js';
import type { SendEventForHits } from 'instantsearch.js/es/lib/utils';
+/**
+ * Converts InstantSearch.js templates into React InstantSearch Hooks translations.
+ * @param templates InstantSearch.js templates received in `widgetParams`
+ * @param map Matching between template keys and translation keys
+ */
+function fromTemplates(
+ templates: Record,
+ map: Record
+) {
+ return Object.entries(map).reduce>(
+ (translations, [templateKey, translationKey]) => {
+ if (templates[templateKey] !== undefined) {
+ translations[translationKey] = templates[templateKey];
+ }
+
+ return translations;
+ },
+ {}
+ );
+}
+
/**
* prevent rethrowing InstantSearch errors, so tests can be asserted.
* IRL this isn't needed, as the error doesn't stop execution.
@@ -41,18 +62,32 @@ function GlobalErrorSwallower() {
}
createRefinementListTests(({ instantSearchOptions, widgetParams }) => {
+ const { templates, ...props } = widgetParams;
+ const translations =
+ templates &&
+ fromTemplates(templates, {
+ showMoreText: 'showMoreButtonText',
+ });
+
render(
-
+
);
}, act);
createHierarchicalMenuTests(({ instantSearchOptions, widgetParams }) => {
+ const { templates, ...props } = widgetParams;
+ const translations =
+ templates &&
+ fromTemplates(templates, {
+ showMoreText: 'showMoreButtonText',
+ });
+
render(
-
+
);
@@ -70,9 +105,16 @@ createBreadcrumbTests(({ instantSearchOptions, widgetParams }) => {
}, act);
createMenuTests(({ instantSearchOptions, widgetParams }) => {
+ const { templates, ...props } = widgetParams;
+ const translations =
+ templates &&
+ fromTemplates(templates, {
+ showMoreText: 'showMoreButtonText',
+ });
+
render(
-
+
);
diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/RefinementList.test.tsx b/packages/react-instantsearch-hooks-web/src/ui/__tests__/RefinementList.test.tsx
index df46d8efd7..df82c89ee1 100644
--- a/packages/react-instantsearch-hooks-web/src/ui/__tests__/RefinementList.test.tsx
+++ b/packages/react-instantsearch-hooks-web/src/ui/__tests__/RefinementList.test.tsx
@@ -682,34 +682,4 @@ describe('RefinementList', () => {
getByRole('button', { name: 'Show less brands' })
).toBeInTheDocument();
});
-
- test('renders with translations show more count', () => {
- const props = createProps({
- showMore: true,
- translations: {
- showMoreButtonText({
- isShowingMore,
- showMoreCount,
- }: {
- isShowingMore: boolean;
- showMoreCount: number;
- }) {
- return isShowingMore
- ? `Show top 5 items`
- : `Show ${showMoreCount} more`;
- },
- },
- });
- const { getByRole, rerender } = render(
-
- );
-
- expect(getByRole('button', { name: 'Show 5 more' })).toBeInTheDocument();
-
- rerender();
-
- expect(
- getByRole('button', { name: 'Show top 5 items' })
- ).toBeInTheDocument();
- });
});
diff --git a/packages/vue-instantsearch/src/__tests__/common.test.js b/packages/vue-instantsearch/src/__tests__/common.test.js
index 611bab8939..63ff324206 100644
--- a/packages/vue-instantsearch/src/__tests__/common.test.js
+++ b/packages/vue-instantsearch/src/__tests__/common.test.js
@@ -28,6 +28,25 @@ import {
} from '../instantsearch';
jest.unmock('instantsearch.js/es');
+/**
+ * Converts InstantSearch.js templates into Vue InstantSearch slots.
+ * @param {Record} templates InstantSearch.js templates received in `widgetParams`
+ * @param {Record} map Matching between template keys and slots names
+ * @returns {Record} Vue InstantSearch slots
+ */
+function fromTemplates(templates, map) {
+ return Object.entries(map).reduce(
+ (translations, [templateKey, translationKey]) => {
+ if (templates[templateKey] !== undefined) {
+ return { ...translations, [translationKey]: templates[templateKey] };
+ }
+
+ return translations;
+ },
+ {}
+ );
+}
+
/**
* prevent rethrowing InstantSearch errors, so tests can be asserted.
* IRL this isn't needed, as the error doesn't stop execution.
@@ -43,11 +62,21 @@ const GlobalErrorSwallower = {
};
createRefinementListTests(async ({ instantSearchOptions, widgetParams }) => {
+ const { templates, ...props } = widgetParams;
+ const scopedSlots =
+ templates &&
+ fromTemplates(templates, {
+ showMoreText: 'showMoreLabel',
+ });
+
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
- h(AisRefinementList, { props: widgetParams }),
+ h(AisRefinementList, {
+ props,
+ scopedSlots,
+ }),
h(GlobalErrorSwallower),
])
),
@@ -59,11 +88,21 @@ createRefinementListTests(async ({ instantSearchOptions, widgetParams }) => {
});
createHierarchicalMenuTests(async ({ instantSearchOptions, widgetParams }) => {
+ const { templates, ...props } = widgetParams;
+ const scopedSlots =
+ templates &&
+ fromTemplates(templates, {
+ showMoreText: 'showMoreLabel',
+ });
+
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
- h(AisHierarchicalMenu, { props: widgetParams }),
+ h(AisHierarchicalMenu, {
+ props,
+ scopedSlots,
+ }),
h(GlobalErrorSwallower),
])
),
@@ -94,11 +133,18 @@ createBreadcrumbTests(async ({ instantSearchOptions, widgetParams }) => {
});
createMenuTests(async ({ instantSearchOptions, widgetParams }) => {
+ const { templates, ...props } = widgetParams;
+ const scopedSlots =
+ templates &&
+ fromTemplates(templates, {
+ showMoreText: 'showMoreLabel',
+ });
+
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
- h(AisMenu, { props: widgetParams }),
+ h(AisMenu, { props, scopedSlots }),
h(GlobalErrorSwallower),
])
),
diff --git a/tests/common/widgets/hierarchical-menu/index.ts b/tests/common/widgets/hierarchical-menu/index.ts
index b8f34e5db6..e96dc1de06 100644
--- a/tests/common/widgets/hierarchical-menu/index.ts
+++ b/tests/common/widgets/hierarchical-menu/index.ts
@@ -2,10 +2,12 @@ import type { HierarchicalMenuWidget } from 'instantsearch.js/es/widgets/hierarc
import type { Act, TestSetup } from '../../common';
import { fakeAct } from '../../common';
import { createOptimisticUiTests } from './optimistic-ui';
+import { createShowMoreTests } from './show-more';
type WidgetParams = Parameters[0];
export type HierarchicalMenuSetup = TestSetup<{
widgetParams: Omit;
+ vueSlots?: Record;
}>;
export function createHierarchicalMenuTests(
@@ -18,5 +20,6 @@ export function createHierarchicalMenuTests(
describe('HierarchicalMenu common tests', () => {
createOptimisticUiTests(setup, act);
+ createShowMoreTests(setup, act);
});
}
diff --git a/tests/common/widgets/hierarchical-menu/show-more.ts b/tests/common/widgets/hierarchical-menu/show-more.ts
new file mode 100644
index 0000000000..b9f9dbcb38
--- /dev/null
+++ b/tests/common/widgets/hierarchical-menu/show-more.ts
@@ -0,0 +1,87 @@
+import { wait } from '@instantsearch/testutils';
+import {
+ createMultiSearchResponse,
+ createSearchClient,
+ createSingleSearchResponse,
+} from '@instantsearch/mocks';
+
+import type { HierarchicalMenuSetup } from '.';
+import type { Act } from '../../common';
+
+export function createShowMoreTests(setup: HierarchicalMenuSetup, act: Act) {
+ describe('show more', () => {
+ test('receives a count of facet values', async () => {
+ const delay = 100;
+ const margin = 10;
+ const attributes = ['brand'];
+ const limit = 2;
+ const showMoreLimit = 6;
+
+ const options = {
+ instantSearchOptions: {
+ indexName: 'indexName',
+ searchClient: createSearchClient({
+ search: jest.fn(async (requests) => {
+ await wait(delay);
+ return createMultiSearchResponse(
+ ...requests.map(() =>
+ createSingleSearchResponse({
+ facets: {
+ [attributes[0]]: {
+ Apple: 746,
+ Samsung: 633,
+ Metra: 591,
+ HP: 530,
+ 'Insignia™': 442,
+ GE: 394,
+ Sony: 350,
+ Incipio: 320,
+ KitchenAid: 318,
+ Whirlpool: 298,
+ LG: 291,
+ Canon: 287,
+ Frigidaire: 275,
+ Speck: 216,
+ OtterBox: 214,
+ Epson: 204,
+ 'Dynex™': 184,
+ Dell: 174,
+ 'Hamilton Beach': 173,
+ Platinum: 155,
+ },
+ },
+ })
+ )
+ );
+ }),
+ }),
+ },
+ widgetParams: {
+ attributes,
+ limit,
+ showMoreLimit,
+ showMore: true,
+ templates: {
+ // @ts-ignore
+ showMoreText({ isShowingMore, showMoreCount }) {
+ return !isShowingMore
+ ? `Show ${showMoreCount} more`
+ : 'Show top items';
+ },
+ },
+ },
+ };
+
+ await setup(options);
+
+ await act(async () => {
+ await wait(margin + delay);
+ await wait(0);
+ });
+
+ expect(
+ document.querySelector('.ais-HierarchicalMenu-showMore')
+ ).toHaveTextContent(`Show ${showMoreLimit - limit} more`);
+ });
+ });
+}
diff --git a/tests/common/widgets/menu/index.ts b/tests/common/widgets/menu/index.ts
index 3df854b115..4f86452de4 100644
--- a/tests/common/widgets/menu/index.ts
+++ b/tests/common/widgets/menu/index.ts
@@ -2,10 +2,12 @@ import type { MenuWidget } from 'instantsearch.js/es/widgets/menu/menu';
import type { Act, TestSetup } from '../../common';
import { fakeAct } from '../../common';
import { createOptimisticUiTests } from './optimistic-ui';
+import { createShowMoreTests } from './show-more';
type WidgetParams = Parameters[0];
export type MenuSetup = TestSetup<{
widgetParams: Omit;
+ vueSlots?: Record;
}>;
export function createMenuTests(setup: MenuSetup, act: Act = fakeAct) {
@@ -15,5 +17,6 @@ export function createMenuTests(setup: MenuSetup, act: Act = fakeAct) {
describe('Menu common tests', () => {
createOptimisticUiTests(setup, act);
+ createShowMoreTests(setup, act);
});
}
diff --git a/tests/common/widgets/menu/show-more.ts b/tests/common/widgets/menu/show-more.ts
new file mode 100644
index 0000000000..e4ebf8aecf
--- /dev/null
+++ b/tests/common/widgets/menu/show-more.ts
@@ -0,0 +1,87 @@
+import { wait } from '@instantsearch/testutils';
+import {
+ createMultiSearchResponse,
+ createSearchClient,
+ createSingleSearchResponse,
+} from '@instantsearch/mocks';
+
+import type { MenuSetup } from '.';
+import type { Act } from '../../common';
+
+export function createShowMoreTests(setup: MenuSetup, act: Act) {
+ describe('show more', () => {
+ test('receives a count of facet values', async () => {
+ const delay = 100;
+ const margin = 10;
+ const attribute = 'brand';
+ const limit = 2;
+ const showMoreLimit = 6;
+
+ const options = {
+ instantSearchOptions: {
+ indexName: 'indexName',
+ searchClient: createSearchClient({
+ search: jest.fn(async (requests) => {
+ await wait(delay);
+ return createMultiSearchResponse(
+ ...requests.map(() =>
+ createSingleSearchResponse({
+ facets: {
+ [attribute]: {
+ Apple: 746,
+ Samsung: 633,
+ Metra: 591,
+ HP: 530,
+ 'Insignia™': 442,
+ GE: 394,
+ Sony: 350,
+ Incipio: 320,
+ KitchenAid: 318,
+ Whirlpool: 298,
+ LG: 291,
+ Canon: 287,
+ Frigidaire: 275,
+ Speck: 216,
+ OtterBox: 214,
+ Epson: 204,
+ 'Dynex™': 184,
+ Dell: 174,
+ 'Hamilton Beach': 173,
+ Platinum: 155,
+ },
+ },
+ })
+ )
+ );
+ }),
+ }),
+ },
+ widgetParams: {
+ attribute,
+ limit,
+ showMoreLimit,
+ showMore: true,
+ templates: {
+ // @ts-ignore
+ showMoreText({ isShowingMore, showMoreCount }) {
+ return !isShowingMore
+ ? `Show ${showMoreCount} more`
+ : 'Show top items';
+ },
+ },
+ },
+ };
+
+ await setup(options);
+
+ await act(async () => {
+ await wait(margin + delay);
+ await wait(0);
+ });
+
+ expect(document.querySelector('.ais-Menu-showMore')).toHaveTextContent(
+ `Show ${showMoreLimit - limit} more`
+ );
+ });
+ });
+}
diff --git a/tests/common/widgets/refinement-list/index.ts b/tests/common/widgets/refinement-list/index.ts
index ad807fbced..75399dd771 100644
--- a/tests/common/widgets/refinement-list/index.ts
+++ b/tests/common/widgets/refinement-list/index.ts
@@ -2,10 +2,12 @@ import type { RefinementListWidget } from 'instantsearch.js/es/widgets/refinemen
import type { TestSetup, Act } from '../../common';
import { fakeAct } from '../../common';
import { createOptimisticUiTests } from './optimistic-ui';
+import { createShowMoreTests } from './show-more';
type WidgetParams = Parameters[0];
export type RefinementListSetup = TestSetup<{
widgetParams: Omit;
+ vueSlots?: Record;
}>;
export function createRefinementListTests(
@@ -18,5 +20,6 @@ export function createRefinementListTests(
describe('RefinementList common tests', () => {
createOptimisticUiTests(setup, act);
+ createShowMoreTests(setup, act);
});
}
diff --git a/tests/common/widgets/refinement-list/show-more.ts b/tests/common/widgets/refinement-list/show-more.ts
new file mode 100644
index 0000000000..5c2e3b7683
--- /dev/null
+++ b/tests/common/widgets/refinement-list/show-more.ts
@@ -0,0 +1,87 @@
+import { wait } from '@instantsearch/testutils';
+import {
+ createMultiSearchResponse,
+ createSearchClient,
+ createSingleSearchResponse,
+} from '@instantsearch/mocks';
+
+import type { RefinementListSetup } from '.';
+import type { Act } from '../../common';
+
+export function createShowMoreTests(setup: RefinementListSetup, act: Act) {
+ describe('show more', () => {
+ test('receives a count of facet values', async () => {
+ const delay = 100;
+ const margin = 10;
+ const attribute = 'brand';
+ const limit = 2;
+ const showMoreLimit = 6;
+
+ const options = {
+ instantSearchOptions: {
+ indexName: 'indexName',
+ searchClient: createSearchClient({
+ search: jest.fn(async (requests) => {
+ await wait(delay);
+ return createMultiSearchResponse(
+ ...requests.map(() =>
+ createSingleSearchResponse({
+ facets: {
+ [attribute]: {
+ Apple: 746,
+ Samsung: 633,
+ Metra: 591,
+ HP: 530,
+ 'Insignia™': 442,
+ GE: 394,
+ Sony: 350,
+ Incipio: 320,
+ KitchenAid: 318,
+ Whirlpool: 298,
+ LG: 291,
+ Canon: 287,
+ Frigidaire: 275,
+ Speck: 216,
+ OtterBox: 214,
+ Epson: 204,
+ 'Dynex™': 184,
+ Dell: 174,
+ 'Hamilton Beach': 173,
+ Platinum: 155,
+ },
+ },
+ })
+ )
+ );
+ }),
+ }),
+ },
+ widgetParams: {
+ attribute,
+ limit,
+ showMoreLimit,
+ showMore: true,
+ templates: {
+ // @ts-ignore
+ showMoreText({ isShowingMore, showMoreCount }) {
+ return !isShowingMore
+ ? `Show ${showMoreCount} more`
+ : 'Show top items';
+ },
+ },
+ },
+ };
+
+ await setup(options);
+
+ await act(async () => {
+ await wait(margin + delay);
+ await wait(0);
+ });
+
+ expect(
+ document.querySelector('.ais-RefinementList-showMore')
+ ).toHaveTextContent(`Show ${showMoreLimit - limit} more`);
+ });
+ });
+}