Skip to content

Commit

Permalink
feat(autocomplete-core): add insights option to enable the Insights…
Browse files Browse the repository at this point in the history
… plugin (#1121)
  • Loading branch information
FabienMotte authored and Haroenv committed Apr 24, 2023
1 parent efb27ce commit c9d06fd
Show file tree
Hide file tree
Showing 53 changed files with 444 additions and 196 deletions.
4 changes: 2 additions & 2 deletions bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"files": [
{
"path": "packages/autocomplete-core/dist/umd/index.production.js",
"maxSize": "6.5 kB"
"maxSize": "8.5 kB"
},
{
"path": "packages/autocomplete-js/dist/umd/index.production.js",
"maxSize": "19 kB"
"maxSize": "20.75 kB"
},
{
"path": "packages/autocomplete-preset-algolia/dist/umd/index.production.js",
Expand Down
2 changes: 2 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ module.exports = {
__TEST__: true,
},
moduleNameMapper: {
'^@algolia/autocomplete-shared/dist/esm/(.*)$':
'<rootDir>/packages/autocomplete-shared/src/$1',
'^@algolia/autocomplete-(.*)$': '<rootDir>/packages/autocomplete-$1/src/',
},
};
3 changes: 2 additions & 1 deletion packages/autocomplete-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"watch": "watch \"yarn on:change\" --ignoreDirectoryPattern \"/dist/\""
},
"dependencies": {
"@algolia/autocomplete-shared": "1.8.3"
"@algolia/autocomplete-shared": "1.8.3",
"@algolia/autocomplete-plugin-algolia-insights": "1.8.3"
},
"devDependencies": {
"@algolia/autocomplete-preset-algolia": "1.8.3",
Expand Down
124 changes: 124 additions & 0 deletions packages/autocomplete-core/src/__tests__/createAutocomplete.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createAlgoliaInsightsPlugin } from '@algolia/autocomplete-plugin-algolia-insights';

import { createAutocomplete } from '../createAutocomplete';

describe('createAutocomplete', () => {
Expand Down Expand Up @@ -43,4 +45,126 @@ describe('createAutocomplete', () => {
setStatus: autocomplete.setStatus,
});
});

describe('Insights plugin', () => {
test('does not add Insights plugin by default', () => {
const onStateChange = jest.fn();

createAutocomplete({ onStateChange });

expect(onStateChange).toHaveBeenCalledTimes(0);
});

test('`insights: true` adds only one Insights plugin', () => {
const onStateChange = jest.fn();

createAutocomplete({
onStateChange,
insights: true,
});

expect(onStateChange).toHaveBeenCalledTimes(1);
expect(onStateChange).toHaveBeenCalledWith(
expect.objectContaining({
state: expect.objectContaining({
context: expect.objectContaining({
algoliaInsightsPlugin: expect.objectContaining({
insights: expect.objectContaining({
init: expect.any(Function),
setUserToken: expect.any(Function),
clickedObjectIDsAfterSearch: expect.any(Function),
clickedObjectIDs: expect.any(Function),
clickedFilters: expect.any(Function),
convertedObjectIDsAfterSearch: expect.any(Function),
convertedObjectIDs: expect.any(Function),
convertedFilters: expect.any(Function),
viewedObjectIDs: expect.any(Function),
viewedFilters: expect.any(Function),
}),
}),
}),
}),
})
);
});

test('`insights` with options still creates one plugin only', () => {
const onStateChange = jest.fn();
const insightsClient = jest.fn();

createAutocomplete({
onStateChange,
insights: { insightsClient },
});

expect(onStateChange).toHaveBeenCalledTimes(1);
expect(onStateChange).toHaveBeenCalledWith(
expect.objectContaining({
state: expect.objectContaining({
context: expect.objectContaining({
algoliaInsightsPlugin: expect.objectContaining({
insights: expect.objectContaining({
init: expect.any(Function),
setUserToken: expect.any(Function),
clickedObjectIDsAfterSearch: expect.any(Function),
clickedObjectIDs: expect.any(Function),
clickedFilters: expect.any(Function),
convertedObjectIDsAfterSearch: expect.any(Function),
convertedObjectIDs: expect.any(Function),
convertedFilters: expect.any(Function),
viewedObjectIDs: expect.any(Function),
viewedFilters: expect.any(Function),
}),
}),
}),
}),
})
);
});

test('`insights` with options passes options to plugin', () => {
const insightsClient = jest.fn();

createAutocomplete({
insights: { insightsClient },
});

expect(insightsClient).toHaveBeenCalledTimes(1);
expect(insightsClient).toHaveBeenCalledWith(
'addAlgoliaAgent',
'insights-plugin'
);
});

test('`insights: false` disables default Insights plugin', () => {
const onStateChange = jest.fn();

createAutocomplete({
insights: false,
onStateChange,
});

expect(onStateChange).toHaveBeenCalledTimes(0);
});

test("users' Insights plugin overrides the default one when `insights: true`", () => {
const defaultInsightsClient = jest.fn();
const userInsightsClient = jest.fn();
const insightsPlugin = createAlgoliaInsightsPlugin({
insightsClient: userInsightsClient,
});

createAutocomplete({
insights: { insightsClient: defaultInsightsClient },
plugins: [insightsPlugin],
});

expect(defaultInsightsClient).toHaveBeenCalledTimes(0);
expect(userInsightsClient).toHaveBeenCalledTimes(1);
expect(userInsightsClient).toHaveBeenCalledWith(
'addAlgoliaAgent',
'insights-plugin'
);
});
});
});
3 changes: 1 addition & 2 deletions packages/autocomplete-core/src/__tests__/openOnFocus.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import {
runAllMicroTasks,
} from '../../../../test/utils';
import { createAutocomplete } from '../createAutocomplete';
import { BaseItem } from '../types/AutocompleteApi';
import { AutocompleteOptions } from '../types/AutocompleteOptions';
import { BaseItem, AutocompleteOptions } from '../types';

