Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Comment thread
dmytrokirpa marked this conversation as resolved.
"type": "patch",
Comment thread
dmytrokirpa marked this conversation as resolved.
Outdated
"comment": "test: add axe accessibility checks to component conformance tests",
"packageName": "@fluentui/react-headless-components-preview",
"email": "dmytrokirpa@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,9 @@
"devDependencies": {
"@fluentui/scripts-cypress": "*",
"@fluentui/verify-bundle-isolation": "*",
"@oddbird/popover-polyfill": "^0.6.1"
"@oddbird/popover-polyfill": "^0.6.1",
"@types/jest-axe": "^3.5.9",
Comment thread
dmytrokirpa marked this conversation as resolved.
Outdated
"jest-axe": "^10.0.0"
},
"type": "module"
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('Avatar', () => {
isConformant({
Component: Avatar,
displayName: 'Avatar',
requiredProps: { name: 'John Doe' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('AvatarGroupItem', () => {
isConformant({
Component: AvatarGroupItem,
displayName: 'AvatarGroupItem',
requiredProps: { name: 'John Doe' },
disabledTests: ['has-top-level-file-extra', 'component-has-root-ref'],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('Button', () => {
isConformant({
Component: Button,
displayName: 'Button',
requiredProps: { children: 'Button' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Checkbox', () => {
Component: Checkbox,
displayName: 'Checkbox',
primarySlot: 'input',
requiredProps: { label: 'Checkbox' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('AlphaSlider', () => {
displayName: 'AlphaSlider',
disabledTests: ['has-top-level-file-extra'],
primarySlot: 'input',
requiredProps: { 'aria-label': 'Alpha' },
});

it('renders opacity as a native range value', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ describe('ColorArea', () => {
isConformant({
Component: ColorArea,
displayName: 'ColorArea',
requiredProps: {
inputX: { 'aria-label': 'Saturation' },
inputY: { 'aria-label': 'Value' },
},
disabledTests: ['has-top-level-file-extra'],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('ColorSlider', () => {
displayName: 'ColorSlider',
disabledTests: ['has-top-level-file-extra'],
primarySlot: 'input',
requiredProps: { 'aria-label': 'Color' },
});

it('renders a native range input with channel semantics', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('Combobox', () => {
displayName: 'Combobox',
primarySlot: 'input',
requiredProps: {
'aria-label': 'Options',
open: true,
children: (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('CompoundButton', () => {
isConformant({
Component: CompoundButton,
displayName: 'CompoundButton',
requiredProps: { children: 'Action' },
});

it('renders a button with primary and secondary text in its accessible name', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('Dropdown', () => {
displayName: 'Dropdown',
primarySlot: 'button',
requiredProps: {
'aria-label': 'Options',
open: true,
children: (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('Image', () => {
isConformant({
Component: Image,
displayName: 'Image',
requiredProps: { alt: 'Image' },
});

it('renders an image element with the correct attributes', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Input', () => {
Component: Input,
displayName: 'Input',
primarySlot: 'input',
requiredProps: { 'aria-label': 'Text' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('Link', () => {
isConformant({
Component: Link,
displayName: 'Link',
requiredProps: { children: 'Link' },
});

it('renders as a button when no href is provided', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('MenuButton', () => {
isConformant({
Component: MenuButton,
displayName: 'MenuButton',
requiredProps: { children: 'Open menu' },
});

it('renders a default state without a default menu icon', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('Persona', () => {
isConformant({
Component: Persona,
displayName: 'Persona',
requiredProps: { name: 'User' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('ProgressBar', () => {
isConformant({
Component: ProgressBar,
displayName: 'ProgressBar',
requiredProps: { 'aria-label': 'Progress' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('RatingDisplay', () => {
isConformant({
Component: RatingDisplay,
displayName: 'RatingDisplay',
requiredProps: { 'aria-label': 'Rating' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('SearchBox', () => {
Component: SearchBox,
displayName: 'SearchBox',
primarySlot: 'input',
requiredProps: { 'aria-label': 'Search' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Select', () => {
Component: Select,
displayName: 'Select',
primarySlot: 'select',
requiredProps: { 'aria-label': 'Options' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('Skeleton', () => {
isConformant({
Component: Skeleton,
displayName: 'Skeleton',
requiredProps: { 'aria-label': 'Loading' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Slider', () => {
Component: Slider,
displayName: 'Slider',
primarySlot: 'input',
requiredProps: { 'aria-label': 'Value' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('SpinButton', () => {
Component: SpinButton,
displayName: 'SpinButton',
primarySlot: 'input',
requiredProps: { 'aria-label': 'Value' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('Spinner', () => {
isConformant({
Component: Spinner,
displayName: 'Spinner',
requiredProps: { 'aria-label': 'Loading' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('SplitButton', () => {
isConformant({
Component: SplitButton,
displayName: 'SplitButton',
requiredProps: { children: 'Action' },
});

it('renders both the primary action button and the menu button', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ describe('ColorSwatch', () => {
isConformant({
Component: ColorSwatch,
displayName: 'ColorSwatch',
requiredProps: { color: '#f09', value: 'pink', 'aria-label': 'Pink' },
renderOptions: {
wrapper: ({ children }) => <SwatchPicker aria-label="Colors">{children}</SwatchPicker>,
},
getTargetElement: result => result.getByRole('radio'),
disabledTests: ['has-top-level-file-extra'],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { isConformant } from '../../../testing/isConformant';
import { EmptySwatch } from './EmptySwatch';

describe('EmptySwatch', () => {
isConformant({ Component: EmptySwatch, displayName: 'EmptySwatch', disabledTests: ['has-top-level-file-extra'] });
isConformant({
Component: EmptySwatch,
displayName: 'EmptySwatch',
requiredProps: { 'aria-label': 'Empty' },
disabledTests: ['has-top-level-file-extra'],
});

it('renders a native radio swatch with state attributes', () => {
const swatch = render(<EmptySwatch aria-label="Empty" disabled />).getByRole('radio');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ import { ImageSwatch } from './ImageSwatch';
import { SwatchPicker } from '../SwatchPicker';

describe('ImageSwatch', () => {
isConformant({ Component: ImageSwatch, displayName: 'ImageSwatch', disabledTests: ['has-top-level-file-extra'] });
isConformant({
Component: ImageSwatch,
displayName: 'ImageSwatch',
requiredProps: { src: 'image.png', value: 'image', 'aria-label': 'Image' },
renderOptions: {
wrapper: ({ children }) => <SwatchPicker aria-label="Images">{children}</SwatchPicker>,
},
getTargetElement: result => result.getByRole('radio'),
disabledTests: ['has-top-level-file-extra'],
});

it('renders an image swatch with its selection state', () => {
const { getByRole } = render(<ImageSwatch src="image.png" value="image" aria-label="Image" />, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ describe('SwatchPickerRow', () => {
isConformant({
Component: SwatchPickerRow,
displayName: 'SwatchPickerRow',
requiredProps: { children: <div role="gridcell">Color</div> },
renderOptions: {
wrapper: ({ children }) => <div role="grid">{children}</div>,
},
getTargetElement: result => result.getByRole('row'),
disabledTests: ['has-top-level-file-extra'],
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Switch', () => {
Component: Switch,
displayName: 'Switch',
primarySlot: 'input',
requiredProps: { label: 'Switch' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('Textarea', () => {
Component: Textarea,
displayName: 'Textarea',
primarySlot: 'textarea',
requiredProps: { 'aria-label': 'Text' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ describe('ToastContainer', () => {
Component: ToastContainer,
displayName: 'ToastContainer',
requiredProps: defaultToastContainerProps,
renderOptions: {
wrapper: ({ children }) => <div role="list">{children}</div>,
},
getTargetElement: result => result.getByRole('listitem'),
Comment thread
dmytrokirpa marked this conversation as resolved.
Outdated
disabledTests: [
// Callback argument signature includes toast metadata from ToastData.
'consistent-callback-args',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ describe('ToggleButton', () => {
isConformant({
Component: ToggleButton,
displayName: 'ToggleButton',
requiredProps: { children: 'Toggle' },
});

it('renders a default state', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import * as React from 'react';
import { render } from '@testing-library/react';
import { isConformant as baseIsConformant } from '@fluentui/react-conformance';
import type { IsConformantOptions } from '@fluentui/react-conformance';
import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations);

function kebabCase(str: string): string {
return str
Expand All @@ -26,6 +31,16 @@ export function isConformant<TProps = {}>(
],
disableTypeTests: true,
extraTests: {
'component-has-no-axe-violations': ({ Component, requiredProps, renderOptions }: IsConformantOptions<TProps>) => {
it('has no axe violations (component-has-no-axe-violations)', async () => {
const { container } = render(
React.createElement(Component as React.ComponentType<Partial<TProps>>, requiredProps),
renderOptions,
);

expect(await axe(container)).toHaveNoViolations();
});
},
'has-top-level-file-extra': ({ displayName, Component }: IsConformantOptions<TProps>) => {
it(`has corresponding top-level file 'src/${name}.ts' (has-top-level-file)`, () => {
const topLevelFile = require(`../${name}.ts`);
Expand Down
6 changes: 4 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4370,6 +4370,8 @@ __metadata:
"@fluentui/verify-bundle-isolation": "npm:*"
"@oddbird/popover-polyfill": "npm:^0.6.1"
"@swc/helpers": "npm:^0.5.1"
"@types/jest-axe": "npm:^3.5.9"
jest-axe: "npm:^10.0.0"
peerDependencies:
"@types/react": ">=16.14.0 <20.0.0"
"@types/react-dom": ">=16.9.0 <20.0.0"
Expand Down Expand Up @@ -10513,7 +10515,7 @@ __metadata:
languageName: node
linkType: hard

"@types/jest-axe@npm:3.5.9":
"@types/jest-axe@npm:3.5.9, @types/jest-axe@npm:^3.5.9":
version: 3.5.9
resolution: "@types/jest-axe@npm:3.5.9"
dependencies:
Expand Down Expand Up @@ -21575,7 +21577,7 @@ __metadata:
languageName: node
linkType: hard

"jest-axe@npm:10.0.0":
"jest-axe@npm:10.0.0, jest-axe@npm:^10.0.0":
version: 10.0.0
resolution: "jest-axe@npm:10.0.0"
dependencies:
Expand Down
Loading