mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-17 13:46:47 +02:00
fix: announce navigation to screen readers (#911)
* refactor: unify page titles * refactor: update page title on navigation * refactor: add AnnouncerContext to test contexts * fix: announce navigation to screen readers
This commit is contained in:
parent
06232a5522
commit
f7266cde10
@ -8,7 +8,7 @@
|
||||
<meta name="cdnPrefix" content="::cdnPrefix::" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="unleash" />
|
||||
<title>Unleash - Enterprise ready feature toggles</title>
|
||||
<title>Unleash</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { render } from 'utils/testRenderer';
|
||||
import { AnnouncerProvider } from 'component/common/Announcer/AnnouncerProvider/AnnouncerProvider';
|
||||
import { AnnouncerContext } from 'component/common/Announcer/AnnouncerContext/AnnouncerContext';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { ANNOUNCER_ELEMENT_TEST_ID } from 'utils/testIds';
|
||||
|
||||
test('AnnouncerContext', async () => {
|
||||
const TestComponent = () => {
|
||||
@ -16,12 +16,9 @@ test('AnnouncerContext', async () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
render(
|
||||
<AnnouncerProvider>
|
||||
<TestComponent />
|
||||
</AnnouncerProvider>
|
||||
);
|
||||
render(<TestComponent />);
|
||||
|
||||
expect(screen.getByRole('status')).not.toHaveTextContent('Foo');
|
||||
expect(screen.getByRole('status')).toHaveTextContent('Bar');
|
||||
const el = screen.getByTestId(ANNOUNCER_ELEMENT_TEST_ID);
|
||||
expect(el).not.toHaveTextContent('Foo');
|
||||
expect(el).toHaveTextContent('Bar');
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { ReactElement } from 'react';
|
||||
import { useStyles } from 'component/common/Announcer/AnnouncerElement/AnnouncerElement.styles';
|
||||
import { ANNOUNCER_ELEMENT_TEST_ID } from 'utils/testIds';
|
||||
|
||||
interface IAnnouncerElementProps {
|
||||
announcement?: string;
|
||||
@ -16,6 +17,7 @@ export const AnnouncerElement = ({
|
||||
aria-live="polite"
|
||||
aria-atomic
|
||||
className={styles.container}
|
||||
data-testid={ANNOUNCER_ELEMENT_TEST_ID}
|
||||
>
|
||||
{announcement}
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@ import { Typography } from '@material-ui/core';
|
||||
import ConditionallyRender from '../ConditionallyRender/ConditionallyRender';
|
||||
|
||||
import { useStyles } from './styles';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
|
||||
const HeaderTitle = ({
|
||||
title,
|
||||
@ -18,6 +19,8 @@ const HeaderTitle = ({
|
||||
const styles = useStyles();
|
||||
const headerClasses = classnames({ skeleton: loading });
|
||||
|
||||
usePageTitle(title);
|
||||
|
||||
return (
|
||||
<div className={styles.headerTitleContainer}>
|
||||
<div className={headerClasses} data-loading>
|
||||
|
@ -96,12 +96,12 @@ const FeatureToggleList = ({
|
||||
};
|
||||
|
||||
const searchResultsHeader = filter.query
|
||||
? `(${features.length} matches)`
|
||||
? ` (${features.length} matches)`
|
||||
: '';
|
||||
|
||||
const headerTitle = archive
|
||||
? `Archived Features ${searchResultsHeader}`
|
||||
: `Features ${searchResultsHeader}`;
|
||||
? `Archived feature toggles${searchResultsHeader}`
|
||||
: `Feature toggles${searchResultsHeader}`;
|
||||
|
||||
return (
|
||||
<div className={styles.featureContainer}>
|
||||
|
@ -6,6 +6,7 @@ import renderer from 'react-test-renderer';
|
||||
import theme from 'themes/mainTheme';
|
||||
import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions';
|
||||
import AccessProvider from 'component/providers/AccessProvider/AccessProvider';
|
||||
import { AnnouncerProvider } from 'component/common/Announcer/AnnouncerProvider/AnnouncerProvider';
|
||||
|
||||
jest.mock('./FeatureToggleListItem/FeatureToggleListItem', () => ({
|
||||
__esModule: true,
|
||||
@ -24,7 +25,10 @@ test('renders correctly with one feature', () => {
|
||||
const tree = renderer.create(
|
||||
<MemoryRouter>
|
||||
<ThemeProvider theme={theme}>
|
||||
<AccessProvider permissions={[{ permission: CREATE_FEATURE }]}>
|
||||
<AnnouncerProvider>
|
||||
<AccessProvider
|
||||
permissions={[{ permission: CREATE_FEATURE }]}
|
||||
>
|
||||
<FeatureToggleList
|
||||
updateSetting={jest.fn()}
|
||||
filter={{}}
|
||||
@ -36,6 +40,7 @@ test('renders correctly with one feature', () => {
|
||||
flags={{}}
|
||||
/>
|
||||
</AccessProvider>
|
||||
</AnnouncerProvider>
|
||||
</ThemeProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
@ -52,7 +57,10 @@ test('renders correctly with one feature without permissions', () => {
|
||||
const tree = renderer.create(
|
||||
<MemoryRouter>
|
||||
<ThemeProvider theme={theme}>
|
||||
<AccessProvider permissions={[{ permission: CREATE_FEATURE }]}>
|
||||
<AnnouncerProvider>
|
||||
<AccessProvider
|
||||
permissions={[{ permission: CREATE_FEATURE }]}
|
||||
>
|
||||
<FeatureToggleList
|
||||
filter={{}}
|
||||
setFilter={jest.fn()}
|
||||
@ -63,6 +71,7 @@ test('renders correctly with one feature without permissions', () => {
|
||||
flags={{}}
|
||||
/>
|
||||
</AccessProvider>
|
||||
</AnnouncerProvider>
|
||||
</ThemeProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
@ -1,7 +1,8 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders correctly with one feature 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div>
|
||||
<div
|
||||
className="makeStyles-searchBarContainer-3"
|
||||
>
|
||||
@ -70,7 +71,7 @@ exports[`renders correctly with one feature 1`] = `
|
||||
<h1
|
||||
className="MuiTypography-root makeStyles-headerTitle-15 MuiTypography-h1"
|
||||
>
|
||||
Features
|
||||
Feature toggles
|
||||
</h1>
|
||||
</div>
|
||||
<div
|
||||
@ -169,11 +170,20 @@ exports[`renders correctly with one feature 1`] = `
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
aria-atomic={true}
|
||||
aria-live="polite"
|
||||
className="makeStyles-container-18"
|
||||
data-testid="ANNOUNCER_ELEMENT_TEST_ID"
|
||||
role="status"
|
||||
/>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders correctly with one feature without permissions 1`] = `
|
||||
<div>
|
||||
Array [
|
||||
<div>
|
||||
<div
|
||||
className="makeStyles-searchBarContainer-3"
|
||||
>
|
||||
@ -242,7 +252,7 @@ exports[`renders correctly with one feature without permissions 1`] = `
|
||||
<h1
|
||||
className="MuiTypography-root makeStyles-headerTitle-15 MuiTypography-h1"
|
||||
>
|
||||
Features
|
||||
Feature toggles
|
||||
</h1>
|
||||
</div>
|
||||
<div
|
||||
@ -344,5 +354,15 @@ exports[`renders correctly with one feature without permissions 1`] = `
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
aria-atomic={true}
|
||||
aria-live="polite"
|
||||
className="makeStyles-container-18"
|
||||
data-testid="ANNOUNCER_ELEMENT_TEST_ID"
|
||||
role="status"
|
||||
>
|
||||
Navigated to Feature toggles
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
@ -16,12 +16,14 @@ import { FeatureMetricsChips } from './FeatureMetricsChips/FeatureMetricsChips';
|
||||
import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
||||
import ConditionallyRender from 'component/common/ConditionallyRender';
|
||||
import { useStyles } from './FeatureMetrics.styles';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
|
||||
export const FeatureMetrics = () => {
|
||||
const { projectId, featureId } = useParams<IFeatureViewParams>();
|
||||
const environments = useFeatureMetricsEnvironments(projectId, featureId);
|
||||
const applications = useFeatureMetricsApplications(featureId);
|
||||
const styles = useStyles();
|
||||
usePageTitle('Metrics');
|
||||
|
||||
const [hoursBack = FEATURE_METRIC_HOURS_BACK_MAX, setHoursBack] =
|
||||
useQueryStringNumberState('hoursBack');
|
||||
|
@ -10,15 +10,16 @@ import {
|
||||
formatFeaturePath,
|
||||
} from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
|
||||
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
|
||||
const FeatureOverview = () => {
|
||||
const styles = useStyles();
|
||||
const { push } = useHistory();
|
||||
|
||||
const projectId = useRequiredPathParam('projectId');
|
||||
const featureId = useRequiredPathParam('featureId');
|
||||
const featurePath = formatFeaturePath(projectId, featureId);
|
||||
const onSidebarClose = () => push(featurePath);
|
||||
usePageTitle(featureId);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { useStyles } from './FeatureVariants.styles';
|
||||
import FeatureOverviewVariants from './FeatureVariantsList/FeatureVariantsList';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
|
||||
const FeatureVariants = () => {
|
||||
const styles = useStyles();
|
||||
usePageTitle('Variants');
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
|
@ -8,5 +8,5 @@ export const EventHistory = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <EventLog history={events} title="Recent changes" />;
|
||||
return <EventLog history={events} title="Event log" />;
|
||||
};
|
||||
|
@ -10,7 +10,7 @@ export const FeatureEventHistory = ({ toggleName }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<EventLog history={events} hideName title="Change log" displayInline />
|
||||
<EventLog history={events} hideName title="Event log" displayInline />
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,13 @@ exports[`renders correctly with empty version 1`] = `
|
||||
</small>
|
||||
<br />
|
||||
</section>
|
||||
<div
|
||||
aria-atomic="true"
|
||||
aria-live="polite"
|
||||
class="makeStyles-container-2"
|
||||
data-testid="ANNOUNCER_ELEMENT_TEST_ID"
|
||||
role="status"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -34,7 +41,7 @@ exports[`renders correctly with ui-config 1`] = `
|
||||
title="API details"
|
||||
>
|
||||
<h2
|
||||
class="makeStyles-title-2"
|
||||
class="makeStyles-title-3"
|
||||
>
|
||||
Unleash 1.1.0
|
||||
|
||||
@ -50,6 +57,13 @@ exports[`renders correctly with ui-config 1`] = `
|
||||
</small>
|
||||
<br />
|
||||
</section>
|
||||
<div
|
||||
aria-atomic="true"
|
||||
aria-live="polite"
|
||||
class="makeStyles-container-4"
|
||||
data-testid="ANNOUNCER_ELEMENT_TEST_ID"
|
||||
role="status"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -61,7 +75,7 @@ exports[`renders correctly with versionInfo 1`] = `
|
||||
title="API details"
|
||||
>
|
||||
<h2
|
||||
class="makeStyles-title-4"
|
||||
class="makeStyles-title-7"
|
||||
>
|
||||
Unleash 1.2.3
|
||||
|
||||
@ -77,6 +91,13 @@ exports[`renders correctly with versionInfo 1`] = `
|
||||
1
|
||||
</small>
|
||||
</section>
|
||||
<div
|
||||
aria-atomic="true"
|
||||
aria-live="polite"
|
||||
class="makeStyles-container-8"
|
||||
data-testid="ANNOUNCER_ELEMENT_TEST_ID"
|
||||
role="status"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
@ -88,7 +109,7 @@ exports[`renders correctly without uiConfig 1`] = `
|
||||
title="API details"
|
||||
>
|
||||
<h2
|
||||
class="makeStyles-title-3"
|
||||
class="makeStyles-title-5"
|
||||
>
|
||||
Unleash 1.1.0
|
||||
|
||||
@ -97,6 +118,13 @@ exports[`renders correctly without uiConfig 1`] = `
|
||||
<small />
|
||||
<br />
|
||||
</section>
|
||||
<div
|
||||
aria-atomic="true"
|
||||
aria-live="polite"
|
||||
class="makeStyles-container-6"
|
||||
data-testid="ANNOUNCER_ELEMENT_TEST_ID"
|
||||
role="status"
|
||||
/>
|
||||
</div>
|
||||
</body>
|
||||
`;
|
||||
|
@ -46,7 +46,7 @@ Array [
|
||||
"menu": Object {},
|
||||
"parent": "/projects",
|
||||
"path": "/projects/:projectId/features/:featureId/edit",
|
||||
"title": "Edit Feature",
|
||||
"title": "Edit feature",
|
||||
"type": "protected",
|
||||
},
|
||||
Object {
|
||||
@ -122,7 +122,7 @@ Array [
|
||||
"mobile": true,
|
||||
},
|
||||
"path": "/features",
|
||||
"title": "Feature Toggles",
|
||||
"title": "Feature toggles",
|
||||
"type": "protected",
|
||||
},
|
||||
Object {
|
||||
@ -169,7 +169,7 @@ Array [
|
||||
"mobile": true,
|
||||
},
|
||||
"path": "/context",
|
||||
"title": "Context Fields",
|
||||
"title": "Context fields",
|
||||
"type": "protected",
|
||||
},
|
||||
Object {
|
||||
@ -331,14 +331,14 @@ Array [
|
||||
"adminSettings": true,
|
||||
},
|
||||
"path": "/history",
|
||||
"title": "Event History",
|
||||
"title": "Event log",
|
||||
"type": "protected",
|
||||
},
|
||||
Object {
|
||||
"component": [Function],
|
||||
"menu": Object {},
|
||||
"path": "/archive",
|
||||
"title": "Archived Toggles",
|
||||
"title": "Archived toggles",
|
||||
"type": "protected",
|
||||
},
|
||||
Object {
|
||||
@ -402,7 +402,7 @@ Array [
|
||||
},
|
||||
"parent": "/admin",
|
||||
"path": "/admin/roles",
|
||||
"title": "Project Roles",
|
||||
"title": "Project roles",
|
||||
"type": "protected",
|
||||
},
|
||||
Object {
|
||||
@ -412,7 +412,7 @@ Array [
|
||||
},
|
||||
"parent": "/admin",
|
||||
"path": "/admin/auth",
|
||||
"title": "Single Sign-On",
|
||||
"title": "Single sign-on",
|
||||
"type": "protected",
|
||||
},
|
||||
Object {
|
||||
|
@ -98,7 +98,7 @@ export const routes: IRoute[] = [
|
||||
{
|
||||
path: '/projects/:projectId/features/:featureId/edit',
|
||||
parent: '/projects',
|
||||
title: 'Edit Feature',
|
||||
title: 'Edit feature',
|
||||
component: EditFeature,
|
||||
type: 'protected',
|
||||
menu: {},
|
||||
@ -172,7 +172,7 @@ export const routes: IRoute[] = [
|
||||
},
|
||||
{
|
||||
path: '/features',
|
||||
title: 'Feature Toggles',
|
||||
title: 'Feature toggles',
|
||||
component: FeatureToggleListContainer,
|
||||
type: 'protected',
|
||||
menu: { mobile: true },
|
||||
@ -216,7 +216,7 @@ export const routes: IRoute[] = [
|
||||
},
|
||||
{
|
||||
path: '/context',
|
||||
title: 'Context Fields',
|
||||
title: 'Context fields',
|
||||
component: ContextList,
|
||||
type: 'protected',
|
||||
flag: C,
|
||||
@ -372,7 +372,7 @@ export const routes: IRoute[] = [
|
||||
},
|
||||
{
|
||||
path: '/history',
|
||||
title: 'Event History',
|
||||
title: 'Event log',
|
||||
component: EventHistoryPage,
|
||||
type: 'protected',
|
||||
menu: { adminSettings: true },
|
||||
@ -381,7 +381,7 @@ export const routes: IRoute[] = [
|
||||
// Archive
|
||||
{
|
||||
path: '/archive',
|
||||
title: 'Archived Toggles',
|
||||
title: 'Archived toggles',
|
||||
component: ArchiveListContainer,
|
||||
type: 'protected',
|
||||
menu: {},
|
||||
@ -447,7 +447,7 @@ export const routes: IRoute[] = [
|
||||
{
|
||||
path: '/admin/roles',
|
||||
parent: '/admin',
|
||||
title: 'Project Roles',
|
||||
title: 'Project roles',
|
||||
component: ProjectRoles,
|
||||
type: 'protected',
|
||||
flag: RE,
|
||||
@ -456,7 +456,7 @@ export const routes: IRoute[] = [
|
||||
{
|
||||
path: '/admin/auth',
|
||||
parent: '/admin',
|
||||
title: 'Single Sign-On',
|
||||
title: 'Single sign-on',
|
||||
component: AuthSettings,
|
||||
type: 'protected',
|
||||
menu: { adminSettings: true },
|
||||
|
@ -49,7 +49,7 @@ export const ProjectFeatureToggles = ({
|
||||
headerContent={
|
||||
<HeaderTitle
|
||||
className={styles.title}
|
||||
title={`Feature toggles (${filteredFeatures.length})`}
|
||||
title={`Project features (${filteredFeatures.length})`}
|
||||
actions={
|
||||
<div className={styles.actionsContainer}>
|
||||
<SearchField
|
||||
|
@ -3,12 +3,15 @@ import ApiError from 'component/common/ApiError/ApiError';
|
||||
import ConditionallyRender from 'component/common/ConditionallyRender';
|
||||
import ReportToggleList from 'component/Reporting/ReportToggleList/ReportToggleList';
|
||||
import { ReportCard } from 'component/Reporting/ReportCard/ReportCard';
|
||||
import { usePageTitle } from 'hooks/usePageTitle';
|
||||
|
||||
interface IProjectHealthProps {
|
||||
projectId: string;
|
||||
}
|
||||
|
||||
const ProjectHealth = ({ projectId }: IProjectHealthProps) => {
|
||||
usePageTitle('Project health');
|
||||
|
||||
const { healthReport, refetchHealthReport, error } =
|
||||
useHealthReport(projectId);
|
||||
|
||||
|
@ -6,6 +6,7 @@ import theme from 'themes/mainTheme';
|
||||
import AccessProvider from 'component/providers/AccessProvider/AccessProvider';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import UIProvider from 'component/providers/UIProvider/UIProvider';
|
||||
import { AnnouncerProvider } from 'component/common/Announcer/AnnouncerProvider/AnnouncerProvider';
|
||||
|
||||
test('renders correctly with one strategy', () => {
|
||||
const strategy = {
|
||||
@ -15,6 +16,7 @@ test('renders correctly with one strategy', () => {
|
||||
const tree = renderer.create(
|
||||
<MemoryRouter>
|
||||
<ThemeProvider theme={theme}>
|
||||
<AnnouncerProvider>
|
||||
<UIProvider>
|
||||
<AccessProvider permissions={[{ permission: ADMIN }]}>
|
||||
<StrategiesList
|
||||
@ -26,6 +28,7 @@ test('renders correctly with one strategy', () => {
|
||||
/>
|
||||
</AccessProvider>
|
||||
</UIProvider>
|
||||
</AnnouncerProvider>
|
||||
</ThemeProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
@ -41,6 +44,7 @@ test('renders correctly with one strategy without permissions', () => {
|
||||
const tree = renderer.create(
|
||||
<MemoryRouter>
|
||||
<ThemeProvider theme={theme}>
|
||||
<AnnouncerProvider>
|
||||
<UIProvider>
|
||||
<AccessProvider permissions={[{ permission: ADMIN }]}>
|
||||
<StrategiesList
|
||||
@ -52,6 +56,7 @@ test('renders correctly with one strategy without permissions', () => {
|
||||
/>
|
||||
</AccessProvider>
|
||||
</UIProvider>
|
||||
</AnnouncerProvider>
|
||||
</ThemeProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
@ -1,7 +1,8 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders correctly with one strategy 1`] = `
|
||||
<div
|
||||
Array [
|
||||
<div
|
||||
className="MuiPaper-root MuiPaper-elevation1 MuiPaper-rounded"
|
||||
style={
|
||||
Object {
|
||||
@ -9,7 +10,7 @@ exports[`renders correctly with one strategy 1`] = `
|
||||
"boxShadow": "none",
|
||||
}
|
||||
}
|
||||
>
|
||||
>
|
||||
<div
|
||||
className="makeStyles-headerContainer-2"
|
||||
>
|
||||
@ -267,11 +268,22 @@ exports[`renders correctly with one strategy 1`] = `
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
aria-atomic={true}
|
||||
aria-live="polite"
|
||||
className="makeStyles-container-11"
|
||||
data-testid="ANNOUNCER_ELEMENT_TEST_ID"
|
||||
role="status"
|
||||
>
|
||||
Navigated to Strategies
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders correctly with one strategy without permissions 1`] = `
|
||||
<div
|
||||
Array [
|
||||
<div
|
||||
className="MuiPaper-root MuiPaper-elevation1 MuiPaper-rounded"
|
||||
style={
|
||||
Object {
|
||||
@ -279,7 +291,7 @@ exports[`renders correctly with one strategy without permissions 1`] = `
|
||||
"boxShadow": "none",
|
||||
}
|
||||
}
|
||||
>
|
||||
>
|
||||
<div
|
||||
className="makeStyles-headerContainer-2"
|
||||
>
|
||||
@ -537,5 +549,15 @@ exports[`renders correctly with one strategy without permissions 1`] = `
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
aria-atomic={true}
|
||||
aria-live="polite"
|
||||
className="makeStyles-container-11"
|
||||
data-testid="ANNOUNCER_ELEMENT_TEST_ID"
|
||||
role="status"
|
||||
>
|
||||
Navigated to Strategies
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
21
frontend/src/hooks/usePageTitle.ts
Normal file
21
frontend/src/hooks/usePageTitle.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { useEffect, useContext } from 'react';
|
||||
import { AnnouncerContext } from 'component/common/Announcer/AnnouncerContext/AnnouncerContext';
|
||||
|
||||
export const usePageTitle = (title: string) => {
|
||||
const { setAnnouncement } = useContext(AnnouncerContext);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = title;
|
||||
return () => {
|
||||
document.title = DEFAULT_PAGE_TITLE;
|
||||
};
|
||||
}, [title]);
|
||||
|
||||
useEffect(() => {
|
||||
if (title !== DEFAULT_PAGE_TITLE) {
|
||||
setAnnouncement(`Navigated to ${title}`);
|
||||
}
|
||||
}, [setAnnouncement, title]);
|
||||
};
|
||||
|
||||
const DEFAULT_PAGE_TITLE = 'Unleash';
|
@ -49,3 +49,4 @@ export const INPUT_ERROR_TEXT = 'INPUT_ERROR_TEXT';
|
||||
export const HEADER_USER_AVATAR = 'HEADER_USER_AVATAR';
|
||||
export const SIDEBAR_MODAL_ID = 'SIDEBAR_MODAL_ID';
|
||||
export const AUTH_PAGE_ID = 'AUTH_PAGE_ID';
|
||||
export const ANNOUNCER_ELEMENT_TEST_ID = 'ANNOUNCER_ELEMENT_TEST_ID';
|
||||
|
@ -3,6 +3,7 @@ import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { render as rtlRender, RenderOptions } from '@testing-library/react';
|
||||
import { SWRConfig } from 'swr';
|
||||
import { MainThemeProvider } from 'themes/MainThemeProvider';
|
||||
import { AnnouncerProvider } from 'component/common/Announcer/AnnouncerProvider/AnnouncerProvider';
|
||||
|
||||
export const render = (
|
||||
ui: JSX.Element,
|
||||
@ -23,7 +24,9 @@ const Wrapper: FC = ({ children }) => {
|
||||
return (
|
||||
<SWRConfig value={{ provider: () => new Map() }}>
|
||||
<MainThemeProvider>
|
||||
<AnnouncerProvider>
|
||||
<Router>{children}</Router>
|
||||
</AnnouncerProvider>
|
||||
</MainThemeProvider>
|
||||
</SWRConfig>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user