Skip to content

Commit

Permalink
Convert flakey Jest focus/keyboard tests to Cypress (#5261)
Browse files Browse the repository at this point in the history
  • Loading branch information
Constance authored Oct 14, 2021
1 parent cd938f2 commit 6cb6bf0
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 124 deletions.
131 changes: 131 additions & 0 deletions src/components/context_menu/context_menu_panel.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* 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.
*/

import React from 'react';
import { mount } from '@cypress/react';

import { EuiContextMenuItem } from './context_menu_item';
import { EuiContextMenuPanel } from './context_menu_panel';

describe('EuiContextMenuPanel', () => {
describe('focus behavior', () => {
it('is set on the first focusable element by default if there are no items and hasFocus is true', () => {
mount(
<EuiContextMenuPanel>
<button data-test-subj="button">Hello world</button>
</EuiContextMenuPanel>
);

cy.focused().should('have.attr', 'data-test-subj', 'button');
});

it('is not set on anything if hasFocus is false', () => {
mount(
<EuiContextMenuPanel hasFocus={false}>
<button data-test-subj="button">Hello world</button>
</EuiContextMenuPanel>
);

cy.focused().should('not.exist');
});
});

describe('keyboard navigation of items', () => {
const items = [
<EuiContextMenuItem key="A" data-test-subj="itemA">
Option A
</EuiContextMenuItem>,
<EuiContextMenuItem key="B" data-test-subj="itemB">
Option B
</EuiContextMenuItem>,
<EuiContextMenuItem key="C" data-test-subj="itemC">
Option C
</EuiContextMenuItem>,
];

describe('up/down keys', () => {
beforeEach(() => {
mount(<EuiContextMenuPanel items={items} />);
cy.wait(100); // Intermittent flake workaround: without this, the first downarrow key does not always focus into the menu items as expected
});

it('focuses the panel by default', () => {
cy.focused().should('have.attr', 'class', 'euiContextMenuPanel');
});

it('down arrow key focuses the first menu item', () => {
cy.get('body').type('{downarrow}');

cy.focused().should('have.attr', 'data-test-subj', 'itemA');
});

it('subsequently, down arrow key focuses the next menu item', () => {
cy.get('body').type('{downarrow}');
cy.get('body').type('{downarrow}');

cy.focused().should('have.attr', 'data-test-subj', 'itemB');
});

it('up arrow key wraps to last menu item', () => {
cy.get('body').type('{uparrow}');

cy.focused().should('have.attr', 'data-test-subj', 'itemC');
});

it('down arrow key wraps to first menu item', () => {
cy.get('body').type('{uparrow}');
cy.get('body').type('{downarrow}');

cy.focused().should('have.attr', 'data-test-subj', 'itemA');
});

it('subsequently, up arrow key focuses the previous menu item', () => {
cy.get('body').type('{uparrow}');
cy.get('body').type('{uparrow}');

cy.focused().should('have.attr', 'data-test-subj', 'itemB');
});
});

describe('left/right arrow keys', () => {
it("right arrow key shows next panel with focused item's index", () => {
const showNextPanelHandler = cy.stub();
mount(
<EuiContextMenuPanel
items={items}
showNextPanel={showNextPanelHandler}
/>
);

cy.get('body')
.type('{downarrow}')
.type('{rightarrow}')
.then(() => {
expect(showNextPanelHandler).to.be.called;
});
});

it('left arrow key shows previous panel', () => {
const showPreviousPanelHandler = cy.stub();
mount(
<EuiContextMenuPanel
items={items}
showPreviousPanel={showPreviousPanelHandler}
/>
);

cy.get('body')
.type('{downarrow}')
.type('{leftarrow}')
.then(() => {
expect(showPreviousPanelHandler).to.be.called;
});
});
});
});
});
126 changes: 2 additions & 124 deletions src/components/context_menu/context_menu_panel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import React from 'react';
import { render, mount, ReactWrapper } from 'enzyme';
import { render, mount } from 'enzyme';
import { findTestSubject, requiredProps } from '../../test';

import { EuiContextMenuPanel, SIZES } from './context_menu_panel';
Expand Down Expand Up @@ -279,129 +279,7 @@ describe('EuiContextMenuPanel', () => {
});
});

