From 16b41fb034689abdfd9deff5ed38f980b3a8ed2e Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Fri, 7 Jun 2024 08:33:46 -0400 Subject: [PATCH 01/16] WIP https://coveord.atlassian.net/browse/KIT-3256 --- .../playwrightUtils/base-page-object.ts | 25 +++++++ packages/atomic/src/components.d.ts | 4 ++ .../atomic-commerce-search-box/e2e/fixture.ts | 2 +- .../atomic-commerce-facets.new.stories.tsx | 65 +++++++++++++++++++ .../atomic-commerce-facets.tsx | 2 +- .../e2e/atomic-commerce-facets.e2e.ts | 31 +++++++++ .../atomic-commerce-facets/e2e/fixture.ts | 18 +++++ .../atomic-commerce-facets/e2e/page-object.ts | 10 ++- .../examples/commerce-website/search.html | 2 +- packages/atomic/src/test-2.spec.ts | 19 ++++++ 10 files changed, 172 insertions(+), 6 deletions(-) create mode 100644 packages/atomic/playwrightUtils/base-page-object.ts create mode 100644 packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx create mode 100644 packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts create mode 100644 packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts create mode 100644 packages/atomic/src/test-2.spec.ts diff --git a/packages/atomic/playwrightUtils/base-page-object.ts b/packages/atomic/playwrightUtils/base-page-object.ts new file mode 100644 index 00000000000..58ea5001fa0 --- /dev/null +++ b/packages/atomic/playwrightUtils/base-page-object.ts @@ -0,0 +1,25 @@ +import type {Page} from '@playwright/test'; + +export class BasePageObject { + constructor(public page: Page) { + //const a = global['HTMLElementTagNameMap']; + } + + get hydrated() { + return ''; + // return this.page.locator(`${this.tag}[class*="hydrated"]`); + } + + goto(story: string = 'default') { + this.page.goto( + `http://localhost:4400/iframe.html?id=${this.tag}--${story}` + ); + } + + gotoParametrized(story: string, args: keyof Component) { + console.log(args); + this.page.goto( + `http://localhost:4400/iframe.html?id=${this.tag}--${story}}` + ); + } +} diff --git a/packages/atomic/src/components.d.ts b/packages/atomic/src/components.d.ts index 24a324838ac..d0bd388d457 100644 --- a/packages/atomic/src/components.d.ts +++ b/packages/atomic/src/components.d.ts @@ -306,6 +306,7 @@ export namespace Components { /** * The `atomic-commerce-facets` component automatically renders commerce facets based on the Commerce API response. * Unlike regular facets, which require explicit definition and request in the query, the `atomic-commerce-facets` component dynamically generates facets. + * @alpha */ interface AtomicCommerceFacets { /** @@ -3488,6 +3489,7 @@ declare global { /** * The `atomic-commerce-facets` component automatically renders commerce facets based on the Commerce API response. * Unlike regular facets, which require explicit definition and request in the query, the `atomic-commerce-facets` component dynamically generates facets. + * @alpha */ interface HTMLAtomicCommerceFacetsElement extends Components.AtomicCommerceFacets, HTMLStencilElement { } @@ -5702,6 +5704,7 @@ declare namespace LocalJSX { /** * The `atomic-commerce-facets` component automatically renders commerce facets based on the Commerce API response. * Unlike regular facets, which require explicit definition and request in the query, the `atomic-commerce-facets` component dynamically generates facets. + * @alpha */ interface AtomicCommerceFacets { /** @@ -8756,6 +8759,7 @@ declare module "@stencil/core" { /** * The `atomic-commerce-facets` component automatically renders commerce facets based on the Commerce API response. * Unlike regular facets, which require explicit definition and request in the query, the `atomic-commerce-facets` component dynamically generates facets. + * @alpha */ "atomic-commerce-facets": LocalJSX.AtomicCommerceFacets & JSXBase.HTMLAttributes; "atomic-commerce-interface": LocalJSX.AtomicCommerceInterface & JSXBase.HTMLAttributes; diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts index feb9519eb06..95ee13b53c4 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts @@ -4,7 +4,7 @@ import { } from '@coveo/atomic/playwrightUtils/base-fixture'; import {test as base} from '@playwright/test'; import {AtomicCommerceLoadMoreProductsLocators as LoadMore} from '../../atomic-commerce-load-more-products/e2e/page-object'; -import {AtomicCommerceFacetsLocators as Facets} from '../../facets/atomic-commerce-facets/e2e/page-object'; +import {AtomicCommerceFacets as Facets} from '../../facets/atomic-commerce-facets/e2e/page-object'; import {AtomicCommerceSearchBoxLocators as SearchBox} from './page-object'; type MyFixtures = { diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx new file mode 100644 index 00000000000..65b9791289f --- /dev/null +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx @@ -0,0 +1,65 @@ +import { + playExecuteFirstSearch, + wrapInCommerceInterface, +} from '@coveo/atomic/storybookUtils/commerce-interface-wrapper'; +import {parameters} from '@coveo/atomic/storybookUtils/common-meta-parameters'; +import {renderComponent} from '@coveo/atomic/storybookUtils/render-component'; +import type {Meta, StoryObj as Story} from '@storybook/web-components'; +import {html} from 'lit/static-html.js'; + +const {decorator, play} = wrapInCommerceInterface({skipFirstSearch: true}); + +const meta: Meta = { + component: 'atomic-commerce-facets', + title: 'Atomic-Commerce/Facets', + id: 'atomic-commerce-facets', + render: renderComponent, + decorators: [decorator], + parameters, + play, +}; + +export default meta; + +export const Default: Story = { + name: 'atomic-commerce-facets', + play: async (context) => { + await play(context); + await playExecuteFirstSearch(context); + }, +}; + +export const InPage: Story = { + name: 'In a page', + decorators: [ + (story) => + html` + + + ${story()} + + + + + + + + + + + + + + + + `, + ], + play: async (context) => { + await play(context); + await playExecuteFirstSearch(context); + }, +}; diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx index 66a62ac43c4..e4a4e0b4360 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx @@ -25,7 +25,7 @@ import {CommerceBindings as Bindings} from '../../atomic-commerce-interface/atom * The `atomic-commerce-facets` component automatically renders commerce facets based on the Commerce API response. * Unlike regular facets, which require explicit definition and request in the query, the `atomic-commerce-facets` component dynamically generates facets. * - * @internal + * @alpha */ @Component({ tag: 'atomic-commerce-facets', diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts new file mode 100644 index 00000000000..45979325b22 --- /dev/null +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts @@ -0,0 +1,31 @@ +import {test, expect} from './fixture'; + +test.describe('default', async () => { + test.beforeEach(async ({page}) => { + await page.goto( + 'http://localhost:4400/iframe.html?id=atomic-commerce-facets--default' + ); + }); + + test('should be A11y compliant', async ({facets, makeAxeBuilder}) => { + await facets.hydrated.waitFor(); + const accessibilityResults = await makeAxeBuilder().analyze(); + expect(accessibilityResults.violations).toEqual([]); + }); + + /*await page.goto('http://localhost:4400/'); + await page.goto( + 'http://localhost:4400/?path=/story/atomic-automatic-facet-generator--default' + ); + await page.getByRole('button', {name: 'Facets'}).click(); + await page.getByRole('link', {name: 'atomic-commerce-facets'}).click(); + await page + .frameLocator('iframe[title="storybook-preview-iframe"]') + .getByText('Barca Sports(40)') + .click(); + await expect( + page + .frameLocator('iframe[title="storybook-preview-iframe"]') + .getByLabel('Inclusion filter on Barca') + ).toBeVisible();*/ +}); diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts new file mode 100644 index 00000000000..c06679c8306 --- /dev/null +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts @@ -0,0 +1,18 @@ +import { + AxeFixture, + makeAxeBuilder, +} from '@coveo/atomic/playwrightUtils/base-fixture'; +import {test as base} from '@playwright/test'; +import {AtomicCommerceFacets as Facets} from './page-object'; + +interface TestFixture { + facets: Facets; +} + +export const test = base.extend({ + makeAxeBuilder, + facets: async ({page}, use) => { + await use(new Facets(page)); + }, +}); +export {expect} from '@playwright/test'; diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts index 27cabbd831b..5210c2c5ef1 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts @@ -1,9 +1,9 @@ import type {Page} from '@playwright/test'; +import {BasePageObject} from '../../../../../../playwrightUtils/base-page-object'; -export class AtomicCommerceFacetsLocators { - private page: Page; +export class AtomicCommerceFacets extends BasePageObject { constructor(page: Page) { - this.page = page; + super(page, 'atomic-commerce-facets'); } get inclusionFilters() { @@ -15,4 +15,8 @@ export class AtomicCommerceFacetsLocators { new RegExp(`Clear ${numberOfFilters ?? '\\d'} filter for`) ); } + + get hydrated() { + return this.page.locator(`${this.tag}[class*="hydrated"]`); + } } diff --git a/packages/atomic/src/pages/examples/commerce-website/search.html b/packages/atomic/src/pages/examples/commerce-website/search.html index 0d38f02b422..9a4ad2ff0df 100644 --- a/packages/atomic/src/pages/examples/commerce-website/search.html +++ b/packages/atomic/src/pages/examples/commerce-website/search.html @@ -63,7 +63,7 @@

