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

Refactored e2e keyboard navigation util functions / tests #16707

Closed
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9ac4720
Adding an e2e test verifying simple keyboard navigation through block…
Jan 23, 2019
dbdf8ff
Moving `navigateToContentEditorTop`, `tabThroughParagraphBlock`, `tab…
Feb 24, 2019
7246607
Rewriting tabThroughBlockToolbar to allow it to tab through any block…
Feb 24, 2019
267cb0e
Moving navigateToContentEditorTop, tabThroughBlockMoverControl, and t…
tjnicolaides Mar 7, 2019
830f01a
Merge branch 'master' of github.com:WordPress/gutenberg into add/1345…
tjnicolaides May 23, 2019
f0da33d
Updating block editor classNames to convention - tab-through-block-to…
tjnicolaides May 23, 2019
2b62a21
Updating e2e-test-utils readme
tjnicolaides May 23, 2019
0b3d0a4
WIP - refactoring keyboard navigability tests to handle all the defau…
tjnicolaides May 26, 2019
6365c7e
WIP - successfully tabbing through all core content block types
tjnicolaides May 28, 2019
286060a
WIP - continuing to refactor e2e test tabbing functions
tjnicolaides May 28, 2019
1fd556f
Extracting more keyboard navigation assertions / helpers into e2e-tes…
tjnicolaides Jul 21, 2019
4e3feaf
WIP - refactoring test dependencies for keyboard navigability tests
tjnicolaides Jul 21, 2019
3dbbdd4
WIP Better JSdocs for keyboard navigation e2e test utils
tjnicolaides Jul 22, 2019
40a2f37
JSDocs for keyboard navigability e2e test utils in readme
tjnicolaides Jul 22, 2019
e59fbf6
Merge branch 'master' into add/13455-add-e2e-keyboard-navigation-util…
tjnicolaides Jul 22, 2019
97c6ffd
Fixing failing tests after merge from upstream
tjnicolaides Jul 22, 2019
b8dd4b2
Fixing docs build - PR #16707
tjnicolaides Jul 22, 2019
42ecca4
Merge branch 'master' into add/13455-add-e2e-keyboard-navigation-util…
tjnicolaides Jul 29, 2019
7c8c666
Assertion in externalWrapperHasFocus does not need to await
tjnicolaides Aug 27, 2019
42ea406
Improving JSDocs in some e2e-test-utils packages to make clear they a…
tjnicolaides Aug 27, 2019
c6513e6
Improving JSDocs in some e2e-test-utils packages to make clear they a…
tjnicolaides Aug 27, 2019
9badfc1
Improving JSDocs in some e2e-test-utils packages to make clear they a…
tjnicolaides Aug 27, 2019
8726c0f
Fixing typo in tabThroughPlaceholderButtons
tjnicolaides Aug 27, 2019
f6e538c
Fixing undocumented declaration in e2e-test-utils/README. Updating fo…
tjnicolaides Aug 27, 2019
7848c4b
Using page.$$eval instead of getElementList
tjnicolaides Aug 27, 2019
c5889d1
Updating JSDoc in e2e-test-utils/README
tjnicolaides Aug 27, 2019
c664379
Re-evaluate isFocusedTextContentArea and textContentAreaContent withi…
tjnicolaides Aug 27, 2019
71dea07
Refactoring 'Order of block keyboard navigation' to a series of more …
tjnicolaides Aug 27, 2019
f3c9746
Merge branch 'master' into add/13455-add-e2e-keyboard-navigation-util…
tjnicolaides Aug 27, 2019
b56bfe0
Renaming tabThroughBlock to tabThroughBlockControls, tabThroughBlockM…
tjnicolaides Aug 27, 2019
bdf6a8f
Improving confusing variable name in insert-and-populate-block
tjnicolaides Aug 27, 2019
2a5a9ce
Renaming helper function from textContentAreasHaveFocus to tabThrough…
tjnicolaides Aug 27, 2019
43bb03b
Merge branch 'master' into add/13455-add-e2e-keyboard-navigation-util…
Sep 23, 2019
56fd018
Linter fixes for /e2e-test-utils changes
Sep 28, 2019
4c82b7b
JSDoc fix for e2e-test-utils changes
Sep 28, 2019
49ea295
Merge branch 'upstream-master' into add/13455-add-e2e-keyboard-naviga…
Sep 28, 2019
5239a9f
Merge branch 'upstream-master' into add/13455-add-e2e-keyboard-naviga…
Oct 19, 2019
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
114 changes: 114 additions & 0 deletions packages/e2e-test-utils/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,14 @@ _Returns_

- `Promise`: Promise resolving once the edit post sidebar is opened.

<a name="externalWrapperHasFocus" href="#externalWrapperHasFocus">#</a> **externalWrapperHasFocus**

Asserts that the element with keyboard focus is a block's external wrapper

_Parameters_

- _blockType_ `string`: The expected value of the data-type attribute of the block's external wrapper

<a name="findSidebarPanelToggleButtonWithTitle" href="#findSidebarPanelToggleButtonWithTitle">#</a> **findSidebarPanelToggleButtonWithTitle**

Finds a sidebar panel with the provided title.
Expand Down Expand Up @@ -259,6 +267,19 @@ _Returns_

- `Promise`: Promise resolving with a boolean.

<a name="insertAndPopulateBlock" href="#insertAndPopulateBlock">#</a> **insertAndPopulateBlock**

Inserts a content block and then, if it has text content areas, fills them with text

_Parameters_

- _blockName_ `string`: The type of block to insert
- _content_ `string`: The text to enter into each contenteditable area

_Returns_

- `Promise`: A promise that resolves when all the blocks are inserted and filled with content.

<a name="insertBlock" href="#insertBlock">#</a> **insertBlock**

Opens the inserter, searches for the given term, then selects the first
Expand All @@ -269,6 +290,10 @@ _Parameters_
- _searchTerm_ `string`: The text to search the inserter for.
- _panelName_ `string`: The inserter panel to open (if it's closed by default).

<a name="inserterToggleHasFocus" href="#inserterToggleHasFocus">#</a> **inserterToggleHasFocus**

Asserts that a content block's inserter toggle has keyboard focus

<a name="installPlugin" href="#installPlugin">#</a> **installPlugin**

Installs a plugin from the WP.org repository.
Expand Down Expand Up @@ -323,6 +348,14 @@ _Returns_

- `Promise`: Promise that uses `mockCheck` to see if a request should be mocked with `mock`, and optionally transforms the response with `responseObjectTransform`.

<a name="navigateToContentEditorTop" href="#navigateToContentEditorTop">#</a> **navigateToContentEditorTop**

Navigates to the top of the content editor using the keyboard.

_Returns_

- `Promise`: A promise that's resolved when the browser has finished emulating the keyboard shortcut for focusing the top of the editor, and tabbed to the next focusable element.

<a name="observeFocusLoss" href="#observeFocusLoss">#</a> **observeFocusLoss**

Binds to the document on page load which throws an error if a `focusout`
Expand Down Expand Up @@ -473,6 +506,87 @@ running the test is not already the admin user).
Switches the current user to whichever user we should be
running the tests as (if we're not already that user).

<a name="tabThroughBlock" href="#tabThroughBlock">#</a> **tabThroughBlock**

Tabs through a content block and asserts that the external wrapper, inserter toggle, mover controls, and toolbar buttons all receive keyboard focus.

_Parameters_

- _blockType_ `string`: The expected value of the data-type attribute of the block's external wrapper

<a name="tabThroughBlockMoverControl" href="#tabThroughBlockMoverControl">#</a> **tabThroughBlockMoverControl**

Navigates through the block mover control using the keyboard. Asserts that the 'move up' and 'move down' controls receive focus.

_Returns_

- `Promise`: A promise that's resolved when the browser has finished tabbing throught the block mover controls.

<a name="tabThroughBlockToolbar" href="#tabThroughBlockToolbar">#</a> **tabThroughBlockToolbar**

Navigate through a block's toolbar using the keyboard. Asserts that each button receives focus.

_Returns_

- `Promise`: A promise that resolves when it's finished tabbing through the buttons in a block's toolbar, asserting that each one received focus.

<a name="tabThroughFileBlock" href="#tabThroughFileBlock">#</a> **tabThroughFileBlock**

Tabs through a content block with file upload buttons, such as an Image, Gallery, Audio, or Cover block

_Parameters_

- _blockType_ `string`: The expected value of the data-type attribute of the block's external wrapper

_Returns_

- `Promise`: A promise that resolves when the browser has completed tabbing through the common block components, and the placeholder buttons that are unique to blocks with file-upload features.

<a name="tabThroughPlaceholderButtons" href="#tabThroughPlaceholderButtons">#</a> **tabThroughPlaceholderButtons**

Tabs through the file upload buttons that appear in a file content block's placeholder area

_Returns_

- `Promise`: A promise that resolves when the browser has completed tabbing through the placeholder buttons that are unique to blocks with file-upload features.

<a name="tabThroughTextBlock" href="#tabThroughTextBlock">#</a> **tabThroughTextBlock**

Tabs through a content block with text content areas, such as a Heading, Quote, or Paragraph block. Asserts that the text content areas all receive focus.

_Parameters_

- _blockType_ `string`: The expected value of the data-type attribute of the block's external wrapper
- _content_ `string`: The expected title of the block

_Returns_

- `Promise`: A promise that resolves when the browser has completed tabbing through the focusable elements of a common block, and through the contenteditbable areas unique to text blocks.

<a name="textContentAreas" href="#textContentAreas">#</a> **textContentAreas**

Returns a list of a block's contenteditable elements.

_Parameters_

- _empty_ `boolean`: When true, restricts the list to contenteditable elements with no value

_Returns_

- `Promise`: A promise that resolves when it's returned an array of classes representing the contenteditable areas of a block with keyboard focus.

<a name="textContentAreasHaveFocus" href="#textContentAreasHaveFocus">#</a> **textContentAreasHaveFocus**

Tabs through the text content areas of a block and asserts the expected values

_Parameters_

- _content_ `string`: The expected value of the block's contenteditable elements

_Returns_

- `Promise`: A promise that's resolved when the browser has finished tabbing throught the contenteditable areas of a block, and asserting they have keyboard focus and the expected content.

<a name="toggleScreenOption" href="#toggleScreenOption">#</a> **toggleScreenOption**

Toggles the screen option with the given label.
Expand Down
11 changes: 11 additions & 0 deletions packages/e2e-test-utils/src/external-wrapper-has-focus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Asserts that the element with keyboard focus is a block's external wrapper
*
* @param {string} blockType The expected value of the data-type attribute of the block's external wrapper
* @returns {Promise} A promise that's resolved when the active element is evaluated and asserted against the expected result.
*/
tjnicolaides marked this conversation as resolved.
Show resolved Hide resolved

export async function externalWrapperHasFocus( blockType ) {
const activeElementDataType = await page.evaluate( () => document.activeElement.dataset.type );
expect( activeElementDataType ).toEqual( blockType );
}
12 changes: 12 additions & 0 deletions packages/e2e-test-utils/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export { enableExperimentalFeatures } from './enable-experimental-features';
export { enablePageDialogAccept } from './enable-page-dialog-accept';
export { enablePrePublishChecks } from './enable-pre-publish-checks';
export { ensureSidebarOpened } from './ensure-sidebar-opened';
export { externalWrapperHasFocus } from './external-wrapper-has-focus';
export { findSidebarPanelToggleButtonWithTitle } from './find-sidebar-panel-toggle-button-with-title';
export { findSidebarPanelWithTitle } from './find-sidebar-panel-with-title';
export { getAllBlockInserterItemTitles } from './get-all-block-inserter-item-titles';
Expand All @@ -23,11 +24,14 @@ export { getAvailableBlockTransforms } from './get-available-block-transforms';
export { getBlockSetting } from './get-block-setting';
export { getEditedPostContent } from './get-edited-post-content';
export { hasBlockSwitcher } from './has-block-switcher';
export { insertAndPopulateBlock } from './insert-and-populate-block';
export { insertBlock } from './insert-block';
export { inserterToggleHasFocus } from './inserter-toggle-has-focus';
export { installPlugin } from './install-plugin';
export { isCurrentURL } from './is-current-url';
export { isInDefaultBlock } from './is-in-default-block';
export { loginUser } from './login-user';
export { navigateToContentEditorTop } from './navigate-to-content-editor-top';
export { observeFocusLoss } from './observe-focus-loss';
export { openAllBlockInserterCategories } from './open-all-block-inserter-categories';
export { openDocumentSettingsSidebar } from './open-document-settings-sidebar';
Expand All @@ -46,6 +50,14 @@ export { switchEditorModeTo } from './switch-editor-mode-to';
export { disableNavigationMode } from './keyboard-mode';
export { switchUserToAdmin } from './switch-user-to-admin';
export { switchUserToTest } from './switch-user-to-test';
export { tabThroughBlock } from './tab-through-block';
export { tabThroughBlockMoverControl } from './tab-through-block-mover-control';
export { tabThroughBlockToolbar } from './tab-through-block-toolbar';
export { tabThroughFileBlock } from './tab-through-file-block';
export { tabThroughPlaceholderButtons } from './tab-through-placeholder-buttons';
export { tabThroughTextBlock } from './tab-through-text-block';
export { textContentAreas } from './text-content-areas';
export { textContentAreasHaveFocus } from './text-content-areas-have-focus';
export { toggleScreenOption } from './toggle-screen-option';
export { transformBlockTo } from './transform-block-to';
export { uninstallPlugin } from './uninstall-plugin';
Expand Down
29 changes: 29 additions & 0 deletions packages/e2e-test-utils/src/insert-and-populate-block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* WordPress dependencies
*/
import {
insertBlock,
textContentAreas,
} from '@wordpress/e2e-test-utils';

/**
* Inserts a content block and then, if it has text content areas, fills them with text
*
* @param {string} blockName The type of block to insert
* @param {string} content The text to enter into each contenteditable area
* @return {Promise} A promise that resolves when all the blocks are inserted and filled with content.
*/
export async function insertAndPopulateBlock( blockName, content ) {
await insertBlock( blockName );
// typing populates the first content area
await page.keyboard.type( content );

// if there are more contenteditable elements, select and populate them too:
const blocks = await textContentAreas( { empty: true } );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should populate other content areas within the same block, is that correct? Yet I noticed when running keyboard-navigable-blocks.test.js in interactive mode that the citation field in the Quote block did not get populated. Shouldn't it have done so?

tjnicolaides marked this conversation as resolved.
Show resolved Hide resolved

for ( let i = 0; i < blocks.length; i++ ) {
await page.keyboard.press( 'Tab' );
await page.keyboard.type( content );
}
await page.keyboard.press( 'Enter' );
}
9 changes: 9 additions & 0 deletions packages/e2e-test-utils/src/inserter-toggle-has-focus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Asserts that a content block's inserter toggle has keyboard focus
* @returns {Promise} A promise that's resolved when the active element is evaluated and asserted to have the inserter toggle's classname.
*/

export async function inserterToggleHasFocus() {
tjnicolaides marked this conversation as resolved.
Show resolved Hide resolved
const isFocusedInserterToggle = await page.evaluate( () => document.activeElement.classList.contains( 'block-editor-inserter__toggle' ) );
expect( isFocusedInserterToggle ).toBe( true );
}
17 changes: 17 additions & 0 deletions packages/e2e-test-utils/src/navigate-to-content-editor-top.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Internal dependencies
*/
import { pressKeyWithModifier } from './press-key-with-modifier';

/**
* Navigates to the top of the content editor using the keyboard.
* @return {Promise} A promise that's resolved when the browser has finished emulating the keyboard shortcut for focusing the top of the editor, and tabbed to the next focusable element.
*/
export async function navigateToContentEditorTop() {
// Use 'Ctrl+`' to return to the top of the editor
await pressKeyWithModifier( 'ctrl', '`' );
await pressKeyWithModifier( 'ctrl', '`' );

