Skip to content

Commit

Permalink
test(dynamic-widgets): common test suite (#6240)
Browse files Browse the repository at this point in the history
* test(dynamic-widgets): common test suite

* add hierarchicalMenu and some refactoring
  • Loading branch information
aymeric-giraudet authored Jun 19, 2024
1 parent fb7cc23 commit adef3fe
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 0 deletions.
24 changes: 24 additions & 0 deletions packages/instantsearch.js/src/__tests__/common-widgets.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
lookingSimilar,
poweredBy,
menuSelect,
dynamicWidgets,
} from '../widgets';

import type { TestOptionsMap, TestSetupsMap } from '@instantsearch/tests';
Expand Down Expand Up @@ -594,6 +595,28 @@ const testSetups: TestSetupsMap<TestSuites> = {
])
.start();
},
createDynamicWidgetsWidgetTests({ instantSearchOptions, widgetParams }) {
instantsearch(instantSearchOptions)
.addWidgets([
dynamicWidgets({
container: document.body.appendChild(document.createElement('div')),
widgets: [
(container) => refinementList({ attribute: 'brand', container }),
(container) => menu({ attribute: 'category', container }),
(container) =>
hierarchicalMenu({
attributes: [
'hierarchicalCategories.lvl0',
'hierarchicalCategories.lvl1',
],
container,
}),
],
...widgetParams,
}),
])
.start();
},
};