Search page

diff --git a/packages/atomic/src/test-2.spec.ts b/packages/atomic/src/test-2.spec.ts new file mode 100644 index 00000000000..f3cb4c46efc --- /dev/null +++ b/packages/atomic/src/test-2.spec.ts @@ -0,0 +1,19 @@ +import {test, expect} from '@playwright/test'; + +test('test', async ({page}) => { + await page.goto('http://localhost:4400/'); + await page.goto( + 'http://localhost:4400/?path=/story/atomic-automatic-facet-generator--default' + ); + await page.getByRole('button', {name: 'Facets'}).click(); + await page.getByRole('link', {name: 'atomic-commerce-facets'}).click(); + await page + .frameLocator('iframe[title="storybook-preview-iframe"]') + .getByText('Barca Sports(40)') + .click(); + await expect( + page + .frameLocator('iframe[title="storybook-preview-iframe"]') + .getByLabel('Inclusion filter on Barca') + ).toBeVisible(); +}); From e88882d945012120594a730e15c7c4af55769593 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Mon, 10 Jun 2024 14:17:53 -0400 Subject: [PATCH 02/16] test(atomic): start tests on atomic-commerce-facets https://coveord.atlassian.net/browse/KIT-3256 --- package-lock.json | 29 ++++++++ packages/atomic/package.json | 1 + .../playwrightUtils/base-page-object.ts | 47 +++++++++---- .../e2e/page-object.ts | 6 +- .../e2e/atomic-commerce-search-box.e2e.ts | 69 ++++++++----------- .../atomic-commerce-search-box/e2e/fixture.ts | 18 ++--- .../e2e/page-object.ts | 10 +-- .../e2e/atomic-commerce-facets.e2e.ts | 50 ++++++++------ .../atomic-commerce-facets/e2e/fixture.ts | 6 +- .../atomic-commerce-facets/e2e/page-object.ts | 34 +++++++-- 10 files changed, 167 insertions(+), 103 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5af54208e52..09954b1cd99 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57440,6 +57440,7 @@ "@storybook/core-server": "8.1.5", "@storybook/jest": "^0.2.3", "@storybook/manager-api": "8.1.5", + "@storybook/router": "8.1.6", "@storybook/test": "8.1.5", "@storybook/test-runner": "0.18.2", "@storybook/testing-library": "^0.2.2", @@ -58547,6 +58548,34 @@ "win32" ] }, + "packages/atomic/node_modules/@storybook/client-logger": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-8.1.6.tgz", + "integrity": "sha512-QfSoUxS1rmrBzO7o99og9g+Gkm7sTmU5ZOpTkjszjlRqfV6/77eUnUOzUikej4LqPLmlJV5fqGuvoP0aNVksDw==", + "dev": true, + "dependencies": { + "@storybook/global": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, + "packages/atomic/node_modules/@storybook/router": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-8.1.6.tgz", + "integrity": "sha512-tvuhB2uXHEKK640Epm1SqVzPhQ9lXYfF7FX6FleJgVYEvZpJpNTD4RojedQoLI6SUUSXNy1Vs2QV26VM0XIPHQ==", + "dev": true, + "dependencies": { + "@storybook/client-logger": "8.1.6", + "memoizerific": "^1.11.3", + "qs": "^6.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, "packages/atomic/node_modules/@types/node": { "version": "18.19.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.33.tgz", diff --git a/packages/atomic/package.json b/packages/atomic/package.json index ea3601ae62b..8bddf5971ed 100644 --- a/packages/atomic/package.json +++ b/packages/atomic/package.json @@ -87,6 +87,7 @@ "@storybook/core-server": "8.1.5", "@storybook/jest": "^0.2.3", "@storybook/manager-api": "8.1.5", + "@storybook/router": "8.1.6", "@storybook/test": "8.1.5", "@storybook/test-runner": "0.18.2", "@storybook/testing-library": "^0.2.2", diff --git a/packages/atomic/playwrightUtils/base-page-object.ts b/packages/atomic/playwrightUtils/base-page-object.ts index 58ea5001fa0..2d84e24d46a 100644 --- a/packages/atomic/playwrightUtils/base-page-object.ts +++ b/packages/atomic/playwrightUtils/base-page-object.ts @@ -1,25 +1,44 @@ import type {Page} from '@playwright/test'; +import {buildArgsParam} from '@storybook/router'; +import {JSX} from '../dist/types/components'; -export class BasePageObject { - constructor(public page: Page) { - //const a = global['HTMLElementTagNameMap']; - } +export class BasePageObject< + TagName extends keyof JSX.IntrinsicElements, + Component = JSX.IntrinsicElements[TagName], +> { + constructor( + public page: Page, + public tag: TagName + ) {} get hydrated() { - return ''; - // return this.page.locator(`${this.tag}[class*="hydrated"]`); + return this.page.locator(`${this.tag}[class*="hydrated"]`); } - goto(story: string = 'default') { - this.page.goto( - `http://localhost:4400/iframe.html?id=${this.tag}--${story}` - ); + get urlRoot() { + return 'http://localhost:4400/iframe.html'; + } + + async gotoAndHydrate(story: string = 'default') { + await this.page.goto(`${this.urlRoot}?id=${this.tag}--${story}`); + await this.hydrated.waitFor(); } - gotoParametrized(story: string, args: keyof Component) { - console.log(args); - this.page.goto( - `http://localhost:4400/iframe.html?id=${this.tag}--${story}}` + async gotoParametrizedAndHydrate(args: Component, story = 'default') { + await this.page.goto( + `${this.urlRoot}?id=${this.tag}--${story}&args=${buildArgsParam(undefined, this.camelToKebab(args))}` ); + await this.hydrated.waitFor(); + } + + private camelToKebab(args: Component) { + const toKebab: Record = {}; + Object.entries(args as Record).forEach(([key, value]) => { + toKebab[ + key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase() + ] = value; + }); + + return toKebab; } } diff --git a/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/e2e/page-object.ts b/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/e2e/page-object.ts index b00512014d4..86b906f66a0 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/e2e/page-object.ts @@ -1,9 +1,9 @@ import type {Page} from '@playwright/test'; +import {BasePageObject} from '../../../../../playwrightUtils/base-page-object'; -export class AtomicCommerceLoadMoreProductsLocators { - private page: Page; +export class LoadMoreProductsPageObject extends BasePageObject<'atomic-commerce-load-more-products'> { constructor(page: Page) { - this.page = page; + super(page, 'atomic-commerce-load-more-products'); } summary({index, total}: {index?: number; total?: number} = {}) { diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts index bf1f918e644..6858b56b4ce 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts @@ -1,10 +1,8 @@ import {test, expect} from './fixture'; test.describe('default', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--default&viewMode=story&args=suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.gotoParametrizedAndHydrate({suggestionTimeout: 5000}); }); test('should have an enabled search button', async ({searchBox}) => { @@ -50,9 +48,10 @@ test.describe('default', () => { }); test.describe('with instant results & query suggestions', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--rich-search-box&viewMode=story&args=suggestion-timeout:5000' + test.beforeEach(async ({searchBox}) => { + searchBox.gotoParametrizedAndHydrate( + {suggestionTimeout: 5000}, + 'rich-search-box' ); }); @@ -82,10 +81,12 @@ test.describe('with instant results & query suggestions', () => { }); test.describe('with disable-search=true and minimum-query-length=1', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--default&viewMode=story&args=disable-search:!true;minimum-query-length:1;suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.gotoParametrizedAndHydrate({ + disableSearch: true, + minimumQueryLength: 1, + suggestionTimeout: 5000, + }); }); const testCases = () => { @@ -124,10 +125,11 @@ test.describe('with disable-search=true and minimum-query-length=1', () => { }); test.describe('with minimum-query-length=3', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--default&viewMode=story&args=minimum-query-length:4;suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.gotoParametrizedAndHydrate({ + minimumQueryLength: 4, + suggestionTimeout: 5000, + }); }); const testCases = () => { @@ -180,10 +182,11 @@ test.describe('with minimum-query-length=3', () => { }); test.describe('with a facet & clear-filters set to true', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--in-page&args=clear-filters:!true;suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.gotoParametrizedAndHydrate({ + clearFilters: true, + suggestionTimeout: 5000, + }); }); test('clicking the submit button should clear the facet value', async ({ @@ -198,9 +201,13 @@ test.describe('with a facet & clear-filters set to true', () => { }); test.describe('with a facet & clear-filters set to false', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--in-page&args=clear-filters:!false;suggestion-timeout:5000' + test.beforeEach(async ({searchBox}) => { + await searchBox.gotoParametrizedAndHydrate( + { + clearFilters: false, + suggestionTimeout: 5000, + }, + 'in-page' ); }); @@ -214,21 +221,3 @@ test.describe('with a facet & clear-filters set to false', () => { await expect(facets.clearFilters()).toBeVisible(); }); }); - -test.describe('with enable-query-syntax=true', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--in-page&viewMode=story&args=enable-query-syntax:!true;suggestion-timeout:5000' - ); - }); - - test('should use query syntax', async ({loadMore, searchBox, page}) => { - await loadMore.loadMoreButton.waitFor({state: 'visible'}); - await searchBox.searchInput - // eslint-disable-next-line @cspell/spellchecker - .fill('@urihash=bzo5fpM1vf8Xñds1'); - await searchBox.submitButton.click(); - await expect(loadMore.summary({total: 1})).toBeVisible(); - await expect(page.getByText('WiLife Life Jacket WiLife')).toBeVisible(); - }); -}); diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts index 95ee13b53c4..9db1de4d895 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts @@ -3,26 +3,26 @@ import { makeAxeBuilder, } from '@coveo/atomic/playwrightUtils/base-fixture'; import {test as base} from '@playwright/test'; -import {AtomicCommerceLoadMoreProductsLocators as LoadMore} from '../../atomic-commerce-load-more-products/e2e/page-object'; -import {AtomicCommerceFacets as Facets} from '../../facets/atomic-commerce-facets/e2e/page-object'; -import {AtomicCommerceSearchBoxLocators as SearchBox} from './page-object'; +import {LoadMoreProductsPageObject} from '../../atomic-commerce-load-more-products/e2e/page-object'; +import {FacetsPageObject} from '../../facets/atomic-commerce-facets/e2e/page-object'; +import {SearchBoxPageObject} from './page-object'; type MyFixtures = { - searchBox: SearchBox; - facets: Facets; - loadMore: LoadMore; + searchBox: SearchBoxPageObject; + facets: FacetsPageObject; + loadMore: LoadMoreProductsPageObject; }; export const test = base.extend({ makeAxeBuilder, searchBox: async ({page}, use) => { - await use(new SearchBox(page)); + await use(new SearchBoxPageObject(page)); }, facets: async ({page}, use) => { - await use(new Facets(page)); + await use(new FacetsPageObject(page)); }, loadMore: async ({page}, use) => { - await use(new LoadMore(page)); + await use(new LoadMoreProductsPageObject(page)); }, }); export {expect} from '@playwright/test'; diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/page-object.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/page-object.ts index dc868c75652..bb429930812 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/page-object.ts @@ -1,9 +1,9 @@ import type {Page} from '@playwright/test'; +import {BasePageObject} from '../../../../../playwrightUtils/base-page-object'; -export class AtomicCommerceSearchBoxLocators { - private page: Page; +export class SearchBoxPageObject extends BasePageObject<'atomic-commerce-search-box'> { constructor(page: Page) { - this.page = page; + super(page, 'atomic-commerce-search-box'); } get submitButton() { @@ -38,10 +38,6 @@ export class AtomicCommerceSearchBoxLocators { ); } - get hydrated() { - return this.page.locator('atomic-commerce-search-box[class*="hydrated"]'); - } - private listSideAffix(listSide?: 'Left' | 'Right') { return listSide ? ` In ${listSide} list\\.` : ''; } diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts index 45979325b22..242c3d7c8a5 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts @@ -1,31 +1,37 @@ import {test, expect} from './fixture'; test.describe('default', async () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-facets--default' - ); - }); - test('should be A11y compliant', async ({facets, makeAxeBuilder}) => { - await facets.hydrated.waitFor(); + await facets.gotoAndHydrate(); const accessibilityResults = await makeAxeBuilder().analyze(); + expect(accessibilityResults.violations).toEqual([]); }); - /*await page.goto('http://localhost:4400/'); - await page.goto( - 'http://localhost:4400/?path=/story/atomic-automatic-facet-generator--default' - ); - await page.getByRole('button', {name: 'Facets'}).click(); - await page.getByRole('link', {name: 'atomic-commerce-facets'}).click(); - await page - .frameLocator('iframe[title="storybook-preview-iframe"]') - .getByText('Barca Sports(40)') - .click(); - await expect( - page - .frameLocator('iframe[title="storybook-preview-iframe"]') - .getByLabel('Inclusion filter on Barca') - ).toBeVisible();*/ + test('should display facets', async ({facets}) => { + await facets.gotoAndHydrate(); + await expect(facets.standardFacets.first()).toBeVisible(); + await expect(facets.numericFacets.first()).toBeVisible(); + await expect(facets.categoryFacets.first()).toBeVisible(); + }); + + // KIT-3300 + test.skip('should collapse facets when set to 1', async ({facets}) => { + await facets.gotoParametrizedAndHydrate({ + collapseFacetsAfter: 1, + }); + await expect(facets.expandedFacets).toHaveCount(1); + await expect(facets.collapsedFacets).toHaveCount(3); + }); + + // KIT-3300 + test.skip('should disable collapse facets when set to -1', async ({ + facets, + }) => { + await facets.gotoParametrizedAndHydrate({ + collapseFacetsAfter: -1, + }); + await expect(facets.collapsedFacets).toHaveCount(0); + await expect(facets.expandedFacets).toHaveCount(4); + }); }); diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts index c06679c8306..96f080f63a7 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts @@ -3,16 +3,16 @@ import { makeAxeBuilder, } from '@coveo/atomic/playwrightUtils/base-fixture'; import {test as base} from '@playwright/test'; -import {AtomicCommerceFacets as Facets} from './page-object'; +import {FacetsPageObject} from './page-object'; interface TestFixture { - facets: Facets; + facets: FacetsPageObject; } export const test = base.extend({ makeAxeBuilder, facets: async ({page}, use) => { - await use(new Facets(page)); + await use(new FacetsPageObject(page)); }, }); export {expect} from '@playwright/test'; diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts index 5210c2c5ef1..97b81c68dc7 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts @@ -1,11 +1,39 @@ import type {Page} from '@playwright/test'; import {BasePageObject} from '../../../../../../playwrightUtils/base-page-object'; -export class AtomicCommerceFacets extends BasePageObject { +export class FacetsPageObject extends BasePageObject<'atomic-commerce-facets'> { constructor(page: Page) { super(page, 'atomic-commerce-facets'); } + get container() { + return this.page.locator('atomic-commerce-facets'); + } + + get standardFacets() { + return this.container.locator('atomic-commerce-facet'); + } + + get numericFacets() { + return this.container.locator('atomic-commerce-numeric-facet'); + } + + get timeframeFacets() { + return this.container.locator('atomic-commerce-timeframe-facet'); + } + + get categoryFacets() { + return this.container.locator('atomic-commerce-category-facet'); + } + + get collapsedFacets() { + return this.container.locator('[aria-expanded="false"]'); + } + + get expandedFacets() { + return this.container.locator('[aria-expanded="true"]'); + } + get inclusionFilters() { return this.page.getByLabel(/Inclusion filter/); } @@ -15,8 +43,4 @@ export class AtomicCommerceFacets extends BasePageObject { new RegExp(`Clear ${numberOfFilters ?? '\\d'} filter for`) ); } - - get hydrated() { - return this.page.locator(`${this.tag}[class*="hydrated"]`); - } } From 1e190bb9ceea72d8653caed373a7d2625e3b0de0 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Mon, 10 Jun 2024 14:20:11 -0400 Subject: [PATCH 03/16] cleanup https://coveord.atlassian.net/browse/KIT-3256 --- .../examples/commerce-website/search.html | 2 +- packages/atomic/src/test-2.spec.ts | 19 ------------------- 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 packages/atomic/src/test-2.spec.ts diff --git a/packages/atomic/src/pages/examples/commerce-website/search.html b/packages/atomic/src/pages/examples/commerce-website/search.html index 9a4ad2ff0df..0d38f02b422 100644 --- a/packages/atomic/src/pages/examples/commerce-website/search.html +++ b/packages/atomic/src/pages/examples/commerce-website/search.html @@ -63,7 +63,7 @@

