Skip to content

Commit

Permalink
test: atomic-commerce-searchbox (playwright demo) (#4033)
Browse files Browse the repository at this point in the history
  • Loading branch information
louis-bompart authored Jun 4, 2024
1 parent 20c0978 commit 7aa6094
Show file tree
Hide file tree
Showing 15 changed files with 621 additions and 6 deletions.
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ AtomicAutomaticFacetGenerator,
AtomicBreadbox,
AtomicCategoryFacet,
AtomicColorFacet,
AtomicCommerceSearchBox,
AtomicComponentError,
AtomicDidYouMean,
AtomicExternal,
Expand Down Expand Up @@ -108,6 +109,7 @@ AtomicAutomaticFacetGenerator,
AtomicBreadbox,
AtomicCategoryFacet,
AtomicColorFacet,
AtomicCommerceSearchBox,
AtomicComponentError,
AtomicDidYouMean,
AtomicExternal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,48 @@ export class AtomicColorFacet {
export declare interface AtomicColorFacet extends Components.AtomicColorFacet {}


@ProxyCmp({
inputs: ['clearFilters', 'disableSearch', 'minimumQueryLength', 'numberOfQueries', 'redirectionUrl', 'suggestionDelay', 'suggestionTimeout']
})
@Component({
selector: 'atomic-commerce-search-box',
changeDetection: ChangeDetectionStrategy.OnPush,
template: '<ng-content></ng-content>',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
inputs: ['clearFilters', 'disableSearch', 'minimumQueryLength', 'numberOfQueries', 'redirectionUrl', 'suggestionDelay', 'suggestionTimeout'],
})
export class AtomicCommerceSearchBox {
protected el: HTMLElement;
constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) {
c.detach();
this.el = r.nativeElement;
proxyOutputs(this, this.el, ['redirect']);
}
}


import type { RedirectionPayload as IAtomicCommerceSearchBoxRedirectionPayload } from '@coveo/atomic';

export declare interface AtomicCommerceSearchBox extends Components.AtomicCommerceSearchBox {
/**
* Event that is emitted when a standalone search box redirection is triggered. By default, the search box will directly change the URL and redirect accordingly, so if you want to handle the redirection differently, use this event.
Example:
```html
<script>
document.querySelector('atomic-commerce-search-box').addEventListener((e) => {
e.preventDefault();
// handle redirection
});
</script>
...
<atomic-commerce-search-box redirection-url="/search"></atomic-commerce-search-box>
```
*/
redirect: EventEmitter<CustomEvent<IAtomicCommerceSearchBoxRedirectionPayload>>;
}


@ProxyCmp({
inputs: ['element', 'error']
})
Expand Down
1 change: 1 addition & 0 deletions packages/atomic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"ts-debounce": "^4.0.0"
},
"devDependencies": {
"@axe-core/playwright": "4.9.1",
"@babel/core": "7.24.5",
"@coveo/atomic": "2.65.5",
"@coveo/headless": "2.63.5",
Expand Down
21 changes: 21 additions & 0 deletions packages/atomic/playwrightUtils/base-fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import AxeBuilder from '@axe-core/playwright';
import type {test as base} from '@playwright/test';

export type AxeFixture = {
makeAxeBuilder: () => AxeBuilder;
};

// Extend base test by providing "makeAxeBuilder"
//
// This new "test" can be used in multiple test files, and each of them will get
// a consistently configured AxeBuilder instance.
export const makeAxeBuilder: Parameters<
typeof base.extend<AxeFixture>
>[0]['makeAxeBuilder'] = async ({page}, use) => {
const makeAxeBuilder = () =>
new AxeBuilder({page})
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.include('#code-root');

await use(makeAxeBuilder);
};
4 changes: 4 additions & 0 deletions packages/atomic/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ export namespace Components {
}
/**
* The `atomic-commerce-search-box` component creates a search box with built-in support for suggestions.
* @alpha
*/
interface AtomicCommerceSearchBox {
/**
Expand Down Expand Up @@ -3586,6 +3587,7 @@ declare global {
}
/**
* The `atomic-commerce-search-box` component creates a search box with built-in support for suggestions.
* @alpha
*/
interface HTMLAtomicCommerceSearchBoxElement extends Components.AtomicCommerceSearchBox, HTMLStencilElement {
addEventListener<K extends keyof HTMLAtomicCommerceSearchBoxElementEventMap>(type: K, listener: (this: HTMLAtomicCommerceSearchBoxElement, ev: AtomicCommerceSearchBoxCustomEvent<HTMLAtomicCommerceSearchBoxElementEventMap[K]>) => any, options?: boolean | AddEventListenerOptions): void;
Expand Down Expand Up @@ -5888,6 +5890,7 @@ declare namespace LocalJSX {
}
/**
* The `atomic-commerce-search-box` component creates a search box with built-in support for suggestions.
* @alpha
*/
interface AtomicCommerceSearchBox {
/**
Expand Down Expand Up @@ -8773,6 +8776,7 @@ declare module "@stencil/core" {
"atomic-commerce-recommendation-list": LocalJSX.AtomicCommerceRecommendationList & JSXBase.HTMLAttributes<HTMLAtomicCommerceRecommendationListElement>;
/**
* The `atomic-commerce-search-box` component creates a search box with built-in support for suggestions.
* @alpha
*/
"atomic-commerce-search-box": LocalJSX.AtomicCommerceSearchBox & JSXBase.HTMLAttributes<HTMLAtomicCommerceSearchBoxElement>;
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type {Page} from '@playwright/test';

export class AtomicCommerceLoadMoreProductsLocators {
private page: Page;
constructor(page: Page) {
this.page = page;
}

summary({index, total}: {index?: number; total?: number} = {}) {
return this.page.getByText(
new RegExp(
`Showing ${index ?? '\\d'} of ${total ?? '\\d'} result${total === 1 ? '' : 's'}.`
)
);
}

get loadMoreButton() {
return this.page.getByText('Load more results');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
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-search-box',
title: 'Atomic-Commerce/Searchbox',
id: 'atomic-commerce-search-box',
render: renderComponent,
decorators: [decorator],
parameters,
play,
};

export default meta;

export const Default: Story = {
name: 'atomic-commerce-search-box',
};

export const RichSearchBox: Story = {
name: 'With suggestions and recent queries',
args: {
default: ` <atomic-commerce-search-box-recent-queries></atomic-commerce-search-box-recent-queries>
<atomic-commerce-search-box-query-suggestions></atomic-commerce-search-box-query-suggestions>
<atomic-commerce-search-box-instant-products
image-size="small"
></atomic-commerce-search-box-instant-products>`,
},
};

export const InPage: Story = {
name: 'In a page',
decorators: [
(story) =>
html` <atomic-commerce-layout>
<atomic-layout-section section="search">
${story()}
</atomic-layout-section>
<atomic-layout-section section="facets"
><atomic-commerce-facets></atomic-commerce-facets
></atomic-layout-section>
<atomic-layout-section section="main">
<atomic-layout-section section="status">
<atomic-commerce-query-summary></atomic-commerce-query-summary>
<atomic-commerce-sort-dropdown></atomic-commerce-sort-dropdown>
</atomic-layout-section>
<atomic-layout-section section="products">
<atomic-commerce-product-list
display="grid"
density="compact"
image-size="small"
>
</atomic-commerce-product-list>
<atomic-commerce-query-error></atomic-commerce-query-error>
</atomic-layout-section>
<atomic-layout-section section="pagination">
<atomic-commerce-load-more-products></atomic-commerce-load-more-products>
<!-- Alternative pagination
<atomic-commerce-pager></atomic-commerce-pager>
-->
</atomic-layout-section>
</atomic-layout-section>
</atomic-commerce-layout>`,
],
play: async (context) => {
await play(context);
await playExecuteFirstSearch(context);
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ import {SelectChildProductEventArgs} from '../product-template-components/atomic
/**
* The `atomic-commerce-search-box` component creates a search box with built-in support for suggestions.
*
* @slot default - The default slot where you can add child components to the search box.
*
* @part wrapper - The search box wrapper.
* @part input - The search box input.
* @part loading - The search box loading animation.
Expand Down Expand Up @@ -92,7 +94,7 @@ import {SelectChildProductEventArgs} from '../product-template-components/atomic
* @part instant-results-show-all - The clickable suggestion to show all items for the current instant results search rendered by an `atomic-commerce-search-box-instant-products` component.
* @part instant-results-show-all-button - The button inside the clickable suggestion from the `atomic-commerce-search-box-instant-products` component.
*
* @internal
* @alpha
*/
@Component({
tag: 'atomic-commerce-search-box',
Expand Down
Loading

0 comments on commit 7aa6094

Please sign in to comment.