Skip to content

Commit

Permalink
feat(algolia): add getAlgoliaFacetHits preset (#451)
Browse files Browse the repository at this point in the history
  • Loading branch information
francoischalifour authored Feb 18, 2021
1 parent 6b0c0ca commit 8876fd3
Show file tree
Hide file tree
Showing 18 changed files with 530 additions and 5 deletions.
2 changes: 1 addition & 1 deletion bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
{
"path": "packages/autocomplete-js/dist/umd/index.production.js",
"maxSize": "14.25 kB"
"maxSize": "14.50 kB"
},
{
"path": "packages/autocomplete-preset-algolia/dist/umd/index.production.js",
Expand Down
3 changes: 3 additions & 0 deletions examples/js/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import insightsClient from 'search-insights';

import '@algolia/autocomplete-theme-classic';

import { createCategoriesPlugin } from './categoriesPlugin';
import { shortcutsPlugin } from './shortcutsPlugin';

type Product = {
Expand Down Expand Up @@ -49,6 +50,7 @@ const querySuggestionsPlugin = createQuerySuggestionsPlugin({
},
categoryAttribute: 'categories',
});
const categoriesPlugin = createCategoriesPlugin({ searchClient });

autocomplete({
container: '#autocomplete',
Expand All @@ -60,6 +62,7 @@ autocomplete({
algoliaInsightsPlugin,
recentSearchesPlugin,
querySuggestionsPlugin,
categoriesPlugin,
],
getSources({ query, state }) {
if (!query) {
Expand Down
87 changes: 87 additions & 0 deletions examples/js/categoriesPlugin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/** @jsx h */
import {
AutocompletePlugin,
getAlgoliaFacetHits,
highlightHit,
} from '@algolia/autocomplete-js';
import { Hit } from '@algolia/client-search';
import { SearchClient } from 'algoliasearch/lite';
import { h, Fragment } from 'preact';

type CategoryItem = {
label: string;
count: number;
};

type CreateCategoriesPluginProps = {
searchClient: SearchClient;
};

export function createCategoriesPlugin({
searchClient,
}: CreateCategoriesPluginProps): AutocompletePlugin<CategoryItem, undefined> {
return {
getSources({ query }) {
return [
{
sourceId: 'categoriesPlugin',
getItems() {
return getAlgoliaFacetHits({
searchClient,
queries: [
{
indexName: 'instant_search',
params: {
facetName: 'categories',
facetQuery: query,
maxFacetHits: query ? 3 : 10,
},
},
],
});
},
templates: {
header() {
return (
<Fragment>
<span className="aa-SourceHeaderTitle">Categories</span>
<div className="aa-SourceHeaderLine" />
</Fragment>
);
},
item({ item }) {
return (
<Fragment>
<div className="aa-ItemIcon aa-ItemIcon--no-border">
<svg
viewBox="0 0 24 24"
width="18"
height="18"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
<polyline points="3.27 6.96 12 12.01 20.73 6.96" />
<line x1="12" y1="22.08" x2="12" y2="12" />
</svg>
</div>
<div className="aa-ItemContent">
<div className="aa-ItemContentTitle">
{highlightHit<Hit<CategoryItem>>({
hit: item as any,
attribute: 'label',
})}
</div>
</div>
</Fragment>
);
},
},
},
];
},
};
}
29 changes: 29 additions & 0 deletions packages/autocomplete-js/src/__tests__/getAlgoliaFacetHits.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import algoliaPreset from '@algolia/autocomplete-preset-algolia';

import { createSearchClient } from '../../../../test/utils';
import { getAlgoliaFacetHits } from '../getAlgoliaFacetHits';
import { version } from '../version';

jest.mock('@algolia/autocomplete-preset-algolia', () => {
const module = jest.requireActual('@algolia/autocomplete-preset-algolia');

return {
...module,
getAlgoliaFacetHits: jest.fn(),
};
});

describe('getAlgoliaFacetHits', () => {
test('forwards params to the preset function', () => {
const searchClient = createSearchClient();

getAlgoliaFacetHits({ searchClient, queries: [] });

expect(algoliaPreset.getAlgoliaFacetHits).toHaveBeenCalledTimes(1);
expect(algoliaPreset.getAlgoliaFacetHits).toHaveBeenCalledWith({
searchClient,
queries: [],
userAgents: [{ segment: 'autocomplete-js', version }],
});
});
});
17 changes: 17 additions & 0 deletions packages/autocomplete-js/src/getAlgoliaFacetHits.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {
getAlgoliaFacetHits as getAlgoliaFacetHitsOriginal,
SearchForFacetValuesParams,
} from '@algolia/autocomplete-preset-algolia';

import { version } from './version';

export function getAlgoliaFacetHits({
searchClient,
queries,
}: Pick<SearchForFacetValuesParams, 'searchClient' | 'queries'>) {
return getAlgoliaFacetHitsOriginal({
searchClient,
queries,
userAgents: [{ segment: 'autocomplete-js', version }],
});
}
1 change: 1 addition & 0 deletions packages/autocomplete-js/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './autocomplete';
export * from './getAlgoliaFacetHits';
export * from './getAlgoliaHits';
export * from './getAlgoliaResults';
export * from './highlight';
Expand Down
2 changes: 2 additions & 0 deletions packages/autocomplete-preset-algolia/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export * from './highlight/parseAlgoliaHitHighlight';
export * from './highlight/parseAlgoliaHitReverseHighlight';
export * from './highlight/parseAlgoliaHitReverseSnippet';
export * from './highlight/parseAlgoliaHitSnippet';
export * from './search/getAlgoliaFacetHits';
export * from './search/getAlgoliaHits';
export * from './search/getAlgoliaResults';
export type { SearchForFacetValuesParams } from './search/searchForFacetValues';
export type { SearchParams } from './search/search';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type UserAgent = { segment: string; version?: string };
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {
createSFFVResponse,
createMultiSearchResponse,
createSearchClient,
} from '../../../../../test/utils';
import { version } from '../../version';
import { getAlgoliaFacetHits } from '../getAlgoliaFacetHits';
import { getAlgoliaHits } from '../getAlgoliaHits';
import { getAlgoliaResults } from '../getAlgoliaResults';

Expand All @@ -16,6 +18,24 @@ function createTestSearchClient() {
)
)
),
searchForFacetValues: jest.fn(() =>
Promise.resolve([
createSFFVResponse({
facetHits: [
{
count: 507,
value: 'Mobile phones',
highlighted: 'Mobile <em>phone</em>s',
},
{
count: 63,
value: 'Phone cases',
highlighted: '<em>Phone</em> cases',
},
],
}),
])
),
});
}

Expand Down Expand Up @@ -256,3 +276,158 @@ describe('getAlgoliaHits', () => {
);
});
});