describe('behavior', () => {
describe('focus', () => {
it('is set on the first focusable element by default if there are no items and hasFocus is true', async () => {
const component = mount(
<EuiContextMenuPanel>
<button data-test-subj="button" />
</EuiContextMenuPanel>
);

await tick(20);

expect(findTestSubject(component, 'button').getDOMNode()).toBe(
document.activeElement
);
});

it('is not set on anything if hasFocus is false', () => {
const component = mount(
<EuiContextMenuPanel hasFocus={false}>
<button data-test-subj="button" />
</EuiContextMenuPanel>
);

expect(findTestSubject(component, 'button').getDOMNode()).not.toBe(
document.activeElement
);
});
});

describe('keyboard navigation of items', () => {
let component: ReactWrapper;
let showNextPanelHandler: jest.Mock;
let showPreviousPanelHandler: jest.Mock;

beforeEach(() => {
showNextPanelHandler = jest.fn();
showPreviousPanelHandler = jest.fn();

component = mount(
<EuiContextMenuPanel
items={items}
showNextPanel={showNextPanelHandler}
showPreviousPanel={showPreviousPanelHandler}
/>
);
});

it('focuses the panel by default', async () => {
await tick(20);

expect(component.getDOMNode()).toBe(document.activeElement);
});

it('down arrow key focuses the first menu item', async () => {
component.simulate('keydown', { key: keys.ARROW_DOWN });

await tick(20);
expect(findTestSubject(component, 'itemA').getDOMNode()).toBe(
document.activeElement
);
});

it('subsequently, down arrow key focuses the next menu item', async () => {
component.simulate('keydown', { key: keys.ARROW_DOWN });
component.simulate('keydown', { key: keys.ARROW_DOWN });

await tick(20);
expect(findTestSubject(component, 'itemB').getDOMNode()).toBe(
document.activeElement
);
});

it('down arrow key wraps to first menu item', async () => {
component.simulate('keydown', { key: keys.ARROW_UP });
component.simulate('keydown', { key: keys.ARROW_DOWN });

await tick(20);
expect(findTestSubject(component, 'itemA').getDOMNode()).toBe(
document.activeElement
);
});

it('up arrow key focuses the last menu item', async () => {
component.simulate('keydown', { key: keys.ARROW_UP });

await tick(20);
expect(findTestSubject(component, 'itemC').getDOMNode()).toBe(
document.activeElement
);
});

it('subsequently, up arrow key focuses the previous menu item', async () => {
component.simulate('keydown', { key: keys.ARROW_UP });
component.simulate('keydown', { key: keys.ARROW_UP });

await tick(20);
expect(findTestSubject(component, 'itemB').getDOMNode()).toBe(
document.activeElement
);
});

it('up arrow key wraps to last menu item', async () => {
component.simulate('keydown', { key: keys.ARROW_DOWN });
component.simulate('keydown', { key: keys.ARROW_UP });

await tick(20);
expect(findTestSubject(component, 'itemC').getDOMNode()).toBe(
document.activeElement
);
});

it("right arrow key shows next panel with focused item's index", () => {
component.simulate('keydown', { key: keys.ARROW_DOWN });
component.simulate('keydown', { key: keys.ARROW_RIGHT });
expect(showNextPanelHandler).toHaveBeenCalledWith(0);
});

it('left arrow key shows previous panel', () => {
component.simulate('keydown', { key: keys.ARROW_LEFT });
expect(showPreviousPanelHandler).toHaveBeenCalledTimes(1);
});
});
});
// @see Cypress context_menu_panel.spec.tsx for focus & keyboard nav testing

describe('updating items and content', () => {
describe('updates to items', () => {
Expand Down

0 comments on commit 6cb6bf0

Please sign in to comment.