Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a11y tests and moving from whitelist to blacklist + misc fixes #3502

Merged
merged 11 commits into from
Jun 4, 2020
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
**Breaking changes**
- Improved `EuiPagination`, `EuiDataGrid`, `EuiBasicTable` and `EuiInMemoryTable` accessibility, causing `EuiPaginationButton` to require a new prop `pageIndex` ([#3294](https://github.com/elastic/eui/pull/3294))

**Bug fixes**
- Fixed `EuiKeyPadMenu` and `EuiKeyPadMenuItem` aria roles ([#3502](https://github.com/elastic/eui/pull/3502))

## [`24.1.0`](https://github.com/elastic/eui/tree/v24.1.0)

- Added `displayAsText` prop to `EuiDataGridColumn` ([#3520](https://github.com/elastic/eui/pull/3520))
Expand Down
121 changes: 45 additions & 76 deletions scripts/a11y-testing.js
Original file line number Diff line number Diff line change
@@ -1,87 +1,56 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with 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.
*/

const chalk = require('chalk');
const puppeteer = require('puppeteer');
const { AxePuppeteer } = require('axe-puppeteer');

const docsPages = async (root, page) => {
let links = [
root,
...(await page.$$eval('nav a', anchors => anchors.map(a => a.href))),
];

links = links.splice(0, 14);
const reflinks = [
`${root}#/layout/horizontal-rule`,
`${root}#/layout/modal`,
`${root}#/layout/nav-drawer`,
`${root}#/layout/page`,
`${root}#/layout/panel`,
`${root}#/layout/popover`,
`${root}#/layout/spacer`,
`${root}#/navigation/breadcrumbs`,
`${root}#/navigation/context-menu`,
`${root}#/navigation/collapsible-nav`,
`${root}#/navigation/control-bar`,
`${root}#/navigation/facet`,
`${root}#/navigation/link`,
`${root}#/navigation/pagination`,
`${root}#/navigation/steps`,
`${root}#/navigation/tabs`,
`${root}#/tabular-content/data-grid`,
`${root}#/tabular-content/data-grid-in-memory-settings`,
`${root}#/tabular-content/data-grid-schemas-and-popovers`,
`${root}#/tabular-content/data-grid-styling-and-toolbar`,
`${root}#/tabular-content/data-grid-control-columns`,
`${root}#/display/avatar`,
`${root}#/display/badge`,
`${root}#/display/callout`,
`${root}#/display/card`,
`${root}#/display/description-list`,
`${root}#/display/emptyprompt`,
`${root}#/display/health`,
`${root}#/display/icons`,
`${root}#/display/image`,
`${root}#/display/list-group`,
`${root}#/display/loading`,
`${root}#/display/progress`,
`${root}#/display/stat`,
`${root}#/display/text`,
`${root}#/display/title`,
`${root}#/display/toast`,
`${root}#/display/tooltip`,
`${root}#/forms/form-controls`,
`${root}#/forms/form-layouts`,
`${root}#/forms/form-validation`,
const pagesToSkip = [
`${root}#/layout/resizable-container`,
`${root}#/navigation/button`,
`${root}#/navigation/tree-view`,
`${root}#/navigation/side-nav`,
`${root}#/tabular-content/tables`,
`${root}#/tabular-content/in-memory-tables`,
`${root}#/display/aspect-ratio`,
`${root}#/display/code`,
`${root}#/display/drag-and-drop`,
`${root}#/forms/compressed-forms`,
`${root}#/forms/super-select`,
`${root}#/forms/combo-box`,
`${root}#/forms/color-selection`,
`${root}#/forms/code-editor`,
`${root}#/forms/expression`,
`${root}#/forms/filter-group`,
`${root}#/forms/range-sliders`,
`${root}#/forms/search-bar`,
`${root}#/elastic-charts/sizing`,
`${root}#/elastic-charts/time-series`,
`${root}#/elastic-charts/categorical`,
`${root}#/utilities/i18n`,
`${root}#/utilities/color`,
`${root}#/utilities/pretty-duration`,
`${root}#/utilities/mutationobserver`,
`${root}#/utilities/outside-click-detector`,
`${root}#/utilities/portal`,
`${root}#/utilities/resizeobserver`,
`${root}#/utilities/responsive`,
`${root}#/utilities/toggle`,
`${root}#/utilities/window-events`,
`${root}#/package/i18n-tokens`,
`${root}#/utilities/accessibility`,
`${root}#/utilities/context`,
`${root}#/utilities/copy`,
`${root}#/utilities/delay`,
`${root}#/utilities/highlight`,
`${root}#/utilities/error-boundary`,
`${root}#/utilities/inner-text`,
`${root}#/forms/date-picker`,
`${root}#/forms/selectable`,
`${root}#/forms/suggest`,
`${root}#/forms/super-date-picker`,
`${root}#/elastic-charts/creating-charts`,
`${root}#/elastic-charts/part-to-whole-comparisons`,
`${root}#/utilities/css-utility-classes`,
`${root}#/utilities/focus-trap`,
];

links = [...links, ...reflinks];

return links;
return [
root,
...(await page.$$eval('nav a', anchors => anchors.map(a => a.href))),
].filter(link => !pagesToSkip.includes(link));
};

const printResult = result =>
Expand Down
2 changes: 1 addition & 1 deletion src-docs/src/components/guide_page/guide_page_chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ export class GuidePageChrome extends Component {
toggleOpenOnMobile={this.toggleOpenOnMobile}
isOpenOnMobile={this.state.isSideNavOpenOnMobile}
items={sideNav}
aria-label="Primary"
aria-label="EUI"
/>
);
} else {
Expand Down
18 changes: 9 additions & 9 deletions src-docs/src/views/datagrid/datagrid_focus_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const DataGridFocusExample = {
based upon the content of the individual inner cells. The following
scenarios are supported and tested:
</p>
<h3>Initial focus</h3>
<h2>Initial focus</h2>
<ul>
<li>
When tabbing to the grid before it has received focus, the first
Expand All @@ -43,7 +43,7 @@ export const DataGridFocusExample = {
focused cell remains focused.
</li>
</ul>
<h3>Click and key events</h3>
<h2>Click and key events</h2>
<ul>
<li>
Clicking on an interactive cell (not its content) should focus on
Expand All @@ -60,37 +60,37 @@ export const DataGridFocusExample = {
if the logic below allows it.
</li>
</ul>
<h3>
<h2>
The content and expandability of the cells dicate the focus target
of the cell
</h3>
</h2>
<p>
The following combinations of focus are maintained to provide for a
good balance between accessibility and ease of use while navigating
a grid with your keyboard.
</p>
<h5>
<h3>
Cell alone recieves the focus, with no possible inner focus action
when:
</h5>
</h3>
<ul>
<li>The cell is not expandable.</li>
<li>The cell has no interactive elements</li>
</ul>
<h5>A single inner element within the cell recieves focus when:</h5>
<h3>A single inner element within the cell recieves focus when:</h3>
<ul>
<li>The cell is not expandable.</li>
<li>The cell has a single interaction element.</li>
</ul>
<h5>A cell will focus on the expansion action when:</h5>
<h3>A cell will focus on the expansion action when:</h3>
<ul>
<li>The expansion ability is allowed on the cell.</li>
<li>
Any combination of interactive / non-interactive is contained in
the cell contents.
</li>
</ul>
<h5>A cell will allow a non-expanding focus trap on keyDown when</h5>
<h3>A cell will allow a non-expanding focus trap on keyDown when</h3>
<ul>
<li>The cell is not expandable.</li>
<li>The cell contains multiple interactive elements.</li>
Expand Down
7 changes: 6 additions & 1 deletion src-docs/src/views/header/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ export default () => {
},
];

return <EuiHeaderBreadcrumbs breadcrumbs={breadcrumbs} />;
return (
<EuiHeaderBreadcrumbs
aria-label="Header breadcrumbs example"
breadcrumbs={breadcrumbs}
/>
);
};

const renderSearch = () => (
Expand Down
11 changes: 8 additions & 3 deletions src-docs/src/views/header/header_app_menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ import {
EuiKeyPadMenuItem,
EuiPopover,
} from '../../../../src/components';
import { htmlIdGenerator } from '../../../../src/services';

export default () => {
const idGenerator = htmlIdGenerator();
const popoverId = idGenerator('popover');
const keypadId = idGenerator('keypad');

const [isOpen, setIsOpen] = useState(false);

const onMenuButtonClick = () => {
Expand All @@ -21,7 +26,7 @@ export default () => {

const button = (
<EuiHeaderSectionItemButton
aria-controls="keyPadMenu"
aria-controls={keypadId}
aria-expanded={isOpen}
aria-haspopup="true"
aria-label="Apps menu with 1 new app"
Expand All @@ -33,13 +38,13 @@ export default () => {

return (
<EuiPopover
id="headerAppMenu"
id={popoverId}
ownFocus
button={button}
isOpen={isOpen}
anchorPosition="downRight"
closePopover={closeMenu}>
<EuiKeyPadMenu id="keyPadMenu" style={{ width: 288 }}>
<EuiKeyPadMenu id={keypadId} style={{ width: 288 }}>
<EuiKeyPadMenuItem label="Discover" href="#">
<EuiIcon type="discoverApp" size="l" />
</EuiKeyPadMenuItem>
Expand Down
2 changes: 1 addition & 1 deletion src-docs/src/views/header/header_dark.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default ({ theme }: { theme: any }) => (
aria-label="Goes to home">
Elastic
</EuiHeaderLogo>,
<EuiHeaderLinks>
<EuiHeaderLinks aria-label="App navigation dark theme example">
<EuiHeaderLink href="#" isActive>
Docs
</EuiHeaderLink>
Expand Down
2 changes: 1 addition & 1 deletion src-docs/src/views/header/header_links.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default () => {
</EuiHeaderSectionItem>

<EuiHeaderSectionItem>
<EuiHeaderLinks>
<EuiHeaderLinks aria-label="App navigation links example">
<EuiHeaderLink href="#" isActive>
Docs
</EuiHeaderLink>
Expand Down
6 changes: 5 additions & 1 deletion src-docs/src/views/header/header_sections.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ export default () => {
];

const renderSearch = (
<EuiFieldSearch placeholder="Search for anything" compressed />
<EuiFieldSearch
placeholder="Search for anything"
aria-label="Search for anything"
compressed
/>
);

const sections = [
Expand Down
11 changes: 6 additions & 5 deletions src-docs/src/views/header/header_spaces_menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {
EuiPopoverTitle,
EuiPopoverFooter,
} from '../../../../src/components';
import { Fragment } from 'react-is';
import { htmlIdGenerator } from '../../../../src/services';

export default () => {
const id = htmlIdGenerator()();
const spacesValues = [
{
label: 'Sales team',
Expand Down Expand Up @@ -81,7 +82,7 @@ export default () => {

const button = (
<EuiHeaderSectionItemButton
aria-controls="headerSpacesMenuList"
aria-controls={id}
cchaos marked this conversation as resolved.
Show resolved Hide resolved
aria-expanded={isOpen}
aria-haspopup="true"
aria-label="Apps menu"
Expand All @@ -92,7 +93,7 @@ export default () => {

return (
<EuiPopover
id="headerSpacesMenu"
id={id}
ownFocus
button={button}
isOpen={isOpen}
Expand All @@ -114,7 +115,7 @@ export default () => {
showIcons: false,
}}>
{(list, search) => (
<Fragment>
<>
<EuiPopoverTitle>{search || 'Your spaces'}</EuiPopoverTitle>
{list}
<EuiPopoverFooter>
Expand All @@ -126,7 +127,7 @@ export default () => {
Add more spaces
</EuiButton>
</EuiPopoverFooter>
</Fragment>
</>
)}
</EuiSelectable>
</EuiPopover>
Expand Down
6 changes: 4 additions & 2 deletions src-docs/src/views/header/header_user_menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import {
EuiSpacer,
EuiPopover,
} from '../../../../src/components';
import { htmlIdGenerator } from '../../../../src/services';

export default () => {
const id = htmlIdGenerator()();
const [isOpen, setIsOpen] = useState(false);

const onMenuButtonClick = () => {
Expand All @@ -24,7 +26,7 @@ export default () => {

const button = (
<EuiHeaderSectionItemButton
aria-controls="headerUserMenu"
aria-controls={id}
cchaos marked this conversation as resolved.
Show resolved Hide resolved
aria-expanded={isOpen}
aria-haspopup="true"
aria-label="Account menu"
Expand All @@ -35,7 +37,7 @@ export default () => {

return (
<EuiPopover
id="headerUserMenu"
id={id}
ownFocus
button={button}
isOpen={isOpen}
Expand Down
Loading