Skip to content

Commit 9c386f4

Browse files
github-actions[bot]Fondryextanguyen-yext2k-gerner
authored
Merge main (v2.1.2) into develop (#646)
* feat: allow users to turn analytics on and off (v2.1.0) (#632) * feat: allow users to turn analytics on and off (v2.1.0) This PR adds a new property to the SearchAnalyticsConfig, which can be used to start with analytics enabled or disabled by default. Three new methods are added to the analytics object- two to turn analytics on/off, and one to get the current enabled status. J=WAT-5404 TEST=auto, manual Ran test site locally with debugging and buttons to turn analytics on and off, saw expected behavior. * Update various names to be in-line with pages code * Automated update to repo's documentation from github action * Add enableYextAnalytics function to window * drop unneeded parens --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> * release: v2.1.0 * More accessbilities fixes for autocomplete results (#635) * More accessbilities fixes for autocomplete results Associate the visible label with the input via `label` + `htmlFor`, and wire `DropdownInput` with `inputId` and `aria-labelledby`. Change the instructions container from `hidden` to `sr-only`, so `aria-describedby` references content that is actually exposed to screen readers. J=WAT-5357 TEST=manual tested with voice over enabled on test-site * Update snapshots --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> * release: v2.1.1 * chore: suppress error/warning spam, fix key errors etc (#642) * fix: point TypeScript output to dist directory (#644) * suppress error/warning spam, fix key errors etc * set ts output dir to dist * retry logic to WCAG * release: v2.1.2 --------- Co-authored-by: Fondryext <160865254+Fondryext@users.noreply.github.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Jacob Fondriest <jfondriest@yext.com> Co-authored-by: anguyen-yext2 <143001514+anguyen-yext2@users.noreply.github.com> Co-authored-by: anguyen-yext2 <anguyen@yext.com> Co-authored-by: Kyle Gerner <49618240+k-gerner@users.noreply.github.com> Co-authored-by: Kyle Gerner <kgerner@yext.com>
1 parent a123c21 commit 9c386f4

9 files changed

Lines changed: 103 additions & 36 deletions

File tree

.storybook/wcag/test-runner.ts

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,49 @@ import { Page } from 'playwright-core';
33
import { runOnly } from '../wcagConfig';
44
import { TestContext, TestRunnerConfig } from '@storybook/test-runner';
55

6+
const AXE_ALREADY_RUNNING_ERROR = 'Axe is already running';
7+
const MAX_AXE_RETRIES = 3;
8+
const AXE_RETRY_DELAY_MS = 250;
9+
10+
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
11+
12+
// Retry if errors from Axe already running to decrease flakiness
13+
const runA11yCheck = async (page: Page, context: TestContext) => {
14+
for (let attempt = 1; attempt <= MAX_AXE_RETRIES; attempt++) {
15+
try {
16+
await checkA11y(
17+
page,
18+
{
19+
exclude: [
20+
'#root .mapboxgl-canvas-container',
21+
'.mapboxgl-marker',
22+
'.mapboxgl-popup-close-button'
23+
],
24+
},
25+
{
26+
axeOptions: {
27+
runOnly,
28+
rules: {
29+
'color-contrast': { enabled: context.name !== 'Loading' },
30+
},
31+
},
32+
detailedReport: true,
33+
detailedReportOptions: {
34+
html: true,
35+
},
36+
}
37+
);
38+
return;
39+
} catch (error) {
40+
const message = error instanceof Error ? error.message : String(error);
41+
if (!message.includes(AXE_ALREADY_RUNNING_ERROR) || attempt === MAX_AXE_RETRIES) {
42+
throw error;
43+
}
44+
await sleep(AXE_RETRY_DELAY_MS * attempt);
45+
}
46+
}
47+
};
48+
649
/**
750
* See https://storybook.js.org/docs/react/writing-tests/test-runner#test-hook-api-experimental
851
* to learn more about the test-runner hooks API.
@@ -12,28 +55,7 @@ const renderFunctions: TestRunnerConfig = {
1255
await injectAxe(page);
1356
},
1457
async postVisit(page: Page, context: TestContext) {
15-
await checkA11y(
16-
page,
17-
{
18-
exclude: [
19-
'#root .mapboxgl-canvas-container',
20-
'.mapboxgl-marker',
21-
'.mapboxgl-popup-close-button'
22-
],
23-
},
24-
{
25-
axeOptions: {
26-
runOnly,
27-
rules: {
28-
'color-contrast': { enabled: context.name !== 'Loading' },
29-
},
30-
},
31-
detailedReport: true,
32-
detailedReportOptions: {
33-
html: true,
34-
},
35-
}
36-
);
58+
await runA11yCheck(page, context);
3759
},
3860
};
3961

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@yext/search-ui-react",
3-
"version": "2.1.1",
3+
"version": "2.1.2",
44
"description": "A library of React Components for powering Yext Search integrations",
55
"author": "watson@yext.com",
66
"license": "BSD-3-Clause",

src/components/AppliedFiltersDisplay.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ export function AppliedFiltersDisplay(props: AppliedFiltersDisplayProps): React.
8080
{removableFiltersWithHandlers.map(({ filter, handleRemove }, i) => {
8181
return (
8282
<RemovableFilter
83+
key={`${filter.displayName ?? 'filter'}-${i}`}
8384
displayName={filter.displayName}
8485
handleRemove={handleRemove}
85-
index={i}
8686
cssClasses={cssClasses}
8787
/>
8888
);
@@ -119,17 +119,15 @@ function getDedupedRemovableFilters(filters: RemovableFilter[]) {
119119
function RemovableFilter({
120120
displayName,
121121
handleRemove,
122-
index,
123122
cssClasses
124123
}: {
125124
displayName: string | undefined,
126125
handleRemove: () => void,
127-
index: number,
128126
cssClasses: AppliedFiltersCssClasses
129127
}): React.JSX.Element {
130128
const { t } = useTranslation();
131129
return (
132-
<div className={cssClasses.removableFilter} key={`${displayName}-${index}`}>
130+
<div className={cssClasses.removableFilter}>
133131
<div className={cssClasses.filterLabel}>{displayName}</div>
134132
<button
135133
className='w-2 h-2 text-neutral m-1.5'

src/components/SearchI18nextProvider.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,24 @@ export function SearchI18nextProvider(props: PropsWithChildren<SearchI18nextConf
9999
translationOverrides && Object.entries(translationOverrides).forEach(([locale, translation]) => {
100100
i18nInstance.addResourceBundle(locale, 'search-ui-react', translation, true, true);
101101
});
102-
i18nInstance.changeLanguage(searcher.state.meta.locale);
103-
searcher.addListener<string | undefined>({
102+
const initialLocale = searcher.state.meta.locale ?? 'en';
103+
if (i18nInstance.language !== initialLocale) {
104+
void i18nInstance.changeLanguage(initialLocale);
105+
}
106+
107+
const unsubscribe = searcher.addListener<string | undefined>({
104108
valueAccessor: state => state.meta.locale,
105109
callback: locale => {
106-
i18nInstance.changeLanguage(locale);
110+
const normalizedLocale = locale ?? 'en';
111+
if (i18nInstance.language !== normalizedLocale) {
112+
void i18nInstance.changeLanguage(normalizedLocale);
113+
}
107114
}
108115
});
116+
117+
return () => {
118+
unsubscribe();
119+
};
109120
}, [searcher, translationOverrides]);
110121

111122
return (

test-site/package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/__setup__/setup-env.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,31 @@ globalWithMessageChannel.MessageChannel = globalWithMessageChannel.MessageChanne
1111
beforeAll(() => server.listen());
1212
afterEach(() => server.resetHandlers());
1313
afterAll(() => server.close());
14+
15+
const SUPPRESSED_TEST_WARNINGS = [
16+
/An update to .* inside a test was not wrapped in act\(\.\.\.\)/,
17+
/Error occured executing generative direct answer\./,
18+
];
19+
20+
const SUPPRESSED_TEST_LOGS = [
21+
/react-i18next:: useTranslation: You will need to pass in an i18next instance/
22+
];
23+
24+
const originalConsoleError = console.error.bind(console);
25+
const originalConsoleWarn = console.warn.bind(console);
26+
27+
console.error = (...args) => {
28+
const firstArg = args[0];
29+
if (typeof firstArg === 'string' && SUPPRESSED_TEST_WARNINGS.some(pattern => pattern.test(firstArg))) {
30+
return;
31+
}
32+
originalConsoleError(...args);
33+
};
34+
35+
console.warn = (...args) => {
36+
const firstArg = args[0];
37+
if (typeof firstArg === 'string' && SUPPRESSED_TEST_LOGS.some(pattern => pattern.test(firstArg))) {
38+
return;
39+
}
40+
originalConsoleWarn(...args);
41+
};

tests/ssr/utils.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { render } from '@testing-library/react';
22
import { renderToString } from 'react-dom/server';
3-
import { ReactElement } from 'react';
3+
import React, { ReactElement } from 'react';
4+
import { I18nextProvider } from 'react-i18next';
5+
import { i18nInstance } from '../../src/utils';
46

57
const USE_LAYOUT_EFFECT_ERROR = /useLayoutEffect does nothing on the server/;
68
const originalConsoleError = console.error.bind(console.error);
79

810
export function testSSR(App: ReactElement) {
9-
const renderOnServer = () => renderToString(App);
11+
const wrappedApp = (
12+
<I18nextProvider i18n={i18nInstance}>
13+
{App}
14+
</I18nextProvider>
15+
);
16+
const renderOnServer = () => renderToString(wrappedApp);
1017
const container = document.body.appendChild(document.createElement('div'));
1118
let unexpectedErrorCount = 0;
1219
jest.spyOn(global.console, 'error')
@@ -28,6 +35,6 @@ export function testSSR(App: ReactElement) {
2835
container.innerHTML = renderOnServer();
2936

3037
// hydrate a container whose HTML contents were rendered by ReactDOMServer
31-
render(App, { container, hydrate: true });
38+
render(wrappedApp, { container, hydrate: true });
3239
expect(unexpectedErrorCount).toEqual(0);
3340
}

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"noImplicitAny": false,
77
"module": "es2020",
88
"moduleResolution": "node",
9+
"outDir": "dist",
910
"forceConsistentCasingInFileNames": true,
1011
"declaration": true,
1112
"declarationMap": true,

0 commit comments

Comments
 (0)