vue-instantsearch
Version:
👀 Lightning-fast Algolia search for Vue apps
631 lines (602 loc) • 18.9 kB
JavaScript
/**
* @jest-environment jsdom
*/
import { runTestSuites } from '@instantsearch/tests/common';
import * as testSuites from '@instantsearch/tests/widgets';
import { nextTick, mountApp } from '../../test/utils';
import {
AisInstantSearch,
AisRefinementList,
AisHierarchicalMenu,
AisBreadcrumb,
AisMenu,
AisPagination,
AisInfiniteHits,
AisSearchBox,
createWidgetMixin,
AisHits,
AisIndex,
AisRangeInput,
AisHitsPerPage,
AisClearRefinements,
AisCurrentRefinements,
AisToggleRefinement,
AisSortBy,
AisStats,
AisRatingMenu,
AisNumericMenu,
AisPoweredBy,
AisMenuSelect,
AisDynamicWidgets,
} from '../instantsearch';
import { renderCompat } from '../util/vue-compat';
jest.unmock('instantsearch.js/es');
/**
* prevent rethrowing InstantSearch errors, so tests can be asserted.
* IRL this isn't needed, as the error doesn't stop execution.
*/
const GlobalErrorSwallower = {
mixins: [createWidgetMixin({ connector: true })],
mounted() {
this.instantSearchInstance.on('error', () => {});
},
render() {
return null;
},
};
const testSetups = {
async createRefinementListWidgetTests({
instantSearchOptions,
widgetParams,
}) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisRefinementList, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createHierarchicalMenuWidgetTests({
instantSearchOptions,
widgetParams,
}) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisHierarchicalMenu, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createBreadcrumbWidgetTests({ instantSearchOptions, widgetParams }) {
// The passed `transformItems` prop is meant to apply only to the breadcrumb,
// not the hierarchical menu
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { transformItems, ...hierarchicalWidgetParams } = widgetParams;
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisBreadcrumb, { props: widgetParams }),
h(AisHierarchicalMenu, { props: hierarchicalWidgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createMenuWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisMenu, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createPaginationWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisPagination, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createInfiniteHitsWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisSearchBox),
h(AisInfiniteHits, {
attrs: { id: 'main-hits' },
props: widgetParams,
scopedSlots: {
item: ({ item: hit, sendEvent }) =>
h(
'div',
{
attrs: {
'data-testid': `main-hits-top-level-${hit.__position}`,
},
},
[
hit.objectID,
h('button', {
attrs: {
'data-testid': `main-hits-convert-${hit.__position}`,
},
on: {
click: () =>
sendEvent('conversion', hit, 'Converted'),
},
}),
h('button', {
attrs: {
'data-testid': `main-hits-click-${hit.__position}`,
},
on: {
click: () => sendEvent('click', hit, 'Clicked'),
},
}),
]
),
},
}),
h('div', { attrs: { id: 'hits-with-defaults' } }, [
h(AisInfiniteHits, { props: widgetParams }),
]),
h(AisIndex, { props: { indexName: 'nested' } }, [
h(AisInfiniteHits, {
attrs: { id: 'nested-hits' },
scopedSlots: {
item: ({ item: hit, sendEvent }) =>
h(
'div',
{
attrs: {
'data-testid': `nested-hits-top-level-${hit.__position}`,
},
},
[
hit.objectID,
h('button', {
attrs: {
'data-testid': `nested-hits-click-${hit.__position}`,
},
on: {
click: () =>
sendEvent('click', hit, 'Clicked nested'),
},
}),
]
),
},
}),
]),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createHitsWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisSearchBox),
h(AisHits, {
attrs: { id: 'main-hits' },
props: widgetParams,
scopedSlots: {
item: ({ item: hit, sendEvent }) =>
h(
'div',
{
attrs: {
'data-testid': `main-hits-top-level-${hit.__position}`,
},
},
[
hit.objectID,
h('button', {
attrs: {
'data-testid': `main-hits-convert-${hit.__position}`,
},
on: {
click: () =>
sendEvent('conversion', hit, 'Converted'),
},
}),
h('button', {
attrs: {
'data-testid': `main-hits-click-${hit.__position}`,
},
on: {
click: () => sendEvent('click', hit, 'Clicked'),
},
}),
]
),
},
}),
h('div', { attrs: { id: 'hits-with-defaults' } }, [
h(AisHits, { props: widgetParams }),
]),
h(AisIndex, { props: { indexName: 'nested' } }, [
h(AisHits, {
attrs: { id: 'nested-hits' },
scopedSlots: {
item: ({ item: hit, sendEvent }) =>
h(
'div',
{
attrs: {
'data-testid': `nested-hits-top-level-${hit.__position}`,
},
},
[
hit.objectID,
h('button', {
attrs: {
'data-testid': `nested-hits-click-${hit.__position}`,
},
on: {
click: () =>
sendEvent('click', hit, 'Clicked nested'),
},
}),
]
),
},
}),
]),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createRangeInputWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisRangeInput, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
createInstantSearchWidgetTests({ instantSearchOptions }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
return {
algoliaAgents: [
`instantsearch.js (${
require('../../../instantsearch.js/package.json').version
})`,
`Vue InstantSearch (${
require('../../../vue-instantsearch/package.json').version
})`,
`Vue (${require('../util/vue-compat').version})`,
],
};
},
async createHitsPerPageWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisHitsPerPage, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createClearRefinementsWidgetTests({
instantSearchOptions,
widgetParams,
}) {
const refinementListAttributes = Object.keys(
instantSearchOptions.initialUiState?.indexName.refinementList || {}
);
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
...refinementListAttributes.map((attribute) =>
h(AisRefinementList, { props: { attribute } })
),
h(AisCurrentRefinements),
h(AisClearRefinements, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createCurrentRefinementsWidgetTests({
instantSearchOptions,
widgetParams,
}) {
mountApp(
{
render: renderCompat((h) =>
h('form', {}, [
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisSearchBox),
h(AisRefinementList, { props: { attribute: 'brand' } }),
h(AisRefinementList, {
props: { operator: 'and', attribute: 'feature' },
}),
h(AisHierarchicalMenu, {
props: {
attributes: [
'hierarchicalCategories.lvl0',
'hierarchicalCategories.lvl1',
'hierarchicalCategories.lvl2',
],
},
}),
h(AisRangeInput, { props: { attribute: 'price' } }),
h(AisCurrentRefinements, { props: widgetParams }),
h(GlobalErrorSwallower),
]),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createRatingMenuWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisRatingMenu, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createNumericMenuWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisNumericMenu, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createToggleRefinementWidgetTests({
instantSearchOptions,
widgetParams,
}) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisToggleRefinement, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createSearchBoxWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisSearchBox, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createSortByWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisSortBy, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
async createStatsWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h('div', {}, [
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisSearchBox),
h(AisStats, { props: widgetParams }),
h(GlobalErrorSwallower),
]),
])
),
},
document.body.appendChild(document.createElement('div'))
);
await nextTick();
},
createRelatedProductsWidgetTests() {
throw new Error('RelatedProduct is not supported in Vue InstantSearch');
},
createFrequentlyBoughtTogetherWidgetTests() {
throw new Error(
'FrequentlyBoughtTogether is not supported in Vue InstantSearch'
);
},
createTrendingItemsWidgetTests() {
throw new Error('TrendingItems is not supported in Vue InstantSearch');
},
createLookingSimilarWidgetTests() {
throw new Error('LookingSimilar is not supported in Vue InstantSearch');
},
createPoweredByWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisPoweredBy, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
return {
flavor: 'vue-instantsearch',
};
},
async createMenuSelectWidgetTests({ instantSearchOptions, widgetParams }) {
mountApp(
{
render: renderCompat((h) =>
h(AisInstantSearch, { props: instantSearchOptions }, [
h(AisMenuSelect, { props: widgetParams }),
h(GlobalErrorSwallower),
])
),
},
document.body.appendChild(document.createElement('div'))
);
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 = {
createRefinementListWidgetTests: undefined,
createHierarchicalMenuWidgetTests: undefined,
createBreadcrumbWidgetTests: undefined,
createMenuWidgetTests: undefined,
createPaginationWidgetTests: undefined,
createInfiniteHitsWidgetTests: undefined,
createHitsWidgetTests: undefined,
createRangeInputWidgetTests: undefined,
createRatingMenuWidgetTests: undefined,
createInstantSearchWidgetTests: undefined,
createHitsPerPageWidgetTests: undefined,
createClearRefinementsWidgetTests: undefined,
createCurrentRefinementsWidgetTests: undefined,
createToggleRefinementWidgetTests: undefined,
createSearchBoxWidgetTests: {
skippedTests: { 'searchAsYouType option': true },
},
createSortByWidgetTests: undefined,
createStatsWidgetTests: undefined,
createRelatedProductsWidgetTests: {
skippedTests: {
'RelatedProducts widget common tests': true,
},
},
createFrequentlyBoughtTogetherWidgetTests: {
skippedTests: { 'FrequentlyBoughtTogether widget common tests': true },
},
createTrendingItemsWidgetTests: {
skippedTests: { 'TrendingItems widget common tests': true },
},
createLookingSimilarWidgetTests: {
skippedTests: { 'LookingSimilar widget common tests': true },
},
createPoweredByWidgetTests: undefined,
createDynamicWidgetsWidgetTests: undefined,
};
describe('Common widget tests (Vue InstantSearch)', () => {
runTestSuites({
testSuites,
testSetups,
testOptions,
});
});