// Tab into the Title block
await page.keyboard.press( 'Tab' );
}
19 changes: 19 additions & 0 deletions packages/e2e-test-utils/src/tab-through-block-mover-control.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Navigates through the block mover control using the keyboard. Asserts that the 'move up' and 'move down' controls receive focus.
* @return {Promise} A promise that's resolved when the browser has finished tabbing throught the block mover controls.
*/
export async function tabThroughBlockMoverControl() {
// Tab to focus on the 'move up' control
await page.keyboard.press( 'Tab' );
const isFocusedMoveUpControl = await page.evaluate( () =>
document.activeElement.classList.contains( 'block-editor-block-mover__control' )
);
expect( isFocusedMoveUpControl ).toBe( true );

// Tab to focus on the 'move down' control
await page.keyboard.press( 'Tab' );
const isFocusedMoveDownControl = await page.evaluate( () =>
document.activeElement.classList.contains( 'block-editor-block-mover__control' )
);
expect( isFocusedMoveDownControl ).toBe( true );
}
17 changes: 17 additions & 0 deletions packages/e2e-test-utils/src/tab-through-block-toolbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Navigate through a block's toolbar using the keyboard. Asserts that each button receives focus.
* @return {Promise} A promise that resolves when it's finished tabbing through the buttons in a block's toolbar, asserting that each one received focus.
*/

