Skip to content

Commit

Permalink
refactor(headless): migrate searchbox submit event for search case (#…
Browse files Browse the repository at this point in the history
…3463)

* migrate searchBox/submit

https://coveord.atlassian.net/browse/KIT-2933

* revert optional legacy analytics

https://coveord.atlassian.net/browse/KIT-2933

* insight case not using the right interface..

https://coveord.atlassian.net/browse/KIT-2933

* beter interfaces

https://coveord.atlassian.net/browse/KIT-2933

* never use coreSearchBox

https://coveord.atlassian.net/browse/KIT-2933

* fix test

https://coveord.atlassian.net/browse/KIT-2933

* refactor(headless): migrate searchboxAsYouType event (#3472)

refactor(headless): migrate searchboxAsYouType

https://coveord.atlassian.net/browse/KIT-2942
  • Loading branch information
alexprudhomme authored Dec 14, 2023
1 parent 19eb84a commit e68025b
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {QuerySuggestState} from '../../../features/query-suggest/query-suggest-s
import {logSearchboxSubmit} from '../../../features/query/query-analytics-actions';
import {queryReducer as query} from '../../../features/query/query-slice';
import {
SearchAction,
TransitiveSearchAction,
prepareForSearchWithQuery,
} from '../../../features/search/search-actions';
Expand Down Expand Up @@ -151,6 +152,7 @@ export interface Suggestion {
}

/**
* @internal
* The `SearchBox` headless controller offers a high-level interface for designing a common search box UI controller
* with [highlighting for query suggestions](https://docs.coveo.com/en/headless/latest/usage/highlighting/).
*/
Expand Down Expand Up @@ -182,9 +184,13 @@ export interface SearchBox extends Controller {
/**
* Deselects all facets and triggers a search query.
*
* @param analytics - The analytics action to log after submitting a query.
* @param legacyAnalytics - The legacy analytics action to log after submitting a query.
* @param nextAnalytics - The next analytics action to log after submitting a query.
*/
submit(analytics?: LegacySearchAction): void;
submit(
legacyAnalytics?: LegacySearchAction,
nextAnalytics?: SearchAction
): void;

/**
* The state of the `SearchBox` controller.
Expand All @@ -193,6 +199,7 @@ export interface SearchBox extends Controller {
}

/**
* @internal
* Creates a `SearchBox` controller instance.
*
* @param engine - The headless engine instance.
Expand Down Expand Up @@ -278,9 +285,12 @@ export function buildCoreSearchBox(
},

submit(
analytics: LegacySearchAction | InsightAction = logSearchboxSubmit()
legacyAnalytics:
| LegacySearchAction
| InsightAction = logSearchboxSubmit(),
nextAnalytics: SearchAction
) {
performSearch({legacy: analytics});
performSearch({legacy: legacyAnalytics, next: nextAnalytics});
dispatch(clearQuerySuggest({id}));
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {
fetchQuerySuggestions,
} from '../../../features/insight-search/insight-search-actions';
import {logSearchboxSubmit} from '../../../features/query/query-insight-analytics-actions';
import {Controller} from '../../controller/headless-controller';
import {
buildCoreSearchBox,
Delimiters,
SearchBox,
SearchBoxState,
Suggestion,
SuggestionHighlightingOptions,
Expand All @@ -17,7 +17,6 @@ import {SearchBoxOptions} from '../../core/search-box/headless-core-search-box-o
export type {
SearchBoxOptions,
SearchBoxState,
SearchBox,
SuggestionHighlightingOptions,
Suggestion,
Delimiters,
Expand All @@ -30,6 +29,42 @@ export interface SearchBoxProps {
options?: SearchBoxOptions;
}

export interface SearchBox extends Controller {
/**
* Updates the search box text value and shows the suggestions for that value.
*
* @param value - The string value to update the search box with.
*/
updateText(value: string): void;

/**
* Clears the search box text and the suggestions.
*/
clear(): void;

/**
* Shows the suggestions for the current search box value.
*/
showSuggestions(): void;

/**
* Selects a suggestion and calls `submit`.
*
* @param value - The string value of the suggestion to select
*/
selectSuggestion(value: string): void;

/**
* Deselects all facets and triggers a search query.
*/
submit(): void;

/**
* The state of the `SearchBox` controller.
*/
state: SearchBoxState;
}

/**
* Creates an insight `SearchBox` controller instance.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {

jest.mock('../../features/query/query-analytics-actions', () => ({
logSearchboxSubmit: jest.fn(() => () => {}),
searchboxSubmit: jest.fn(() => () => {}),
}));

describe('headless searchBox', () => {
Expand Down Expand Up @@ -119,7 +120,7 @@ describe('headless searchBox', () => {
(a) => a.type === executeSearch.pending.type
);
expect(action).toBeTruthy();
expect(logSearchboxSubmit).toBeCalledTimes(1);
expect(logSearchboxSubmit).toHaveBeenCalledTimes(1);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {SearchEngine} from '../../app/search-engine/search-engine';
import {fetchQuerySuggestions} from '../../features/query-suggest/query-suggest-actions';
import {logSearchboxSubmit} from '../../features/query/query-analytics-actions';
import {
logSearchboxSubmit,
searchboxSubmit,
} from '../../features/query/query-analytics-actions';
import {executeSearch} from '../../features/search/search-actions';
import {SuggestionHighlightingOptions, Delimiters} from '../../utils/highlight';
import {Controller} from '../controller/headless-controller';
Expand Down Expand Up @@ -87,7 +90,7 @@ export function buildSearchBox(
return {
...searchBox,
submit() {
searchBox.submit(logSearchboxSubmit());
searchBox.submit(logSearchboxSubmit(), searchboxSubmit());
},
get state() {
return searchBox.state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
InstantResultsAnalyticsProvider,
StateNeededByInstantResultsAnalyticsProvider,
} from '../../api/analytics/instant-result-analytics';
import {SearchAnalyticsProvider} from '../../api/analytics/search-analytics';
import {Result} from '../../api/search/search/result';
import {
partialDocumentInformation,
Expand All @@ -12,6 +13,8 @@ import {
InstantResultsSearchAction,
InstantResultsClickAction,
} from '../analytics/analytics-utils';
import {SearchPageEvents} from '../analytics/search-action-cause';
import {SearchAction} from '../search/search-actions';

export const logInstantResultOpen = (
result: Result
Expand Down Expand Up @@ -47,9 +50,18 @@ export const logInstantResultOpen = (
},
});

//TODO: KIT-2859
export const logInstantResultsSearch = (): InstantResultsSearchAction =>
makeAnalyticsAction(
'analytics/instantResult/searchboxAsYouType',
(client) => client.makeSearchboxAsYouType(),
(getState) => new InstantResultsAnalyticsProvider(getState)
);

export const searchboxAsYouType = (): SearchAction => {
return {
actionCause: SearchPageEvents.searchboxAsYouType,
getEventExtraPayload: (state) =>
new SearchAnalyticsProvider(() => state).getBaseMetadata(),
};
};
12 changes: 12 additions & 0 deletions packages/headless/src/features/query/query-analytics-actions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import {SearchAnalyticsProvider} from '../../api/analytics/search-analytics';
import {
makeAnalyticsAction,
LegacySearchAction,
} from '../analytics/analytics-utils';
import {SearchPageEvents} from '../analytics/search-action-cause';
import {SearchAction} from '../search/search-actions';

//TODO: KIT-2859
export const logSearchboxSubmit = (): LegacySearchAction =>
makeAnalyticsAction('analytics/searchbox/submit', (client) =>
client.makeSearchboxSubmit()
);

export const searchboxSubmit = (): SearchAction => {
return {
actionCause: SearchPageEvents.searchboxSubmit,
getEventExtraPayload: (state) =>
new SearchAnalyticsProvider(() => state).getBaseMetadata(),
};
};
26 changes: 14 additions & 12 deletions packages/headless/src/features/search/search-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
deselectAllNonBreadcrumbs,
} from '../breadcrumb/breadcrumb-actions';
import {updateFacetAutoSelection} from '../facets/generic/facet-actions';
import {searchboxAsYouType} from '../instant-results/instant-result-analytics-actions';
import {
FetchInstantResultsActionCreatorPayload,
FetchInstantResultsThunkReturn,
Expand Down Expand Up @@ -277,28 +278,28 @@ export const fetchInstantResults = createAsyncThunk<
cacheTimeout: new NumberValue(),
});
const {q, maxResultsPerQuery} = payload;
const analyticsAction = makeBasicNewSearchAnalyticsAction(
SearchPageEvents.searchboxAsYouType,
config.getState

const analyticsAction = buildSearchReduxAction(searchboxAsYouType(), state);

const request = await buildInstantResultSearchRequest(
state,
q,
maxResultsPerQuery,
analyticsAction
);

const processor = new AsyncSearchThunkProcessor<
ReturnType<typeof config.rejectWithValue>
>({...config, analyticsAction}, (modification) => {
config.dispatch(
updateInstantResultsQuery({q: modification, id: payload.id})
);
});

const request = await buildInstantResultSearchRequest(
state,
q,
maxResultsPerQuery
);

const fetched = await processor.fetchFromAPI(request, {
origin: 'instantResults',
disableAbortWarning: true,
});

const processed = await processor.process(fetched);
if ('response' in processed) {
return {
Expand Down Expand Up @@ -330,10 +331,11 @@ const buildFetchMoreRequest = async (
export const buildInstantResultSearchRequest = async (
state: StateNeededByExecuteSearch,
q: string,
numberOfResults: number
numberOfResults: number,
eventDescription: EventDescription
) => {
const sharedWithFoldingRequest =
await buildSearchAndFoldingLoadCollectionRequest(state);
await buildSearchAndFoldingLoadCollectionRequest(state, eventDescription);

return mapSearchRequest({
...sharedWithFoldingRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
omniboxFromLink,
searchFromLink,
} from '../features/analytics/analytics-actions';
import {LegacySearchAction} from '../features/analytics/analytics-utils';
import {
didYouMeanClick,
logDidYouMeanClick,
Expand Down Expand Up @@ -69,8 +70,16 @@ import {
historyForward,
noResultsBack,
} from '../features/history/history-analytics-actions';
import {
logInstantResultsSearch,
searchboxAsYouType,
} from '../features/instant-results/instant-result-analytics-actions';
import {fetchQuerySuggestions} from '../features/query-suggest/query-suggest-actions';
import {OmniboxSuggestionMetadata} from '../features/query-suggest/query-suggest-analytics-actions';
import {
logSearchboxSubmit,
searchboxSubmit,
} from '../features/query/query-analytics-actions';
import {
logRecentQueryClick,
recentQueryClick,
Expand Down Expand Up @@ -921,6 +930,29 @@ describe('Analytics Search Migration', () => {
assertNextEqualsLegacy(callSpy);
});

it('analytics/instantResult/searchboxAsYouType', async () => {
const action = executeSearch({
legacy: logInstantResultsSearch() as LegacySearchAction,
next: searchboxAsYouType(),
});
legacySearchEngine.dispatch(action);
nextSearchEngine.dispatch(action);
await wait();

assertNextEqualsLegacy(callSpy);
});
it('analytics/searchbox/submit', async () => {
const action = executeSearch({
legacy: logSearchboxSubmit(),
next: searchboxSubmit(),
});
legacySearchEngine.dispatch(action);
nextSearchEngine.dispatch(action);
await wait();

assertNextEqualsLegacy(callSpy);
});

it('analytics/recommendation/update', async () => {
const action = executeSearch({
legacy: logRecommendationUpdate(),
Expand Down

0 comments on commit e68025b

Please sign in to comment.