const testOptions: TestOptionsMap<TestSuites> = {
Expand Down Expand Up @@ -625,6 +648,7 @@ const testOptions: TestOptionsMap<TestSuites> = {
createLookingSimilarWidgetTests: undefined,
createPoweredByWidgetTests: undefined,
createMenuSelectWidgetTests: undefined,
createDynamicWidgetsWidgetTests: undefined,
};

describe('Common widget tests (InstantSearch.js)', () => {
Expand Down
21 changes: 21 additions & 0 deletions packages/react-instantsearch/src/__tests__/common-widgets.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
TrendingItems,
LookingSimilar,
PoweredBy,
DynamicWidgets,
} from '..';

import type { TestOptionsMap, TestSetupsMap } from '@instantsearch/tests';
Expand Down Expand Up @@ -372,6 +373,25 @@ const testSetups: TestSetupsMap<TestSuites> = {
createMenuSelectWidgetTests() {
throw new Error('MenuSelect is not supported in React InstantSearch');
},
createDynamicWidgetsWidgetTests({ instantSearchOptions, widgetParams }) {
render(
<InstantSearch {...instantSearchOptions}>
<div className="ais-DynamicWidgets">
<DynamicWidgets {...widgetParams}>
<RefinementList attribute="brand" />
<Menu attribute="category" />
<HierarchicalMenu
attributes={[
'hierarchicalCategories.lvl0',
'hierarchicalCategories.lvl1',
]}
/>
</DynamicWidgets>
</div>
<GlobalErrorSwallower />
</InstantSearch>
);
},
};

const testOptions: TestOptionsMap<TestSuites> = {
Expand Down Expand Up @@ -414,6 +434,7 @@ const testOptions: TestOptionsMap<TestSuites> = {
'MenuSelect widget common tests': true,
},
},
createDynamicWidgetsWidgetTests: { act },
};

/**
Expand Down
28 changes: 28 additions & 0 deletions packages/vue-instantsearch/src/__tests__/common-widgets.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
AisNumericMenu,
AisPoweredBy,
AisMenuSelect,
AisDynamicWidgets,
} from '../instantsearch';
import { renderCompat } from '../util/vue-compat';

Expand Down Expand Up @@ -554,6 +555,32 @@ const testSetups = {

await nextTick();
},
createDynamicWidgetsWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(
AisDynamicWidgets,
{ props: widgetParams },
h(AisRefinementList, { props: { attribute: 'brand' } }),
h(AisMenu, { props: { attribute: 'category' } }),
h(AisHierarchicalMenu, {
props: {
attributes: [
'hierarchicalCategories.lvl0',
'hierarchicalCategories.lvl1',
],
},
})
),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
},
};

const testOptions = {
Expand Down Expand Up @@ -591,6 +618,7 @@ const testOptions = {
skippedTests: { 'LookingSimilar widget common tests': true },
},
createPoweredByWidgetTests: undefined,
createDynamicWidgetsWidgetTests: undefined,
};

describe('Common widget tests (Vue InstantSearch)', () => {
Expand Down
24 changes: 24 additions & 0 deletions tests/common/widgets/dynamic-widgets/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { fakeAct } from '../../common';

import { createOptionsTests } from './options';

import type { TestOptions, TestSetup } from '../../common';
import type { DynamicWidgetsWidget } from 'instantsearch.js/es/widgets/dynamic-widgets/dynamic-widgets';

type WidgetParams = Parameters<DynamicWidgetsWidget>[0];
export type DynamicWidgetsWidgetSetup = TestSetup<{
widgetParams: Omit<WidgetParams, 'container' | 'widgets' | 'fallbackWidget'>;
}>;

export function createDynamicWidgetsWidgetTests(
setup: DynamicWidgetsWidgetSetup,
{ act = fakeAct, skippedTests = {} }: TestOptions = {}
) {
beforeEach(() => {
document.body.innerHTML = '';
});

describe('DynamicWidgets widget common tests', () => {
createOptionsTests(setup, { act, skippedTests });
});
}
184 changes: 184 additions & 0 deletions tests/common/widgets/dynamic-widgets/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import {
createAlgoliaSearchClient,
createMultiSearchResponse,
createSingleSearchResponse,
} from '@instantsearch/mocks';
import { wait } from '@instantsearch/testutils';
import { within, screen } from '@testing-library/dom';

import type { DynamicWidgetsWidgetSetup } from '.';
import type { TestOptions } from '../../common';

export function createOptionsTests(
setup: DynamicWidgetsWidgetSetup,
{ act }: Required<TestOptions>
) {
describe('options', () => {
it('renders with default options', async () => {
const searchClient = createMockedSearchClient();

await setup({
instantSearchOptions: {
searchClient,
indexName: 'indexName',
initialUiState: {
indexName: {},
},
},
widgetParams: {},
});

await act(async () => {
await wait(0);
});

const dynamicWidgets = Array.from(
document.querySelector('.ais-DynamicWidgets')!.childNodes
// Vue 3 outputs comment nodes
).filter((node) => node.nodeType === Node.ELEMENT_NODE);

expect(dynamicWidgets).toHaveLength(3);

expect(
within(dynamicWidgets[0] as HTMLElement).getByRole('link', {
name: /tv/i,
})
).toBeInTheDocument();

expect(
within(dynamicWidgets[1] as HTMLElement).getByRole('checkbox', {
name: /samsung/i,
})
).toBeInTheDocument();

expect(
within(dynamicWidgets[2] as HTMLElement).getByRole('link', {
name: /books/i,
})
).toBeInTheDocument();
});

it('forwards the `maxValuesPerFacet` option', async () => {
const searchClient = createMockedSearchClient();

await setup({
instantSearchOptions: {
searchClient,
indexName: 'indexName',
initialUiState: {
indexName: {},
},
},
widgetParams: { maxValuesPerFacet: 25 },
});

await act(async () => {
await wait(0);
});

expect(searchClient.search).toHaveBeenCalledWith(
expect.arrayContaining([
expect.objectContaining({
params: expect.objectContaining({
maxValuesPerFacet: 25,
}),
}),
])
);
});

it('forwards the `facets` option', async () => {
const searchClient = createMockedSearchClient();

await setup({
instantSearchOptions: {
searchClient,
indexName: 'indexName',
initialUiState: {
indexName: {},
},
},
widgetParams: { facets: ['other'] },
});

await act(async () => {
await wait(0);
});

expect(searchClient.search).toHaveBeenCalledWith(
expect.arrayContaining([
expect.objectContaining({
params: expect.objectContaining({
facets: expect.arrayContaining(['other']),
}),
}),
])
);
});

it('transforms items by calling the `transformItem` option', async () => {
const searchClient = createMockedSearchClient();

await setup({
instantSearchOptions: {
searchClient,
indexName: 'indexName',
initialUiState: {
indexName: {},
},
},
widgetParams: {
transformItems: () => ['brand'],
},
});

await act(async () => {
await wait(0);
});

expect(
screen.queryByRole('checkbox', { name: /samsung/i })
).toBeInTheDocument();

expect(
screen.queryByRole('link', { name: /tv/i })
).not.toBeInTheDocument();
});
});
}

function createMockedSearchClient() {
return createAlgoliaSearchClient({
search: jest.fn((requests) => {
return Promise.resolve(
createMultiSearchResponse(
...requests.map(() => {
return createSingleSearchResponse({
facets: {
brand: {
Samsung: 633,
Metra: 591,
},
category: {
TV: 633,
Radio: 591,
},
'hierarchicalCategories.lvl0': {
Electronics: 633,
Books: 591,
},
},
renderingContent: {
facetOrdering: {
facets: {
order: ['category', 'brand', 'hierarchicalCategories.lvl0'],
},
},
},
});
})
)
);
}),
});
}
1 change: 1 addition & 0 deletions tests/common/widgets/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './breadcrumb';
export * from './clear-refinements';
export * from './current-refinements';
export * from './dynamic-widgets';
export * from './hierarchical-menu';
export * from './hits';
export * from './infinite-hits';
Expand Down

0 comments on commit adef3fe

Please sign in to comment.