Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(metadata): register metadata around middleware #5491

Closed
wants to merge 10 commits into from
8 changes: 4 additions & 4 deletions bundlesize.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
},
{
"path": "packages/react-instantsearch-hooks/dist/umd/ReactInstantSearchHooks.min.js",
"maxSize": "41.75 kB"
"maxSize": "42.75 kB"
},
{
"path": "packages/react-instantsearch-hooks-web/dist/umd/ReactInstantSearchHooksDOM.min.js",
"maxSize": "51.25 kB"
"maxSize": "52.25 kB"
},
{
"path": "packages/react-instantsearch-dom/dist/umd/ReactInstantSearchDOM.min.js",
Expand All @@ -42,11 +42,11 @@
},
{
"path": "packages/vue-instantsearch/vue2/umd/index.js",
"maxSize": "60 kB"
"maxSize": "61.25 kB"
},
{
"path": "packages/vue-instantsearch/vue3/umd/index.js",
"maxSize": "60 kB"
"maxSize": "61.25 kB"
},
{
"path": "packages/vue-instantsearch/vue2/cjs/index.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import './Refresh.css';

export function Refresh() {
const { refresh } = useInstantSearch();

return (
<button
className="Refresh"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -855,8 +855,8 @@ search.addWidgets([
stalledSearchDelay: 1,
indexName: 'indexName',
});
instantSearchInstance.sendEventToInsights = jest.fn();
instantSearchInstance.start();
instantSearchInstance.sendEventToInsights = jest.fn();

instantSearchInstance.addWidgets([widget]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/configure-r
{
indexName: 'indexName',
params: {
clickAnalytics: true,
facets: [],
facetFilters: ['objectID:-1'],
tagFilters: '',
Expand Down Expand Up @@ -166,6 +167,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/configure-r
{
indexName: 'indexName',
params: {
clickAnalytics: true,
facets: [],
facetFilters: ['objectID:-1'],
tagFilters: '',
Expand Down Expand Up @@ -211,6 +213,7 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/configure-r
{
indexName: 'indexName',
params: {
clickAnalytics: true,
facets: [],
facetFilters: ['objectID:-1'],
tagFilters: '',
Expand Down Expand Up @@ -274,6 +277,7 @@ See https://www.algolia.com/doc/api-reference/api-parameters/optionalFilters/`);
{
indexName: 'indexName',
params: {
clickAnalytics: true,
facets: [],
facetFilters: ['objectID:-1'],
tagFilters: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1748,8 +1748,8 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/geo-search/
stalledSearchDelay: 1,
indexName: 'indexName',
});
instantSearchInstance.sendEventToInsights = jest.fn();
instantSearchInstance.start();
instantSearchInstance.sendEventToInsights = jest.fn();

instantSearchInstance.addWidgets([widget]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -868,8 +868,8 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/hits/js/#co
stalledSearchDelay: 1,
indexName: 'indexName',
});
instantSearchInstance.sendEventToInsights = jest.fn();
instantSearchInstance.start();
instantSearchInstance.sendEventToInsights = jest.fn();

instantSearchInstance.addWidgets([widget]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1458,8 +1458,8 @@ See documentation: https://www.algolia.com/doc/api-reference/widgets/infinite-hi
stalledSearchDelay: 1,
indexName: 'indexName',
});
instantSearchInstance.sendEventToInsights = jest.fn();
instantSearchInstance.start();
instantSearchInstance.sendEventToInsights = jest.fn();

instantSearchInstance.addWidgets([widget]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ function getStateWithoutPage(state: PlainSearchParameters) {
return rest;
}

function normalizeState(state: PlainSearchParameters) {
const { clickAnalytics, userToken, ...rest } = state || {};
return rest;
}

function getInMemoryCache<THit extends BaseHit>(): InfiniteHitsCache<THit> {
let cachedHits: InfiniteHitsCachedHits<THit> | null = null;
let cachedState: PlainSearchParameters | null = null;
Expand Down Expand Up @@ -237,7 +242,7 @@ const connectInfiniteHits: InfiniteHitsConnector = function connectInfiniteHits(
page:
getFirstReceivedPage(
helper.state,
cache.read({ state: helper.state }) || {}
cache.read({ state: normalizeState(helper.state) }) || {}
) - 1,
})
.searchWithoutTriggeringOnStateChange();
Expand All @@ -250,7 +255,7 @@ const connectInfiniteHits: InfiniteHitsConnector = function connectInfiniteHits(
.setPage(
getLastReceivedPage(
helper.state,
cache.read({ state: helper.state }) || {}
cache.read({ state: normalizeState(helper.state) }) || {}
) + 1
)
.search();
Expand Down Expand Up @@ -308,7 +313,7 @@ const connectInfiniteHits: InfiniteHitsConnector = function connectInfiniteHits(
*/
const state = parent.getPreviousState() || existingState;

const cachedHits = cache.read({ state }) || {};
const cachedHits = cache.read({ state: normalizeState(state) }) || {};

if (!results) {
showPrevious = getShowPrevious(helper);
Expand Down Expand Up @@ -355,7 +360,7 @@ const connectInfiniteHits: InfiniteHitsConnector = function connectInfiniteHits(
instantSearchInstance.status === 'idle'
) {
cachedHits[page] = transformedHits;
cache.write({ state, hits: cachedHits });
cache.write({ state: normalizeState(state), hits: cachedHits });
}
currentPageHits = transformedHits;

Expand Down
12 changes: 10 additions & 2 deletions packages/instantsearch.js/src/lib/InstantSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type {
import type { RouterProps } from '../middlewares/createRouterMiddleware';
import { createRouterMiddleware } from '../middlewares/createRouterMiddleware';
import type { InsightsEvent } from '../middlewares/createInsightsMiddleware';
import { createInsightsMiddleware } from '../middlewares/createInsightsMiddleware';
import {
createMetadataMiddleware,
isMetadataEnabled,
Expand Down Expand Up @@ -297,12 +298,17 @@ See ${createDocumentationLink({
this.sendEventToInsights = noop;

if (routing) {
const routerOptions = typeof routing === 'boolean' ? undefined : routing;
const routerOptions = typeof routing === 'boolean' ? {} : routing;
routerOptions.$$internal = true;
this.use(createRouterMiddleware(routerOptions));
}

// This is the default middleware,
// any user-provided middleware will be added later and override this one.
this.use(createInsightsMiddleware({ $$internal: true }));

if (isMetadataEnabled()) {
this.use(createMetadataMiddleware());
this.use(createMetadataMiddleware({ $$internal: true }));
}
}

Expand All @@ -312,6 +318,8 @@ See ${createDocumentationLink({
public use(...middleware: Middleware[]): this {
const newMiddlewareList = middleware.map((fn) => {
const newMiddleware = {
$$type: '__unknown__',
$$internal: false,
subscribe: noop,
started: noop,
unsubscribe: noop,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ describe('middleware', () => {
});

const middlewareDefinition: MiddlewareDefinition = {
$$type: 'fake',
$$internal: false,
onStateChange: jest.fn(),
subscribe: jest.fn(),
started: jest.fn(),
Expand Down Expand Up @@ -96,6 +98,8 @@ describe('middleware', () => {
});

const middlewareDefinition: MiddlewareDefinition = {
$$type: 'fake',
$$internal: false,
onStateChange: jest.fn(),
subscribe: jest.fn(),
started: jest.fn(),
Expand Down
38 changes: 28 additions & 10 deletions packages/instantsearch.js/src/lib/__tests__/InstantSearch-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -449,29 +449,47 @@ See https://www.algolia.com/doc/api-reference/widgets/configure/js/`);
});

it("doesn't add metadata middleware by default", () => {
const useSpy = jest.spyOn(InstantSearch.prototype, 'use');

// eslint-disable-next-line no-new
new InstantSearch({
const search = new InstantSearch({
searchClient: createSearchClient(),
indexName: 'test',
});

expect(useSpy).toHaveBeenCalledTimes(0);
expect(
search.middleware.map(({ instance: { $$type, $$internal } }) => ({
$$type,
$$internal,
}))
).toEqual([
{
$$type: 'ais.insights',
$$internal: true,
},
]);
});

it('adds metadata middleware on the Crawler user agent', () => {
userAgentMock = algoliaUserAgent;

const useSpy = jest.spyOn(InstantSearch.prototype, 'use');

// eslint-disable-next-line no-new
new InstantSearch({
const search = new InstantSearch({
searchClient: createSearchClient(),
indexName: 'test',
});

expect(useSpy).toHaveBeenCalledTimes(1);
expect(
search.middleware.map(({ instance: { $$type, $$internal } }) => ({
$$type,
$$internal,
}))
).toEqual([
{
$$type: 'ais.insights',
$$internal: true,
},
{
$$type: 'ais.metadata',
$$internal: true,
},
]);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { wait } from '@instantsearch/testutils/wait';
import type { JSDOM } from 'jsdom';
import type { PlainSearchParameters } from 'algoliasearch-helper';
import { fireEvent } from '@testing-library/dom';
import { createInstantSearch } from '../../../test/createInstantSearch';

declare const jsdom: JSDOM;

Expand Down Expand Up @@ -227,15 +228,36 @@ describe('insights', () => {
});

it('throws when search client does not have credentials', () => {
const { insightsClient, instantSearchInstance } = createTestEnvironment({
searchClient: createSearchClient(),
const { insightsClient } = createInsights();
const instantSearchInstance = createInstantSearch({
// @ts-expect-error fake client
client: { search: () => {} },
});
expect(() =>
createInsightsMiddleware({
insightsClient,
})({ instantSearchInstance })
).toThrowErrorMatchingInlineSnapshot(
`"[insights middleware]: could not extract Algolia credentials from searchClient"`
`"apiKey is missing, please provide it so we can authenticate the application"`
);
});

it('warns when search client does not have credentials', () => {
const { insightsClient } = createInsights();
const instantSearchInstance = createInstantSearch({
// @ts-expect-error fake client
client: { search: () => {} },
});
expect(() => {
try {
createInsightsMiddleware({
insightsClient,
})({ instantSearchInstance });
} catch (e) {
// insights error
}
}).toWarnDev(
'[InstantSearch.js]: could not extract Algolia credentials from searchClient in insights middleware.'
);
});

Expand Down Expand Up @@ -396,6 +418,79 @@ See documentation: https://www.algolia.com/doc/guides/building-search-ui/going-f
'insights-middleware'
);
});

it('removes default middleware if user adds a custom one', () => {
const { instantSearchInstance } = createTestEnvironment();

// just the internal one
expect(instantSearchInstance.middleware).toHaveLength(1);
expect(instantSearchInstance.middleware).toMatchInlineSnapshot(`
[
{
"creator": [Function],
"instance": {
"$$internal": true,
"$$type": "ais.insights",
"onStateChange": [Function],
"started": [Function],
"subscribe": [Function],
"unsubscribe": [Function],
},
},
]
`);

instantSearchInstance.use(createInsightsMiddleware({}));

// just the user-provided one
expect(instantSearchInstance.middleware).toHaveLength(1);
expect(instantSearchInstance.middleware).toMatchInlineSnapshot(`
[
{
"creator": [Function],
"instance": {
"$$internal": false,
"$$type": "ais.insights",
"onStateChange": [Function],
"started": [Function],
"subscribe": [Function],
"unsubscribe": [Function],
},
},
]
`);

instantSearchInstance.use(createInsightsMiddleware({}));

// both user-provided
expect(instantSearchInstance.middleware).toHaveLength(2);
expect(instantSearchInstance.middleware).toMatchInlineSnapshot(`
[
{
"creator": [Function],
"instance": {
"$$internal": false,
"$$type": "ais.insights",
"onStateChange": [Function],
"started": [Function],
"subscribe": [Function],
"unsubscribe": [Function],
},
},
{
"creator": [Function],
"instance": {
"$$internal": false,
"$$type": "ais.insights",
"onStateChange": [Function],
"started": [Function],
"subscribe": [Function],
"unsubscribe": [Function],
},
},
]
`);
});
});

describe('userToken', () => {
Expand Down
Loading