diff --git a/.storybook/wcag/test-runner.ts b/.storybook/wcag/test-runner.ts index c8183794f..afc1189ab 100644 --- a/.storybook/wcag/test-runner.ts +++ b/.storybook/wcag/test-runner.ts @@ -3,6 +3,49 @@ import { Page } from 'playwright-core'; import { runOnly } from '../wcagConfig'; import { TestContext, TestRunnerConfig } from '@storybook/test-runner'; +const AXE_ALREADY_RUNNING_ERROR = 'Axe is already running'; +const MAX_AXE_RETRIES = 3; +const AXE_RETRY_DELAY_MS = 250; + +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +// Retry if errors from Axe already running to decrease flakiness +const runA11yCheck = async (page: Page, context: TestContext) => { + for (let attempt = 1; attempt <= MAX_AXE_RETRIES; attempt++) { + try { + await checkA11y( + page, + { + exclude: [ + '#root .mapboxgl-canvas-container', + '.mapboxgl-marker', + '.mapboxgl-popup-close-button' + ], + }, + { + axeOptions: { + runOnly, + rules: { + 'color-contrast': { enabled: context.name !== 'Loading' }, + }, + }, + detailedReport: true, + detailedReportOptions: { + html: true, + }, + } + ); + return; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + if (!message.includes(AXE_ALREADY_RUNNING_ERROR) || attempt === MAX_AXE_RETRIES) { + throw error; + } + await sleep(AXE_RETRY_DELAY_MS * attempt); + } + } +}; + /** * See https://storybook.js.org/docs/react/writing-tests/test-runner#test-hook-api-experimental * to learn more about the test-runner hooks API. @@ -12,28 +55,7 @@ const renderFunctions: TestRunnerConfig = { await injectAxe(page); }, async postVisit(page: Page, context: TestContext) { - await checkA11y( - page, - { - exclude: [ - '#root .mapboxgl-canvas-container', - '.mapboxgl-marker', - '.mapboxgl-popup-close-button' - ], - }, - { - axeOptions: { - runOnly, - rules: { - 'color-contrast': { enabled: context.name !== 'Loading' }, - }, - }, - detailedReport: true, - detailedReportOptions: { - html: true, - }, - } - ); + await runA11yCheck(page, context); }, }; diff --git a/package-lock.json b/package-lock.json index f38c1bc4b..fe0ba50a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@yext/search-ui-react", - "version": "2.1.1", + "version": "2.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@yext/search-ui-react", - "version": "2.1.1", + "version": "2.1.2", "license": "BSD-3-Clause", "dependencies": { "@restart/ui": "^1.0.1", diff --git a/package.json b/package.json index 9418feb58..d15c28580 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@yext/search-ui-react", - "version": "2.1.1", + "version": "2.1.2", "description": "A library of React Components for powering Yext Search integrations", "author": "watson@yext.com", "license": "BSD-3-Clause", diff --git a/src/components/AppliedFiltersDisplay.tsx b/src/components/AppliedFiltersDisplay.tsx index 1ac67aac7..c0b4e552b 100644 --- a/src/components/AppliedFiltersDisplay.tsx +++ b/src/components/AppliedFiltersDisplay.tsx @@ -80,9 +80,9 @@ export function AppliedFiltersDisplay(props: AppliedFiltersDisplayProps): React. {removableFiltersWithHandlers.map(({ filter, handleRemove }, i) => { return ( ); @@ -119,17 +119,15 @@ function getDedupedRemovableFilters(filters: RemovableFilter[]) { function RemovableFilter({ displayName, handleRemove, - index, cssClasses }: { displayName: string | undefined, handleRemove: () => void, - index: number, cssClasses: AppliedFiltersCssClasses }): React.JSX.Element { const { t } = useTranslation(); return ( -
+
{displayName}