diff --git a/.cspell.json b/.cspell.json index 31c5434cbcd..978e7a167fa 100644 --- a/.cspell.json +++ b/.cspell.json @@ -19,7 +19,6 @@ "behaviour", "bloup", "bpsb", - "btoashim", "CAPI", "cfcomment", "cfpage", diff --git a/.github/actions/e2e-atomic-screenshots/action.yml b/.github/actions/e2e-atomic-screenshots/action.yml index b8eb01d1d54..76190d0b5d8 100644 --- a/.github/actions/e2e-atomic-screenshots/action.yml +++ b/.github/actions/e2e-atomic-screenshots/action.yml @@ -8,6 +8,8 @@ inputs: runs: using: composite steps: + - run: npx cypress install + shell: bash - uses: cypress-io/github-action@v5 name: Run Cypress with: diff --git a/.github/actions/e2e-atomic/action.yml b/.github/actions/e2e-atomic/action.yml index 32e0fb6978f..d35dcdfb723 100644 --- a/.github/actions/e2e-atomic/action.yml +++ b/.github/actions/e2e-atomic/action.yml @@ -17,6 +17,8 @@ inputs: runs: using: composite steps: + - run: npx cypress install + shell: bash - uses: cypress-io/github-action@v5 name: Run Cypress with: diff --git a/package-lock.json b/package-lock.json index c28f680b347..8505768392f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6158,6 +6158,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "dev": true, "engines": { "node": ">=14" } @@ -20468,17 +20469,12 @@ "@types/istanbul-lib-report": "*" } }, - "node_modules/@types/jasmine": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-5.1.4.tgz", - "integrity": "sha512-px7OMFO/ncXxixDe1zR13V1iycqWae0MxTaw62RpFlksUi5QuNWgQJFkTQjIOvrmutJbI7Fp2Y2N1F6D2R4G6w==", - "dev": true - }, "node_modules/@types/jest": { "version": "29.5.12", "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -25502,6 +25498,40 @@ "typescript": ">=4" } }, + "node_modules/coveo.analytics": { + "version": "2.30.26", + "resolved": "https://registry.npmjs.org/coveo.analytics/-/coveo.analytics-2.30.26.tgz", + "integrity": "sha512-HeKmwt254jHws2w7nCklKa8VCo0vnmZGv79/rXqJcNZraig5XQxBQoLbpphP3/L+SoP4F/m5nAOdE1C0QbaSuQ==", + "license": "MIT", + "dependencies": { + "@types/uuid": "^9.0.0", + "cross-fetch": "^3.1.5", + "react-native-get-random-values": "^1.11.0", + "uuid": "^9.0.0" + } + }, + "node_modules/coveo.analytics/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/coveo.analytics/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -49588,6 +49618,7 @@ "version": "5.28.4", "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -51966,7 +51997,6 @@ "@angular/cli": "17.3.9", "@angular/compiler-cli": "17.3.12", "@coveo/headless": "2.80.0", - "@types/jasmine": "5.1.4", "@types/node": "20.14.12", "jasmine-core": "5.2.0", "karma": "6.4.3", @@ -52122,6 +52152,7 @@ "@coveo/headless": "2.80.0", "@coveo/release": "1.0.0", "@rollup/plugin-commonjs": "^25.0.0", + "@rollup/plugin-json": "6.1.0", "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-replace": "^5.0.0", "@rollup/plugin-terser": "0.4.4", @@ -55294,8 +55325,7 @@ "node-abort-controller": "^3.0.0", "pino": "8.21.0", "redux-thunk": "3.1.0", - "ts-debounce": "4.0.0", - "undici": "5.28.4" + "ts-debounce": "4.0.0" }, "devDependencies": { "@coveo/release": "1.0.0", @@ -55340,8 +55370,7 @@ "publint": "0.2.9", "rimraf": "5.0.9", "ts-jest": "29.2.3", - "typescript": "5.4.5", - "undici": "5.28.4" + "typescript": "5.4.5" }, "engines": { "node": "^20.9.0" @@ -55654,25 +55683,6 @@ } } }, - "packages/headless/node_modules/coveo.analytics": { - "version": "2.30.26", - "resolved": "https://registry.npmjs.org/coveo.analytics/-/coveo.analytics-2.30.26.tgz", - "integrity": "sha512-HeKmwt254jHws2w7nCklKa8VCo0vnmZGv79/rXqJcNZraig5XQxBQoLbpphP3/L+SoP4F/m5nAOdE1C0QbaSuQ==", - "dependencies": { - "@types/uuid": "^9.0.0", - "cross-fetch": "^3.1.5", - "react-native-get-random-values": "^1.11.0", - "uuid": "^9.0.0" - } - }, - "packages/headless/node_modules/cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, "packages/headless/node_modules/dayjs": { "version": "1.11.12", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.12.tgz", @@ -57588,7 +57598,6 @@ "@angular-devkit/build-angular": "17.3.9", "@angular/cli": "17.3.9", "@angular/compiler-cli": "17.3.12", - "@types/jasmine": "5.1.4", "@types/node": "20.14.12", "@typescript-eslint/eslint-plugin": "^7.0.0", "cypress": "13.13.1", diff --git a/packages/atomic-angular/package.json b/packages/atomic-angular/package.json index aff53dc7b4b..a10a83396ac 100644 --- a/packages/atomic-angular/package.json +++ b/packages/atomic-angular/package.json @@ -31,7 +31,6 @@ "@angular/cli": "17.3.9", "@angular/compiler-cli": "17.3.12", "@coveo/headless": "2.80.0", - "@types/jasmine": "5.1.4", "@types/node": "20.14.12", "jasmine-core": "5.2.0", "karma": "6.4.3", diff --git a/packages/atomic-react/package.json b/packages/atomic-react/package.json index 3bac62dbbba..c9846dcda70 100644 --- a/packages/atomic-react/package.json +++ b/packages/atomic-react/package.json @@ -32,11 +32,13 @@ "@coveo/atomic": "2.78.0" }, "devDependencies": { - "@coveo/release": "1.0.0", "@coveo/headless": "2.80.0", + "@coveo/release": "1.0.0", "@rollup/plugin-commonjs": "^25.0.0", + "@rollup/plugin-json": "6.1.0", "@rollup/plugin-node-resolve": "^15.0.0", "@rollup/plugin-replace": "^5.0.0", + "@rollup/plugin-terser": "0.4.4", "@rollup/plugin-typescript": "^11.0.0", "@types/node": "20.14.12", "@types/react": "18.3.3", @@ -45,8 +47,7 @@ "react": "18.3.1", "react-dom": "18.3.1", "rollup": "3.29.4", - "rollup-plugin-polyfill-node": "^0.13.0", - "@rollup/plugin-terser": "0.4.4" + "rollup-plugin-polyfill-node": "^0.13.0" }, "peerDependencies": { "@coveo/headless": "2.80.0", diff --git a/packages/atomic-react/rollup.config.mjs b/packages/atomic-react/rollup.config.mjs index c960ca0ac2a..0e73c0d81c0 100644 --- a/packages/atomic-react/rollup.config.mjs +++ b/packages/atomic-react/rollup.config.mjs @@ -1,4 +1,5 @@ import commonjs from '@rollup/plugin-commonjs'; +import json from '@rollup/plugin-json'; import {nodeResolve} from '@rollup/plugin-node-resolve'; import replace from '@rollup/plugin-replace'; import terser from '@rollup/plugin-terser'; @@ -54,6 +55,7 @@ const outputIIFECommerce = ({minify}) => ({ }); const plugins = [ + json(), nodePolyfills(), typescript({tsconfig: 'tsconfig.iife.json'}), commonjs(), diff --git a/packages/atomic/src/components/search/result-template-components/result-template-decorators.spec.tsx b/packages/atomic/src/components/search/result-template-components/result-template-decorators.spec.tsx index c9856778a6e..6f779cbd307 100644 --- a/packages/atomic/src/components/search/result-template-components/result-template-decorators.spec.tsx +++ b/packages/atomic/src/components/search/result-template-components/result-template-decorators.spec.tsx @@ -1,4 +1,8 @@ -import {buildInteractiveResult, TestUtils} from '@coveo/headless'; +import { + buildInteractiveResult, + buildSearchEngine, + Result, +} from '@coveo/headless'; import {h} from '@stencil/core'; import {newSpecPage, SpecPage} from '@stencil/core/testing'; import {MissingParentError} from '../../common/item-list/item-decorators'; @@ -54,18 +58,21 @@ describe('resultContext method', () => { }); it("revolves the bindings when it's a child of an atomic-result element", async () => { - const mockEngine = TestUtils.buildMockSearchEngine( - TestUtils.createMockState() - ); - const mockResult = TestUtils.buildMockResult(); + const engine = buildSearchEngine({ + configuration: { + accessToken: 'accessToken', + organizationId: 'organizationId', + }, + }); + const mockResult = jest.mocked({} as Result); const page = await newSpecPage({ components: [AtomicResult], template: () => ( { it(`when "engine" is defined should render the content `, () => { component['bindings'] = { - engine: TestUtils.buildMockSearchEngine(TestUtils.createMockState()), + engine: buildSearchEngine({ + configuration: { + accessToken: 'accessToken', + organizationId: 'organizationId', + }, + }), i18n: i18next, store: createAtomicStore(), interfaceElement: document.createElement('atomic-search-interface'), @@ -127,7 +132,12 @@ describe('BindStateToController decorator', () => { console.error = jest.fn(); component = { bindings: { - engine: TestUtils.buildMockSearchEngine(TestUtils.createMockState()), + engine: buildSearchEngine({ + configuration: { + accessToken: 'accessToken', + organizationId: 'organizationId', + }, + }), i18n: i18next, store: createAtomicStore(), interfaceElement: document.createElement('atomic-search-interface'), diff --git a/packages/atomic/src/utils/result-utils.spec.ts b/packages/atomic/src/utils/result-utils.spec.ts index 630cf07c6fa..eb3676bf98e 100644 --- a/packages/atomic/src/utils/result-utils.spec.ts +++ b/packages/atomic/src/utils/result-utils.spec.ts @@ -1,24 +1,23 @@ import { buildSearchEngine, getSampleSearchEngineConfiguration, + Raw, + Result, } from '@coveo/headless'; -import {TestUtils} from '@coveo/headless'; import {Bindings} from '../components/search/atomic-search-interface/atomic-search-interface'; import {buildStringTemplateFromResult} from './result-utils'; describe('buildStringTemplateFromResult', () => { + const mockRaw = jest.mocked({source: 'the source'} as Raw); + const mockResult = jest.mocked({ + title: 'foo', + uri: 'http://uri.foo.com', + raw: mockRaw, + } as Result); const engine = buildSearchEngine({ configuration: getSampleSearchEngineConfiguration(), }); const bindings = {engine} as Bindings; - const result = TestUtils.buildMockResult({ - title: 'foo', - uri: 'http://uri.foo.com', - raw: { - ...TestUtils.buildMockResult().raw, - source: 'the source', - }, - }); it('should create string templates', () => { const templates = [ @@ -30,9 +29,9 @@ describe('buildStringTemplateFromResult', () => { ]; templates.forEach((template) => - expect(buildStringTemplateFromResult(template.in, result, bindings)).toBe( - template.out - ) + expect( + buildStringTemplateFromResult(template.in, mockResult, bindings) + ).toBe(template.out) ); }); @@ -41,7 +40,7 @@ describe('buildStringTemplateFromResult', () => { expect( buildStringTemplateFromResult( '${title}/${raw.notafield}', - result, + mockResult, bindings ) ).toBe('foo/'); diff --git a/packages/headless-react/package.json b/packages/headless-react/package.json index d7c82c5f7e3..a34ecd9d63a 100644 --- a/packages/headless-react/package.json +++ b/packages/headless-react/package.json @@ -51,8 +51,7 @@ "publint": "0.2.9", "rimraf": "5.0.9", "ts-jest": "29.2.3", - "typescript": "5.4.5", - "undici": "5.28.4" + "typescript": "5.4.5" }, "peerDependencies": { "react": "^18", diff --git a/packages/headless/esbuild.mjs b/packages/headless/esbuild.mjs index 0db3fbab006..45b91b597a1 100644 --- a/packages/headless/esbuild.mjs +++ b/packages/headless/esbuild.mjs @@ -174,6 +174,15 @@ function resolveEsm(moduleName) { ); } +function resolveBrowser(moduleName) { + const packageJsonPath = require.resolve(`${moduleName}/package.json`); + const packageJson = require(packageJsonPath); + return resolve( + dirname(packageJsonPath), + packageJson['browser'] || packageJson['main'] + ); +} + /** * @param {import('esbuild').BuildOptions} options * @returns {Promise} @@ -190,10 +199,7 @@ async function buildBrowserConfig(options, outDir) { plugins: [ alias({ 'coveo.analytics': resolveEsm('coveo.analytics'), - '@coveo/please-give-me-fetch': resolve( - './ponyfills', - 'fetch-ponyfill-browser.js' - ), + pino: resolveBrowser('pino'), '@coveo/pendragon': resolve('./ponyfills', 'magic-cookie-browser.js'), }), ...(options.plugins || []), @@ -227,6 +233,7 @@ const nodeEsm = Object.entries(useCaseEntries).map((entry) => { entryPoints: [entryPoint], outfile, format: 'esm', + external: ['pino'], }, dir ); @@ -244,11 +251,7 @@ async function buildNodeConfig(options, outDir) { treeShaking: true, plugins: [ alias({ - 'coveo.analytics': require.resolve('coveo.analytics'), - '@coveo/please-give-me-fetch': resolve( - './ponyfills', - 'fetch-ponyfill-node.js' - ), + 'coveo.analytics': resolveEsm('coveo.analytics'), '@coveo/pendragon': resolve('./ponyfills', 'magic-cookie-node.js'), }), ], diff --git a/packages/headless/jest.config.js b/packages/headless/jest.config.js index a900fdb1e4b..3199372c884 100644 --- a/packages/headless/jest.config.js +++ b/packages/headless/jest.config.js @@ -3,10 +3,7 @@ process.env.TZ = 'Australia/Eucla'; module.exports = { preset: 'ts-jest', silent: true, - setupFiles: ['./jest.setup.js'], moduleNameMapper: { - '@coveo/please-give-me-fetch': - '/ponyfills/fetch-ponyfill-browser.js', '@coveo/pendragon': '/ponyfills/magic-cookie-node.js', }, }; diff --git a/packages/headless/jest.setup.js b/packages/headless/jest.setup.js deleted file mode 100644 index 9cf2ccfc13e..00000000000 --- a/packages/headless/jest.setup.js +++ /dev/null @@ -1,3 +0,0 @@ -const polyfill = require('./src/api/analytics/analytics-crypto-polyfill'); - -polyfill.polyfillCryptoNode(); diff --git a/packages/headless/package.json b/packages/headless/package.json index ec35637761a..0248fc4f90f 100644 --- a/packages/headless/package.json +++ b/packages/headless/package.json @@ -179,7 +179,6 @@ "@coveo/relay-event-types": "9.4.0", "@microsoft/fetch-event-source": "2.0.1", "@reduxjs/toolkit": "2.2.7", - "abab": "2.0.6", "abortcontroller-polyfill": "1.7.5", "coveo.analytics": "2.30.26", "dayjs": "1.11.12", @@ -189,8 +188,7 @@ "node-abort-controller": "^3.0.0", "pino": "8.21.0", "redux-thunk": "3.1.0", - "ts-debounce": "4.0.0", - "undici": "5.28.4" + "ts-debounce": "4.0.0" }, "devDependencies": { "@coveo/release": "1.0.0", diff --git a/packages/headless/ponyfills/fetch-ponyfill-browser.js b/packages/headless/ponyfills/fetch-ponyfill-browser.js deleted file mode 100644 index 23e48e7cbb7..00000000000 --- a/packages/headless/ponyfills/fetch-ponyfill-browser.js +++ /dev/null @@ -1,2 +0,0 @@ -// TODO V3: remove this file, global fetch will be a runtime requirement. -module.exports = fetch; diff --git a/packages/headless/ponyfills/fetch-ponyfill-node.js b/packages/headless/ponyfills/fetch-ponyfill-node.js deleted file mode 100644 index 77b63279ebd..00000000000 --- a/packages/headless/ponyfills/fetch-ponyfill-node.js +++ /dev/null @@ -1,2 +0,0 @@ -// TODO V3: remove this file, global fetch will be a runtime requirement. -module.exports = typeof fetch === 'undefined' ? require('undici').fetch : fetch; diff --git a/packages/headless/src/api/analytics/analytics-crypto-polyfill.ts b/packages/headless/src/api/analytics/analytics-crypto-polyfill.ts deleted file mode 100644 index 2a8283852b4..00000000000 --- a/packages/headless/src/api/analytics/analytics-crypto-polyfill.ts +++ /dev/null @@ -1,24 +0,0 @@ -interface CryptoModuleInNode { - getRandomValues?: typeof crypto.getRandomValues; - webcrypto?: {getRandomValues: typeof crypto.getRandomValues}; -} - -const getGlobalCrypto = () => global.crypto as CryptoModuleInNode; - -// This polyfill is needed for node environment below 20. -// This could be removed when Headless no longer needs to support NodeJS below that version; -export const polyfillCryptoNode = () => { - if (typeof window !== 'undefined') { - return; - } - if (!getGlobalCrypto()) { - global.crypto = require('crypto'); - } - - if (!getGlobalCrypto().getRandomValues && getGlobalCrypto().webcrypto) { - global.crypto.getRandomValues = - getGlobalCrypto().webcrypto!.getRandomValues.bind( - getGlobalCrypto().webcrypto - ); - } -}; diff --git a/packages/headless/src/api/platform-client.test.ts b/packages/headless/src/api/platform-client.test.ts index f3c7ffa8d4a..cc8f29c4dc7 100644 --- a/packages/headless/src/api/platform-client.test.ts +++ b/packages/headless/src/api/platform-client.test.ts @@ -1,6 +1,3 @@ -//TODO V3: remove this import, global fetch is a requirement now. -//@ts-expect-error package is just an alias. -import fetch from '@coveo/please-give-me-fetch'; import * as BackOff from 'exponential-backoff'; import pino from 'pino'; import {allValidPlatformCombination} from '../test/platform-url'; @@ -19,10 +16,9 @@ import { PreprocessRequest, } from './preprocess-request'; -jest.mock('@coveo/please-give-me-fetch'); - const {Response} = jest.requireActual('node-fetch'); -const mockFetch = fetch as jest.Mock; +global.fetch = jest.fn(); +const mockFetch = global.fetch as jest.Mock; describe('url helper', () => { it('return the correct #platformUrl()', () => { diff --git a/packages/headless/src/api/platform-client.ts b/packages/headless/src/api/platform-client.ts index 45e759d4c68..7072e0b2ba9 100644 --- a/packages/headless/src/api/platform-client.ts +++ b/packages/headless/src/api/platform-client.ts @@ -1,6 +1,3 @@ -//TODO V3: remove this import, global fetch is a requirement now. -//@ts-expect-error package is just an alias. -import fetch from '@coveo/please-give-me-fetch'; import {backOff} from 'exponential-backoff'; import {Logger} from 'pino'; import {DisconnectedError, ExpiredTokenError} from '../utils/errors'; diff --git a/packages/headless/src/app/search-engine/jwt-reducer.ts b/packages/headless/src/app/search-engine/jwt-reducer.ts index c48afb2827a..523cab76e47 100644 --- a/packages/headless/src/app/search-engine/jwt-reducer.ts +++ b/packages/headless/src/app/search-engine/jwt-reducer.ts @@ -1,6 +1,5 @@ import {isNullOrUndefined} from '@coveo/bueno'; import {createReducer, Reducer} from '@reduxjs/toolkit'; -import {atob as atobShim} from 'abab'; import P, {Logger} from 'pino'; import { updateAnalyticsConfiguration, @@ -70,10 +69,9 @@ const shouldReconcileValues = ( const decodeJSONWebToken = (token: string): CoveoJSONWebToken | false => { try { - const atobImplementation = typeof atob !== 'undefined' ? atob : atobShim; const base64Url = token.split('.')[1]; const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/'); - const base64decoded = atobImplementation(base64); + const base64decoded = atob(base64); if (!base64decoded) { return false; } diff --git a/packages/headless/src/case-assist.index.ts b/packages/headless/src/case-assist.index.ts index 258f66b319d..5af695f4c5c 100644 --- a/packages/headless/src/case-assist.index.ts +++ b/packages/headless/src/case-assist.index.ts @@ -1,6 +1,3 @@ -import {polyfillCryptoNode} from './api/analytics/analytics-crypto-polyfill'; - -polyfillCryptoNode(); // 3rd Party Libraries export type {Unsubscribe, Middleware} from '@reduxjs/toolkit'; export type {Relay} from '@coveo/relay'; diff --git a/packages/headless/src/commerce.index.ts b/packages/headless/src/commerce.index.ts index 69fff8d0b8a..ef62cba7f75 100644 --- a/packages/headless/src/commerce.index.ts +++ b/packages/headless/src/commerce.index.ts @@ -1,10 +1,8 @@ -import {polyfillCryptoNode} from './api/analytics/analytics-crypto-polyfill'; import * as Selectors from './selectors/commerce-selectors.index'; import * as HighlightUtils from './utils/highlight'; export type {HighlightKeyword} from './utils/highlight'; -polyfillCryptoNode(); export type {Unsubscribe, Middleware} from '@reduxjs/toolkit'; export type {Relay} from '@coveo/relay'; diff --git a/packages/headless/src/features/insight-user-actions/insight-user-actions-preprocessing.test.ts b/packages/headless/src/features/insight-user-actions/insight-user-actions-preprocessing.test.ts index 10f3ce03434..90f9032a5c8 100644 --- a/packages/headless/src/features/insight-user-actions/insight-user-actions-preprocessing.test.ts +++ b/packages/headless/src/features/insight-user-actions/insight-user-actions-preprocessing.test.ts @@ -27,7 +27,7 @@ const actionsToExclude = ['useless_event']; const fakeActions = [ { - time: createRelativeDate(caseCreationDate, -1, 0).getTime(), + time: createRelativeDate(caseCreationDate, -15, 0).getTime(), name: 'Custom', value: { event_type: 'smartSnippetSuggestions', @@ -36,7 +36,16 @@ const fakeActions = [ }, }, { - time: createRelativeDate(caseCreationDate, 2, 0).getTime(), + time: createRelativeDate(caseCreationDate, 10, 0).getTime(), + name: 'Click', + value: { + title: 'title', + uri_hash: 'caCgiG2JPzjZfS7G', + origin_level_1: 'in-product-help', + }, + }, + { + time: createRelativeDate(caseCreationDate, 30, 0).getTime(), name: 'Click', value: { title: 'title', @@ -156,7 +165,17 @@ describe('insight user actions preprocessing', () => { }, { actionType: 'CLICK', - timestamp: new Date('Tue Mar 31 2022 16:32:00 GMT').valueOf(), + timestamp: new Date('Tue Mar 31 2022 17:00:00 GMT').valueOf(), + eventData: {}, + searchHub: 'in-product-help', + document: { + title: 'title', + uriHash: 'caCgiG2JPzjZfS7G', + }, + }, + { + actionType: 'CLICK', + timestamp: new Date('Tue Mar 31 2022 16:40:00 GMT').valueOf(), eventData: {}, searchHub: 'in-product-help', document: { @@ -166,7 +185,7 @@ describe('insight user actions preprocessing', () => { }, { actionType: 'CUSTOM', - timestamp: new Date('Tue Mar 31 2022 16:29:00 GMT').valueOf(), + timestamp: new Date('Tue Mar 31 2022 16:15:00 GMT').valueOf(), eventData: { type: 'smartSnippetSuggestions', value: 'expandSmartSnippetSuggestion', @@ -397,12 +416,22 @@ describe('insight user actions preprocessing', () => { }, ], session: { - start: new Date('Tue Mar 31 2022 16:29:00 GMT').valueOf(), - end: new Date('Tue Mar 31 2022 16:32:00 GMT').valueOf(), + start: new Date('Tue Mar 31 2022 16:15:00 GMT').valueOf(), + end: new Date('Tue Mar 31 2022 17:00:00 GMT').valueOf(), actions: [ { actionType: 'CLICK', - timestamp: new Date('Tue Mar 31 2022 16:32:00 GMT').valueOf(), + timestamp: new Date('Tue Mar 31 2022 17:00:00 GMT').valueOf(), + eventData: {}, + searchHub: 'in-product-help', + document: { + title: 'title', + uriHash: 'caCgiG2JPzjZfS7G', + }, + }, + { + actionType: 'CLICK', + timestamp: new Date('Tue Mar 31 2022 16:40:00 GMT').valueOf(), eventData: {}, searchHub: 'in-product-help', document: { @@ -417,7 +446,7 @@ describe('insight user actions preprocessing', () => { }, { actionType: 'CUSTOM', - timestamp: new Date('Tue Mar 31 2022 16:29:00 GMT').valueOf(), + timestamp: new Date('Tue Mar 31 2022 16:15:00 GMT').valueOf(), eventData: { type: 'smartSnippetSuggestions', value: 'expandSmartSnippetSuggestion', @@ -481,7 +510,7 @@ describe('insight user actions preprocessing', () => { expect(timeline.precedingSessions.length).toEqual( expectedTimeline.precedingSessions.length ); - expect(timeline.session?.actions[1].actionType).toEqual( + expect(timeline.session?.actions[2].actionType).toEqual( UserActionType.TICKET_CREATION ); }); @@ -610,13 +639,25 @@ describe('insight user actions preprocessing', () => { ], }, { - start: new Date('Tue Mar 31 2022 16:29:00 GMT').valueOf(), - end: new Date('Tue Mar 31 2022 16:32:00 GMT').valueOf(), + start: new Date('Tue Mar 31 2022 16:15:00 GMT').valueOf(), + end: new Date('Tue Mar 31 2022 17:00:00 GMT').valueOf(), actions: [ { actionType: 'CLICK', timestamp: new Date( - 'Tue Mar 31 2022 16:32:00 GMT' + 'Tue Mar 31 2022 17:00:00 GMT' + ).valueOf(), + eventData: {}, + searchHub: 'in-product-help', + document: { + title: 'title', + uriHash: 'caCgiG2JPzjZfS7G', + }, + }, + { + actionType: 'CLICK', + timestamp: new Date( + 'Tue Mar 31 2022 16:40:00 GMT' ).valueOf(), eventData: {}, searchHub: 'in-product-help', @@ -628,7 +669,7 @@ describe('insight user actions preprocessing', () => { { actionType: 'CUSTOM', timestamp: new Date( - 'Tue Mar 31 2022 16:29:00 GMT' + 'Tue Mar 31 2022 16:15:00 GMT' ).valueOf(), eventData: { type: 'smartSnippetSuggestions', @@ -881,12 +922,19 @@ describe('insight user actions preprocessing', () => { }, ], session: { - start: new Date('Tue Mar 31 2022 16:29:00 GMT').valueOf(), - end: new Date('Tue Mar 31 2022 16:32:00 GMT').valueOf(), + start: new Date('Tue Mar 31 2022 16:15:00 GMT').valueOf(), + end: new Date('Tue Mar 31 2022 17:00:00 GMT').valueOf(), actions: [ { actionType: 'CLICK', - timestamp: new Date('Tue Mar 31 2022 16:32:00 GMT').valueOf(), + timestamp: new Date('Tue Mar 31 2022 17:00:00 GMT').valueOf(), + eventData: {}, + searchHub: 'in-product-help', + document: {title: 'title', uriHash: 'caCgiG2JPzjZfS7G'}, + }, + { + actionType: 'CLICK', + timestamp: new Date('Tue Mar 31 2022 16:40:00 GMT').valueOf(), eventData: {}, searchHub: 'in-product-help', document: {title: 'title', uriHash: 'caCgiG2JPzjZfS7G'}, @@ -898,7 +946,7 @@ describe('insight user actions preprocessing', () => { }, { actionType: 'CUSTOM', - timestamp: new Date('Tue Mar 31 2022 16:29:00 GMT').valueOf(), + timestamp: new Date('Tue Mar 31 2022 16:15:00 GMT').valueOf(), eventData: { type: 'smartSnippetSuggestions', value: 'expandSmartSnippetSuggestion', @@ -953,7 +1001,7 @@ describe('insight user actions preprocessing', () => { expect(preprocessedTimeline.followingSessions.length).toEqual( expectedTimeline.followingSessions.length ); - expect(preprocessedTimeline.session?.actions[1].actionType).toEqual( + expect(preprocessedTimeline.session?.actions[2].actionType).toEqual( UserActionType.TICKET_CREATION ); }); diff --git a/packages/headless/src/features/insight-user-actions/insight-user-actions-preprocessing.ts b/packages/headless/src/features/insight-user-actions/insight-user-actions-preprocessing.ts index ccc51272ee5..cf4a15fe027 100644 --- a/packages/headless/src/features/insight-user-actions/insight-user-actions-preprocessing.ts +++ b/packages/headless/src/features/insight-user-actions/insight-user-actions-preprocessing.ts @@ -232,7 +232,7 @@ export const splitActionsIntoTimelineSessions = ( }; actions.forEach((action) => { - if (isActionWithinSessionThreshold(action, currentSession.end)) { + if (isActionWithinSessionThreshold(action, currentSession.start)) { currentSession.actions.push(action); currentSession.start = action.timestamp; return; diff --git a/packages/headless/src/index.ts b/packages/headless/src/index.ts index 4263d71ad97..ac02a684885 100644 --- a/packages/headless/src/index.ts +++ b/packages/headless/src/index.ts @@ -1,19 +1,5 @@ -import {polyfillCryptoNode} from './api/analytics/analytics-crypto-polyfill'; -import {buildMockSearchEngine} from './test/mock-engine-v2'; -import {buildMockRaw} from './test/mock-raw'; -import {buildMockResult} from './test/mock-result'; -import {createMockState} from './test/mock-state'; import * as HighlightUtils from './utils/highlight'; -const TestUtils = { - buildMockRaw, - buildMockSearchEngine, - buildMockResult, - createMockState, -}; - -polyfillCryptoNode(); - // 3rd Party Libraries export type {Unsubscribe, Middleware} from '@reduxjs/toolkit'; export type {AnalyticsClientSendEventHook} from 'coveo.analytics'; @@ -562,7 +548,7 @@ export * from './features/actions-history/ipx-actions-history-actions-loader'; // Types & Helpers export {API_DATE_FORMAT} from './api/search/date/date-format'; -export {TestUtils, HighlightUtils}; +export {HighlightUtils}; export type {Result} from './api/search/search/result'; export type {FieldDescription} from './api/search/fields/fields-response'; export type {Raw} from './api/search/search/raw'; diff --git a/packages/headless/src/insight.index.ts b/packages/headless/src/insight.index.ts index 8bd84dbddbc..40a079af2a2 100644 --- a/packages/headless/src/insight.index.ts +++ b/packages/headless/src/insight.index.ts @@ -1,7 +1,5 @@ -import {polyfillCryptoNode} from './api/analytics/analytics-crypto-polyfill'; import * as HighlightUtils from './utils/highlight'; -polyfillCryptoNode(); // 3rd Party Libraries export type {Unsubscribe, Middleware} from '@reduxjs/toolkit'; export type {Relay} from '@coveo/relay'; diff --git a/packages/headless/src/product-listing.index.ts b/packages/headless/src/product-listing.index.ts index 1a4cee17ee4..fa9bd34d9d1 100644 --- a/packages/headless/src/product-listing.index.ts +++ b/packages/headless/src/product-listing.index.ts @@ -1,6 +1,3 @@ -import {polyfillCryptoNode} from './api/analytics/analytics-crypto-polyfill'; - -polyfillCryptoNode(); export type {Unsubscribe, Middleware} from '@reduxjs/toolkit'; export type {Relay} from '@coveo/relay'; diff --git a/packages/headless/src/product-recommendation.index.ts b/packages/headless/src/product-recommendation.index.ts index 040bd40723e..2860bf0553d 100644 --- a/packages/headless/src/product-recommendation.index.ts +++ b/packages/headless/src/product-recommendation.index.ts @@ -1,7 +1,3 @@ -import {polyfillCryptoNode} from './api/analytics/analytics-crypto-polyfill'; - -polyfillCryptoNode(); - export type {Unsubscribe, Middleware} from '@reduxjs/toolkit'; export type {Relay} from '@coveo/relay'; diff --git a/packages/headless/src/recommendation.index.ts b/packages/headless/src/recommendation.index.ts index a2215111105..3fd62985afd 100644 --- a/packages/headless/src/recommendation.index.ts +++ b/packages/headless/src/recommendation.index.ts @@ -1,9 +1,7 @@ -import {polyfillCryptoNode} from './api/analytics/analytics-crypto-polyfill'; import * as HighlightUtils from './utils/highlight'; export {HighlightUtils}; -polyfillCryptoNode(); export type {Unsubscribe, Middleware} from '@reduxjs/toolkit'; export type {Relay} from '@coveo/relay'; diff --git a/packages/headless/src/ssr.index.ts b/packages/headless/src/ssr.index.ts index a8e2db4cdfa..328c7f7b36e 100644 --- a/packages/headless/src/ssr.index.ts +++ b/packages/headless/src/ssr.index.ts @@ -1,7 +1,3 @@ -import {polyfillCryptoNode} from './api/analytics/analytics-crypto-polyfill'; - -polyfillCryptoNode(); - // 3rd Party Libraries export type {Unsubscribe, Middleware} from '@reduxjs/toolkit'; export type {AnalyticsClientSendEventHook} from 'coveo.analytics'; diff --git a/packages/headless/src/utils/utils.ts b/packages/headless/src/utils/utils.ts index 49eee62e2a6..e0785d0b06c 100644 --- a/packages/headless/src/utils/utils.ts +++ b/packages/headless/src/utils/utils.ts @@ -1,5 +1,4 @@ import {Middleware, Action} from '@reduxjs/toolkit'; -import {btoa as btoashim} from 'abab'; export const randomID = (prepend?: string, length = 5) => prepend + @@ -30,9 +29,7 @@ export function removeDuplicates(arr: T[], predicate: (value: T) => string) { } export function encodedBtoa(stringToEncode: string) { - return (typeof btoa !== 'undefined' ? btoa : btoashim)( - encodeURI(stringToEncode) - )!; + return btoa(encodeURI(stringToEncode))!; } export function omit(key: keyof T, obj: T) { diff --git a/packages/quantic/cypress/e2e/default-2/document-suggestion/document-suggestion.cypress.ts b/packages/quantic/cypress/e2e/default-2/document-suggestion/document-suggestion.cypress.ts index c256bc42151..f8dcd8aade0 100644 --- a/packages/quantic/cypress/e2e/default-2/document-suggestion/document-suggestion.cypress.ts +++ b/packages/quantic/cypress/e2e/default-2/document-suggestion/document-suggestion.cypress.ts @@ -22,7 +22,7 @@ import {DocumentSuggestionExpectations as Expect} from './document-suggestion-ex interface DocumentSuggestionOptions { maxDocuments: number; fetchOnInit: boolean; - showQuickview: boolean; + withoutQuickview: boolean; numberOfAutoOpenedDocuments: number; } @@ -76,6 +76,7 @@ describe('quantic-document-suggestion', () => { Expect.displayAccordion(true); Expect.numberOfSuggestions(defaultMaxDocuments); Expect.displayAccordionSectionContent(true, 0); + Expect.displayQuickviewButton(true, 0); }); scope('when clicking on a document suggestion', () => { @@ -97,6 +98,8 @@ describe('quantic-document-suggestion', () => { } Expect.displayAccordionSectionContent(true, 0); Expect.displayAccordionSectionContent(true, clickIndex); + Expect.displayQuickviewButton(true, 0); + Expect.displayQuickviewButton(true, clickIndex); }); scope('when rating a document suggestion', () => { @@ -118,14 +121,40 @@ describe('quantic-document-suggestion', () => { Expect.logRatingSuggestion(clickIndex, allDocuments); } }); + + scope('when opening a quickview of a document suggestion', () => { + const clickIndex = 0; + + Actions.openQuickview(clickIndex); + cy.wait(InterceptAliases.ResultHtml); + if (analyticsMode === 'next') { + NextAnalyticsExpectations.emitItemClick( + { + position: clickIndex + 1, + actionCause: 'preview', + itemMetadata: { + uniqueFieldName: 'uniqueId', + uniqueFieldValue: allDocuments[clickIndex].uniqueId, + title: allDocuments[clickIndex].title, + url: allDocuments[clickIndex].clickUri, + }, + searchUid: exampleResponseId, + }, + exampleTrackingId + ); + } else { + Expect.logClickingSuggestion(clickIndex, allDocuments, true); + } + Actions.closeQuickview(); + }); }); }); - describe('when showQuickView is set to true', () => { - it('should render the component and all parts with the quick view button', () => { + describe('when withoutQuickview is set to true', () => { + it('should not render quick view button', () => { const exampleResponseId = crypto.randomUUID(); visitDocumentSuggestion({ - showQuickview: true, + withoutQuickview: true, }); scope('when loading the page', () => { @@ -141,7 +170,7 @@ describe('quantic-document-suggestion', () => { Expect.displayAccordion(true); Expect.numberOfSuggestions(defaultMaxDocuments); Expect.displayAccordionSectionContent(true, 0); - Expect.displayQuickviewButton(true, 0); + Expect.displayQuickviews(false); }); scope('when clicking on a document suggestion', () => { @@ -163,54 +192,7 @@ describe('quantic-document-suggestion', () => { } Expect.displayAccordionSectionContent(true, 0); Expect.displayAccordionSectionContent(true, clickIndex); - Expect.displayQuickviewButton(true, 0); - Expect.displayQuickviewButton(true, 1); - }); - - scope('when rating a document suggestion', () => { - const clickIndex = 1; - - sendRating(clickIndex); - if (analyticsMode === 'next') { - NextAnalyticsExpectations.emitCaseAssistDocumentSuggestionFeedback( - { - documentSuggestion: { - id: allDocuments[clickIndex].uniqueId, - responseId: exampleResponseId, - }, - liked: true, - }, - exampleTrackingId - ); - } else { - Expect.logRatingSuggestion(clickIndex, allDocuments); - } - }); - - scope('when opening a quickview of a document suggestion', () => { - const clickIndex = 0; - - Actions.openQuickview(clickIndex); - cy.wait(InterceptAliases.ResultHtml); - if (analyticsMode === 'next') { - NextAnalyticsExpectations.emitItemClick( - { - position: clickIndex + 1, - actionCause: 'preview', - itemMetadata: { - uniqueFieldName: 'uniqueId', - uniqueFieldValue: allDocuments[clickIndex].uniqueId, - title: allDocuments[clickIndex].title, - url: allDocuments[clickIndex].clickUri, - }, - searchUid: exampleResponseId, - }, - exampleTrackingId - ); - } else { - Expect.logClickingSuggestion(clickIndex, allDocuments, true); - } - Actions.closeQuickview(); + Expect.displayQuickviews(false); }); }); }); @@ -317,7 +299,7 @@ describe('quantic-document-suggestion', () => { Expect.displayAccordion(true); Expect.numberOfSuggestions(maxDocuments); Expect.displayAccordionSectionContent(true, 0); - Expect.displayQuickviews(false); + Expect.displayQuickviews(true); }); }); }); @@ -345,7 +327,7 @@ describe('quantic-document-suggestion', () => { for (let i = 0; i < numberOfAutoOpenedDocuments; i++) { Expect.displayAccordionSectionContent(true, i); } - Expect.displayQuickviews(false); + Expect.displayQuickviews(true); }); }); @@ -368,7 +350,7 @@ describe('quantic-document-suggestion', () => { Expect.numberOfSuggestions(defaultMaxDocuments); Expect.displayAccordionSectionContent(false, 0); - Expect.displayQuickviews(false); + Expect.displayQuickviews(true); }); }); }); @@ -411,7 +393,7 @@ describe('quantic-document-suggestion', () => { for (let i = 0; i < defaultMaxDocuments; i++) { Expect.displayAccordionSectionContent(true, i); } - Expect.displayQuickviews(false); + Expect.displayQuickviews(true); }); }); }); @@ -465,7 +447,7 @@ describe('quantic-document-suggestion', () => { Expect.displayAccordion(true); Expect.numberOfSuggestions(5); Expect.displayAccordionSectionContent(true, 0); - Expect.displayQuickviews(false); + Expect.displayQuickviews(true); }); }); }); diff --git a/packages/quantic/force-app/examples/main/lwc/exampleQuanticDocumentSuggestion/exampleQuanticDocumentSuggestion.html b/packages/quantic/force-app/examples/main/lwc/exampleQuanticDocumentSuggestion/exampleQuanticDocumentSuggestion.html index 5194fc83efa..4f20f23709c 100644 --- a/packages/quantic/force-app/examples/main/lwc/exampleQuanticDocumentSuggestion/exampleQuanticDocumentSuggestion.html +++ b/packages/quantic/force-app/examples/main/lwc/exampleQuanticDocumentSuggestion/exampleQuanticDocumentSuggestion.html @@ -7,7 +7,7 @@ diff --git a/packages/quantic/force-app/examples/main/lwc/exampleQuanticDocumentSuggestion/exampleQuanticDocumentSuggestion.js b/packages/quantic/force-app/examples/main/lwc/exampleQuanticDocumentSuggestion/exampleQuanticDocumentSuggestion.js index 33b75e47b71..fd3a23de7b8 100644 --- a/packages/quantic/force-app/examples/main/lwc/exampleQuanticDocumentSuggestion/exampleQuanticDocumentSuggestion.js +++ b/packages/quantic/force-app/examples/main/lwc/exampleQuanticDocumentSuggestion/exampleQuanticDocumentSuggestion.js @@ -38,10 +38,10 @@ export default class ExampleQuanticDocumentSuggestion extends LightningElement { defaultValue: false, }, { - attribute: 'showQuickview', - label: 'Show quickview', + attribute: 'withoutQuickview', + label: 'Hide quickview', description: - 'Whether or not we want to display the quick view for the document suggestions.', + 'Whether or not we want to hide the quick view for the document suggestions.', defaultValue: false, }, { diff --git a/packages/quantic/force-app/main/default/lwc/quanticCitation/__tests__/quanticCitation.test.js b/packages/quantic/force-app/main/default/lwc/quanticCitation/__tests__/quanticCitation.test.js index f9fe034c507..cc4d1754e2c 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticCitation/__tests__/quanticCitation.test.js +++ b/packages/quantic/force-app/main/default/lwc/quanticCitation/__tests__/quanticCitation.test.js @@ -1,6 +1,5 @@ import { - // @ts-ignore - getNavigateCalledWith, // @ts-ignore + getNavigateCalledWith, getGenerateUrlCalledWith, } from 'lightning/navigation'; // @ts-ignore diff --git a/packages/quantic/force-app/main/default/lwc/quanticDocumentSuggestion/quanticDocumentSuggestion.html b/packages/quantic/force-app/main/default/lwc/quanticDocumentSuggestion/quanticDocumentSuggestion.html index f290602bc80..7f72cd805a5 100644 --- a/packages/quantic/force-app/main/default/lwc/quanticDocumentSuggestion/quanticDocumentSuggestion.html +++ b/packages/quantic/force-app/main/default/lwc/quanticDocumentSuggestion/quanticDocumentSuggestion.html @@ -27,7 +27,7 @@ ">

{it.value.excerpt}

-