Skip to content

Commit

Permalink
chore: Adds i18n strings to the alert status component
Browse files Browse the repository at this point in the history
  • Loading branch information
orangevolon committed Jan 3, 2025
1 parent 5fd71dd commit 4f9845f
Show file tree
Hide file tree
Showing 25 changed files with 336 additions and 45 deletions.
18 changes: 13 additions & 5 deletions pages/alert/permutations.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,22 @@ const longTextWithExpandableSection = (

const allTypes: AlertProps.Type[] = ['info', 'success', 'warning', 'error'];

const i18nStrings: AlertProps.I18nStrings = {
dismissAriaLabel: 'Close alert',
errorIconAriaLabel: 'error',
warningIconAriaLabel: 'warning',
infoIconAriaLabel: 'info',
successIconAriaLabel: 'success',
};

/* eslint-disable react/jsx-key */
const permutations = createPermutations<AlertProps>([
{
children: [longText, longTextWithLink],
type: allTypes,
},
{
dismissAriaLabel: ['Close alert'],
i18nStrings: [{ dismissAriaLabel: 'Close alert' }],
dismissible: [true],
header: ['Default Example Header'],
type: allTypes,
Expand All @@ -69,15 +77,15 @@ const permutations = createPermutations<AlertProps>([
},
{
dismissible: [true],
dismissAriaLabel: ['Close alert'],
i18nStrings: [{ dismissAriaLabel: 'Close alert' }],
buttonText: ['Button text'],
header: ['Default Example Header', longText],
children: ['Default Example Body', longText],
type: allTypes,
},
{
dismissible: [true, false],
dismissAriaLabel: ['Close alert'],
i18nStrings: [{ dismissAriaLabel: 'Close alert' }],
header: [undefined, 'Default Example Header'],
children: ['Default Example Body', longText],
action: [
Expand All @@ -97,7 +105,7 @@ const permutations = createPermutations<AlertProps>([
children: [longTextWithUnbreakableWord],
type: ['info'],
dismissible: [true, false],
dismissAriaLabel: ['Close alert'],
i18nStrings: [{ dismissAriaLabel: 'Close alert' }],
action: [undefined, <Button>Action</Button>],
},
]);
Expand All @@ -109,7 +117,7 @@ export default function AlertScenario() {
<ScreenshotArea>
<PermutationsView
permutations={permutations}
render={permutation => <Alert statusIconAriaLabel={permutation.type ?? 'Info'} {...permutation} />}
render={permutation => <Alert i18nStrings={i18nStrings} {...permutation} />}
/>
</ScreenshotArea>
</article>
Expand Down
12 changes: 9 additions & 3 deletions pages/alert/runtime-action.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ import createPermutations from '../utils/permutations';
import PermutationsView from '../utils/permutations-view';
import ScreenshotArea from '../utils/screenshot-area';

const i18nStrings: AlertProps.I18nStrings = {
dismissAriaLabel: 'Dismiss',
errorIconAriaLabel: 'error',
warningIconAriaLabel: 'warning',
infoIconAriaLabel: 'info',
successIconAriaLabel: 'success',
};

awsuiPlugins.alert.registerAction({
id: 'awsui/alert-test-action',
mountContent: (container, context) => {
Expand Down Expand Up @@ -66,9 +74,7 @@ export default function () {
<ScreenshotArea>
<PermutationsView
permutations={permutations}
render={permutation => (
<Alert statusIconAriaLabel={permutation.type} dismissAriaLabel="Dismiss" {...permutation} />
)}
render={permutation => <Alert i18nStrings={i18nStrings} {...permutation} />}
/>
</ScreenshotArea>
</>
Expand Down
19 changes: 10 additions & 9 deletions pages/alert/runtime-content.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ awsuiPlugins.alertContent.registerContentReplacer({

const alertTypeOptions = ['error', 'warning', 'info', 'success'].map(type => ({ value: type }));

const i18nStrings: AlertProps.I18nStrings = {
dismissAriaLabel: 'Dismiss',
errorIconAriaLabel: 'error',
warningIconAriaLabel: 'warning',
infoIconAriaLabel: 'info',
successIconAriaLabel: 'success',
};

export default function () {
const {
urlParams: { loading = false, hidden = false, type = 'error', autofocus = false },
Expand Down Expand Up @@ -134,20 +142,13 @@ export default function () {
<ScreenshotArea gutters={false}>
{hidden ? null : (
<SpaceBetween size="m">
<Alert
type={type}
statusIconAriaLabel={type}
dismissAriaLabel="Dismiss"
header="Header"
action={<Button>Action</Button>}
>
<Alert type={type} i18nStrings={i18nStrings} header="Header" action={<Button>Action</Button>}>
{!contentSwapped ? content1 : content2}
</Alert>

<Alert
type={type}
statusIconAriaLabel={type}
dismissAriaLabel="Dismiss"
i18nStrings={i18nStrings}
header="Header"
action={<Button>Action</Button>}
ref={alertRef}
Expand Down
12 changes: 10 additions & 2 deletions pages/alert/simple.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ import ScreenshotArea from '../utils/screenshot-area';

import styles from './styles.scss';

const i18nStrings: AlertProps.I18nStrings = {
dismissAriaLabel: 'Dismiss',
errorIconAriaLabel: 'Error',
warningIconAriaLabel: 'Warning',
infoIconAriaLabel: 'Info',
successIconAriaLabel: 'Success',
};

export default function AlertScenario() {
const [visible, setVisible] = useState(true);
const alertRef = useRef<AlertProps.Ref>(null);
Expand All @@ -34,7 +42,7 @@ export default function AlertScenario() {
<Alert
header="This is going to be an extremely long title for an alert not sure whether it makes any sense but whatever"
visible={visible}
statusIconAriaLabel="Warning"
i18nStrings={i18nStrings}
dismissible={true}
buttonText="Button text"
type="warning"
Expand All @@ -48,7 +56,7 @@ export default function AlertScenario() {
<Link href="#">This is a secondary link</Link>
</Alert>
</div>
<Alert header="Info" statusIconAriaLabel="Info">
<Alert header="Info" i18nStrings={i18nStrings}>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
Expand Down
42 changes: 42 additions & 0 deletions src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ when the \`dismissible\` property is set to \`true\`.",
"type": "string",
},
{
"deprecatedTag": "Use the label properties inside \`i18nStrings\` instead.
If the label is assigned via the \`i18nStrings\` property, this label will be ignored.",
"description": "Adds an aria-label to the dismiss button.",
"i18nTag": true,
"name": "dismissAriaLabel",
Expand All @@ -47,6 +49,44 @@ An \`onDismiss\` event is fired when a user clicks the button.",
"optional": true,
"type": "boolean",
},
{
"description": "An object containing all the necessary localized strings required by the component.",
"i18nTag": true,
"inlineType": {
"name": "AlertProps.I18nStrings",
"properties": [
{
"name": "dismissAriaLabel",
"optional": true,
"type": "string",
},
{
"name": "errorIconAriaLabel",
"optional": true,
"type": "string",
},
{
"name": "infoIconAriaLabel",
"optional": true,
"type": "string",
},
{
"name": "successIconAriaLabel",
"optional": true,
"type": "string",
},
{
"name": "warningIconAriaLabel",
"optional": true,
"type": "string",
},
],
"type": "object",
},
"name": "i18nStrings",
"optional": true,
"type": "AlertProps.I18nStrings",
},
{
"deprecatedTag": "The usage of the \`id\` attribute is reserved for internal use cases. For testing and other use cases,
use [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes). If you must
Expand All @@ -57,6 +97,8 @@ use the \`id\` attribute, consider setting it on a parent element instead.",
"type": "string",
},
{
"deprecatedTag": "Use the label properties inside \`i18nStrings\` instead.
If the label is assigned via the \`i18nStrings\` property, this label will be ignored.",
"description": "Provides a text alternative for the icon.",
"name": "statusIconAriaLabel",
"optional": true,
Expand Down
82 changes: 76 additions & 6 deletions src/alert/__tests__/alert.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { render } from '@testing-library/react';
import '../../__a11y__/to-validate-a11y';
import Alert, { AlertProps } from '../../../lib/components/alert';
import Button from '../../../lib/components/button';
import TestI18nProvider from '../../../lib/components/i18n/testing';
import { DATA_ATTR_ANALYTICS_ALERT } from '../../../lib/components/internal/analytics/selectors';
import { useVisualRefresh } from '../../../lib/components/internal/hooks/use-visual-mode';
import createWrapper from '../../../lib/components/test-utils/dom';
Expand All @@ -22,6 +23,14 @@ function renderAlert(props: AlertProps = {}) {
return { wrapper: createWrapper(container).findAlert()!, container };
}

const i18nStrings: AlertProps.I18nStrings = {
successIconAriaLabel: 'status: success',
infoIconAriaLabel: 'status: info',
warningIconAriaLabel: 'status: warning',
errorIconAriaLabel: 'status: error',
dismissAriaLabel: 'dismiss',
};

beforeEach(() => {
jest.mocked(useVisualRefresh).mockReset();
});
Expand Down Expand Up @@ -71,16 +80,16 @@ describe('Alert Component', () => {
expect(wrapper.findDismissButton()!.getElement()).not.toHaveAttribute('aria-label');
});
it('dismiss button can have specified label', () => {
const { wrapper } = renderAlert({ dismissible: true, dismissAriaLabel: 'close' });
expect(wrapper.findDismissButton()!.getElement()).toHaveAttribute('aria-label', 'close');
const { wrapper } = renderAlert({ dismissible: true, i18nStrings });
expect(wrapper.findDismissButton()!.getElement()).toHaveAttribute('aria-label', 'dismiss');
});
it('status icon does not have a label by default', () => {
const { wrapper } = renderAlert({});
expect(wrapper.find('[role="img"]')!.getElement()).not.toHaveAttribute('aria-label');
});
it('status icon can have a label', () => {
const { wrapper } = renderAlert({ statusIconAriaLabel: 'Info' });
expect(wrapper.find('[role="img"]')!.getElement()).toHaveAttribute('aria-label', 'Info');
const { wrapper } = renderAlert({ i18nStrings });
expect(wrapper.find('[role="img"]')!.getElement()).toHaveAttribute('aria-label', 'status: info');
});
});
describe('visibility', () => {
Expand Down Expand Up @@ -145,8 +154,7 @@ describe('Alert Component', () => {
const { container } = renderAlert({
dismissible: true,
header: 'Header',
dismissAriaLabel: 'Dismiss',
statusIconAriaLabel: 'Icon',
i18nStrings,
action: <button type="button">Action</button>,
});
await expect(container).toValidateA11y();
Expand Down Expand Up @@ -187,4 +195,66 @@ describe('Alert Component', () => {
expect(wrapper.findByClassName(styles['icon-size-normal'])).toBeTruthy();
});
});

describe('i18n', () => {
const alertTypes: AlertProps.Type[] = ['info', 'success', 'error', 'warning'];
const i18nMessages = {
alert: {
'i18nStrings.successIconAriaLabel': 'success default label',
'i18nStrings.infoIconAriaLabel': 'info default label',
'i18nStrings.warningIconAriaLabel': 'warning default label',
'i18nStrings.errorIconAriaLabel': 'error default label',
'i18nStrings.dismissAriaLabel': 'dismiss default label',
},
};

function renderAlertForI18n(props: AlertProps = {}) {
const { container } = render(
<TestI18nProvider messages={i18nMessages}>
<Alert {...props} />
</TestI18nProvider>
);
const wrapper = createWrapper(container)!.findAlert()!;
const statusIcon = wrapper.findByClassName(styles.icon)!.getElement();
const dismissButton = wrapper.findDismissButton()!.getElement();
return { statusIcon, dismissButton };
}

describe.each(alertTypes)('alert type: %s', type => {
it('assigns the specified aria labels via i18nStrings prop', () => {
const { statusIcon, dismissButton } = renderAlertForI18n({ dismissible: true, type, i18nStrings });
expect(statusIcon).toHaveAccessibleName(`status: ${type}`);
expect(dismissButton).toHaveAccessibleName('dismiss');
});

it('assigns the labels from i18n provider, when not specified', () => {
const { statusIcon, dismissButton } = renderAlertForI18n({ dismissible: true, type });
expect(statusIcon).toHaveAccessibleName(`${type} default label`);
expect(dismissButton).toHaveAccessibleName('dismiss default label');
});
});

describe('deprecated aria labels', () => {
it('ignores the deprecated values if i18nStrings is specified', () => {
const { statusIcon, dismissButton } = renderAlertForI18n({
dismissible: true,
dismissAriaLabel: 'deprecated dismiss label',
statusIconAriaLabel: 'deprecated status icon label',
i18nStrings,
});
expect(statusIcon).toHaveAccessibleName('status: info');
expect(dismissButton).toHaveAccessibleName('dismiss');
});

it('uses the deprecated values if i18nStrings is not specified', () => {
const { statusIcon, dismissButton } = renderAlertForI18n({
dismissible: true,
dismissAriaLabel: 'deprecated dismiss label',
statusIconAriaLabel: 'deprecated status icon label',
});
expect(statusIcon).toHaveAccessibleName('deprecated status icon label');
expect(dismissButton).toHaveAccessibleName('deprecated dismiss label');
});
});
});
});
2 changes: 1 addition & 1 deletion src/alert/__tests__/analytics-metadata.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ beforeAll(() => {
});
describe('Alert renders correct analytics metadata', () => {
test('on dismiss button', () => {
const wrapper = renderAlert({ dismissible: true, dismissAriaLabel: 'dismiss label' });
const wrapper = renderAlert({ dismissible: true, i18nStrings: { dismissAriaLabel: 'dismiss label' } });
const dismissButton = wrapper.findDismissButton()!.getElement();
validateComponentNameAndLabels(dismissButton, labels);
expect(getGeneratedAnalyticsMetadata(dismissButton)).toEqual({
Expand Down
Loading

0 comments on commit 4f9845f

Please sign in to comment.