From bbb352c7aa2f6ae30de81502ae9930f9e08f8fd6 Mon Sep 17 00:00:00 2001 From: Louis Bompart Date: Fri, 23 Aug 2024 12:17:08 -0400 Subject: [PATCH 01/13] docs(analytics): make trackingId & analyticsMode public (#4300) CDX-1565 --------- Co-authored-by: jpmarceau <39384459+jpmarceau@users.noreply.github.com> --- packages/headless/src/app/engine-configuration.ts | 10 ++++++---- .../features/configuration/configuration-actions.ts | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/headless/src/app/engine-configuration.ts b/packages/headless/src/app/engine-configuration.ts index b7f204f7d5b..6f026d34507 100644 --- a/packages/headless/src/app/engine-configuration.ts +++ b/packages/headless/src/app/engine-configuration.ts @@ -157,13 +157,15 @@ export interface AnalyticsConfiguration { documentLocation?: string; /** * The unique identifier of the tracking target. - * @internal */ trackingId?: string; /** - * Specifies the analytics mode to use. - * By default, `legacy`. - * @internal + * The analytics client to use. + * - `legacy`: The legacy analytics client, i.e., the Coveo Analytics.js library. + * - `next`: The next analytics client, i.e., the Coveo Event Protocol with the Relay library. + * + * Starting at V3.0, the default value will be `next`. + * @default 'legacy' */ analyticsMode?: 'legacy' | 'next'; /** diff --git a/packages/headless/src/features/configuration/configuration-actions.ts b/packages/headless/src/features/configuration/configuration-actions.ts index 7b94cc88473..4845443b773 100644 --- a/packages/headless/src/features/configuration/configuration-actions.ts +++ b/packages/headless/src/features/configuration/configuration-actions.ts @@ -157,9 +157,12 @@ export interface UpdateAnalyticsConfigurationActionCreatorPayload { */ trackingId?: string; /** - * Specifies the analytics mode to use. - * By default, `legacy`. - * @internal + * The analytics client to use. + * - `legacy`: The legacy analytics client, i.e., the Coveo Analytics.js library. + * - `next`: The next analytics client, i.e., the Coveo Event Protocol with the Relay library. + * + * Starting at V3.0, the default value will be `next`. + * @default 'legacy' */ analyticsMode?: 'legacy' | 'next'; /** From a88c5b34c05a3e75fcffae16f200561fb3e3d096 Mon Sep 17 00:00:00 2001 From: Louis Bompart Date: Fri, 23 Aug 2024 13:35:03 -0400 Subject: [PATCH 02/13] fix(genqa): ensure preloaded state can be used w/ rga (#4299) Ensure existing state is considered by the subscribeStateManager. [SVCC-4080](https://coveord.atlassian.net/browse/SVCC-4080) [SVCC-4080]: https://coveord.atlassian.net/browse/SVCC-4080?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- ...eadless-searchapi-generated-answer.test.ts | 25 ++++++++++++++++--- .../headless-searchapi-generated-answer.ts | 17 ++++++++++++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/packages/headless/src/controllers/core/generated-answer/headless-searchapi-generated-answer.test.ts b/packages/headless/src/controllers/core/generated-answer/headless-searchapi-generated-answer.test.ts index 0b9bad9340d..c5e374207d5 100644 --- a/packages/headless/src/controllers/core/generated-answer/headless-searchapi-generated-answer.test.ts +++ b/packages/headless/src/controllers/core/generated-answer/headless-searchapi-generated-answer.test.ts @@ -36,10 +36,6 @@ jest.mock( jest.mock('../../../features/search/search-actions'); describe('searchapi-generated-answer', () => { - it('should be tested', () => { - expect(true).toBe(true); - }); - let engine: MockedSearchEngine; const createGeneratedAnswer = (props: GeneratedAnswerProps = {}) => @@ -290,4 +286,25 @@ describe('searchapi-generated-answer', () => { exampleFieldsToIncludeInCitations ); }); + + describe('when used with a preloaded state', () => { + beforeEach(() => { + const state = createMockState({ + generatedAnswer: { + ...getGeneratedAnswerInitialState(), + id: 'some-id', + }, + }); + state.search.requestId = 'some-request-id'; + state.search.extendedResults.generativeQuestionAnsweringId = + 'some-stream-id'; + engine = buildMockSearchEngine(state); + }); + + it('should not trigger any actions on initialization', () => { + engine.dispatch.mockClear(); + createGeneratedAnswer(); + expect(engine.dispatch).not.toHaveBeenCalled(); + }); + }); }); diff --git a/packages/headless/src/controllers/core/generated-answer/headless-searchapi-generated-answer.ts b/packages/headless/src/controllers/core/generated-answer/headless-searchapi-generated-answer.ts index 29dc37aabad..6de5c23049c 100644 --- a/packages/headless/src/controllers/core/generated-answer/headless-searchapi-generated-answer.ts +++ b/packages/headless/src/controllers/core/generated-answer/headless-searchapi-generated-answer.ts @@ -127,10 +127,25 @@ export function buildSearchAPIGeneratedAnswer( const controller = buildCoreGeneratedAnswer(engine, analyticsClient, props); const getState = () => engine.state; + if ( + engine.state.generatedAnswer.id && + !subscribeStateManager.engines[engine.state.generatedAnswer.id] + ) { + subscribeStateManager.engines[engine.state.generatedAnswer.id] = { + abortController: undefined, + lastRequestId: engine.state.search.requestId, + lastStreamId: + engine.state.search.extendedResults.generativeQuestionAnsweringId ?? '', + }; + } + if (!engine.state.generatedAnswer.id) { const genQaEngineId = randomID('genQA-', 12); engine.dispatch(setId({id: genQaEngineId})); - subscribeStateManager.engines[genQaEngineId] = { + } + + if (!subscribeStateManager.engines[engine.state.generatedAnswer.id]) { + subscribeStateManager.engines[engine.state.generatedAnswer.id] = { abortController: undefined, lastRequestId: '', lastStreamId: '', From 67d0416470b8b1fa77488da4bd8e534ffcc715eb Mon Sep 17 00:00:00 2001 From: Louis Bompart Date: Fri, 23 Aug 2024 13:56:21 -0400 Subject: [PATCH 03/13] fix(atomic): prevent item click when carousel buttons are clicked (#4297) When you click on an element within another, you are clicking both. This is why you must 'stop' the event propagation at the target in this situation. (otherwise, if the parent & the child elements have listeners, both will be triggered) https://coveord.atlassian.net/browse/KIT-3477 --- .../e2e/atomic-product-image.e2e.ts | 12 ++++++++++++ .../atomic-product-image/e2e/fixture.ts | 18 ++++++++++++++++++ .../atomic-product-image/e2e/page-object.ts | 9 +++++++++ .../common/image-carousel/image-carousel.tsx | 10 ++++++++-- 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/atomic-product-image.e2e.ts create mode 100644 packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/fixture.ts create mode 100644 packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/page-object.ts diff --git a/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/atomic-product-image.e2e.ts b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/atomic-product-image.e2e.ts new file mode 100644 index 00000000000..c95f69122bf --- /dev/null +++ b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/atomic-product-image.e2e.ts @@ -0,0 +1,12 @@ +// import {test, expect} from './fixture'; + +// test.describe('default', async () => { +// test.describe('when clicking on the next button', async ({productImage}) => { +// test.fixme('should navigate to the next image', () => {}); +// test.fixme('should not open the product', () => {}); +// }); +// test.describe('when clicking on the previous button', async ({productImage}) => { +// test.fixme('should navigate to the previous image', () => {}); +// test.fixme('should not open the product', () => {}); +// }); +// }); diff --git a/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/fixture.ts b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/fixture.ts new file mode 100644 index 00000000000..ca73e2a7976 --- /dev/null +++ b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/fixture.ts @@ -0,0 +1,18 @@ +import {test as base} from '@playwright/test'; +import { + AxeFixture, + makeAxeBuilder, +} from '../../../../../../playwright-utils/base-fixture'; +import {ProductImageObject} from './page-object'; + +interface TestFixture { + productImage: ProductImageObject; +} + +export const test = base.extend({ + makeAxeBuilder, + productImage: async ({page}, use) => { + await use(new ProductImageObject(page)); + }, +}); +export {expect} from '@playwright/test'; diff --git a/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/page-object.ts b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/page-object.ts new file mode 100644 index 00000000000..30a89aebb3a --- /dev/null +++ b/packages/atomic/src/components/commerce/product-template-components/atomic-product-image/e2e/page-object.ts @@ -0,0 +1,9 @@ +import type {Page} from '@playwright/test'; +import {BasePageObject} from '../../../../../../playwright-utils/base-page-object'; + +export class ProductImageObject extends BasePageObject<'atomic-product-image'> { + constructor(page: Page) { + super(page, 'atomic-product-image'); + } + // TODO tests +} diff --git a/packages/atomic/src/components/common/image-carousel/image-carousel.tsx b/packages/atomic/src/components/common/image-carousel/image-carousel.tsx index 06f4063d248..6a812afccdc 100644 --- a/packages/atomic/src/components/common/image-carousel/image-carousel.tsx +++ b/packages/atomic/src/components/common/image-carousel/image-carousel.tsx @@ -27,7 +27,10 @@ export const ImageCarousel: FunctionalComponent<