describe('getAlgoliaFacetHits', () => {
test('with default options', async () => {
const searchClient = createTestSearchClient();

const facetHits = await getAlgoliaFacetHits({
searchClient,
queries: [
{
indexName: 'indexName',
params: {
facetName: 'facetName',
facetQuery: 'facetQuery',
},
},
],
});

expect(searchClient.searchForFacetValues).toHaveBeenCalledTimes(1);
expect(searchClient.searchForFacetValues).toHaveBeenCalledWith([
{
indexName: 'indexName',
params: {
facetName: 'facetName',
facetQuery: 'facetQuery',
highlightPreTag: '__aa-highlight__',
highlightPostTag: '__/aa-highlight__',
},
},
]);
expect(facetHits).toEqual([
[
{
count: 507,
label: 'Mobile phones',
_highlightResult: {
label: {
value: 'Mobile <em>phone</em>s',
},
},
},
{
count: 63,
label: 'Phone cases',
_highlightResult: {
label: {
value: '<em>Phone</em> cases',
},
},
},
],
]);
});

test('with custom search parameters', async () => {
const searchClient = createTestSearchClient();

const facetHits = await getAlgoliaFacetHits({
searchClient,
queries: [
{
indexName: 'indexName',
params: {
facetName: 'facetName',
facetQuery: 'facetQuery',
highlightPreTag: '<em>',
highlightPostTag: '</em>',
maxFacetHits: 10,
},
},
],
});

expect(searchClient.searchForFacetValues).toHaveBeenCalledTimes(1);
expect(searchClient.searchForFacetValues).toHaveBeenCalledWith([
{
indexName: 'indexName',
params: {
facetName: 'facetName',
facetQuery: 'facetQuery',
highlightPreTag: '<em>',
highlightPostTag: '</em>',
maxFacetHits: 10,
},
},
]);
expect(facetHits).toEqual([
[
{
count: 507,
label: 'Mobile phones',
_highlightResult: {
label: {
value: 'Mobile <em>phone</em>s',
},
},
},
{
count: 63,
label: 'Phone cases',
_highlightResult: {
label: {
value: '<em>Phone</em> cases',
},
},
},
],
]);
});

test('attaches Algolia agent', async () => {
const searchClient = createTestSearchClient();

await getAlgoliaFacetHits({
searchClient,
queries: [
{
indexName: 'indexName',
params: {
facetName: 'facetName',
facetQuery: 'facetQuery',
},
},
],
});

expect(searchClient.addAlgoliaAgent).toHaveBeenCalledTimes(1);
expect(searchClient.addAlgoliaAgent).toHaveBeenCalledWith(
'autocomplete-core',
version
);
});

test('allows custom user agents', async () => {
const searchClient = createTestSearchClient();

await getAlgoliaFacetHits({
searchClient,
queries: [],
userAgents: [{ segment: 'custom-ua', version: '1.0.0' }],
});

expect(searchClient.addAlgoliaAgent).toHaveBeenCalledTimes(2);
expect(searchClient.addAlgoliaAgent).toHaveBeenNthCalledWith(
1,
'autocomplete-core',
version
);
expect(searchClient.addAlgoliaAgent).toHaveBeenNthCalledWith(
2,
'custom-ua',
'1.0.0'
);
});
});
Loading

0 comments on commit 8876fd3

Please sign in to comment.