Skip to content

Commit

Permalink
fix: specfy accessibility tags section508, wcag21aa (#1839)
Browse files Browse the repository at this point in the history
* fix: specfy accessibility tags section508, wcag21aa
* fix: a11y test for toast, typography, radio, checkbox
  • Loading branch information
ganeshsomasundaram-okta authored Jun 20, 2023
1 parent 1e9f461 commit 0da693e
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 87 deletions.
Binary file not shown.
12 changes: 12 additions & 0 deletions packages/odyssey-storybook/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ import type { Preview } from "@storybook/react";

const preview: Preview = {
parameters: {
a11y: {
options: {
runOnly: [
"section508",
"wcag2a",
"wcag2aa",
"wcag21a",
"wcag21aa",
"wcag22aa",
],
},
},
controls: {
expanded: true,
sort: "requiredFirst",
Expand Down
13 changes: 13 additions & 0 deletions packages/odyssey-storybook/.storybook/test-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ module.exports = {
// whether or not to include the full html for the offending nodes
html: true,
},
axeOptions: {
runOnly: {
type: "tag",
values: [
"section508",
"wcag2a",
"wcag2aa",
"wcag21a",
"wcag21aa",
"wcag22aa",
],
},
},
},

// skipFailures
Expand Down
1 change: 1 addition & 0 deletions packages/odyssey-storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@types/react": "^17.0.11",
"@types/react-dom": "^17.0.2",
"@vitejs/plugin-react-swc": "^3.0.0",
"axe-core": "^4.7.2",
"axe-playwright": "^1.2.3",
"babel-loader": "^8",
"markdown-to-jsx": "^7.1.7",
Expand Down
49 changes: 49 additions & 0 deletions packages/odyssey-storybook/src/axe-util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*!
* Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
*
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and limitations under the License.
*/

// eslint-disable-next-line import/no-extraneous-dependencies
import axe from "axe-core";

export const sleep = (ms = 1000) => new Promise((r) => setTimeout(r, ms));

export const axeRun = async (interaction = "") => {
await sleep();

await axe
.run({
runOnly: {
type: "tag",
values: [
"section508",
"wcag2a",
"wcag2aa",
"wcag21a",
"wcag21aa",
"wcag22aa",
],
},
})
.then((results) => {
if (results.violations.length) {
console.log("Accessibility issues found ==> ", results.violations);
throw new Error(`Accessibility issues found ${interaction}`);
}
})
.catch((e) => {
console.log(
e instanceof Error ? e.message : "Unknown Error in play-test"
);
throw new Error(
e instanceof Error ? e.message : "Unknown Error in play-test"
);
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
* See the License for the specific language governing permissions and limitations under the License.
*/

import type { Meta, StoryObj } from "@storybook/react";
import type { Meta, ReactRenderer, StoryObj } from "@storybook/react";

import { Button, AddIcon } from "@okta/odyssey-react-mui";
import type { ButtonProps } from "@okta/odyssey-react-mui";
import { MuiThemeDecorator } from "../../../../.storybook/components/MuiThemeDecorator";

import { userEvent, within } from "@storybook/testing-library";
import { expect } from "@storybook/jest";
import { axeRun } from "../../../axe-util";
// eslint-disable-next-line import/no-extraneous-dependencies
import { StepFunction } from "@storybook/types";

const storybookMeta: Meta<ButtonProps> = {
title: "MUI Components/Button",
Expand Down Expand Up @@ -59,16 +62,34 @@ const storybookMeta: Meta<ButtonProps> = {

export default storybookMeta;

const interactWithButton = async (
args: ButtonProps,
canvasElement: HTMLElement,
step: StepFunction<ReactRenderer, ButtonProps>,
action: string
) => {
try {
if (args.text) {
await step("hover and click", async () => {
const canvas = within(canvasElement);
const button = canvas.getByText(args.text ?? "");
await userEvent.tab();
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalledTimes(1);
await axeRun(action);
});
}
} catch (e) {
console.log(e instanceof Error && e.message);
throw new Error(
e instanceof Error ? e.message : "Unknown Error in play-test"
);
}
};

export const ButtonPrimary: StoryObj<ButtonProps> = {
play: async ({ args, canvasElement, step }) => {
const canvas = within(canvasElement);
const button = canvas.getByText("Add crew");
await step("hover and click", async (ctx) => {
console.log(ctx);
await userEvent.hover(button);
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalledTimes(1);
});
interactWithButton(args, canvasElement, step, "Button Primary: Hover");
},
};

Expand All @@ -77,48 +98,69 @@ export const ButtonSecondary: StoryObj<ButtonProps> = {
text: "Add crew",
variant: "secondary",
},
play: async ({ args, canvasElement, step }) => {
interactWithButton(args, canvasElement, step, "Button Secondary: Hover");
},
};

export const ButtonDanger: StoryObj<ButtonProps> = {
args: {
text: "Add crew",
variant: "danger",
},
play: async ({ args, canvasElement, step }) => {
interactWithButton(args, canvasElement, step, "Button Danger: Hover");
},
};

export const ButtonFloating: StoryObj<ButtonProps> = {
args: {
text: "Add crew",
variant: "floating",
},
play: async ({ args, canvasElement, step }) => {
interactWithButton(args, canvasElement, step, "Button Floating: Hover");
},
};

export const ButtonSmall: StoryObj<ButtonProps> = {
args: {
text: "Add crew",
size: "small",
},
play: async ({ args, canvasElement, step }) => {
interactWithButton(args, canvasElement, step, "Button Small: Hover");
},
};

export const ButtonMedium: StoryObj<ButtonProps> = {
args: {
text: "Add crew",
size: "medium",
},
play: async ({ args, canvasElement, step }) => {
interactWithButton(args, canvasElement, step, "Button Medium: Hover");
},
};

export const ButtonLarge: StoryObj<ButtonProps> = {
args: {
text: "Add crew",
size: "large",
},
play: async ({ args, canvasElement, step }) => {
interactWithButton(args, canvasElement, step, "Button Large: Hover");
},
};

export const ButtonFullWidth: StoryObj<ButtonProps> = {
args: {
text: "Add crew",
isFullWidth: true,
},
play: async ({ args, canvasElement, step }) => {
interactWithButton(args, canvasElement, step, "Button FullWidth: Hover");
},
};

export const ButtonPrimaryDisabled: StoryObj<ButtonProps> = {
Expand All @@ -133,13 +175,16 @@ export const ButtonWithIcon: StoryObj<ButtonProps> = {
text: "Add crew",
startIcon: <AddIcon />,
},
play: async ({ args, canvasElement, step }) => {
interactWithButton(args, canvasElement, step, "Button With Icon: Hover");
},
};

export const IconOnly: StoryObj<ButtonProps> = {
args: {
startIcon: <AddIcon />,
ariaLabel: "Add",
text: undefined,
ariaLabel: "Add crew",
text: "",
tooltipText: "Add crew",
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@
*/

import { Checkbox, CheckboxProps } from "@okta/odyssey-react-mui";
import { Meta, StoryObj } from "@storybook/react";
import { Meta, ReactRenderer, StoryObj } from "@storybook/react";

import { MuiThemeDecorator } from "../../../../.storybook/components";

import { userEvent, within } from "@storybook/testing-library";
import { expect } from "@storybook/jest";
import { axeRun } from "../../../axe-util";
// eslint-disable-next-line import/no-extraneous-dependencies
import { StepFunction } from "@storybook/types";

const storybookMeta: Meta<CheckboxProps> = {
title: "MUI Components/Forms/Checkbox",
component: Checkbox,
Expand Down Expand Up @@ -44,15 +50,35 @@ const storybookMeta: Meta<CheckboxProps> = {

export default storybookMeta;

const checkTheBox = async (
canvasElement: HTMLElement,
step: StepFunction<ReactRenderer, CheckboxProps>,
action: string
) => {
await step("check the box", async () => {
const canvas = within(canvasElement);
const checkBox = canvas.getByRole("checkbox") as HTMLInputElement;
checkBox && (await userEvent.click(checkBox));
expect(checkBox.checked).toBe(true);
await axeRun(action);
});
};

export const Default: StoryObj<CheckboxProps> = {
args: {
label: "Enable warp drive recalibration",
},
play: async ({ canvasElement, step }) => {
checkTheBox(canvasElement, step, "Checkbox Default");
},
};

export const Required: StoryObj<CheckboxProps> = {
args: {
label: "I agree to the terms and conditions",
isRequired: true,
},
play: async ({ canvasElement, step }) => {
checkTheBox(canvasElement, step, "Checkbox Required");
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@
*/

import { Radio, RadioProps } from "@okta/odyssey-react-mui";
import { Meta, StoryObj } from "@storybook/react";
import { Meta, ReactRenderer, StoryObj } from "@storybook/react";

import { MuiThemeDecorator } from "../../../../.storybook/components";

import { userEvent, within } from "@storybook/testing-library";
import { expect } from "@storybook/jest";
import { axeRun } from "../../../axe-util";
// eslint-disable-next-line import/no-extraneous-dependencies
import { StepFunction } from "@storybook/types";

const storybookMeta: Meta<RadioProps> = {
title: "MUI Components/Forms/Radio",
component: Radio,
Expand Down Expand Up @@ -44,4 +50,22 @@ const storybookMeta: Meta<RadioProps> = {

export default storybookMeta;

export const Default: StoryObj<RadioProps> = {};
const selectRadio = async (
canvasElement: HTMLElement,
step: StepFunction<ReactRenderer, RadioProps>,
action: string
) => {
await step("select the radio button", async () => {
const canvas = within(canvasElement);
const radio = canvas.getByRole("radio") as HTMLInputElement;
radio && (await userEvent.click(radio));
expect(radio.checked).toBe(true);
await axeRun(action);
});
};

export const Default: StoryObj<RadioProps> = {
play: async ({ canvasElement, step }) => {
selectRadio(canvasElement, step, "Radio Default");
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Each Toast is made up of up to three parts: Severity, Title, and Message.
</dl>

<Canvas>
<Story of={ToastStories.InfoStatic} />
<Story of={ToastStories.Info} />
</Canvas>

`Toast` handles the visual appearance and show/hide logic, but not positioning. To have a `Toast` positioned correctly, it must be wrapped inside
Expand All @@ -45,7 +45,7 @@ If multiple Toasts are triggered in a short time, they will stack in order of ap
### Dismissible

<Canvas>
<Story of={ToastStories.DismissibleStatic} />
<Story of={ToastStories.Dismissible} />
</Canvas>

## Severity
Expand All @@ -57,15 +57,15 @@ Use Info Toasts to surface neutral information to users.
This is the default variant for this component.

<Canvas>
<Story of={ToastStories.InfoStatic} />
<Story of={ToastStories.Info} />
</Canvas>

### Success

Use Success Toasts to inform users of successful or completed processes.

<Canvas>
<Story of={ToastStories.SuccessStatic} />
<Story of={ToastStories.Success} />
</Canvas>

### Warning
Expand All @@ -75,7 +75,7 @@ Use Warning Toasts to inform users of tasks or processes that may need their att
When using the Warning variant, ensure the user does not need more context than you can give in the space available.

<Canvas>
<Story of={ToastStories.WarningStatic} />
<Story of={ToastStories.Warning} />
</Canvas>

### Error
Expand All @@ -87,7 +87,7 @@ When using a Error Toast, be sure that the error is also logged elsewhere, so a
Do not use Error Toasts for in-page errors such as invalid form fields. Instead, use static messaging the user can refer to while addressing their error.

<Canvas>
<Story of={ToastStories.ErrorStatic} />
<Story of={ToastStories.ErrorToast} />
</Canvas>

### Multiple Toasts
Expand Down
Loading

0 comments on commit 0da693e

Please sign in to comment.