From dcd43fed2d814cbaa399f961274ea3adb782e09e Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Tue, 23 Nov 2021 11:02:34 -0500 Subject: [PATCH 1/6] Support autocompleteSessionId J=SLAP-1723 TEST=auto use updated core in headless, see that jest tests passed. --- package-lock.json | 164 +++++++++++++++++---------------- package.json | 6 +- src/answers-headless.ts | 33 ++++++- src/index.ts | 6 +- src/models/slices/query.ts | 8 +- src/models/state.ts | 2 +- src/slices/query.ts | 26 ++++-- tests/integration/query.ts | 80 ++++++++++++++++ tests/unit/answers-headless.ts | 22 +++++ tests/unit/slices/query.ts | 60 +++++++++++- 10 files changed, 306 insertions(+), 101 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f3421d8..6230df39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,10 @@ "license": "ISC", "dependencies": { "@reduxjs/toolkit": "^1.6.0", - "@yext/answers-core": "^1.3.2", + "@yext/answers-core": "file:~/answers-core", "js-levenshtein": "^1.1.6", - "redux-thunk": "^2.3.0" + "redux-thunk": "^2.3.0", + "uuid": "^8.3.2" }, "devDependencies": { "@babel/preset-env": "^7.14.7", @@ -20,6 +21,7 @@ "@types/jest": "^26.0.24", "@types/lodash": "^4.14.175", "@types/node": "^14.14.28", + "@types/uuid": "^8.3.3", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", "@yext/eslint-plugin-export-star": "^1.0.0", @@ -32,6 +34,38 @@ "typescript": "^4.1.5" } }, + "../answers-core": { + "name": "@yext/answers-core", + "version": "1.5.0-beta.0", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime-corejs3": "^7.12.5", + "cross-fetch": "^3.1.4" + }, + "devDependencies": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-runtime": "^7.12.10", + "@babel/preset-env": "^7.12.1", + "@babel/preset-typescript": "^7.12.1", + "@microsoft/api-documenter": "^7.11.3", + "@microsoft/api-extractor": "^7.12.0", + "@types/jest": "^26.0.15", + "@typescript-eslint/eslint-plugin": "^4.6.0", + "@typescript-eslint/parser": "^4.6.0", + "babel-jest": "^26.6.1", + "babel-loader": "^8.2.2", + "eslint": "^7.11.0", + "generate-license-file": "^1.1.0", + "jest": "^26.6.0", + "ts-loader": "^8.0.14", + "typescript": "^4.0.3", + "webpack": "^5.18.0", + "webpack-cli": "^4.4.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@babel/code-frame": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", @@ -1660,18 +1694,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.4.tgz", - "integrity": "sha512-lWcAqKeB624/twtTc3w6w/2o9RqJPaNBhPGK6DKLSiwuVWC7WFkypWyNg+CpZoyJH0jVzv1uMtXZ/5/lQOLtCg==", - "dependencies": { - "core-js-pure": "^3.16.0", - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", @@ -2335,6 +2357,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/uuid": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.3.tgz", + "integrity": "sha512-0LbEEx1zxrYB3pgpd1M5lEhLcXjKJnYghvhTRgaBeUivLHMDM1TzF3IJ6hXU2+8uA4Xz+5BA63mtZo5DjVT8iA==", + "dev": true + }, "node_modules/@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -2555,16 +2583,8 @@ } }, "node_modules/@yext/answers-core": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@yext/answers-core/-/answers-core-1.3.2.tgz", - "integrity": "sha512-hZO5XigSH3n5FtLYjhAAlvcBFVe0rQOv30BlbXr4cgGTR5+0w2D7c+Lu+N9RaGTuec7lcwFYIDLSeDAh/mZDRw==", - "dependencies": { - "@babel/runtime-corejs3": "^7.12.5", - "cross-fetch": "^3.1.4" - }, - "engines": { - "node": ">=0.12" - } + "resolved": "../answers-core", + "link": true }, "node_modules/@yext/eslint-plugin-export-star": { "version": "1.0.0", @@ -3402,30 +3422,12 @@ "semver": "bin/semver.js" } }, - "node_modules/core-js-pure": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.17.3.tgz", - "integrity": "sha512-YusrqwiOTTn8058JDa0cv9unbXdIiIgcgI9gXso0ey4WgkFLd3lYlV9rp9n7nDCsYxXsMDTjA4m1h3T348mdlQ==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "node_modules/cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", - "dependencies": { - "node-fetch": "2.6.1" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -6440,14 +6442,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "engines": { - "node": "4.x || >=6.0.0" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -7954,6 +7948,14 @@ "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", "dev": true }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -9367,15 +9369,6 @@ "regenerator-runtime": "^0.13.4" } }, - "@babel/runtime-corejs3": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.15.4.tgz", - "integrity": "sha512-lWcAqKeB624/twtTc3w6w/2o9RqJPaNBhPGK6DKLSiwuVWC7WFkypWyNg+CpZoyJH0jVzv1uMtXZ/5/lQOLtCg==", - "requires": { - "core-js-pure": "^3.16.0", - "regenerator-runtime": "^0.13.4" - } - }, "@babel/template": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", @@ -9922,6 +9915,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "@types/uuid": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.3.tgz", + "integrity": "sha512-0LbEEx1zxrYB3pgpd1M5lEhLcXjKJnYghvhTRgaBeUivLHMDM1TzF3IJ6hXU2+8uA4Xz+5BA63mtZo5DjVT8iA==", + "dev": true + }, "@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", @@ -10053,12 +10052,28 @@ } }, "@yext/answers-core": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@yext/answers-core/-/answers-core-1.3.2.tgz", - "integrity": "sha512-hZO5XigSH3n5FtLYjhAAlvcBFVe0rQOv30BlbXr4cgGTR5+0w2D7c+Lu+N9RaGTuec7lcwFYIDLSeDAh/mZDRw==", + "version": "file:../answers-core", "requires": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-runtime": "^7.12.10", + "@babel/preset-env": "^7.12.1", + "@babel/preset-typescript": "^7.12.1", "@babel/runtime-corejs3": "^7.12.5", - "cross-fetch": "^3.1.4" + "@microsoft/api-documenter": "^7.11.3", + "@microsoft/api-extractor": "^7.12.0", + "@types/jest": "^26.0.15", + "@typescript-eslint/eslint-plugin": "^4.6.0", + "@typescript-eslint/parser": "^4.6.0", + "babel-jest": "^26.6.1", + "babel-loader": "^8.2.2", + "cross-fetch": "^3.1.4", + "eslint": "^7.11.0", + "generate-license-file": "^1.1.0", + "jest": "^26.6.0", + "ts-loader": "^8.0.14", + "typescript": "^4.0.3", + "webpack": "^5.18.0", + "webpack-cli": "^4.4.0" } }, "@yext/eslint-plugin-export-star": { @@ -10681,25 +10696,12 @@ } } }, - "core-js-pure": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.17.3.tgz", - "integrity": "sha512-YusrqwiOTTn8058JDa0cv9unbXdIiIgcgI9gXso0ey4WgkFLd3lYlV9rp9n7nDCsYxXsMDTjA4m1h3T348mdlQ==" - }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, - "cross-fetch": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", - "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", - "requires": { - "node-fetch": "2.6.1" - } - }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -13013,11 +13015,6 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" - }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -14168,6 +14165,11 @@ "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", "dev": true }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", diff --git a/package.json b/package.json index 5b31d92d..442e72be 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,10 @@ }, "dependencies": { "@reduxjs/toolkit": "^1.6.0", - "@yext/answers-core": "^1.3.2", + "@yext/answers-core": "file:~/answers-core", "js-levenshtein": "^1.1.6", - "redux-thunk": "^2.3.0" + "redux-thunk": "^2.3.0", + "uuid": "^8.3.2" }, "devDependencies": { "@babel/preset-env": "^7.14.7", @@ -28,6 +29,7 @@ "@types/jest": "^26.0.24", "@types/lodash": "^4.14.175", "@types/node": "^14.14.28", + "@types/uuid": "^8.3.3", "@typescript-eslint/eslint-plugin": "^4.28.2", "@typescript-eslint/parser": "^4.28.2", "@yext/eslint-plugin-export-star": "^1.0.0", diff --git a/src/answers-headless.ts b/src/answers-headless.ts index 7b0f334a..ab57347a 100644 --- a/src/answers-headless.ts +++ b/src/answers-headless.ts @@ -16,7 +16,7 @@ import { FilterSearchResponse, UniversalLimit, VerticalSearchResponse -} from '@yext/answers-core'; +} from '../../answers-core/lib/esm'; import StateListener from './models/state-listener'; import { State } from './models/state'; @@ -26,6 +26,7 @@ import HttpManager from './http-manager'; import answersUtilities from './answers-utilities'; import { SelectableFilter } from './models/utils/selectablefilter'; import { transformFiltersToCoreFormat } from './utils/transform-filters'; +import { v4 as uuidv4 } from 'uuid'; export default class AnswersHeadless { public readonly utilities = answersUtilities; @@ -48,6 +49,14 @@ export default class AnswersHeadless { this.stateManager.dispatchEvent('query/setSource', source); } + setSearchAggregationEnabled(enabled: boolean): void { + this.stateManager.dispatchEvent('query/setSearchAggregationEnabled', enabled); + } + + setSearchAggregationId(uuid: string): void { + this.stateManager.dispatchEvent('query/setSearchAggregationId', uuid); + } + setVerticalKey(verticalKey: string): void { this.stateManager.dispatchEvent('vertical/setVerticalKey', verticalKey); } @@ -145,7 +154,9 @@ export default class AnswersHeadless { limit, location: userLocation, context, - referrerPageUrl + referrerPageUrl, + ...(this.state.query.searchAggregation?.enabled + && { autocompleteSessionId: this.state.query.searchAggregation.id }) }); const latestResponseId = this.httpManager.getLatestResponseId('universalQuery'); @@ -162,13 +173,18 @@ export default class AnswersHeadless { this.stateManager.dispatchEvent('searchStatus/setIsLoading', false); this.stateManager.dispatchEvent('meta/setUUID', response.uuid); this.stateManager.dispatchEvent('directAnswer/setResult', response.directAnswer); + if (this.state.query.searchAggregation?.enabled) { + this.stateManager.dispatchEvent('query/setSearchAggregationId', uuidv4()); + } return response; } async executeUniversalAutocomplete(): Promise { const query = this.state.query.input || ''; return this.core.universalAutocomplete({ - input: query + input: query, + ...(this.state.query.searchAggregation?.enabled + && { autocompleteSessionId: this.state.query.searchAggregation.id }) }); } @@ -215,7 +231,9 @@ export default class AnswersHeadless { location: userLocation, sortBys, context, - referrerPageUrl + referrerPageUrl, + ...(this.state.query.searchAggregation?.enabled + && { autocompleteSessionId: this.state.query.searchAggregation.id }) }; const response = await this.core.verticalSearch(request); const latestResponseId = this.httpManager.getLatestResponseId('verticalQuery'); @@ -233,6 +251,9 @@ export default class AnswersHeadless { this.stateManager.dispatchEvent('meta/setUUID', response.uuid); this.stateManager.dispatchEvent('searchStatus/setIsLoading', false); this.stateManager.dispatchEvent('vertical/handleSearchResponse', response); + if (this.state.query.searchAggregation?.enabled) { + this.stateManager.dispatchEvent('query/setSearchAggregationId', uuidv4()); + } return response; } @@ -246,7 +267,9 @@ export default class AnswersHeadless { return this.core.verticalAutocomplete({ input: query, - verticalKey + verticalKey, + ...(this.state.query.searchAggregation?.enabled + && { autocompleteSessionId: this.state.query.searchAggregation.id }) }); } diff --git a/src/index.ts b/src/index.ts index bdcb2ea0..cfffa0ef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { provideCore, AnswersConfig } from '@yext/answers-core'; +import { provideCore, AnswersConfig } from '../../answers-core/lib/esm'; import HttpManager from './http-manager'; import ReduxStateManager from './redux-state-manager'; import AnswersHeadless from './answers-headless'; @@ -10,9 +10,7 @@ import { SessionTrackingState } from './models/slices/sessiontracking'; export * from '@yext/answers-core'; export * from './utils/filter-creators'; -export interface HeadlessConfig extends AnswersConfig { - headlessId?: string -} +type HeadlessConfig = AnswersConfig & { headlessId?: string } let firstHeadlessInstance: AnswersHeadless; const store = createBaseStore(); diff --git a/src/models/slices/query.ts b/src/models/slices/query.ts index 6f7ef91f..86b2c91d 100644 --- a/src/models/slices/query.ts +++ b/src/models/slices/query.ts @@ -1,10 +1,16 @@ import { QuerySource, QueryTrigger, SearchIntent } from '@yext/answers-core'; +interface SearchAggregationState { + enabled: boolean, + id: string +} + export interface QueryState { input?: string, queryId?: string, queryTrigger?: QueryTrigger, querySource?: QuerySource, mostRecentSearch?: string, - searchIntents?: SearchIntent[] + searchIntents?: SearchIntent[], + searchAggregation?: SearchAggregationState } \ No newline at end of file diff --git a/src/models/state.ts b/src/models/state.ts index 49b67dfc..5b73dda4 100644 --- a/src/models/state.ts +++ b/src/models/state.ts @@ -25,7 +25,7 @@ export interface State { filters: FiltersState, searchStatus: SearchStatusState, spellCheck: SpellCheckState, - sessionTracking: SessionTrackingState + sessionTracking: SessionTrackingState, meta: MetaState, location: LocationState, } diff --git a/src/slices/query.ts b/src/slices/query.ts index 81a6a2af..51d3a6c0 100644 --- a/src/slices/query.ts +++ b/src/slices/query.ts @@ -1,26 +1,40 @@ import { createSlice, PayloadAction, Slice } from '@reduxjs/toolkit'; import { QuerySource, QueryTrigger, SearchIntent } from '@yext/answers-core'; import { QueryState } from '../models/slices/query'; +import { v4 as uuidv4 } from 'uuid'; const initialState: QueryState = {}; const reducers = { - setInput: (state, action: PayloadAction) => { + setInput: (state: QueryState, action: PayloadAction) => { state.input = action.payload; }, - setTrigger: (state, action: PayloadAction) => { + setTrigger: (state: QueryState, action: PayloadAction) => { state.queryTrigger = action.payload; }, - setSource: (state, action: PayloadAction) => { + setSource: (state: QueryState, action: PayloadAction) => { state.querySource = action.payload; }, - setQueryId: (state, action: PayloadAction) => { + setQueryId: (state: QueryState, action: PayloadAction) => { state.queryId = action.payload; }, - setMostRecentSearch: (state, action: PayloadAction) => { + setSearchAggregationEnabled: (state: QueryState, action: PayloadAction) => { + state.searchAggregation = { + enabled: action.payload, + id: action.payload ? uuidv4() : undefined + }; + }, + setSearchAggregationId: (state: QueryState, action: PayloadAction) => { + if (!state.searchAggregation) { + console.error('Search aggregation is not enabled.'); + return; + } + state.searchAggregation.id = action.payload; + }, + setMostRecentSearch: (state: QueryState, action: PayloadAction) => { state.mostRecentSearch = action.payload; }, - setSearchIntents: (state, action: PayloadAction) => { + setSearchIntents: (state: QueryState, action: PayloadAction) => { state.searchIntents = action.payload; } }; diff --git a/tests/integration/query.ts b/tests/integration/query.ts index f5b8892b..c66f1aa8 100644 --- a/tests/integration/query.ts +++ b/tests/integration/query.ts @@ -118,3 +118,83 @@ describe('ensure correct results from latest request', () => { expect(updateResult.mock.calls).toHaveLength(2); }); }); + + +let uuidString = 'some-uuid-value'; +const mockUuid = jest.fn(() => uuidString); +jest.mock('uuid', () => ({ + v4: () => mockUuid() +})); + +describe('ensure correct searchAggregationId passed to related requests', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('autocompleteSessionId is properly handle in request when search aggregation is disabled/enabled', async () => { + const mockVerticalSearch = jest.fn().mockReturnValue(Promise.resolve({})); + const mockVerticalAutocomplete = jest.fn().mockReturnValue(Promise.resolve({}));; + const answers = createMockedAnswersHeadless({ + verticalSearch: mockVerticalSearch, + verticalAutocomplete: mockVerticalAutocomplete + }); + answers.setVerticalKey('someKey'); + + // search term aggregation disabled + await answers.executeVerticalAutocomplete(); + await answers.executeVerticalQuery(); + expect(mockVerticalAutocomplete).toHaveBeenLastCalledWith( + expect.not.objectContaining({ autocompleteSessionId: expect.anything }) + ); + expect(mockVerticalSearch).toHaveBeenLastCalledWith( + expect.not.objectContaining({ autocompleteSessionId: expect.anything }) + ); + expect(mockUuid).toHaveBeenCalledTimes(0); + + // search term aggregation enabled + answers.setSearchAggregationEnabled(true); + expect(mockUuid).toHaveBeenCalledTimes(1); + await answers.executeVerticalAutocomplete(); + await answers.executeVerticalQuery(); + expect(mockVerticalAutocomplete).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) + ); + expect(mockVerticalSearch).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) + ); + expect(mockUuid).toHaveBeenCalledTimes(2); + }) + + it('related autocomplete and query search a grouped with updated uuid after new query search', async () => { + const mockUniversalSearch = jest.fn().mockReturnValue(Promise.resolve({})); + const mockUniversalAutocomplete = jest.fn().mockReturnValue(Promise.resolve({}));; + const answers = createMockedAnswersHeadless({ + universalSearch: mockUniversalSearch, + universalAutocomplete: mockUniversalAutocomplete + }); + answers.setSearchAggregationEnabled(true); + expect(mockUuid).toHaveBeenCalledTimes(1); + uuidString = 'different-uuid-value'; + + //first grouping + await answers.executeUniversalAutocomplete(); + await answers.executeUniversalQuery(); + expect(mockUniversalAutocomplete).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) + ); + expect(mockUniversalSearch).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) + ); + expect(mockUuid).toHaveBeenCalledTimes(2); + + // second grouping + await answers.executeUniversalAutocomplete(); + await answers.executeUniversalQuery(); + expect(mockUniversalAutocomplete).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'different-uuid-value' }) + ); + expect(mockUniversalSearch).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'different-uuid-value' }) + ); + }) +}) diff --git a/tests/unit/answers-headless.ts b/tests/unit/answers-headless.ts index e0270c2a..848de42a 100644 --- a/tests/unit/answers-headless.ts +++ b/tests/unit/answers-headless.ts @@ -229,6 +229,28 @@ describe('setters work as expected', () => { expect(dispatchEventCalls[0][0]).toBe('vertical/setOffset'); expect(dispatchEventCalls[0][1]).toBe(offset); }); + + it('setSearchAggregationEnabled works as expected', () => { + answers.setSearchAggregationEnabled(true); + + const dispatchEventCalls = + mockedStateManager.dispatchEvent.mock.calls; + + expect(dispatchEventCalls.length).toBe(1); + expect(dispatchEventCalls[0][0]).toBe('query/setSearchAggregationEnabled'); + expect(dispatchEventCalls[0][1]).toBe(true); + }); + + it('setSearchAggregationId works as expected', () => { + answers.setSearchAggregationId('some-uuid-value'); + + const dispatchEventCalls = + mockedStateManager.dispatchEvent.mock.calls; + + expect(dispatchEventCalls.length).toBe(1); + expect(dispatchEventCalls[0][0]).toBe('query/setSearchAggregationId'); + expect(dispatchEventCalls[0][1]).toBe('some-uuid-value'); + }); }); describe('filter functions work as expected', () => { diff --git a/tests/unit/slices/query.ts b/tests/unit/slices/query.ts index 5be826cd..2fa995e7 100644 --- a/tests/unit/slices/query.ts +++ b/tests/unit/slices/query.ts @@ -1,8 +1,19 @@ import { QuerySource, QueryTrigger } from '@yext/answers-core'; import createQuerySlice from '../../../src/slices/query'; +jest.mock('uuid', () => ({ + v4: jest.fn(() => 'some-uuid-value') +})); + const { reducer, actions } = createQuerySlice(''); -const { setInput, setQueryId, setSource, setTrigger } = actions; +const { + setInput, + setQueryId, + setSource, + setTrigger, + setSearchAggregationEnabled, + setSearchAggregationId +} = actions; describe('query slice reducer works as expected', () => { it('setQuery action is handled properly', () => { @@ -36,4 +47,51 @@ describe('query slice reducer works as expected', () => { expect(actualState).toEqual(expectedState); }); + + it('setSearchAggregationEnabled action is handled properly when set to false', () => { + const expectedState = { + searchAggregation: { + enabled: false, + id: undefined + } + }; + const actualState = reducer({}, setSearchAggregationEnabled(false)); + expect(actualState).toEqual(expectedState); + }); + + it('setSearchAggregationEnabled action is handled properly when set to true', () => { + const expectedState = { + searchAggregation: { + enabled: true, + id: 'some-uuid-value' + } + }; + const actualState = reducer({}, setSearchAggregationEnabled(true)); + expect(actualState).toEqual(expectedState); + }); + + it('setSearchAggregationId action is handled properly', () => { + const initalState = { + searchAggregation: { + enabled: true, + id: 'very-old-uuid-value' + } + }; + const expectedState = { + searchAggregation: { + enabled: true, + id: 'some-uuid-value' + } + }; + const actualState = reducer(initalState, setSearchAggregationId('some-uuid-value')); + expect(actualState).toEqual(expectedState); + }); + + it('setSearchAggregationId action is handled properly when searchAggregation is never set', () => { + const consoleErrorSpy = jest.spyOn(global.console, 'error').mockImplementation(); + const actualState = reducer({}, setSearchAggregationId('some-uuid-value')); + expect(consoleErrorSpy).toHaveBeenCalledTimes(1); + consoleErrorSpy.mockClear(); + expect(actualState).toEqual({}); + }); }); \ No newline at end of file From 740154df3459dcb8484f6d3f44bb1248b9fc152e Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Nov 2021 16:13:55 +0000 Subject: [PATCH 2/6] Automated update to THIRD-PARTY-NOTICES from github action's 3rd party notices check --- THIRD-PARTY-NOTICES | 116 +++++++++----------------------------------- 1 file changed, 22 insertions(+), 94 deletions(-) diff --git a/THIRD-PARTY-NOTICES b/THIRD-PARTY-NOTICES index ede2848a..e2aab506 100644 --- a/THIRD-PARTY-NOTICES +++ b/THIRD-PARTY-NOTICES @@ -1,9 +1,8 @@ -The following NPM packages may be included in this product: +The following NPM package may be included in this product: - - @babel/runtime-corejs3@7.15.4 - @babel/runtime@7.14.6 -These packages each contain the following license and notice below: +This package contains the following license and notice below: MIT License @@ -60,12 +59,11 @@ SOFTWARE. ----------- -The following NPM packages may be included in this product: +The following NPM package may be included in this product: - - @yext/answers-core@1.3.2 - @yext/answers-headless@0.1.0-beta.4 -These packages each contain the following license and notice below: +This package contains the following license and notice below: BSD 3-Clause License @@ -99,64 +97,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------- -The following NPM package may be included in this product: - - - core-js-pure@3.17.3 - -This package contains the following license and notice below: - -Copyright (c) 2014-2021 Denis Pushkarev - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - ------------ - -The following NPM package may be included in this product: - - - cross-fetch@3.1.4 - -This package contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2017 Leonardo Quixadá - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------------ - The following NPM package may be included in this product: - immer@9.0.6 @@ -217,36 +157,6 @@ SOFTWARE. ----------- -The following NPM package may be included in this product: - - - node-fetch@2.6.1 - -This package contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2016 David Frank - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - ------------ - The following NPM packages may be included in this product: - redux-thunk@2.3.0 @@ -338,4 +248,22 @@ SOFTWARE. ----------- +The following NPM package may be included in this product: + + - uuid@8.3.2 + +This package contains the following license and notice below: + +The MIT License (MIT) + +Copyright (c) 2010-2020 Robert Kieffer and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +----------- + This file was generated with generate-license-file! https://www.npmjs.com/package/generate-license-file \ No newline at end of file From 652ccce3ca4d06929304340a74fa7458a32c3ed3 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Tue, 23 Nov 2021 17:22:19 -0500 Subject: [PATCH 3/6] update to just id in state, and only use in search functions --- src/answers-headless.ts | 26 ++------ src/models/slices/query.ts | 7 +-- src/slices/query.ts | 13 +--- tests/integration/query.ts | 110 +++++++++------------------------ tests/unit/answers-headless.ts | 11 ---- tests/unit/slices/query.ts | 41 +----------- 6 files changed, 40 insertions(+), 168 deletions(-) diff --git a/src/answers-headless.ts b/src/answers-headless.ts index ab57347a..b85d8730 100644 --- a/src/answers-headless.ts +++ b/src/answers-headless.ts @@ -49,10 +49,6 @@ export default class AnswersHeadless { this.stateManager.dispatchEvent('query/setSource', source); } - setSearchAggregationEnabled(enabled: boolean): void { - this.stateManager.dispatchEvent('query/setSearchAggregationEnabled', enabled); - } - setSearchAggregationId(uuid: string): void { this.stateManager.dispatchEvent('query/setSearchAggregationId', uuid); } @@ -143,6 +139,7 @@ export default class AnswersHeadless { const sessionId = this.state.sessionTracking.sessionId; const { referrerPageUrl, context } = this.state.meta; const { userLocation } = this.state.location; + const autocompleteSessionId = this.state.query.searchAggregationId; const response = await this.core.universalSearch({ query: input || '', @@ -155,8 +152,7 @@ export default class AnswersHeadless { location: userLocation, context, referrerPageUrl, - ...(this.state.query.searchAggregation?.enabled - && { autocompleteSessionId: this.state.query.searchAggregation.id }) + autocompleteSessionId }); const latestResponseId = this.httpManager.getLatestResponseId('universalQuery'); @@ -173,18 +169,13 @@ export default class AnswersHeadless { this.stateManager.dispatchEvent('searchStatus/setIsLoading', false); this.stateManager.dispatchEvent('meta/setUUID', response.uuid); this.stateManager.dispatchEvent('directAnswer/setResult', response.directAnswer); - if (this.state.query.searchAggregation?.enabled) { - this.stateManager.dispatchEvent('query/setSearchAggregationId', uuidv4()); - } return response; } async executeUniversalAutocomplete(): Promise { const query = this.state.query.input || ''; return this.core.universalAutocomplete({ - input: query, - ...(this.state.query.searchAggregation?.enabled - && { autocompleteSessionId: this.state.query.searchAggregation.id }) + input: query }); } @@ -207,6 +198,7 @@ export default class AnswersHeadless { const sortBys = this.state.filters?.sortBys; const { referrerPageUrl, context } = this.state.meta; const { userLocation } = this.state.location; + const autocompleteSessionId = this.state.query.searchAggregationId; const facetsToApply = facets?.map(facet => { return { @@ -232,8 +224,7 @@ export default class AnswersHeadless { sortBys, context, referrerPageUrl, - ...(this.state.query.searchAggregation?.enabled - && { autocompleteSessionId: this.state.query.searchAggregation.id }) + autocompleteSessionId }; const response = await this.core.verticalSearch(request); const latestResponseId = this.httpManager.getLatestResponseId('verticalQuery'); @@ -251,9 +242,6 @@ export default class AnswersHeadless { this.stateManager.dispatchEvent('meta/setUUID', response.uuid); this.stateManager.dispatchEvent('searchStatus/setIsLoading', false); this.stateManager.dispatchEvent('vertical/handleSearchResponse', response); - if (this.state.query.searchAggregation?.enabled) { - this.stateManager.dispatchEvent('query/setSearchAggregationId', uuidv4()); - } return response; } @@ -267,9 +255,7 @@ export default class AnswersHeadless { return this.core.verticalAutocomplete({ input: query, - verticalKey, - ...(this.state.query.searchAggregation?.enabled - && { autocompleteSessionId: this.state.query.searchAggregation.id }) + verticalKey }); } diff --git a/src/models/slices/query.ts b/src/models/slices/query.ts index 86b2c91d..922c1c4f 100644 --- a/src/models/slices/query.ts +++ b/src/models/slices/query.ts @@ -1,10 +1,5 @@ import { QuerySource, QueryTrigger, SearchIntent } from '@yext/answers-core'; -interface SearchAggregationState { - enabled: boolean, - id: string -} - export interface QueryState { input?: string, queryId?: string, @@ -12,5 +7,5 @@ export interface QueryState { querySource?: QuerySource, mostRecentSearch?: string, searchIntents?: SearchIntent[], - searchAggregation?: SearchAggregationState + searchAggregationId?: string } \ No newline at end of file diff --git a/src/slices/query.ts b/src/slices/query.ts index 51d3a6c0..2cc7a179 100644 --- a/src/slices/query.ts +++ b/src/slices/query.ts @@ -1,7 +1,6 @@ import { createSlice, PayloadAction, Slice } from '@reduxjs/toolkit'; import { QuerySource, QueryTrigger, SearchIntent } from '@yext/answers-core'; import { QueryState } from '../models/slices/query'; -import { v4 as uuidv4 } from 'uuid'; const initialState: QueryState = {}; @@ -18,18 +17,8 @@ const reducers = { setQueryId: (state: QueryState, action: PayloadAction) => { state.queryId = action.payload; }, - setSearchAggregationEnabled: (state: QueryState, action: PayloadAction) => { - state.searchAggregation = { - enabled: action.payload, - id: action.payload ? uuidv4() : undefined - }; - }, setSearchAggregationId: (state: QueryState, action: PayloadAction) => { - if (!state.searchAggregation) { - console.error('Search aggregation is not enabled.'); - return; - } - state.searchAggregation.id = action.payload; + state.searchAggregationId = action.payload; }, setMostRecentSearch: (state: QueryState, action: PayloadAction) => { state.mostRecentSearch = action.payload; diff --git a/tests/integration/query.ts b/tests/integration/query.ts index c66f1aa8..d68013b2 100644 --- a/tests/integration/query.ts +++ b/tests/integration/query.ts @@ -24,6 +24,36 @@ it('vertical searches set search intents', async () => { expect(answers.state.query.searchIntents).toEqual(['NEAR_ME']); }); +it('related query search a grouped with updated uuid', async () => { + const mockUniversalSearch = jest.fn().mockReturnValue(Promise.resolve({})); + const mockVerticalSearch = jest.fn().mockReturnValue(Promise.resolve({})); + const answers = createMockedAnswersHeadless({ + universalSearch: mockUniversalSearch, + verticalSearch: mockVerticalSearch + }); + answers.setVerticalKey('vertical-key'); + + answers.setSearchAggregationId('some-uuid-value'); + await answers.executeUniversalQuery(); + await answers.executeVerticalQuery(); + expect(mockUniversalSearch).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) + ); + expect(mockVerticalSearch).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) + ); + + answers.setSearchAggregationId('different-uuid-value'); + await answers.executeUniversalQuery(); + await answers.executeVerticalQuery(); + expect(mockUniversalSearch).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'different-uuid-value' }) + ); + expect(mockVerticalSearch).toHaveBeenLastCalledWith( + expect.objectContaining({ autocompleteSessionId: 'different-uuid-value' }) + ); +}); + it('universal searches set search intents', async () => { const mockSearch = jest.fn((_request: UniversalSearchRequest) => Promise.resolve({ searchIntents: [SearchIntent.NearMe] @@ -118,83 +148,3 @@ describe('ensure correct results from latest request', () => { expect(updateResult.mock.calls).toHaveLength(2); }); }); - - -let uuidString = 'some-uuid-value'; -const mockUuid = jest.fn(() => uuidString); -jest.mock('uuid', () => ({ - v4: () => mockUuid() -})); - -describe('ensure correct searchAggregationId passed to related requests', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('autocompleteSessionId is properly handle in request when search aggregation is disabled/enabled', async () => { - const mockVerticalSearch = jest.fn().mockReturnValue(Promise.resolve({})); - const mockVerticalAutocomplete = jest.fn().mockReturnValue(Promise.resolve({}));; - const answers = createMockedAnswersHeadless({ - verticalSearch: mockVerticalSearch, - verticalAutocomplete: mockVerticalAutocomplete - }); - answers.setVerticalKey('someKey'); - - // search term aggregation disabled - await answers.executeVerticalAutocomplete(); - await answers.executeVerticalQuery(); - expect(mockVerticalAutocomplete).toHaveBeenLastCalledWith( - expect.not.objectContaining({ autocompleteSessionId: expect.anything }) - ); - expect(mockVerticalSearch).toHaveBeenLastCalledWith( - expect.not.objectContaining({ autocompleteSessionId: expect.anything }) - ); - expect(mockUuid).toHaveBeenCalledTimes(0); - - // search term aggregation enabled - answers.setSearchAggregationEnabled(true); - expect(mockUuid).toHaveBeenCalledTimes(1); - await answers.executeVerticalAutocomplete(); - await answers.executeVerticalQuery(); - expect(mockVerticalAutocomplete).toHaveBeenLastCalledWith( - expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) - ); - expect(mockVerticalSearch).toHaveBeenLastCalledWith( - expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) - ); - expect(mockUuid).toHaveBeenCalledTimes(2); - }) - - it('related autocomplete and query search a grouped with updated uuid after new query search', async () => { - const mockUniversalSearch = jest.fn().mockReturnValue(Promise.resolve({})); - const mockUniversalAutocomplete = jest.fn().mockReturnValue(Promise.resolve({}));; - const answers = createMockedAnswersHeadless({ - universalSearch: mockUniversalSearch, - universalAutocomplete: mockUniversalAutocomplete - }); - answers.setSearchAggregationEnabled(true); - expect(mockUuid).toHaveBeenCalledTimes(1); - uuidString = 'different-uuid-value'; - - //first grouping - await answers.executeUniversalAutocomplete(); - await answers.executeUniversalQuery(); - expect(mockUniversalAutocomplete).toHaveBeenLastCalledWith( - expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) - ); - expect(mockUniversalSearch).toHaveBeenLastCalledWith( - expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) - ); - expect(mockUuid).toHaveBeenCalledTimes(2); - - // second grouping - await answers.executeUniversalAutocomplete(); - await answers.executeUniversalQuery(); - expect(mockUniversalAutocomplete).toHaveBeenLastCalledWith( - expect.objectContaining({ autocompleteSessionId: 'different-uuid-value' }) - ); - expect(mockUniversalSearch).toHaveBeenLastCalledWith( - expect.objectContaining({ autocompleteSessionId: 'different-uuid-value' }) - ); - }) -}) diff --git a/tests/unit/answers-headless.ts b/tests/unit/answers-headless.ts index 848de42a..4917e822 100644 --- a/tests/unit/answers-headless.ts +++ b/tests/unit/answers-headless.ts @@ -230,17 +230,6 @@ describe('setters work as expected', () => { expect(dispatchEventCalls[0][1]).toBe(offset); }); - it('setSearchAggregationEnabled works as expected', () => { - answers.setSearchAggregationEnabled(true); - - const dispatchEventCalls = - mockedStateManager.dispatchEvent.mock.calls; - - expect(dispatchEventCalls.length).toBe(1); - expect(dispatchEventCalls[0][0]).toBe('query/setSearchAggregationEnabled'); - expect(dispatchEventCalls[0][1]).toBe(true); - }); - it('setSearchAggregationId works as expected', () => { answers.setSearchAggregationId('some-uuid-value'); diff --git a/tests/unit/slices/query.ts b/tests/unit/slices/query.ts index 2fa995e7..512707b1 100644 --- a/tests/unit/slices/query.ts +++ b/tests/unit/slices/query.ts @@ -11,7 +11,6 @@ const { setQueryId, setSource, setTrigger, - setSearchAggregationEnabled, setSearchAggregationId } = actions; @@ -48,50 +47,14 @@ describe('query slice reducer works as expected', () => { expect(actualState).toEqual(expectedState); }); - it('setSearchAggregationEnabled action is handled properly when set to false', () => { - const expectedState = { - searchAggregation: { - enabled: false, - id: undefined - } - }; - const actualState = reducer({}, setSearchAggregationEnabled(false)); - expect(actualState).toEqual(expectedState); - }); - - it('setSearchAggregationEnabled action is handled properly when set to true', () => { - const expectedState = { - searchAggregation: { - enabled: true, - id: 'some-uuid-value' - } - }; - const actualState = reducer({}, setSearchAggregationEnabled(true)); - expect(actualState).toEqual(expectedState); - }); - it('setSearchAggregationId action is handled properly', () => { const initalState = { - searchAggregation: { - enabled: true, - id: 'very-old-uuid-value' - } + searchAggregationId: 'very-old-uuid-value' }; const expectedState = { - searchAggregation: { - enabled: true, - id: 'some-uuid-value' - } + searchAggregationId: 'some-uuid-value' }; const actualState = reducer(initalState, setSearchAggregationId('some-uuid-value')); expect(actualState).toEqual(expectedState); }); - - it('setSearchAggregationId action is handled properly when searchAggregation is never set', () => { - const consoleErrorSpy = jest.spyOn(global.console, 'error').mockImplementation(); - const actualState = reducer({}, setSearchAggregationId('some-uuid-value')); - expect(consoleErrorSpy).toHaveBeenCalledTimes(1); - consoleErrorSpy.mockClear(); - expect(actualState).toEqual({}); - }); }); \ No newline at end of file From 3dbe60288a5a9e5af95fc4b63345937dd9eae7ac Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Tue, 23 Nov 2021 17:24:42 -0500 Subject: [PATCH 4/6] get rid of uuid package --- package-lock.json | 18 ++---------------- package.json | 3 +-- src/answers-headless.ts | 1 - tests/unit/slices/query.ts | 4 ---- 4 files changed, 3 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6230df39..1d565fc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,8 +12,7 @@ "@reduxjs/toolkit": "^1.6.0", "@yext/answers-core": "file:~/answers-core", "js-levenshtein": "^1.1.6", - "redux-thunk": "^2.3.0", - "uuid": "^8.3.2" + "redux-thunk": "^2.3.0" }, "devDependencies": { "@babel/preset-env": "^7.14.7", @@ -36,7 +35,7 @@ }, "../answers-core": { "name": "@yext/answers-core", - "version": "1.5.0-beta.0", + "version": "1.5.0-beta.1", "license": "BSD-3-Clause", "dependencies": { "@babel/runtime-corejs3": "^7.12.5", @@ -7948,14 +7947,6 @@ "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", "dev": true }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -14165,11 +14156,6 @@ "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", "dev": true }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", diff --git a/package.json b/package.json index 442e72be..23fcf8d4 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,7 @@ "@reduxjs/toolkit": "^1.6.0", "@yext/answers-core": "file:~/answers-core", "js-levenshtein": "^1.1.6", - "redux-thunk": "^2.3.0", - "uuid": "^8.3.2" + "redux-thunk": "^2.3.0" }, "devDependencies": { "@babel/preset-env": "^7.14.7", diff --git a/src/answers-headless.ts b/src/answers-headless.ts index b85d8730..edf6621f 100644 --- a/src/answers-headless.ts +++ b/src/answers-headless.ts @@ -26,7 +26,6 @@ import HttpManager from './http-manager'; import answersUtilities from './answers-utilities'; import { SelectableFilter } from './models/utils/selectablefilter'; import { transformFiltersToCoreFormat } from './utils/transform-filters'; -import { v4 as uuidv4 } from 'uuid'; export default class AnswersHeadless { public readonly utilities = answersUtilities; diff --git a/tests/unit/slices/query.ts b/tests/unit/slices/query.ts index 512707b1..fc8205cd 100644 --- a/tests/unit/slices/query.ts +++ b/tests/unit/slices/query.ts @@ -1,10 +1,6 @@ import { QuerySource, QueryTrigger } from '@yext/answers-core'; import createQuerySlice from '../../../src/slices/query'; -jest.mock('uuid', () => ({ - v4: jest.fn(() => 'some-uuid-value') -})); - const { reducer, actions } = createQuerySlice(''); const { setInput, From a4d2a0e09734f6ef892b78edb33694d761ae1d3e Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 23 Nov 2021 22:25:32 +0000 Subject: [PATCH 5/6] Automated update to THIRD-PARTY-NOTICES from github action's 3rd party notices check --- THIRD-PARTY-NOTICES | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/THIRD-PARTY-NOTICES b/THIRD-PARTY-NOTICES index e2aab506..d71b2a88 100644 --- a/THIRD-PARTY-NOTICES +++ b/THIRD-PARTY-NOTICES @@ -248,22 +248,4 @@ SOFTWARE. ----------- -The following NPM package may be included in this product: - - - uuid@8.3.2 - -This package contains the following license and notice below: - -The MIT License (MIT) - -Copyright (c) 2010-2020 Robert Kieffer and other contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ------------ - This file was generated with generate-license-file! https://www.npmjs.com/package/generate-license-file \ No newline at end of file From 4a41dc99192f98175a34662444135b10aef8bf20 Mon Sep 17 00:00:00 2001 From: Yen Truong Date: Tue, 23 Nov 2021 17:52:36 -0500 Subject: [PATCH 6/6] name change --- src/answers-headless.ts | 12 ++++++------ src/models/slices/query.ts | 2 +- src/slices/query.ts | 4 ++-- tests/integration/query.ts | 4 ++-- tests/unit/answers-headless.ts | 6 +++--- tests/unit/slices/query.ts | 10 +++++----- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/answers-headless.ts b/src/answers-headless.ts index edf6621f..bb9ccda9 100644 --- a/src/answers-headless.ts +++ b/src/answers-headless.ts @@ -48,8 +48,8 @@ export default class AnswersHeadless { this.stateManager.dispatchEvent('query/setSource', source); } - setSearchAggregationId(uuid: string): void { - this.stateManager.dispatchEvent('query/setSearchAggregationId', uuid); + setAutocompleteSessionId(uuid: string): void { + this.stateManager.dispatchEvent('query/setAutocompleteSessionId', uuid); } setVerticalKey(verticalKey: string): void { @@ -138,7 +138,7 @@ export default class AnswersHeadless { const sessionId = this.state.sessionTracking.sessionId; const { referrerPageUrl, context } = this.state.meta; const { userLocation } = this.state.location; - const autocompleteSessionId = this.state.query.searchAggregationId; + const autocompleteSessionId = this.state.query.autocompleteSessionId; const response = await this.core.universalSearch({ query: input || '', @@ -151,7 +151,7 @@ export default class AnswersHeadless { location: userLocation, context, referrerPageUrl, - autocompleteSessionId + ...(autocompleteSessionId && { autocompleteSessionId }) }); const latestResponseId = this.httpManager.getLatestResponseId('universalQuery'); @@ -197,7 +197,7 @@ export default class AnswersHeadless { const sortBys = this.state.filters?.sortBys; const { referrerPageUrl, context } = this.state.meta; const { userLocation } = this.state.location; - const autocompleteSessionId = this.state.query.searchAggregationId; + const autocompleteSessionId = this.state.query.autocompleteSessionId; const facetsToApply = facets?.map(facet => { return { @@ -223,7 +223,7 @@ export default class AnswersHeadless { sortBys, context, referrerPageUrl, - autocompleteSessionId + ...(autocompleteSessionId && { autocompleteSessionId }) }; const response = await this.core.verticalSearch(request); const latestResponseId = this.httpManager.getLatestResponseId('verticalQuery'); diff --git a/src/models/slices/query.ts b/src/models/slices/query.ts index 922c1c4f..e4f4e9bc 100644 --- a/src/models/slices/query.ts +++ b/src/models/slices/query.ts @@ -7,5 +7,5 @@ export interface QueryState { querySource?: QuerySource, mostRecentSearch?: string, searchIntents?: SearchIntent[], - searchAggregationId?: string + autocompleteSessionId?: string } \ No newline at end of file diff --git a/src/slices/query.ts b/src/slices/query.ts index 2cc7a179..7990e1ac 100644 --- a/src/slices/query.ts +++ b/src/slices/query.ts @@ -17,8 +17,8 @@ const reducers = { setQueryId: (state: QueryState, action: PayloadAction) => { state.queryId = action.payload; }, - setSearchAggregationId: (state: QueryState, action: PayloadAction) => { - state.searchAggregationId = action.payload; + setAutocompleteSessionId: (state: QueryState, action: PayloadAction) => { + state.autocompleteSessionId = action.payload; }, setMostRecentSearch: (state: QueryState, action: PayloadAction) => { state.mostRecentSearch = action.payload; diff --git a/tests/integration/query.ts b/tests/integration/query.ts index d68013b2..f39eccb6 100644 --- a/tests/integration/query.ts +++ b/tests/integration/query.ts @@ -33,7 +33,7 @@ it('related query search a grouped with updated uuid', async () => { }); answers.setVerticalKey('vertical-key'); - answers.setSearchAggregationId('some-uuid-value'); + answers.setAutocompleteSessionId('some-uuid-value'); await answers.executeUniversalQuery(); await answers.executeVerticalQuery(); expect(mockUniversalSearch).toHaveBeenLastCalledWith( @@ -43,7 +43,7 @@ it('related query search a grouped with updated uuid', async () => { expect.objectContaining({ autocompleteSessionId: 'some-uuid-value' }) ); - answers.setSearchAggregationId('different-uuid-value'); + answers.setAutocompleteSessionId('different-uuid-value'); await answers.executeUniversalQuery(); await answers.executeVerticalQuery(); expect(mockUniversalSearch).toHaveBeenLastCalledWith( diff --git a/tests/unit/answers-headless.ts b/tests/unit/answers-headless.ts index 4917e822..7d483660 100644 --- a/tests/unit/answers-headless.ts +++ b/tests/unit/answers-headless.ts @@ -230,14 +230,14 @@ describe('setters work as expected', () => { expect(dispatchEventCalls[0][1]).toBe(offset); }); - it('setSearchAggregationId works as expected', () => { - answers.setSearchAggregationId('some-uuid-value'); + it('setAutocompleteSessionId works as expected', () => { + answers.setAutocompleteSessionId('some-uuid-value'); const dispatchEventCalls = mockedStateManager.dispatchEvent.mock.calls; expect(dispatchEventCalls.length).toBe(1); - expect(dispatchEventCalls[0][0]).toBe('query/setSearchAggregationId'); + expect(dispatchEventCalls[0][0]).toBe('query/setAutocompleteSessionId'); expect(dispatchEventCalls[0][1]).toBe('some-uuid-value'); }); }); diff --git a/tests/unit/slices/query.ts b/tests/unit/slices/query.ts index fc8205cd..4d83b760 100644 --- a/tests/unit/slices/query.ts +++ b/tests/unit/slices/query.ts @@ -7,7 +7,7 @@ const { setQueryId, setSource, setTrigger, - setSearchAggregationId + setAutocompleteSessionId } = actions; describe('query slice reducer works as expected', () => { @@ -43,14 +43,14 @@ describe('query slice reducer works as expected', () => { expect(actualState).toEqual(expectedState); }); - it('setSearchAggregationId action is handled properly', () => { + it('setAutocompleteSessionId action is handled properly', () => { const initalState = { - searchAggregationId: 'very-old-uuid-value' + autocompleteSessionId: 'very-old-uuid-value' }; const expectedState = { - searchAggregationId: 'some-uuid-value' + autocompleteSessionId: 'some-uuid-value' }; - const actualState = reducer(initalState, setSearchAggregationId('some-uuid-value')); + const actualState = reducer(initalState, setAutocompleteSessionId('some-uuid-value')); expect(actualState).toEqual(expectedState); }); }); \ No newline at end of file