diff --git a/packages/e2e-test-utils/README.md b/packages/e2e-test-utils/README.md
index 35cd91fd6c14b..8cfd7554eb782 100644
--- a/packages/e2e-test-utils/README.md
+++ b/packages/e2e-test-utils/README.md
@@ -377,14 +377,6 @@ _Parameters_
- _searchTerm_ `string`: The text to search the inserter for.
-# **selectAllBlocks**
-
-Selects all blocks present in the block editor.
-
-_Returns_
-
-- `Promise`: Promise resolving once active element selected.
-
# **selectBlockByClientId**
Given the clientId of a block, selects the block on the editor.
diff --git a/packages/e2e-test-utils/src/index.js b/packages/e2e-test-utils/src/index.js
index e0832b1d9a5e4..e984658a99f6d 100644
--- a/packages/e2e-test-utils/src/index.js
+++ b/packages/e2e-test-utils/src/index.js
@@ -1,4 +1,3 @@
-export { __unstableSelectAll } from './select-all';
export { activatePlugin } from './activate-plugin';
export { arePrePublishChecksEnabled } from './are-pre-publish-checks-enabled';
export { clearLocalStorage } from './clear-local-storage';
@@ -38,7 +37,6 @@ export { publishPost } from './publish-post';
export { publishPostWithPrePublishChecksDisabled } from './publish-post-with-pre-publish-checks-disabled';
export { saveDraft } from './save-draft';
export { searchForBlock } from './search-for-block';
-export { selectAllBlocks } from './select-all-blocks';
export { selectBlockByClientId } from './select-block-by-client-id';
export { setBrowserViewport } from './set-browser-viewport';
export { setPostContent } from './set-post-content';
diff --git a/packages/e2e-test-utils/src/login-user.js b/packages/e2e-test-utils/src/login-user.js
index 63465582efb81..d06878d69186e 100644
--- a/packages/e2e-test-utils/src/login-user.js
+++ b/packages/e2e-test-utils/src/login-user.js
@@ -4,7 +4,7 @@
import { WP_USERNAME, WP_PASSWORD } from './shared/config';
import { createURL } from './create-url';
import { isCurrentURL } from './is-current-url';
-import { __unstableSelectAll } from './select-all';
+import { pressKeyWithModifier } from './press-key-with-modifier';
/**
* Performs log in with specified username and password.
@@ -20,10 +20,10 @@ export async function loginUser( username = WP_USERNAME, password = WP_PASSWORD
}
await page.focus( '#user_login' );
- await __unstableSelectAll();
+ await pressKeyWithModifier( 'primary', 'a' );
await page.type( '#user_login', username );
await page.focus( '#user_pass' );
- await __unstableSelectAll();
+ await pressKeyWithModifier( 'primary', 'a' );
await page.type( '#user_pass', password );
await Promise.all( [ page.waitForNavigation(), page.click( '#wp-submit' ) ] );
diff --git a/packages/e2e-test-utils/src/press-key-with-modifier.js b/packages/e2e-test-utils/src/press-key-with-modifier.js
index e20100ba54e5f..59f5c8330672e 100644
--- a/packages/e2e-test-utils/src/press-key-with-modifier.js
+++ b/packages/e2e-test-utils/src/press-key-with-modifier.js
@@ -8,6 +8,78 @@ import { capitalize } from 'lodash';
*/
import { modifiers, SHIFT, ALT, CTRL } from '@wordpress/keycodes';
+/**
+ * Emulates a Ctrl+A SelectAll key combination by dispatching custom keyboard
+ * events and using the results of those events to determine whether to call
+ * `document.execCommand( 'selectall' );`. This is necessary because Puppeteer
+ * does not emulate Ctrl+A SelectAll in macOS. Events are dispatched to ensure
+ * that any `Event#preventDefault` which would have normally occurred in the
+ * application as a result of Ctrl+A is respected.
+ *
+ * @link https://github.com/GoogleChrome/puppeteer/issues/1313
+ * @link https://w3c.github.io/uievents/tools/key-event-viewer.html
+ *
+ * @return {Promise} Promise resolving once the SelectAll emulation completes.
+ */
+async function emulateSelectAll() {
+ await page.evaluate( () => {
+ const isMac = /Mac|iPod|iPhone|iPad/.test( window.navigator.platform );
+
+ document.activeElement.dispatchEvent(
+ new KeyboardEvent( 'keydown', {
+ bubbles: true,
+ cancelable: true,
+ key: isMac ? 'Meta' : 'Control',
+ code: isMac ? 'MetaLeft' : 'ControlLeft',
+ location: window.KeyboardEvent.DOM_KEY_LOCATION_LEFT,
+ getModifierState: ( keyArg ) => keyArg === ( isMac ? 'Meta' : 'Control' ),
+ ctrlKey: ! isMac,
+ metaKey: isMac,
+ charCode: 0,
+ keyCode: isMac ? 93 : 17,
+ which: isMac ? 93 : 17,
+ } )
+ );
+
+ const preventableEvent = new KeyboardEvent( 'keydown', {
+ bubbles: true,
+ cancelable: true,
+ key: 'a',
+ code: 'KeyA',
+ location: window.KeyboardEvent.DOM_KEY_LOCATION_STANDARD,
+ getModifierState: ( keyArg ) => keyArg === ( isMac ? 'Meta' : 'Control' ),
+ ctrlKey: ! isMac,
+ metaKey: isMac,
+ charCode: 0,
+ keyCode: 65,
+ which: 65,
+ } );
+
+ const wasPrevented = (
+ ! document.activeElement.dispatchEvent( preventableEvent ) ||
+ preventableEvent.defaultPrevented
+ );
+
+ if ( ! wasPrevented ) {
+ document.execCommand( 'selectall', false, null );
+ }
+
+ document.activeElement.dispatchEvent(
+ new KeyboardEvent( 'keyup', {
+ bubbles: true,
+ cancelable: true,
+ key: isMac ? 'Meta' : 'Control',
+ code: isMac ? 'MetaLeft' : 'ControlLeft',
+ location: window.KeyboardEvent.DOM_KEY_LOCATION_LEFT,
+ getModifierState: () => false,
+ charCode: 0,
+ keyCode: isMac ? 93 : 17,
+ which: isMac ? 93 : 17,
+ } ),
+ );
+ } );
+}
+
/**
* Performs a key press with modifier (Shift, Control, Meta, Alt), where each modifier
* is normalized to platform-specific modifier.
@@ -16,6 +88,10 @@ import { modifiers, SHIFT, ALT, CTRL } from '@wordpress/keycodes';
* @param {string} key Key to press while modifier held.
*/
export async function pressKeyWithModifier( modifier, key ) {
+ if ( modifier.toLowerCase() === 'primary' && key.toLowerCase() === 'a' ) {
+ return await emulateSelectAll();
+ }
+
const isAppleOS = () => process.platform === 'darwin';
const overWrittenModifiers = {
...modifiers,
diff --git a/packages/e2e-test-utils/src/select-all-blocks.js b/packages/e2e-test-utils/src/select-all-blocks.js
deleted file mode 100644
index adfe905c63188..0000000000000
--- a/packages/e2e-test-utils/src/select-all-blocks.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Internal dependencies
- */
-import { pressKeyWithModifier } from './press-key-with-modifier';
-import { __unstableSelectAll } from './select-all';
-
-/**
- * Selects all blocks present in the block editor.
- *
- * @return {Promise} Promise resolving once active element selected.
- */
-export async function selectAllBlocks() {
- // NOTE: `__unstableSelectAll` is used for cross-platform compatibility
- // alternative to Cmd+A. The second issuance of the key combination is
- // handled internerally by the block editor's KeyboardShortcuts utility,
- // and is not subject to the same buggy browser/OS emulation.
- await __unstableSelectAll();
- await pressKeyWithModifier( 'primary', 'a' );
-}
diff --git a/packages/e2e-test-utils/src/select-all.js b/packages/e2e-test-utils/src/select-all.js
deleted file mode 100644
index 1f670bb865bf3..0000000000000
--- a/packages/e2e-test-utils/src/select-all.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Selects all text within the current active element field. Throws if there is
- * no active element.
- *
- * This serves as a temporary solution to a bug present as of Puppeteer 1.6.1
- * in which the Cmd+A keyboard combination does not work correctly in macOS
- * environments. Once the bug is resolved, the utility will be removed.
- *
- * @link https://github.com/GoogleChrome/puppeteer/issues/1313
- *
- * @return {Promise} Promise resolving once active element selected.
- */
-export async function __unstableSelectAll() {
- await page.evaluate( () => document.execCommand( 'selectall', false, null ) );
-}
diff --git a/packages/e2e-tests/specs/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/block-hierarchy-navigation.test.js
index 63ea25ca8b88a..c53adb01730bd 100644
--- a/packages/e2e-tests/specs/block-hierarchy-navigation.test.js
+++ b/packages/e2e-tests/specs/block-hierarchy-navigation.test.js
@@ -7,7 +7,6 @@ import {
getEditedPostContent,
pressKeyTimes,
pressKeyWithModifier,
- __unstableSelectAll,
} from '@wordpress/e2e-test-utils';
async function openBlockNavigator() {
@@ -100,7 +99,7 @@ describe( 'Navigating the block hierarchy', () => {
await page.keyboard.press( 'Space' );
// Replace its content.
- await __unstableSelectAll();
+ await pressKeyWithModifier( 'primary', 'a' );
await page.keyboard.type( 'and I say hello' );
expect( await getEditedPostContent() ).toMatchSnapshot();
diff --git a/packages/e2e-tests/specs/multi-block-selection.test.js b/packages/e2e-tests/specs/multi-block-selection.test.js
index 44701ca1e0ce2..6bf7a62bf7789 100644
--- a/packages/e2e-tests/specs/multi-block-selection.test.js
+++ b/packages/e2e-tests/specs/multi-block-selection.test.js
@@ -8,8 +8,6 @@ import {
pressKeyWithModifier,
pressKeyTimes,
getEditedPostContent,
- selectAllBlocks,
- __unstableSelectAll,
} from '@wordpress/e2e-test-utils';
describe( 'Multi-block selection', () => {
@@ -76,11 +74,7 @@ describe( 'Multi-block selection', () => {
// Select all via double shortcut.
await page.click( firstBlockSelector );
- // NOTE: `__unstableSelectAll` is used for cross-platform compatibility
- // alternative to Cmd+A. The second issuance of the key combination is
- // handled internerally by the block editor's KeyboardShortcuts utility
- // and is not subject to the same buggy emulation.
- await __unstableSelectAll();
+ await pressKeyWithModifier( 'primary', 'a' );
await pressKeyWithModifier( 'primary', 'a' );
await expectMultiSelected( blocks, true );
} );
@@ -132,7 +126,10 @@ describe( 'Multi-block selection', () => {
await page.keyboard.type( 'Second Paragraph' );
await insertBlock( 'Paragraph' );
await page.keyboard.type( 'Third Paragraph' );
- await selectAllBlocks();
+
+ // Multiselect via keyboard.
+ await pressKeyWithModifier( 'primary', 'a' );
+ await pressKeyWithModifier( 'primary', 'a' );
// TODO: It would be great to do this test by spying on `wp.a11y.speak`,
// but it's very difficult to do that because `wp.a11y` has
diff --git a/packages/e2e-tests/specs/reusable-blocks.test.js b/packages/e2e-tests/specs/reusable-blocks.test.js
index 7e25f743f0c82..73d7b9117bf43 100644
--- a/packages/e2e-tests/specs/reusable-blocks.test.js
+++ b/packages/e2e-tests/specs/reusable-blocks.test.js
@@ -5,9 +5,9 @@ import {
insertBlock,
createNewPost,
clickBlockToolbarButton,
+ pressKeyWithModifier,
searchForBlock,
getEditedPostContent,
- selectAllBlocks,
} from '@wordpress/e2e-test-utils';
function waitForAndAcceptDialog() {
@@ -210,7 +210,8 @@ describe( 'Reusable Blocks', () => {
await page.keyboard.type( 'Second paragraph' );
// Select all the blocks
- await selectAllBlocks();
+ await pressKeyWithModifier( 'primary', 'a' );
+ await pressKeyWithModifier( 'primary', 'a' );
// Convert block to a reusable block
await page.waitForSelector( 'button[aria-label="More options"]' );
diff --git a/packages/e2e-tests/specs/rich-text.test.js b/packages/e2e-tests/specs/rich-text.test.js
index 0034ac3b106e0..dcb1434abd89b 100644
--- a/packages/e2e-tests/specs/rich-text.test.js
+++ b/packages/e2e-tests/specs/rich-text.test.js
@@ -7,7 +7,6 @@ import {
insertBlock,
clickBlockAppender,
pressKeyWithModifier,
- __unstableSelectAll,
} from '@wordpress/e2e-test-utils';
describe( 'RichText', () => {
@@ -31,7 +30,7 @@ describe( 'RichText', () => {
it( 'should apply formatting with access shortcut', async () => {
await clickBlockAppender();
await page.keyboard.type( 'test' );
- await __unstableSelectAll();
+ await pressKeyWithModifier( 'primary', 'a' );
await pressKeyWithModifier( 'access', 'd' );
expect( await getEditedPostContent() ).toMatchSnapshot();
@@ -40,7 +39,7 @@ describe( 'RichText', () => {
it( 'should apply formatting with primary shortcut', async () => {
await clickBlockAppender();
await page.keyboard.type( 'test' );
- await __unstableSelectAll();
+ await pressKeyWithModifier( 'primary', 'a' );
await pressKeyWithModifier( 'primary', 'b' );
expect( await getEditedPostContent() ).toMatchSnapshot();