describe('openOnFocus', () => {
function setupTest<TItem extends BaseItem>(
Expand Down
11 changes: 11 additions & 0 deletions packages/autocomplete-core/src/createAutocomplete.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createAlgoliaInsightsPlugin } from '@algolia/autocomplete-plugin-algolia-insights';

import { checkOptions } from './checkOptions';
import { createStore } from './createStore';
import { getAutocompleteSetters } from './getAutocompleteSetters';
Expand Down Expand Up @@ -66,6 +68,15 @@ export function createAutocomplete<
});
}

if (
options.insights &&
!props.plugins.some((plugin) => plugin.name === 'aa.algoliaInsightsPlugin')
) {
const insightsParams =
typeof options.insights === 'boolean' ? {} : options.insights;
props.plugins.push(createAlgoliaInsightsPlugin(insightsParams));
}

props.plugins.forEach((plugin) =>
plugin.subscribe?.({
...setters,
Expand Down
1 change: 1 addition & 0 deletions packages/autocomplete-core/src/getDefaultProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export function getDefaultProps<TItem extends BaseItem>(
autoFocus: false,
defaultActiveItemId: null,
stallThreshold: 300,
insights: false,
environment,
shouldPanelOpen: ({ state }) => getItemsCount(state) > 0,
reshape: ({ sources }) => sources,
Expand Down
4 changes: 1 addition & 3 deletions packages/autocomplete-core/src/types/AutocompleteStore.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { CancelablePromiseList } from '../utils';

import { BaseItem } from './AutocompleteApi';
import { InternalAutocompleteOptions } from './AutocompleteOptions';
import { AutocompleteState } from './AutocompleteState';
import { BaseItem, InternalAutocompleteOptions, AutocompleteState } from './';

export interface AutocompleteStore<TItem extends BaseItem> {
getState(): AutocompleteState<TItem>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import { BaseItem } from './AutocompleteApi';
import {
OnActiveParams,
OnResolveParams,
OnSelectParams,
} from './AutocompleteSource';
import { BaseItem, OnActiveParams, OnResolveParams, OnSelectParams } from './';

export type AutocompleteSubscriber<TItem extends BaseItem> = {
onSelect(params: OnSelectParams<TItem>): void;
Expand Down
31 changes: 20 additions & 11 deletions packages/autocomplete-core/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
export * from './AutocompleteApi';
export * from './AutocompleteCollection';
export * from './AutocompleteContext';
export * from './AutocompleteEnvironment';
export * from './AutocompleteOptions';
export * from './AutocompleteSource';
export * from './AutocompletePropGetters';
export * from './AutocompletePlugin';
export * from './AutocompleteReshape';
export * from './AutocompleteSetters';
export * from './AutocompleteState';
export * from '@algolia/autocomplete-shared/dist/esm/core';
export * from './AutocompleteStore';
export * from './AutocompleteSubscribers';

import { CreateAlgoliaInsightsPluginParams } from '@algolia/autocomplete-plugin-algolia-insights';
import {
AutocompleteOptions as _AutocompleteOptions,
BaseItem,
} from '@algolia/autocomplete-shared/dist/esm/core';

export interface AutocompleteOptions<TItem extends BaseItem>
extends _AutocompleteOptions<TItem> {
/**
* Whether to enable the Insights plugin and load the Insights library if it has not been loaded yet.
*
* See [**autocomplete-plugin-algolia-insights**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-algolia-insights/) for more information.
*
* @default false
* @link https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-insights
*/
insights?: CreateAlgoliaInsightsPluginParams | boolean;
}
84 changes: 78 additions & 6 deletions packages/autocomplete-js/src/__tests__/autocomplete.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { createAlgoliaInsightsPlugin } from '@algolia/autocomplete-plugin-algolia-insights';
import * as autocompleteShared from '@algolia/autocomplete-shared';
import { fireEvent, waitFor } from '@testing-library/dom';
import userEvent from '@testing-library/user-event';
Expand Down Expand Up @@ -285,7 +286,7 @@ See: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocom
},
});

const input = container.querySelector<HTMLInputElement>('.aa-Input');
const input = container.querySelector<HTMLInputElement>('.aa-Input')!;

fireEvent.input(input, { target: { value: 'a' } });

Expand Down Expand Up @@ -325,7 +326,7 @@ See: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocom
},
});

