-
Notifications
You must be signed in to change notification settings - Fork 895
Added a11y specs for EuiNotificationEvent, EuiPageHeader, EuiPortal #6524
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
Changes from 3 commits
a835997
89212ff
9abb1b7
4128249
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License | ||
| * 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
| * in compliance with, at your election, the Elastic License 2.0 or the Server | ||
| * Side Public License, v 1. | ||
| */ | ||
|
|
||
| /// <reference types="../../../cypress/support"/> | ||
|
|
||
| import React, { useState } from 'react'; | ||
| import { EuiContextMenuItem } from '../context_menu'; | ||
| import { EuiNotificationEvent } from './notification_event'; | ||
| import { EuiPanel } from '../panel'; | ||
|
|
||
| const NotificationEvent = () => { | ||
| const [isRead, setIsRead] = useState(false); | ||
|
|
||
| const onRead = (id, isRead) => { | ||
| setIsRead(!isRead); | ||
| }; | ||
|
|
||
| const onOpenContextMenu = (id) => { | ||
| return [ | ||
| <EuiContextMenuItem | ||
| key="contextMenuItemA" | ||
| onClick={() => onRead(id, isRead)} | ||
| > | ||
| {isRead ? 'Mark as unread' : 'Mark as read'} | ||
| </EuiContextMenuItem>, | ||
|
|
||
| <EuiContextMenuItem key="contextMenuItemB" onClick={() => {}}> | ||
| View messages like this | ||
| </EuiContextMenuItem>, | ||
|
|
||
| <EuiContextMenuItem key="contextMenuItemC" onClick={() => {}}> | ||
| Don’t notify me about this | ||
| </EuiContextMenuItem>, | ||
| ]; | ||
| }; | ||
|
|
||
| return ( | ||
| <EuiPanel paddingSize="none" hasShadow={true} style={{ maxWidth: '540px' }}> | ||
| <EuiNotificationEvent | ||
| id="cy-eui-notification-1" | ||
| type="Report" | ||
| iconType="logoKibana" | ||
| iconAriaLabel="Kibana" | ||
| time="1 min ago" | ||
| title="[Error Monitoring Report] is generated" | ||
| primaryAction="Download" | ||
| primaryActionProps={{ | ||
| iconType: 'download', | ||
| }} | ||
| messages={['The reported was generated at 17:12:16 GMT+4']} | ||
| isRead={isRead} | ||
| onRead={onRead} | ||
| onOpenContextMenu={onOpenContextMenu} | ||
| onClickPrimaryAction={() => {}} | ||
| onClickTitle={() => {}} | ||
| /> | ||
| </EuiPanel> | ||
| ); | ||
| }; | ||
|
|
||
| describe('EuiNotificationEvent', () => { | ||
| beforeEach(() => { | ||
| cy.viewport(1024, 768); // medium breakpoint | ||
| cy.realMount(<NotificationEvent />); | ||
| cy.get('article.euiNotificationEvent').should('exist'); | ||
| }); | ||
|
|
||
| describe('Automated accessibility check', () => { | ||
| it('has zero violations on first render', () => { | ||
| cy.checkAxe(); | ||
| }); | ||
|
|
||
| it('has zero violations when popover is open', () => { | ||
| cy.get( | ||
| 'button[data-test-subj="cy-eui-notification-1-notificationEventMetaButton"]' | ||
| ).realClick(); | ||
| cy.get('div.euiPopover__panel').should('exist'); | ||
| cy.checkAxe(); | ||
| }); | ||
|
|
||
| it('has zero violations after the Mark as read button is clicked', () => { | ||
| cy.get( | ||
| 'button[data-test-subj="cy-eui-notification-1-notificationEventMetaButton"]' | ||
| ).realClick(); | ||
| cy.get('div.euiPopover__panel').should('exist'); | ||
| cy.get('div.euiPopover__panel button').first().realClick(); | ||
| cy.checkAxe(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Keyboard accessibility', () => { | ||
| it('has zero violations when the popover is opened by keyboard', () => { | ||
| cy.repeatRealPress('Tab'); | ||
| cy.get( | ||
| 'button[data-test-subj="cy-eui-notification-1-notificationEventMetaButton"]' | ||
| ).should('have.focus'); | ||
| cy.realPress('Enter'); | ||
| cy.get('div.euiPopover__panel').should('exist'); | ||
| cy.checkAxe(); | ||
| cy.realPress('Escape'); | ||
| cy.get('div.euiPopover__panel').should('not.exist'); | ||
| cy.checkAxe(); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License | ||
| * 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
| * in compliance with, at your election, the Elastic License 2.0 or the Server | ||
| * Side Public License, v 1. | ||
| */ | ||
|
|
||
| /// <reference types="../../../../cypress/support"/> | ||
|
|
||
| import React from 'react'; | ||
| import { EuiButton } from '../../button'; | ||
| import { EuiPageHeader } from './page_header'; | ||
|
|
||
| describe('EuiPageHeader', () => { | ||
| beforeEach(() => { | ||
| cy.viewport(1024, 768); // medium breakpoint | ||
| cy.realMount( | ||
| <EuiPageHeader | ||
|
1Copenut marked this conversation as resolved.
|
||
| pageTitle="Page title" | ||
| iconType="logoKibana" | ||
| description="This description should be describing the current page as depicted by the page title. It will never extend beneath the right side content." | ||
| rightSideItems={[ | ||
| <EuiButton fill>Add something</EuiButton>, | ||
| <EuiButton>Do something</EuiButton>, | ||
| ]} | ||
| /> | ||
| ); | ||
| cy.get('h1.euiTitle').should('exist'); | ||
| }); | ||
|
|
||
| describe('Automated accessibility check', () => { | ||
| it('has zero violations on first render', () => { | ||
| cy.checkAxe(); | ||
| }); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
| * or more contributor license agreements. Licensed under the Elastic License | ||
| * 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
| * in compliance with, at your election, the Elastic License 2.0 or the Server | ||
| * Side Public License, v 1. | ||
| */ | ||
|
|
||
| /// <reference types="../../../cypress/support"/> | ||
|
|
||
| import React, { useState } from 'react'; | ||
| import { EuiButton } from '../button'; | ||
| import { EuiPortal } from './portal'; | ||
|
|
||
| const Portal = () => { | ||
| const [isCustomFlyoutVisible, setIsCustomFlyoutVisible] = useState(false); | ||
|
|
||
| const toggleCustomFlyout = () => { | ||
| setIsCustomFlyoutVisible(!isCustomFlyoutVisible); | ||
| }; | ||
|
|
||
| const closeCustomFlyout = () => { | ||
| setIsCustomFlyoutVisible(false); | ||
| }; | ||
|
|
||
| let customFlyout; | ||
|
|
||
| if (isCustomFlyoutVisible) { | ||
| customFlyout = ( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would rename all references of |
||
| <EuiPortal> | ||
| <div>This is the portal. Click anywhere to close.</div> | ||
| <EuiButton onClick={closeCustomFlyout}>Close portal</EuiButton> | ||
| </EuiPortal> | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <div> | ||
| <EuiButton onClick={toggleCustomFlyout}>View guide</EuiButton> | ||
| {customFlyout} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| describe('EuiPortal', () => { | ||
| beforeEach(() => { | ||
|
1Copenut marked this conversation as resolved.
|
||
| cy.viewport(1024, 768); // medium breakpoint | ||
| cy.realMount(<Portal />); | ||
| cy.get('div[data-relative-to-header="above"]').should('not.exist'); | ||
| }); | ||
|
|
||
| describe('Automated accessibility check', () => { | ||
| it('has zero violations on first render', () => { | ||
| cy.checkAxe(); | ||
| }); | ||
|
|
||
| it('has zero violations after the portal is activated', () => { | ||
| cy.get('button[type="button"]').contains('View guide').realClick(); | ||
| cy.get('div[data-euiportal="true"]').should('exist'); | ||
| cy.checkAxe(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Keyboard accessibility', () => { | ||
| it('has zero violations when the portal is opened by keyboard', () => { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little confused by this test - it's not clear to me at all what this test adds compared to the one before it (which just clicks the button). Portals do not inherently have any opinion about mouse vs keyboard interaction, so this test is literally just apparently testing that you can tab to and press enter on a button, which I don't think is particularly helpful or specific to EuiPortal.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's valid. I was aiming for 1:1 mouse to keyboard coverage but this feels right at the edge of diminishing returns. I'm removing the keyboard test here and will push an update in a few minutes. |
||
| cy.realPress('Tab'); | ||
| cy.get('button[type="button"]').should('have.focus'); | ||
| cy.realPress('Enter'); | ||
| cy.get('div[data-euiportal="true"]').should('exist'); | ||
| cy.checkAxe(); | ||
| cy.realPress('Tab'); | ||
| cy.realPress('Enter'); | ||
| cy.get('div[data-euiportal="true"]').should('not.exist'); | ||
| cy.checkAxe(); | ||
| }); | ||
| }); | ||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.