Search page

diff --git a/packages/atomic/src/test-2.spec.ts b/packages/atomic/src/test-2.spec.ts deleted file mode 100644 index f3cb4c46efc..00000000000 --- a/packages/atomic/src/test-2.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {test, expect} from '@playwright/test'; - -test('test', async ({page}) => { - await page.goto('http://localhost:4400/'); - await page.goto( - 'http://localhost:4400/?path=/story/atomic-automatic-facet-generator--default' - ); - await page.getByRole('button', {name: 'Facets'}).click(); - await page.getByRole('link', {name: 'atomic-commerce-facets'}).click(); - await page - .frameLocator('iframe[title="storybook-preview-iframe"]') - .getByText('Barca Sports(40)') - .click(); - await expect( - page - .frameLocator('iframe[title="storybook-preview-iframe"]') - .getByLabel('Inclusion filter on Barca') - ).toBeVisible(); -}); From 1110783d3489322a203e90dce82704a420a069e3 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Mon, 10 Jun 2024 14:25:39 -0400 Subject: [PATCH 04/16] more cleanup https://coveord.atlassian.net/browse/KIT-3256 --- .../base-fixture.ts | 0 .../base-page-object.ts | 17 ++++++++--------- .../e2e/page-object.ts | 2 +- .../e2e/atomic-commerce-search-box.e2e.ts | 15 ++++++--------- .../atomic-commerce-search-box/e2e/fixture.ts | 4 ++-- .../e2e/page-object.ts | 2 +- .../e2e/atomic-commerce-facets.e2e.ts | 8 ++++---- .../atomic-commerce-facets/e2e/fixture.ts | 4 ++-- .../atomic-commerce-facets/e2e/page-object.ts | 2 +- 9 files changed, 25 insertions(+), 29 deletions(-) rename packages/atomic/{playwrightUtils => playwright-utils}/base-fixture.ts (100%) rename packages/atomic/{playwrightUtils => playwright-utils}/base-page-object.ts (69%) diff --git a/packages/atomic/playwrightUtils/base-fixture.ts b/packages/atomic/playwright-utils/base-fixture.ts similarity index 100% rename from packages/atomic/playwrightUtils/base-fixture.ts rename to packages/atomic/playwright-utils/base-fixture.ts diff --git a/packages/atomic/playwrightUtils/base-page-object.ts b/packages/atomic/playwright-utils/base-page-object.ts similarity index 69% rename from packages/atomic/playwrightUtils/base-page-object.ts rename to packages/atomic/playwright-utils/base-page-object.ts index 2d84e24d46a..2da37f6ff0c 100644 --- a/packages/atomic/playwrightUtils/base-page-object.ts +++ b/packages/atomic/playwright-utils/base-page-object.ts @@ -19,15 +19,14 @@ export class BasePageObject< return 'http://localhost:4400/iframe.html'; } - async gotoAndHydrate(story: string = 'default') { - await this.page.goto(`${this.urlRoot}?id=${this.tag}--${story}`); - await this.hydrated.waitFor(); - } - - async gotoParametrizedAndHydrate(args: Component, story = 'default') { - await this.page.goto( - `${this.urlRoot}?id=${this.tag}--${story}&args=${buildArgsParam(undefined, this.camelToKebab(args))}` - ); + async load(args?: Component, story: string = 'default') { + if (args) { + await this.page.goto( + `${this.urlRoot}?id=${this.tag}--${story}&args=${buildArgsParam(undefined, this.camelToKebab(args))}` + ); + } else { + await this.page.goto(`${this.urlRoot}?id=${this.tag}--${story}`); + } await this.hydrated.waitFor(); } diff --git a/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/e2e/page-object.ts b/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/e2e/page-object.ts index 86b906f66a0..21fe40afe45 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-load-more-products/e2e/page-object.ts @@ -1,5 +1,5 @@ import type {Page} from '@playwright/test'; -import {BasePageObject} from '../../../../../playwrightUtils/base-page-object'; +import {BasePageObject} from '../../../../../playwright-utils/base-page-object'; export class LoadMoreProductsPageObject extends BasePageObject<'atomic-commerce-load-more-products'> { constructor(page: Page) { diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts index 6858b56b4ce..c992274c8a8 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts @@ -2,7 +2,7 @@ import {test, expect} from './fixture'; test.describe('default', () => { test.beforeEach(async ({searchBox}) => { - await searchBox.gotoParametrizedAndHydrate({suggestionTimeout: 5000}); + await searchBox.load({suggestionTimeout: 5000}); }); test('should have an enabled search button', async ({searchBox}) => { @@ -49,10 +49,7 @@ test.describe('default', () => { test.describe('with instant results & query suggestions', () => { test.beforeEach(async ({searchBox}) => { - searchBox.gotoParametrizedAndHydrate( - {suggestionTimeout: 5000}, - 'rich-search-box' - ); + searchBox.load({suggestionTimeout: 5000}, 'rich-search-box'); }); test.describe('after clicking the searchbox input', () => { @@ -82,7 +79,7 @@ test.describe('with instant results & query suggestions', () => { test.describe('with disable-search=true and minimum-query-length=1', () => { test.beforeEach(async ({searchBox}) => { - await searchBox.gotoParametrizedAndHydrate({ + await searchBox.load({ disableSearch: true, minimumQueryLength: 1, suggestionTimeout: 5000, @@ -126,7 +123,7 @@ test.describe('with disable-search=true and minimum-query-length=1', () => { test.describe('with minimum-query-length=3', () => { test.beforeEach(async ({searchBox}) => { - await searchBox.gotoParametrizedAndHydrate({ + await searchBox.load({ minimumQueryLength: 4, suggestionTimeout: 5000, }); @@ -183,7 +180,7 @@ test.describe('with minimum-query-length=3', () => { test.describe('with a facet & clear-filters set to true', () => { test.beforeEach(async ({searchBox}) => { - await searchBox.gotoParametrizedAndHydrate({ + await searchBox.load({ clearFilters: true, suggestionTimeout: 5000, }); @@ -202,7 +199,7 @@ test.describe('with a facet & clear-filters set to true', () => { test.describe('with a facet & clear-filters set to false', () => { test.beforeEach(async ({searchBox}) => { - await searchBox.gotoParametrizedAndHydrate( + await searchBox.load( { clearFilters: false, suggestionTimeout: 5000, diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts index 9db1de4d895..aa62c3a1ef4 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/fixture.ts @@ -1,8 +1,8 @@ +import {test as base} from '@playwright/test'; import { AxeFixture, makeAxeBuilder, -} from '@coveo/atomic/playwrightUtils/base-fixture'; -import {test as base} from '@playwright/test'; +} from '../../../../../playwright-utils/base-fixture'; import {LoadMoreProductsPageObject} from '../../atomic-commerce-load-more-products/e2e/page-object'; import {FacetsPageObject} from '../../facets/atomic-commerce-facets/e2e/page-object'; import {SearchBoxPageObject} from './page-object'; diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/page-object.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/page-object.ts index bb429930812..21e15b6fd77 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/page-object.ts @@ -1,5 +1,5 @@ import type {Page} from '@playwright/test'; -import {BasePageObject} from '../../../../../playwrightUtils/base-page-object'; +import {BasePageObject} from '../../../../../playwright-utils/base-page-object'; export class SearchBoxPageObject extends BasePageObject<'atomic-commerce-search-box'> { constructor(page: Page) { diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts index 242c3d7c8a5..b1d8c83f3a5 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts @@ -2,14 +2,14 @@ import {test, expect} from './fixture'; test.describe('default', async () => { test('should be A11y compliant', async ({facets, makeAxeBuilder}) => { - await facets.gotoAndHydrate(); + await facets.load(); const accessibilityResults = await makeAxeBuilder().analyze(); expect(accessibilityResults.violations).toEqual([]); }); test('should display facets', async ({facets}) => { - await facets.gotoAndHydrate(); + await facets.load(); await expect(facets.standardFacets.first()).toBeVisible(); await expect(facets.numericFacets.first()).toBeVisible(); await expect(facets.categoryFacets.first()).toBeVisible(); @@ -17,7 +17,7 @@ test.describe('default', async () => { // KIT-3300 test.skip('should collapse facets when set to 1', async ({facets}) => { - await facets.gotoParametrizedAndHydrate({ + await facets.load({ collapseFacetsAfter: 1, }); await expect(facets.expandedFacets).toHaveCount(1); @@ -28,7 +28,7 @@ test.describe('default', async () => { test.skip('should disable collapse facets when set to -1', async ({ facets, }) => { - await facets.gotoParametrizedAndHydrate({ + await facets.load({ collapseFacetsAfter: -1, }); await expect(facets.collapsedFacets).toHaveCount(0); diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts index 96f080f63a7..52a2273ebc5 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/fixture.ts @@ -1,8 +1,8 @@ +import {test as base} from '@playwright/test'; import { AxeFixture, makeAxeBuilder, -} from '@coveo/atomic/playwrightUtils/base-fixture'; -import {test as base} from '@playwright/test'; +} from '../../../../../../playwright-utils/base-fixture'; import {FacetsPageObject} from './page-object'; interface TestFixture { diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts index 97b81c68dc7..2c087d8a80a 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts @@ -1,5 +1,5 @@ import type {Page} from '@playwright/test'; -import {BasePageObject} from '../../../../../../playwrightUtils/base-page-object'; +import {BasePageObject} from '../../../../../../playwright-utils/base-page-object'; export class FacetsPageObject extends BasePageObject<'atomic-commerce-facets'> { constructor(page: Page) { From a69a26f35e7e4ae43a8c82cb660b8135682fdd03 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Mon, 10 Jun 2024 14:27:07 -0400 Subject: [PATCH 05/16] missing await https://coveord.atlassian.net/browse/KIT-3256 --- .../e2e/atomic-commerce-search-box.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts index c992274c8a8..9679e7d050f 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts @@ -49,7 +49,7 @@ test.describe('default', () => { test.describe('with instant results & query suggestions', () => { test.beforeEach(async ({searchBox}) => { - searchBox.load({suggestionTimeout: 5000}, 'rich-search-box'); + await searchBox.load({suggestionTimeout: 5000}, 'rich-search-box'); }); test.describe('after clicking the searchbox input', () => { From 2bc635c44215ba6dda62be4c67e2d2232cd8a1fc Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Mon, 10 Jun 2024 15:30:25 -0400 Subject: [PATCH 06/16] remove wait for https://coveord.atlassian.net/browse/KIT-3256 --- packages/atomic/playwright-utils/base-page-object.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/atomic/playwright-utils/base-page-object.ts b/packages/atomic/playwright-utils/base-page-object.ts index 2da37f6ff0c..7f3d7359cf4 100644 --- a/packages/atomic/playwright-utils/base-page-object.ts +++ b/packages/atomic/playwright-utils/base-page-object.ts @@ -27,7 +27,6 @@ export class BasePageObject< } else { await this.page.goto(`${this.urlRoot}?id=${this.tag}--${story}`); } - await this.hydrated.waitFor(); } private camelToKebab(args: Component) { From f4748555f55e7b8b9c41cbc9d6389844a88eb1ac Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Mon, 10 Jun 2024 15:55:37 -0400 Subject: [PATCH 07/16] fix(atomic): fix collapse-facets-after support for atomic-commerce-facets https://coveord.atlassian.net/browse/KIT-3300 --- .../atomic-commerce-category-facet.tsx | 6 ++++-- .../facets/atomic-commerce-facet/atomic-commerce-facet.tsx | 5 ++++- .../atomic-commerce-numeric-facet.tsx | 5 ++++- .../atomic-commerce-timeframe-facet.tsx | 5 ++++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-category-facet/atomic-commerce-category-facet.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-category-facet/atomic-commerce-category-facet.tsx index e917d4edbc7..e39f9d793a7 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-category-facet/atomic-commerce-category-facet.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-category-facet/atomic-commerce-category-facet.tsx @@ -64,14 +64,16 @@ export class AtomicCategoryFacet implements InitializableComponent { * The category facet controller instance. */ @Prop() public facet!: CategoryFacet; + /** + * Specifies whether the facet is collapsed. + */ + @Prop({reflect: true, mutable: true}) public isCollapsed = false; @BindStateToController('facet') @State() public facetState!: CategoryFacetState; @State() public error!: Error; - @State() private isCollapsed = false; - private resultIndexToFocusOnShowMore = 0; private showLessFocus?: FocusTargetController; private showMoreFocus?: FocusTargetController; diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facet/atomic-commerce-facet.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-facet/atomic-commerce-facet.tsx index 753088fd683..8ccec14d17d 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facet/atomic-commerce-facet.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facet/atomic-commerce-facet.tsx @@ -66,6 +66,10 @@ export class AtomicCommerceFacet implements InitializableComponent { * The facet controller instance. */ @Prop() public facet!: RegularFacet; + /** + * Specifies whether the facet is collapsed. + */ + @Prop({reflect: true, mutable: true}) public isCollapsed = false; @BindStateToController('facet') @State() @@ -73,7 +77,6 @@ export class AtomicCommerceFacet implements InitializableComponent { @State() public error!: Error; - @State() private isCollapsed = false; private showLessFocus?: FocusTargetController; private showMoreFocus?: FocusTargetController; private headerFocus?: FocusTargetController; diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-numeric-facet/atomic-commerce-numeric-facet.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-numeric-facet/atomic-commerce-numeric-facet.tsx index 8ae87983b16..b5e2f071123 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-numeric-facet/atomic-commerce-numeric-facet.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-numeric-facet/atomic-commerce-numeric-facet.tsx @@ -52,7 +52,6 @@ export class AtomicCommerceNumericFacet @State() public error!: Error; - @State() private isCollapsed = false; private manualRanges: (NumericRangeRequest & {label?: string})[] = []; private formatter: NumberFormatter = defaultNumberFormatter; @@ -64,6 +63,10 @@ export class AtomicCommerceNumericFacet * The numeric facet controller instance. */ @Prop({reflect: true}) public facet!: NumericFacet; + /** + * Specifies whether the facet is collapsed. + */ + @Prop({reflect: true, mutable: true}) public isCollapsed = false; private headerFocus?: FocusTargetController; diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-timeframe-facet/atomic-commerce-timeframe-facet.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-timeframe-facet/atomic-commerce-timeframe-facet.tsx index 1388bfb86fe..78b5d12763a 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-timeframe-facet/atomic-commerce-timeframe-facet.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-timeframe-facet/atomic-commerce-timeframe-facet.tsx @@ -52,13 +52,16 @@ export class AtomicCommerceTimeframeFacet * The date facet controller instance. */ @Prop() public facet!: DateFacet; + /** + * Specifies whether the facet is collapsed. + */ + @Prop({reflect: true, mutable: true}) public isCollapsed = false; @BindStateToController('facet') @State() public facetState?: DateFacetState; @State() public error!: Error; - @State() private isCollapsed = false; @State() private inputRange?: DateFilterRange; private headerFocus?: FocusTargetController; From c6dfc832d1adc8cad4c07b020e606b7c2c2a843c Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Tue, 11 Jun 2024 13:10:11 -0400 Subject: [PATCH 08/16] WIP https://coveord.atlassian.net/browse/KIT-3256 --- packages/atomic/src/components.d.ts | 32 +++++++++++++++++++ .../atomic-commerce-facets.new.stories.tsx | 15 +++++++++ .../atomic-commerce-facets.tsx | 13 ++++++-- .../e2e/atomic-commerce-facets.e2e.ts | 13 +++----- .../atomic-commerce-facets/e2e/page-object.ts | 22 +++++-------- 5 files changed, 70 insertions(+), 25 deletions(-) diff --git a/packages/atomic/src/components.d.ts b/packages/atomic/src/components.d.ts index c843af33172..790bf74577d 100644 --- a/packages/atomic/src/components.d.ts +++ b/packages/atomic/src/components.d.ts @@ -274,6 +274,10 @@ export namespace Components { * The category facet controller instance. */ "facet": CategoryFacet; + /** + * Specifies whether the facet is collapsed. + */ + "isCollapsed": boolean; /** * The summary controller instance. */ @@ -289,6 +293,10 @@ export namespace Components { * The facet controller instance. */ "facet": RegularFacet; + /** + * Specifies whether the facet is collapsed. + */ + "isCollapsed": boolean; /** * The Summary controller instance. */ @@ -395,6 +403,10 @@ export namespace Components { * The numeric facet controller instance. */ "facet": NumericFacet; + /** + * Specifies whether the facet is collapsed. + */ + "isCollapsed": boolean; /** * The Summary controller instance. */ @@ -659,6 +671,10 @@ export namespace Components { * The date facet controller instance. */ "facet": DateFacet; + /** + * Specifies whether the facet is collapsed. + */ + "isCollapsed": boolean; /** * The summary controller instance. */ @@ -5665,6 +5681,10 @@ declare namespace LocalJSX { * The category facet controller instance. */ "facet": CategoryFacet; + /** + * Specifies whether the facet is collapsed. + */ + "isCollapsed"?: boolean; /** * The summary controller instance. */ @@ -5680,6 +5700,10 @@ declare namespace LocalJSX { * The facet controller instance. */ "facet": RegularFacet; + /** + * Specifies whether the facet is collapsed. + */ + "isCollapsed"?: boolean; /** * The Summary controller instance. */ @@ -5775,6 +5799,10 @@ declare namespace LocalJSX { * The numeric facet controller instance. */ "facet": NumericFacet; + /** + * Specifies whether the facet is collapsed. + */ + "isCollapsed"?: boolean; /** * The Summary controller instance. */ @@ -6011,6 +6039,10 @@ declare namespace LocalJSX { * The date facet controller instance. */ "facet": DateFacet; + /** + * Specifies whether the facet is collapsed. + */ + "isCollapsed"?: boolean; /** * The summary controller instance. */ diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx index 65b9791289f..2f73a4e3c33 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx @@ -63,3 +63,18 @@ export const InPage: Story = { await playExecuteFirstSearch(context); }, }; + +export const LoadingState: Story = { + name: 'Loading state', + decorators: [ + (story) => + html` + + ${story()} + + `, + ], + play: async (context) => { + await play(context); + }, +}; diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx index e4a4e0b4360..27c8a8e94c0 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx @@ -13,12 +13,13 @@ import { ListingSummary, SearchSummary, } from '@coveo/headless/commerce'; -import {Component, h, Element, Host, State, Prop} from '@stencil/core'; +import {Component, h, Element, State, Prop, Fragment} from '@stencil/core'; import { BindStateToController, InitializableComponent, InitializeBindings, } from '../../../../utils/initialization-utils'; +import {FacetPlaceholder} from '../../../common/facets/facet-placeholder/facet-placeholder'; import {CommerceBindings as Bindings} from '../../atomic-commerce-interface/atomic-commerce-interface'; /** @@ -90,10 +91,16 @@ export class AtomicCommerceFacets implements InitializableComponent { } public render() { + if (!this.summary.state.firstSearchExecuted) { + return [...Array(this.collapseFacetsAfter)].map(() => ( + + )); + } return ( - + {this.facetGenerator.facets.map((facet, index) => { if (facet.state.values.length === 0) { + console.log('yo'); return; } @@ -136,7 +143,7 @@ export class AtomicCommerceFacets implements InitializableComponent { } } })} - + ); } } diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts index b1d8c83f3a5..a94a505b1ba 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts @@ -3,6 +3,7 @@ import {test, expect} from './fixture'; test.describe('default', async () => { test('should be A11y compliant', async ({facets, makeAxeBuilder}) => { await facets.load(); + await facets.hydrated.waitFor(); const accessibilityResults = await makeAxeBuilder().analyze(); expect(accessibilityResults.violations).toEqual([]); @@ -15,23 +16,19 @@ test.describe('default', async () => { await expect(facets.categoryFacets.first()).toBeVisible(); }); - // KIT-3300 - test.skip('should collapse facets when set to 1', async ({facets}) => { + test('should collapse facets when set to 1', async ({facets}) => { await facets.load({ collapseFacetsAfter: 1, }); await expect(facets.expandedFacets).toHaveCount(1); - await expect(facets.collapsedFacets).toHaveCount(3); + await expect(facets.collapsedFacets).toHaveCount(4); }); - // KIT-3300 - test.skip('should disable collapse facets when set to -1', async ({ - facets, - }) => { + test('should disable collapse facets when set to -1', async ({facets}) => { await facets.load({ collapseFacetsAfter: -1, }); await expect(facets.collapsedFacets).toHaveCount(0); - await expect(facets.expandedFacets).toHaveCount(4); + await expect(facets.expandedFacets).toHaveCount(5); }); }); diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts index 2c087d8a80a..69e7dc7baef 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts @@ -5,33 +5,27 @@ export class FacetsPageObject extends BasePageObject<'atomic-commerce-facets'> { constructor(page: Page) { super(page, 'atomic-commerce-facets'); } - - get container() { - return this.page.locator('atomic-commerce-facets'); - } - get standardFacets() { - return this.container.locator('atomic-commerce-facet'); + return this.page + .getByText('Brand') + .or(this.page.getByText('Color')) + .or(this.page.getByText('Size')); } get numericFacets() { - return this.container.locator('atomic-commerce-numeric-facet'); - } - - get timeframeFacets() { - return this.container.locator('atomic-commerce-timeframe-facet'); + return this.page.getByText('Price'); } get categoryFacets() { - return this.container.locator('atomic-commerce-category-facet'); + return this.page.getByText('Category'); } get collapsedFacets() { - return this.container.locator('[aria-expanded="false"]'); + return this.page.getByRole('button', {expanded: false}); } get expandedFacets() { - return this.container.locator('[aria-expanded="true"]'); + return this.page.getByRole('button', {expanded: true}); } get inclusionFilters() { From 849f44989a05d20d8fdccc304169c155d7bb47b9 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Tue, 11 Jun 2024 14:30:44 -0400 Subject: [PATCH 09/16] fix(atomic): fix facet and product list loading state https://coveord.atlassian.net/browse/KIT-3311 --- packages/atomic/src/components.d.ts | 8 ++++++++ .../atomic-commerce-interface.tsx | 1 + .../atomic-commerce-product-list.tsx | 7 ++++++- .../atomic-commerce-facets.tsx | 16 +++++++++++----- .../facet-placeholder/facet-placeholder.tsx | 13 +++++-------- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/atomic/src/components.d.ts b/packages/atomic/src/components.d.ts index a6798173151..767481ff475 100644 --- a/packages/atomic/src/components.d.ts +++ b/packages/atomic/src/components.d.ts @@ -434,6 +434,10 @@ export namespace Components { * The expected size of the image displayed for products. */ "imageSize": ItemDisplayImageSize; + /** + * The desired number of placeholders to display while the product list is loading. + */ + "numberOfPlaceholders": number; /** * Sets a rendering function to bypass the standard HTML template mechanism for rendering products. You can use this function while working with web frameworks that don't use plain HTML syntax, e.g., React, Angular or Vue. Do not use this method if you integrate Atomic in a plain HTML deployment. * @param productRenderingFunction @@ -5813,6 +5817,10 @@ declare namespace LocalJSX { * The expected size of the image displayed for products. */ "imageSize"?: ItemDisplayImageSize; + /** + * The desired number of placeholders to display while the product list is loading. + */ + "numberOfPlaceholders"?: number; } /** * The `atomic-commerce-query-error` component handles fatal errors when performing a query on the Commerce API. When the error is known, it displays a link to relevant documentation for debugging purposes. When the error is unknown, it displays a small text area with the JSON content of the error. diff --git a/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx b/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx index 25649ef9134..cae8de4d94b 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx @@ -181,6 +181,7 @@ export class AtomicCommerceInterface } public connectedCallback() { + this.store.setLoadingFlag(FirstSearchExecutedFlag); this.i18nClone = this.i18n.cloneInstance(); this.i18n.addResourceBundle = ( lng: string, diff --git a/packages/atomic/src/components/commerce/atomic-commerce-product-list/atomic-commerce-product-list.tsx b/packages/atomic/src/components/commerce/atomic-commerce-product-list/atomic-commerce-product-list.tsx index 7b337b8a9b3..5d31a993670 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-product-list/atomic-commerce-product-list.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-product-list/atomic-commerce-product-list.tsx @@ -80,6 +80,11 @@ export class AtomicCommerceProductList @State() public error!: Error; @State() private templateHasError = false; + /** + * The desired number of placeholders to display while the product list is loading. + */ + @Prop({reflect: true}) numberOfPlaceholders = 24; + /** * The desired layout to use when displaying products. Layouts affect how many products to display per row and how visually distinct they are from each other. */ @@ -188,7 +193,7 @@ export class AtomicCommerceProductList display={this.display} imageSize={this.imageSize} displayPlaceholders={!this.bindings.store.isAppLoaded()} - numberOfPlaceholders={this.productState.products.length} + numberOfPlaceholders={this.numberOfPlaceholders} > { @InitializeBindings() public bindings!: Bindings; public facetGenerator!: FacetGenerator; + public summary!: ListingSummary | SearchSummary; @Element() host!: HTMLElement; /** @@ -48,8 +50,7 @@ export class AtomicCommerceFacets implements InitializableComponent { @BindStateToController('facetGenerator') @State() - public facetGeneratorState!: FacetGeneratorState[]; - public summary!: ListingSummary | SearchSummary; + public facetGeneratorState!: FacetGeneratorState; @State() public error!: Error; @@ -90,8 +91,13 @@ export class AtomicCommerceFacets implements InitializableComponent { } public render() { + if (!this.bindings.store.isAppLoaded()) { + return [...Array.from({length: this.collapseFacetsAfter})].map(() => ( + + )); + } return ( - + {this.facetGenerator.facets.map((facet, index) => { if (facet.state.values.length === 0) { return; @@ -136,7 +142,7 @@ export class AtomicCommerceFacets implements InitializableComponent { } } })} - + ); } } diff --git a/packages/atomic/src/components/common/facets/facet-placeholder/facet-placeholder.tsx b/packages/atomic/src/components/common/facets/facet-placeholder/facet-placeholder.tsx index 2add303c308..c52402422a3 100644 --- a/packages/atomic/src/components/common/facets/facet-placeholder/facet-placeholder.tsx +++ b/packages/atomic/src/components/common/facets/facet-placeholder/facet-placeholder.tsx @@ -1,5 +1,4 @@ import {FunctionalComponent, h} from '@stencil/core'; -import {getRandomArbitrary} from '../../../../utils/utils'; export interface FacetPlaceholderProps { numberOfValues: number; @@ -12,10 +11,11 @@ export const FacetPlaceholder: FunctionalComponent = ({ }) => { const facetValues = []; for (let i = 0; i < numberOfValues; i++) { - const width = `${getRandomArbitrary(60, 100)}%`; - const opacity = `${getRandomArbitrary(0.3, 1)}`; facetValues.push( -
+
); } @@ -25,10 +25,7 @@ export const FacetPlaceholder: FunctionalComponent = ({ class="bg-background animate-pulse border border-neutral rounded-lg mb-4 p-7" aria-hidden="true" > -
+
{!isCollapsed &&
{facetValues}
} ); From b2917fba3a1d493f4678a3543c1af4cedcf366f6 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Tue, 11 Jun 2024 16:04:11 -0400 Subject: [PATCH 10/16] wip https://coveord.atlassian.net/browse/KIT-3256 --- .../atomic-angular.module.ts | 2 + .../src/lib/stencil-generated/components.ts | 22 +++++ .../atomic-commerce-interface.tsx | 15 +--- .../atomic-commerce-facets.new.stories.tsx | 8 -- .../atomic-commerce-facets.tsx | 1 + .../e2e/atomic-commerce-facets.e2e.ts | 7 ++ .../atomic-commerce-facets/e2e/page-object.ts | 4 + .../search/atomic-pager/atomic-pager.tsx | 4 +- .../examples/commerce-website/search.html | 82 ------------------- 9 files changed, 42 insertions(+), 103 deletions(-) diff --git a/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/atomic-angular.module.ts b/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/atomic-angular.module.ts index afa95b9b85c..f421d1f1f3c 100644 --- a/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/atomic-angular.module.ts +++ b/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/atomic-angular.module.ts @@ -11,6 +11,7 @@ AtomicAutomaticFacetGenerator, AtomicBreadbox, AtomicCategoryFacet, AtomicColorFacet, +AtomicCommerceFacets, AtomicCommerceSearchBox, AtomicComponentError, AtomicDidYouMean, @@ -109,6 +110,7 @@ AtomicAutomaticFacetGenerator, AtomicBreadbox, AtomicCategoryFacet, AtomicColorFacet, +AtomicCommerceFacets, AtomicCommerceSearchBox, AtomicComponentError, AtomicDidYouMean, diff --git a/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts b/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts index 3844ee543ed..76b49df659d 100644 --- a/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts +++ b/packages/atomic-angular/projects/atomic-angular/src/lib/stencil-generated/components.ts @@ -138,6 +138,28 @@ export class AtomicColorFacet { export declare interface AtomicColorFacet extends Components.AtomicColorFacet {} +@ProxyCmp({ + inputs: ['collapseFacetsAfter'] +}) +@Component({ + selector: 'atomic-commerce-facets', + changeDetection: ChangeDetectionStrategy.OnPush, + template: '', + // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property + inputs: ['collapseFacetsAfter'], +}) +export class AtomicCommerceFacets { + protected el: HTMLElement; + constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { + c.detach(); + this.el = r.nativeElement; + } +} + + +export declare interface AtomicCommerceFacets extends Components.AtomicCommerceFacets {} + + @ProxyCmp({ inputs: ['clearFilters', 'disableSearch', 'minimumQueryLength', 'numberOfQueries', 'redirectionUrl', 'suggestionDelay', 'suggestionTimeout'] }) diff --git a/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx b/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx index cae8de4d94b..2f45d5ec9e4 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx @@ -79,7 +79,6 @@ export class AtomicCommerceInterface private summary!: SearchSummary | ListingSummary; private context!: Context; private unsubscribeUrlManager: Unsubscribe = () => {}; - private unsubscribeSearchStatus: Unsubscribe = () => {}; private unsubscribeSummary: Unsubscribe = () => {}; private initialized = false; private store: AtomicCommerceStore; @@ -221,7 +220,6 @@ export class AtomicCommerceInterface public disconnectedCallback() { this.unsubscribeUrlManager(); - this.unsubscribeSearchStatus(); this.unsubscribeSummary(); window.removeEventListener('hashchange', this.onHashChange); } @@ -368,15 +366,6 @@ export class AtomicCommerceInterface this.type === 'product-listing' ? buildProductListing(this.engine!) : buildSearch(this.engine!); - - this.unsubscribeSearchStatus = this.searchOrListing.subscribe(() => { - if ( - !this.searchOrListing.state.isLoading && - this.store.hasLoadingFlag(FirstSearchExecutedFlag) - ) { - this.store.unsetLoadingFlag(FirstSearchExecutedFlag); - } - }); } private initSummary() { @@ -401,6 +390,10 @@ export class AtomicCommerceInterface firstSearchExecutedSelector, firstSearchExecuted ); + + if (firstSearchExecuted) { + this.bindings.store.unsetLoadingFlag(FirstSearchExecutedFlag); + } }); } diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx index 2f73a4e3c33..0a3773c1a34 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.new.stories.tsx @@ -66,14 +66,6 @@ export const InPage: Story = { export const LoadingState: Story = { name: 'Loading state', - decorators: [ - (story) => - html` - - ${story()} - - `, - ], play: async (context) => { await play(context); }, diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx index bc5337e6c59..cc739e6f343 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx @@ -96,6 +96,7 @@ export class AtomicCommerceFacets implements InitializableComponent { )); } + return ( {this.facetGenerator.facets.map((facet, index) => { diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts index a94a505b1ba..5c3c9f4e3eb 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts @@ -31,4 +31,11 @@ test.describe('default', async () => { await expect(facets.collapsedFacets).toHaveCount(0); await expect(facets.expandedFacets).toHaveCount(5); }); + + test('should display placeholder equal to the collapse facet after property', async ({ + facets, + }) => { + await facets.load({collapseFacetsAfter: 5}, 'loading-state'); + await expect(facets.placeholders).toHaveCount(5); + }); }); diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts index 69e7dc7baef..6c345bb30e2 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/page-object.ts @@ -32,6 +32,10 @@ export class FacetsPageObject extends BasePageObject<'atomic-commerce-facets'> { return this.page.getByLabel(/Inclusion filter/); } + get placeholders() { + return this.page.locator('[part="placeholder"]'); + } + clearFilters(numberOfFilters?: number) { return this.page.getByLabel( new RegExp(`Clear ${numberOfFilters ?? '\\d'} filter for`) diff --git a/packages/atomic/src/components/search/atomic-pager/atomic-pager.tsx b/packages/atomic/src/components/search/atomic-pager/atomic-pager.tsx index 37c74bab35f..6ded759e15b 100644 --- a/packages/atomic/src/components/search/atomic-pager/atomic-pager.tsx +++ b/packages/atomic/src/components/search/atomic-pager/atomic-pager.tsx @@ -35,7 +35,7 @@ import {Bindings} from '../atomic-search-interface/atomic-search-interface'; * @part active-page-button - The active page button. * @part previous-button - The previous button. * @part next-button - The next button. - * @part previous-button-icon - Icon of the previous button. + * @part previous-button-icon-2 - Icon of the previous button. * @part next-button-icon - Icon of the next button. */ @Component({ @@ -73,7 +73,7 @@ export class AtomicPager implements InitializableComponent { * - Use a value that starts with `assets://`, to display an icon from the Atomic package. * - Use a stringified SVG to display it directly. */ - @Prop({reflect: true}) previousButtonIcon = ArrowLeftIcon; + @Prop({reflect: true}) previousButtonIcon: string = ArrowLeftIcon; /** * The SVG icon to use to display the Next button. diff --git a/packages/atomic/src/pages/examples/commerce-website/search.html b/packages/atomic/src/pages/examples/commerce-website/search.html index 0d38f02b422..dbdeec0f8c5 100644 --- a/packages/atomic/src/pages/examples/commerce-website/search.html +++ b/packages/atomic/src/pages/examples/commerce-website/search.html @@ -28,91 +28,9 @@

Search page

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
From 96c3980f07d3c2977e7050124263b62f58f4f250 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Thu, 13 Jun 2024 14:54:15 -0400 Subject: [PATCH 11/16] fix merge https://coveord.atlassian.net/browse/KIT-3256 --- .../playwright-utils/base-page-object.ts | 2 +- .../e2e/atomic-commerce-search-box.e2e.ts | 58 +++++-------------- packages/atomic/tsconfig.json | 3 +- 3 files changed, 19 insertions(+), 44 deletions(-) diff --git a/packages/atomic/playwright-utils/base-page-object.ts b/packages/atomic/playwright-utils/base-page-object.ts index 7f3d7359cf4..17663a8af7d 100644 --- a/packages/atomic/playwright-utils/base-page-object.ts +++ b/packages/atomic/playwright-utils/base-page-object.ts @@ -33,7 +33,7 @@ export class BasePageObject< const toKebab: Record = {}; Object.entries(args as Record).forEach(([key, value]) => { toKebab[ - key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase() + `attributes-${key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase()}` ] = value; }); diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts index f7ad243c2e3..6f8a138e6ff 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts @@ -1,10 +1,8 @@ import {test, expect} from './fixture'; test.describe('default', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--default&viewMode=story&args=attributes-suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.load({suggestionTimeout: 5000}); }); test('should have an enabled search button', async ({searchBox}) => { @@ -50,10 +48,8 @@ test.describe('default', () => { }); test.describe('with instant results & query suggestions', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--rich-search-box&viewMode=story&args=attributes-suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.load({suggestionTimeout: 5000}, 'rich-search-box'); }); test.describe('after clicking the searchbox input', () => { @@ -82,10 +78,12 @@ test.describe('with instant results & query suggestions', () => { }); test.describe('with disable-search=true and minimum-query-length=1', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--default&viewMode=story&args=attributes-disable-search:!true;attributes-minimum-query-length:1;attributes-suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.load({ + suggestionTimeout: 5000, + disableSearch: true, + minimumQueryLength: 1, + }); }); const testCases = () => { @@ -124,10 +122,8 @@ test.describe('with disable-search=true and minimum-query-length=1', () => { }); test.describe('with minimum-query-length=4', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--default&viewMode=story&args=attributes-minimum-query-length:4;attributes-suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.load({minimumQueryLength: 4, suggestionTimeout: 5000}); }); const testCases = () => { @@ -180,10 +176,8 @@ test.describe('with minimum-query-length=4', () => { }); test.describe('with a facet & clear-filters set to true', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--in-page&args=attributes-clear-filters:!true;attributes-suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.load({clearFilters: true, suggestionTimeout: 5000}); }); test('clicking the submit button should clear the facet value', async ({ @@ -198,10 +192,8 @@ test.describe('with a facet & clear-filters set to true', () => { }); test.describe('with a facet & clear-filters set to false', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--in-page&args=attributes-clear-filters:!false;attributes-suggestion-timeout:5000' - ); + test.beforeEach(async ({searchBox}) => { + await searchBox.load({clearFilters: false, suggestionTimeout: 5000}); }); test('clicking the submit button should not clear the facet value', async ({ @@ -214,21 +206,3 @@ test.describe('with a facet & clear-filters set to false', () => { await expect(facets.clearFilters()).toBeVisible(); }); }); - -test.describe('with enable-query-syntax=true', () => { - test.beforeEach(async ({page}) => { - await page.goto( - 'http://localhost:4400/iframe.html?id=atomic-commerce-search-box--in-page&viewMode=story&args=attributes-enable-query-syntax:!true;attributes-suggestion-timeout:5000' - ); - }); - - test('should use query syntax', async ({loadMore, searchBox, page}) => { - await loadMore.loadMoreButton.waitFor({state: 'visible'}); - await searchBox.searchInput - // eslint-disable-next-line @cspell/spellchecker - .fill('@urihash=bzo5fpM1vf8Xñds1'); - await searchBox.submitButton.click(); - await expect(loadMore.summary({total: 1})).toBeVisible(); - await expect(page.getByText('WiLife Life Jacket WiLife')).toBeVisible(); - }); -}); diff --git a/packages/atomic/tsconfig.json b/packages/atomic/tsconfig.json index bf0a1ed5230..88a30e3ee65 100644 --- a/packages/atomic/tsconfig.json +++ b/packages/atomic/tsconfig.json @@ -26,6 +26,7 @@ "src/external-builds", "**/*.stories.tsx", "**/*.stories.ts", - "**/*.stories.js" + "**/*.stories.js", + "**/e2e/**/*" ] } From dab5a6e5db5a7b02dc75fa3554f9bb14490b6e80 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Thu, 13 Jun 2024 15:07:20 -0400 Subject: [PATCH 12/16] cleanup https://coveord.atlassian.net/browse/KIT-3256 --- .../atomic-commerce-interface.tsx | 15 +++++--- .../search/atomic-pager/atomic-pager.tsx | 2 +- .../examples/commerce-website/search.html | 34 +++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx b/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx index 2f45d5ec9e4..cae8de4d94b 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx @@ -79,6 +79,7 @@ export class AtomicCommerceInterface private summary!: SearchSummary | ListingSummary; private context!: Context; private unsubscribeUrlManager: Unsubscribe = () => {}; + private unsubscribeSearchStatus: Unsubscribe = () => {}; private unsubscribeSummary: Unsubscribe = () => {}; private initialized = false; private store: AtomicCommerceStore; @@ -220,6 +221,7 @@ export class AtomicCommerceInterface public disconnectedCallback() { this.unsubscribeUrlManager(); + this.unsubscribeSearchStatus(); this.unsubscribeSummary(); window.removeEventListener('hashchange', this.onHashChange); } @@ -366,6 +368,15 @@ export class AtomicCommerceInterface this.type === 'product-listing' ? buildProductListing(this.engine!) : buildSearch(this.engine!); + + this.unsubscribeSearchStatus = this.searchOrListing.subscribe(() => { + if ( + !this.searchOrListing.state.isLoading && + this.store.hasLoadingFlag(FirstSearchExecutedFlag) + ) { + this.store.unsetLoadingFlag(FirstSearchExecutedFlag); + } + }); } private initSummary() { @@ -390,10 +401,6 @@ export class AtomicCommerceInterface firstSearchExecutedSelector, firstSearchExecuted ); - - if (firstSearchExecuted) { - this.bindings.store.unsetLoadingFlag(FirstSearchExecutedFlag); - } }); } diff --git a/packages/atomic/src/components/search/atomic-pager/atomic-pager.tsx b/packages/atomic/src/components/search/atomic-pager/atomic-pager.tsx index 1b3378bbdeb..0e9d35f451a 100644 --- a/packages/atomic/src/components/search/atomic-pager/atomic-pager.tsx +++ b/packages/atomic/src/components/search/atomic-pager/atomic-pager.tsx @@ -35,7 +35,7 @@ import {Bindings} from '../atomic-search-interface/atomic-search-interface'; * @part active-page-button - The active page button. * @part previous-button - The previous button. * @part next-button - The next button. - * @part previous-button-icon-2 - Icon of the previous button. + * @part previous-button-icon - Icon of the previous button. * @part next-button-icon - Icon of the next button. */ @Component({ diff --git a/packages/atomic/src/pages/examples/commerce-website/search.html b/packages/atomic/src/pages/examples/commerce-website/search.html index 8dcc441ae5d..2be8bd1afea 100644 --- a/packages/atomic/src/pages/examples/commerce-website/search.html +++ b/packages/atomic/src/pages/examples/commerce-website/search.html @@ -28,6 +28,40 @@

Search page

+ + + + + + + + + + + From 655d7586280f95d89c6f9be0afc56c1083058459 Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Thu, 13 Jun 2024 15:08:45 -0400 Subject: [PATCH 13/16] cleanup https://coveord.atlassian.net/browse/KIT-3256 --- .../facets/atomic-commerce-facets/atomic-commerce-facets.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx index bc5337e6c59..dfd22b4e06f 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/atomic-commerce-facets.tsx @@ -100,7 +100,6 @@ export class AtomicCommerceFacets implements InitializableComponent { {this.facetGenerator.facets.map((facet, index) => { if (facet.state.values.length === 0) { - console.log('yo'); return; } From 26e6061c98827c4abd407862f71fdeaa6b1787af Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Mon, 17 Jun 2024 15:22:56 -0400 Subject: [PATCH 14/16] fix loading state https://coveord.atlassian.net/browse/KIT-3256 --- .../atomic-commerce-interface.tsx | 15 ++++----------- .../e2e/atomic-commerce-facets.e2e.ts | 2 ++ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx b/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx index 0da28c7368e..afacd4e1b23 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx +++ b/packages/atomic/src/components/commerce/atomic-commerce-interface/atomic-commerce-interface.tsx @@ -79,7 +79,6 @@ export class AtomicCommerceInterface private summary!: SearchSummary | ListingSummary; private context!: Context; private unsubscribeUrlManager: Unsubscribe = () => {}; - private unsubscribeSearchStatus: Unsubscribe = () => {}; private unsubscribeSummary: Unsubscribe = () => {}; private initialized = false; private store: AtomicCommerceStore; @@ -226,7 +225,6 @@ export class AtomicCommerceInterface public disconnectedCallback() { this.unsubscribeUrlManager(); - this.unsubscribeSearchStatus(); this.unsubscribeSummary(); window.removeEventListener('hashchange', this.onHashChange); } @@ -373,15 +371,6 @@ export class AtomicCommerceInterface this.type === 'product-listing' ? buildProductListing(this.engine!) : buildSearch(this.engine!); - - this.unsubscribeSearchStatus = this.searchOrListing.subscribe(() => { - if ( - !this.searchOrListing.state.isLoading && - this.store.hasLoadingFlag(FirstSearchExecutedFlag) - ) { - this.store.unsetLoadingFlag(FirstSearchExecutedFlag); - } - }); } private initSummary() { @@ -406,6 +395,10 @@ export class AtomicCommerceInterface firstSearchExecutedSelector, firstSearchExecuted ); + + if (firstSearchExecuted) { + this.store.unsetLoadingFlag(FirstSearchExecutedFlag); + } }); } diff --git a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts index 5c3c9f4e3eb..c4719114b91 100644 --- a/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts +++ b/packages/atomic/src/components/commerce/facets/atomic-commerce-facets/e2e/atomic-commerce-facets.e2e.ts @@ -31,7 +31,9 @@ test.describe('default', async () => { await expect(facets.collapsedFacets).toHaveCount(0); await expect(facets.expandedFacets).toHaveCount(5); }); +}); +test.describe('loading state', async () => { test('should display placeholder equal to the collapse facet after property', async ({ facets, }) => { From 949df6444f28076554f676c02de113e1e7d63fbc Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Tue, 18 Jun 2024 09:30:10 -0400 Subject: [PATCH 15/16] fix story id https://coveord.atlassian.net/browse/KIT-3256 --- .../e2e/atomic-commerce-search-box.e2e.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts index 6f8a138e6ff..f3534c2c100 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts @@ -177,7 +177,10 @@ test.describe('with minimum-query-length=4', () => { test.describe('with a facet & clear-filters set to true', () => { test.beforeEach(async ({searchBox}) => { - await searchBox.load({clearFilters: true, suggestionTimeout: 5000}); + await searchBox.load( + {clearFilters: true, suggestionTimeout: 5000}, + 'in-page' + ); }); test('clicking the submit button should clear the facet value', async ({ From ff3363bfc0e0327769dbb6bfc05f9db6b7cbfcee Mon Sep 17 00:00:00 2001 From: Olivier Lamothe Date: Tue, 18 Jun 2024 09:45:47 -0400 Subject: [PATCH 16/16] fix story id https://coveord.atlassian.net/browse/KIT-3256 --- .../e2e/atomic-commerce-search-box.e2e.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts index f3534c2c100..3e34756ba45 100644 --- a/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts +++ b/packages/atomic/src/components/commerce/atomic-commerce-search-box/e2e/atomic-commerce-search-box.e2e.ts @@ -196,7 +196,10 @@ test.describe('with a facet & clear-filters set to true', () => { test.describe('with a facet & clear-filters set to false', () => { test.beforeEach(async ({searchBox}) => { - await searchBox.load({clearFilters: false, suggestionTimeout: 5000}); + await searchBox.load( + {clearFilters: false, suggestionTimeout: 5000}, + 'in-page' + ); }); test('clicking the submit button should not clear the facet value', async ({