const input = container.querySelector<HTMLInputElement>('.aa-Input');
const input = container.querySelector<HTMLInputElement>('.aa-Input')!;

fireEvent.focus(input);

Expand Down Expand Up @@ -365,7 +366,7 @@ See: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocom
},
});

const input = container.querySelector<HTMLInputElement>('.aa-Input');
const input = container.querySelector<HTMLInputElement>('.aa-Input')!;

fireEvent.focus(input);

Expand Down Expand Up @@ -405,7 +406,7 @@ See: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocom
},
});

const input = container.querySelector<HTMLInputElement>('.aa-Input');
const input = container.querySelector<HTMLInputElement>('.aa-Input')!;

fireEvent.input(input, { target: { value: 'Query' } });

Expand Down Expand Up @@ -446,7 +447,7 @@ See: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocom
},
});

const input = container.querySelector<HTMLInputElement>('.aa-Input');
const input = container.querySelector<HTMLInputElement>('.aa-Input')!;

fireEvent.input(input, { target: { value: 'a' } });

Expand Down Expand Up @@ -579,7 +580,7 @@ See: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocom
},
});

const input = container.querySelector<HTMLInputElement>('.aa-Input');
const input = container.querySelector<HTMLInputElement>('.aa-Input')!;

fireEvent.input(input, { target: { value: 'a' } });

Expand Down Expand Up @@ -691,4 +692,75 @@ See: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocom
);
});
});

describe('Insights plugin', () => {
test('does not add Insights plugin by default', () => {
const onStateChange = jest.fn();

const container = document.createElement('div');
autocomplete({
container,
onStateChange,
});

expect(onStateChange).toHaveBeenCalledTimes(0);
});

test('`insights: true` adds only one Insights plugin', () => {
const onStateChange = jest.fn();

const container = document.createElement('div');
autocomplete({
container,
insights: true,
onStateChange,
});

expect(onStateChange).toHaveBeenCalledTimes(1);
expect(onStateChange).toHaveBeenCalledWith(
expect.objectContaining({
state: expect.objectContaining({
context: expect.objectContaining({
algoliaInsightsPlugin: expect.objectContaining({
insights: expect.objectContaining({
init: expect.any(Function),
setUserToken: expect.any(Function),
clickedObjectIDsAfterSearch: expect.any(Function),
clickedObjectIDs: expect.any(Function),
clickedFilters: expect.any(Function),
convertedObjectIDsAfterSearch: expect.any(Function),
convertedObjectIDs: expect.any(Function),
convertedFilters: expect.any(Function),
viewedObjectIDs: expect.any(Function),
viewedFilters: expect.any(Function),
}),
}),
}),
}),
})
);
});

test("users' Insights plugin overrides the default one using `update`", () => {
const defaultInsightsClient = jest.fn();
const userInsightsClient = jest.fn();

const container = document.createElement('div');
const { update } = autocomplete({
container,
insights: { insightsClient: defaultInsightsClient },
});

expect(defaultInsightsClient).toHaveBeenCalledTimes(1);
expect(userInsightsClient).toHaveBeenCalledTimes(0);

const insightsPlugin = createAlgoliaInsightsPlugin({
insightsClient: userInsightsClient,
});
update({ plugins: [insightsPlugin] });

expect(defaultInsightsClient).toHaveBeenCalledTimes(1);
expect(userInsightsClient).toHaveBeenCalledTimes(1);
});
});
});
Loading

0 comments on commit c9d06fd

Please sign in to comment.