export async function tabThroughBlockToolbar() {
const blockToolbarButtons = await page.$$eval( '.block-editor-block-contextual-toolbar button:not([disabled])',
( elements ) => elements.map( ( elem ) => elem.className ) );

for ( const buttonClassName of blockToolbarButtons ) {
await page.keyboard.press( 'Tab' );
const focusedBlockToolBarButton = await page.evaluate( () =>
document.activeElement.className
);
expect( focusedBlockToolBarButton ).toEqual( buttonClassName );
}
}
29 changes: 29 additions & 0 deletions packages/e2e-test-utils/src/tab-through-block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* WordPress dependencies
*/
import {
externalWrapperHasFocus,
inserterToggleHasFocus,
tabThroughBlockMoverControl,
tabThroughBlockToolbar,
} from '@wordpress/e2e-test-utils';

/**
* Tabs through a content block and asserts that the external wrapper, inserter toggle, mover controls, and toolbar buttons all receive keyboard focus.
*
* @param {string} blockType The expected value of the data-type attribute of the block's external wrapper
* @returns {Promise} A promise that's resolved when the browser has finished tabbing through the major components of a common block.
*/

export async function tabThroughBlock( blockType ) {
tjnicolaides marked this conversation as resolved.
Show resolved Hide resolved
// Tab to the next block
await page.keyboard.press( 'Tab' );
await externalWrapperHasFocus( blockType );

// Tab causes 'add block' button to receive focus
await page.keyboard.press( 'Tab' );
await inserterToggleHasFocus();

await tabThroughBlockMoverControl();
await tabThroughBlockToolbar();
}
18 changes: 18 additions & 0 deletions packages/e2e-test-utils/src/tab-through-file-block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

/**
* Internal dependencies
*/

import { tabThroughBlock } from './tab-through-block';
import { tabThroughPlaceholderButtons } from './tab-through-placeholder-buttons';

/**
* Tabs through a content block with file upload buttons, such as an Image, Gallery, Audio, or Cover block
*
* @param {string} blockType The expected value of the data-type attribute of the block's external wrapper
* @return {Promise} A promise that resolves when the browser has completed tabbing through the common block components, and the placeholder buttons that are unique to blocks with file-upload features.
*/
export async function tabThroughFileBlock( blockType ) {
await tabThroughBlock( blockType );
await tabThroughPlaceholderButtons();
}
16 changes: 16 additions & 0 deletions packages/e2e-test-utils/src/tab-through-placeholder-buttons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Tabs through the file upload buttons that appear in a file content block's placeholder area
* @return {Promise} A promise that resolves when the browser has completed tabbing through the placeholder buttons that are unique to blocks with file-upload features.
*/
export const tabThroughPlaceholderButtons = async () => {
const placeholderButtons = await page.$$eval( '.wp-block.is-selected .block-editor-media-placeholder button:not([disabled])',
( elements ) => elements.map( ( elem ) => elem.className ) );

for ( const buttonClassName of placeholderButtons ) {
await page.keyboard.press( 'Tab' );
const focusedPlaceholderButton = await page.evaluate( () =>
document.activeElement.className
);
expect( focusedPlaceholderButton ).toEqual( buttonClassName );
}
};
21 changes: 21 additions & 0 deletions packages/e2e-test-utils/src/tab-through-text-block.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Internal dependencies
*/
import { tabThroughBlock } from './tab-through-block';
import { textContentAreasHaveFocus } from './text-content-areas-have-focus';

/**
* Tabs through a content block with text content areas, such as a Heading, Quote, or Paragraph block. Asserts that the text content areas all receive focus.
*
* @param {string} blockType The expected value of the data-type attribute of the block's external wrapper
* @param {string} content The expected title of the block
* @return {Promise} A promise that resolves when the browser has completed tabbing through the focusable elements of a common block, and through the contenteditbable areas unique to text blocks.
*/

export async function tabThroughTextBlock( blockType, content ) {
await tabThroughBlock( blockType );

// Tab causes the block text content to receive focus
await page.keyboard.press( 'Tab' );
await textContentAreasHaveFocus( content );
}
Loading