diff --git a/lib/client-assets.php b/lib/client-assets.php index 47d178667b2ba..df7c8959d721a 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -663,3 +663,42 @@ function gutenberg_extend_block_editor_settings_with_fse_theme_flag( $settings ) return $settings; } add_filter( 'block_editor_settings', 'gutenberg_extend_block_editor_settings_with_fse_theme_flag' ); + +/** + * Sets the editor styles to be consumed by JS. + */ +function gutenberg_extend_block_editor_styles_html() { + $handles = array( + 'wp-block-editor', + 'wp-block-library', + 'wp-edit-blocks', + ); + + $block_registry = WP_Block_Type_Registry::get_instance(); + + foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) { + if ( ! empty( $block_type->style ) ) { + $handles[] = $block_type->style; + } + + if ( ! empty( $block_type->editor_style ) ) { + $handles[] = $block_type->editor_style; + } + } + + $handles = array_unique( $handles ); + $done = wp_styles()->done; + + ob_start(); + + wp_styles()->done = array(); + wp_styles()->do_items( $handles ); + wp_styles()->done = $done; + + $editor_styles = wp_json_encode( array( 'html' => ob_get_clean() ) ); + + echo ""; +} +add_action( 'admin_footer-post.php', 'gutenberg_extend_block_editor_styles_html' ); +add_action( 'admin_footer-post-new.php', 'gutenberg_extend_block_editor_styles_html' ); +add_action( 'admin_footer-toplevel_page_gutenberg-edit-site', 'gutenberg_extend_block_editor_styles_html' ); diff --git a/package-lock.json b/package-lock.json index 52fe92d9eba9c..49f6473790c92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1155,30 +1155,6 @@ "@babel/helper-plugin-utils": "^7.10.4" } }, - "@babel/polyfill": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz", - "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==", - "dev": true, - "requires": { - "core-js": "^2.6.5", - "regenerator-runtime": "^0.13.4" - }, - "dependencies": { - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - } - } - }, "@babel/preset-env": { "version": "7.12.7", "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.7.tgz", @@ -13246,6 +13222,7 @@ "lodash": "^4.17.19", "memize": "^1.1.0", "react-autosize-textarea": "^7.1.0", + "react-merge-refs": "^1.0.0", "react-spring": "^8.0.19", "reakit": "1.1.0", "redux-multi": "^0.1.12", @@ -14834,6 +14811,33 @@ "keypather": "^1.10.2" } }, + "@babel/polyfill": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.10.4.tgz", + "integrity": "sha512-8BYcnVqQ5kMD2HXoHInBH7H1b/uP3KdnwCYXOqFnXqguOyuu443WXusbIUbWEfY3Z0Txk0M1uG/8YuAMhNl6zg==", + "dev": true, + "requires": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", + "dev": true + } + } + }, + "@babel/runtime": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.4.tgz", + "integrity": "sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, "@dabh/diagnostics": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz", diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index bd98e24d88e2c..0f0b58c305473 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -60,6 +60,7 @@ "lodash": "^4.17.19", "memize": "^1.1.0", "react-autosize-textarea": "^7.1.0", + "react-merge-refs": "^1.0.0", "react-spring": "^8.0.19", "reakit": "1.1.0", "redux-multi": "^0.1.12", diff --git a/packages/block-editor/src/components/block-edit/edit.js b/packages/block-editor/src/components/block-edit/edit.js index 0746699eb145d..9b1907c4cfb2b 100644 --- a/packages/block-editor/src/components/block-edit/edit.js +++ b/packages/block-editor/src/components/block-edit/edit.js @@ -7,13 +7,13 @@ import { pick } from 'lodash'; /** * WordPress dependencies */ -import { withFilters } from '@wordpress/components'; +import { withFilters, Popover } from '@wordpress/components'; import { getBlockDefaultClassName, hasBlockSupport, getBlockType, } from '@wordpress/blocks'; -import { useContext, useMemo } from '@wordpress/element'; +import { useContext, useMemo, useState } from '@wordpress/element'; /** * Internal dependencies @@ -30,6 +30,31 @@ import BlockContext from '../block-context'; */ const DEFAULT_BLOCK_CONTEXT = {}; +function IframeCompat( { children } ) { + const [ ref, setRef ] = useState(); + const [ height, setHeight ] = useState(); + + return ( +
+ { ref && ( + + { children } + + ) } +
+ ); +} + export const Edit = ( props ) => { const { attributes = {}, name } = props; const blockType = getBlockType( name ); @@ -50,23 +75,40 @@ export const Edit = ( props ) => { // with which a block is displayed. If `blockType` is valid, assign // them preferentially as the render value for the block. const Component = blockType.edit || blockType.save; + let component; if ( blockType.apiVersion > 1 || hasBlockSupport( blockType, 'lightBlockWrapper', false ) ) { - return ; + component = ; + } else { + // Generate a class name for the block's editable form + const generatedClassName = hasBlockSupport( + blockType, + 'className', + true + ) + ? getBlockDefaultClassName( name ) + : null; + const className = classnames( + generatedClassName, + attributes.className + ); + component = ( + + ); } - // Generate a class name for the block's editable form - const generatedClassName = hasBlockSupport( blockType, 'className', true ) - ? getBlockDefaultClassName( name ) - : null; - const className = classnames( generatedClassName, attributes.className ); + if ( ! hasBlockSupport( blockType, 'iframe', true ) ) { + component = { component }; + } - return ( - - ); + return component; }; export default withFilters( 'editor.BlockEdit' )( Edit ); diff --git a/packages/block-editor/src/components/block-list/block-popover.js b/packages/block-editor/src/components/block-list/block-popover.js index 5bf1e5a12164d..819765d7913f4 100644 --- a/packages/block-editor/src/components/block-list/block-popover.js +++ b/packages/block-editor/src/components/block-list/block-popover.js @@ -167,7 +167,13 @@ function BlockPopover( { : 'top right left'; const stickyBoundaryElement = showEmptyBlockSideInserter ? undefined - : getScrollContainer( node ) || ownerDocument.body; + : // The sticky boundary element should be the boundary at which the + // the block toolbar becomes sticky when the block scolls out of view. + // In case of an iframe, this should be the iframe boundary, otherwise + // the scroll container. + ownerDocument.defaultView.frameElement || + getScrollContainer( node ) || + ownerDocument.body; return ( { + try { + // May fail for external styles. + // eslint-disable-next-line no-unused-expressions + styleSheet.cssRules; + } catch ( e ) { + return; + } + + const { ownerNode, cssRules } = styleSheet; + + if ( ! cssRules ) { + return; + } + + const isMatch = Array.from( cssRules ).find( + ( { selectorText } ) => + selectorText && + ( selectorText.includes( `.${ BODY_CLASS_NAME }` ) || + selectorText.includes( `.${ BLOCK_PREFIX }` ) ) + ); + + if ( isMatch && ! doc.getElementById( ownerNode.id ) ) { + doc.head.appendChild( ownerNode.cloneNode( true ) ); + } + } ); +} + +/** + * Bubbles some event types (keydown, keypress, and dragover) to parent document + * document to ensure that the keyboard shortcuts and drag and drop work. + * + * Ideally, we should remove event bubbling in the future. Keyboard shortcuts + * should be context dependent, e.g. actions on blocks like Cmd+A should not + * work globally outside the block editor. + * + * @param {Document} doc Document to attach listeners to. + */ +function bubbleEvents( doc ) { + const { defaultView } = doc; + const { frameElement } = defaultView; + + function bubbleEvent( event ) { + const prototype = Object.getPrototypeOf( event ); + const constructorName = prototype.constructor.name; + const Constructor = window[ constructorName ]; + + const init = {}; + + for ( const key in event ) { + init[ key ] = event[ key ]; + } + + if ( event instanceof defaultView.MouseEvent ) { + const rect = frameElement.getBoundingClientRect(); + init.clientX += rect.left; + init.clientY += rect.top; + } + + const newEvent = new Constructor( event.type, init ); + const cancelled = ! frameElement.dispatchEvent( newEvent ); + + if ( cancelled ) { + event.preventDefault(); + } + } + + const eventTypes = [ 'keydown', 'keypress', 'dragover' ]; + + for ( const name of eventTypes ) { + doc.addEventListener( name, bubbleEvent ); + } +} + +/** + * Sets the document direction. + * + * Sets the `editor-styles-wrapper` class name on the body. + * + * Copies the `admin-color-*` class name to the body so that the admin color + * scheme applies to components in the iframe. + * + * @param {Document} doc Document to add class name to. + */ +function setBodyClassName( doc ) { + doc.dir = document.dir; + doc.body.className = BODY_CLASS_NAME; + + for ( const name of document.body.classList ) { + if ( name.startsWith( 'admin-color-' ) ) { + doc.body.classList.add( name ); + } + } +} + +/** + * Sets the document head and default styles. + * + * @param {Document} doc Document to set the head for. + * @param {string} head HTML to set as the head. + */ +function setHead( doc, head ) { + doc.head.innerHTML = + // Body margin must be overridable by themes. + '' + head; +} + +function Iframe( { contentRef, children, head, ...props }, ref ) { + const [ iframeDocument, setIframeDocument ] = useState(); + + const setRef = useCallback( ( node ) => { + if ( ! node ) { + return; + } + + function setDocumentIfReady() { + const { contentDocument } = node; + const { readyState } = contentDocument; + + if ( readyState !== 'interactive' && readyState !== 'complete' ) { + return false; + } + + setIframeDocument( contentDocument ); + setHead( contentDocument, head ); + setBodyClassName( contentDocument ); + styleSheetsCompat( contentDocument ); + bubbleEvents( contentDocument ); + setBodyClassName( contentDocument ); + + if ( contentRef ) { + contentRef.current = contentDocument.body; + } + + return true; + } + + if ( setDocumentIfReady() ) { + return; + } + + // Document is not immediately loaded in Firefox. + node.addEventListener( 'load', () => { + setDocumentIfReady(); + } ); + }, [] ); + + return ( + + ); +} + +export default forwardRef( Iframe ); diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js index 3e845204bed82..0949671bc525b 100644 --- a/packages/block-editor/src/components/index.js +++ b/packages/block-editor/src/components/index.js @@ -108,6 +108,7 @@ export { default as NavigableToolbar } from './navigable-toolbar'; export { default as ObserveTyping, useTypingObserver as __unstableUseTypingObserver, + useMouseMoveTypingReset as __unstableUseMouseMoveTypingReset, } from './observe-typing'; export { default as PreserveScrollInReorder } from './preserve-scroll-in-reorder'; export { default as SkipToSelectedBlock } from './skip-to-selected-block'; @@ -118,6 +119,7 @@ export { export { default as Warning } from './warning'; export { default as WritingFlow } from './writing-flow'; export { useCanvasClickRedirect as __unstableUseCanvasClickRedirect } from './use-canvas-click-redirect'; +export { default as __unstableIframe } from './iframe'; /* * State Related Components diff --git a/packages/block-editor/src/components/keyboard-shortcuts/index.js b/packages/block-editor/src/components/keyboard-shortcuts/index.js index d13ea908c9cda..95bba1d130f48 100644 --- a/packages/block-editor/src/components/keyboard-shortcuts/index.js +++ b/packages/block-editor/src/components/keyboard-shortcuts/index.js @@ -12,6 +12,7 @@ import { store as keyboardShortcutsStore, } from '@wordpress/keyboard-shortcuts'; import { __ } from '@wordpress/i18n'; +import { documentHasSelection } from '@wordpress/dom'; function KeyboardShortcuts() { // Shortcuts Logic @@ -141,6 +142,14 @@ function KeyboardShortcuts() { 'core/block-editor/select-all', useCallback( ( event ) => { + const { ownerDocument, contentDocument } = event.target; + + if ( + documentHasSelection( contentDocument || ownerDocument ) + ) { + return; + } + event.preventDefault(); multiSelect( first( rootBlocksClientIds ), diff --git a/packages/block-editor/src/components/multi-select-scroll-into-view/index.js b/packages/block-editor/src/components/multi-select-scroll-into-view/index.js index fca97d6621f83..e1e33620c57d6 100644 --- a/packages/block-editor/src/components/multi-select-scroll-into-view/index.js +++ b/packages/block-editor/src/components/multi-select-scroll-into-view/index.js @@ -8,7 +8,6 @@ import scrollIntoView from 'dom-scroll-into-view'; */ import { useEffect, useRef } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; -import { getScrollContainer } from '@wordpress/dom'; /** * Internal dependencies @@ -42,21 +41,14 @@ export function useScrollMultiSelectionIntoView( ref ) { } const { ownerDocument } = ref.current; + const { defaultView } = ownerDocument; const extentNode = getBlockDOMNode( selectionEnd, ownerDocument ); if ( ! extentNode ) { return; } - const scrollContainer = getScrollContainer( extentNode ); - - // If there's no scroll container, it follows that there's no scrollbar - // and thus there's no need to try to scroll into view. - if ( ! scrollContainer ) { - return; - } - - scrollIntoView( extentNode, scrollContainer, { + scrollIntoView( extentNode, defaultView, { onlyScrollIfNeeded: true, } ); }, [ selectionEnd ] ); diff --git a/packages/block-editor/src/components/observe-typing/index.js b/packages/block-editor/src/components/observe-typing/index.js index e33628c92b374..3476d62c9692b 100644 --- a/packages/block-editor/src/components/observe-typing/index.js +++ b/packages/block-editor/src/components/observe-typing/index.js @@ -15,6 +15,8 @@ import { TAB, } from '@wordpress/keycodes'; +/** @typedef {import('@wordpress/element').RefObject} RefObject */ + /** * Set of key codes upon which typing is to be initiated on a keydown event. * @@ -43,12 +45,77 @@ function isKeyDownEligibleForStartTyping( event ) { return ! shiftKey && KEY_DOWN_ELIGIBLE_KEY_CODES.has( keyCode ); } +/** + * Removes the `isTyping` flag when the mouse moves in the document of the given + * element. + * + * @param {RefObject} ref React ref containing an element. + */ +export function useMouseMoveTypingReset( ref ) { + const isTyping = useSelect( ( select ) => + select( 'core/block-editor' ).isTyping() + ); + const { stopTyping } = useDispatch( 'core/block-editor' ); + + useEffect( () => { + if ( ! isTyping ) { + return; + } + + const element = ref.current; + const { ownerDocument } = element; + let lastClientX; + let lastClientY; + + /** + * On mouse move, unset typing flag if user has moved cursor. + * + * @param {MouseEvent} event Mousemove event. + */ + function stopTypingOnMouseMove( event ) { + const { clientX, clientY } = event; + + // We need to check that the mouse really moved because Safari + // triggers mousemove events when shift or ctrl are pressed. + if ( + lastClientX && + lastClientY && + ( lastClientX !== clientX || lastClientY !== clientY ) + ) { + stopTyping(); + } + + lastClientX = clientX; + lastClientY = clientY; + } + + ownerDocument.addEventListener( 'mousemove', stopTypingOnMouseMove ); + + return () => { + ownerDocument.removeEventListener( + 'mousemove', + stopTypingOnMouseMove + ); + }; + }, [ isTyping, stopTyping ] ); +} + +/** + * Sets and removes the `isTyping` flag based on user actions: + * + * - Sets the flag if the user types within the given element. + * - Removes the flag when the user selects some text, focusses a non-text + * field, presses ESC or TAB, or moves the mouse in the document. + * + * @param {RefObject} ref React ref containing an element. + */ export function useTypingObserver( ref ) { const isTyping = useSelect( ( select ) => select( 'core/block-editor' ).isTyping() ); const { startTyping, stopTyping } = useDispatch( 'core/block-editor' ); + useMouseMoveTypingReset( ref ); useEffect( () => { const element = ref.current; const { ownerDocument } = element; @@ -108,41 +175,12 @@ export function useTypingObserver( ref ) { } } - let lastClientX; - let lastClientY; - - /** - * On mouse move, unset typing flag if user has moved cursor. - * - * @param {MouseEvent} event Mousemove event. - */ - function stopTypingOnMouseMove( event ) { - const { clientX, clientY } = event; - - // We need to check that the mouse really moved because Safari - // triggers mousemove events when shift or ctrl are pressed. - if ( - lastClientX && - lastClientY && - ( lastClientX !== clientX || lastClientY !== clientY ) - ) { - stopTyping(); - } - - lastClientX = clientX; - lastClientY = clientY; - } - element.addEventListener( 'focus', stopTypingOnNonTextField ); element.addEventListener( 'keydown', stopTypingOnEscapeKey ); ownerDocument.addEventListener( 'selectionchange', stopTypingOnSelectionUncollapse ); - ownerDocument.addEventListener( - 'mousemove', - stopTypingOnMouseMove - ); return () => { defaultView.clearTimeout( timerId ); @@ -155,10 +193,6 @@ export function useTypingObserver( ref ) { 'selectionchange', stopTypingOnSelectionUncollapse ); - ownerDocument.removeEventListener( - 'mousemove', - stopTypingOnMouseMove - ); }; } diff --git a/packages/block-editor/src/components/typewriter/index.js b/packages/block-editor/src/components/typewriter/index.js index 522509f8e6756..d109cae97d65e 100644 --- a/packages/block-editor/src/components/typewriter/index.js +++ b/packages/block-editor/src/components/typewriter/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { useEffect, useRef } from '@wordpress/element'; -import { computeCaretRect, getScrollContainer } from '@wordpress/dom'; +import { computeCaretRect } from '@wordpress/dom'; import { useSelect } from '@wordpress/data'; import { UP, DOWN, LEFT, RIGHT } from '@wordpress/keycodes'; @@ -69,16 +69,16 @@ export function useTypewriter( ref ) { return; } - // If for some reason there is no position set to be scrolled to, let - // this be the position to be scrolled to in the future. + // If for some reason there is no position set to be scrolled to, + // let this be the position to be scrolled to in the future. if ( ! caretRect ) { caretRect = currentCaretRect; return; } - // Even though enabling the typewriter effect for arrow keys results in - // a pleasant experience, it may not be the case for everyone, so, for - // now, let's disable it. + // Even though enabling the typewriter effect for arrow keys results + // in a pleasant experience, it may not be the case for everyone, + // so, for now, let's disable it. if ( arrowKeyCodes.has( keyCode ) ) { // Reset the caret position to maintain. caretRect = currentCaretRect; @@ -91,31 +91,16 @@ export function useTypewriter( ref ) { return; } - const scrollContainer = getScrollContainer( ref.current ); + const { scrollY, innerHeight } = defaultView; + const { top, height } = caretRect; + const relativeScrollPosition = top / innerHeight; - // The page must be scrollable. - if ( ! scrollContainer ) { - return; - } - - const windowScroll = scrollContainer === ownerDocument.body; - const scrollY = windowScroll - ? defaultView.scrollY - : scrollContainer.scrollTop; - const scrollContainerY = windowScroll - ? 0 - : scrollContainer.getBoundingClientRect().top; - const relativeScrollPosition = windowScroll - ? caretRect.top / defaultView.innerHeight - : ( caretRect.top - scrollContainerY ) / - ( defaultView.innerHeight - scrollContainerY ); - - // If the scroll position is at the start, the active editable element - // is the last one, and the caret is positioned within the initial - // trigger percentage of the page, do not scroll the page. - // The typewriter effect should not kick in until an empty page has been - // filled with the initial trigger percentage or the user scrolls - // intentionally down. + // If the scroll position is at the start, the active editable + // element is the last one, and the caret is positioned within the + // initial trigger percentage of the page, do not scroll the page. + // The typewriter effect should not kick in until an empty page has + // been filled with the initial trigger percentage or the user + // scrolls intentionally down. if ( scrollY === 0 && relativeScrollPosition < initialTriggerPercentage && @@ -126,29 +111,20 @@ export function useTypewriter( ref ) { return; } - const scrollContainerHeight = windowScroll - ? defaultView.innerHeight - : scrollContainer.clientHeight; - // Abort if the target scroll position would scroll the caret out of // view. if ( // The caret is under the lower fold. - caretRect.top + caretRect.height > - scrollContainerY + scrollContainerHeight || + top + height > innerHeight || // The caret is above the upper fold. - caretRect.top < scrollContainerY + top < 0 ) { // Reset the caret position to maintain. caretRect = currentCaretRect; return; } - if ( windowScroll ) { - defaultView.scrollBy( 0, diff ); - } else { - scrollContainer.scrollTop += diff; - } + defaultView.scrollBy( 0, diff ); } /** @@ -163,8 +139,9 @@ export function useTypewriter( ref ) { } /** - * Resets the scroll position to be maintained during a `selectionchange` - * event. Also removes the listener, so it acts as a one-time listener. + * Resets the scroll position to be maintained during a + * `selectionchange` event. Also removes the listener, so it acts as a + * one-time listener. */ function computeCaretRectOnSelectionChange() { ownerDocument.removeEventListener( diff --git a/packages/block-editor/src/components/use-resize-canvas/index.js b/packages/block-editor/src/components/use-resize-canvas/index.js index d5134d634aabd..bd55ab5d6b3b2 100644 --- a/packages/block-editor/src/components/use-resize-canvas/index.js +++ b/packages/block-editor/src/components/use-resize-canvas/index.js @@ -11,11 +11,15 @@ import { default as useSimulatedMediaQuery } from '../../components/use-simulate /** * Function to resize the editor window. * - * @param {string} deviceType Used for determining the size of the container (e.g. Desktop, Tablet, Mobile) + * @param {string} deviceType Used for determining the size of the container (e.g. Desktop, Tablet, Mobile) + * @param {boolean} __unstableDisableSimulation Whether to disable media query simulation. * * @return {Object} Inline styles to be added to resizable container. */ -export default function useResizeCanvas( deviceType ) { +export default function useResizeCanvas( + deviceType, + __unstableDisableSimulation +) { const [ actualWidth, updateActualWidth ] = useState( window.innerWidth ); useEffect( () => { @@ -69,10 +73,11 @@ export default function useResizeCanvas( deviceType ) { } }; - useSimulatedMediaQuery( - 'resizable-editor-section', - getCanvasWidth( deviceType ) - ); + const width = __unstableDisableSimulation + ? null + : getCanvasWidth( deviceType ); + + useSimulatedMediaQuery( 'resizable-editor-section', width ); return contentInlineStyles( deviceType ); } diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss index 1ea21ed457452..e4201596a11f1 100644 --- a/packages/block-editor/src/style.scss +++ b/packages/block-editor/src/style.scss @@ -64,3 +64,5 @@ @import "./components/block-toolbar/style.scss"; @import "./components/inserter/style.scss"; @import "./components/preview-options/style.scss"; + +@include wordpress-admin-schemes(); diff --git a/packages/block-library/src/block/edit-panel/editor.scss b/packages/block-library/src/block/edit-panel/editor.scss index 702f72e4dbace..3272b30514731 100644 --- a/packages/block-library/src/block/edit-panel/editor.scss +++ b/packages/block-library/src/block/edit-panel/editor.scss @@ -34,7 +34,7 @@ flex-shrink: 0; } - @include break-large() { + @include break-medium() { flex-wrap: nowrap; .reusable-block-edit-panel__title { diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 81037be60ee63..87d9f1c147b91 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { useCallback, useState } from '@wordpress/element'; +import { useCallback, useRef, useState } from '@wordpress/element'; import { Button, ButtonGroup, @@ -107,6 +107,7 @@ function URLPicker( { setAttributes, opensInNewTab, onToggleOpenInNewTab, + buttonRef, } ) { const [ isURLPickerOpen, setIsURLPickerOpen ] = useState( false ); const urlIsSet = !! url; @@ -126,7 +127,10 @@ function URLPicker( { const linkControl = ( isURLPickerOpen || urlIsSetandSelected ) && ( setIsURLPickerOpen( false ) } + onClose={ () => { + buttonRef.current.focus(); + setIsURLPickerOpen( false ); + } } > @@ -241,6 +246,7 @@ function ButtonEdit( props ) { } ) } > setIsLinkOpen( false ) } + onClose={ () => { + ref.current.focus(); + setIsLinkOpen( false ); + } } > { @@ -239,6 +290,12 @@ const Popover = ( { const [ containerResizeListener, contentSize ] = useResizeObserver(); noArrow = isExpanded || noArrow; + useEffect( () => { + if ( __unstabelOnHeightChange ) { + __unstabelOnHeightChange( contentSize.height ); + } + }, [ contentSize.height ] ); + useLayoutEffect( () => { if ( isExpanded ) { setClass( containerRef.current, 'is-without-arrow', noArrow ); @@ -308,6 +365,7 @@ const Popover = ( { yAxis, contentHeight, contentWidth, + popoverWidth, } = computePopoverPosition( anchor, usedContentSize, @@ -316,7 +374,8 @@ const Popover = ( { containerRef.current, relativeOffsetTop, boundaryElement, - __unstableForcePosition + __unstableForcePosition, + __unstableSpanOverAnchor ); if ( @@ -345,6 +404,11 @@ const Popover = ( { 'maxWidth', typeof contentWidth === 'number' ? contentWidth + 'px' : '' ); + setStyle( + contentRef.current, + 'width', + typeof popoverWidth === 'number' ? popoverWidth + 'px' : '' + ); // Compute the animation position const yAxisMapping = { @@ -363,6 +427,9 @@ const Popover = ( { refresh(); + const { ownerDocument } = containerRef.current; + const { defaultView } = ownerDocument; + /* * There are sometimes we need to reposition or resize the popover that * are not handled by the resize/scroll window events (i.e. CSS changes @@ -370,35 +437,60 @@ const Popover = ( { * * For these situations, we refresh the popover every 0.5s */ - const intervalHandle = window.setInterval( refresh, 500 ); + const intervalHandle = defaultView.setInterval( refresh, 500 ); let rafId; const refreshOnAnimationFrame = () => { - window.cancelAnimationFrame( rafId ); - rafId = window.requestAnimationFrame( refresh ); + defaultView.cancelAnimationFrame( rafId ); + rafId = defaultView.requestAnimationFrame( refresh ); }; // Sometimes a click trigger a layout change that affects the popover // position. This is an opportunity to immediately refresh rather than // at the interval. - window.addEventListener( 'click', refreshOnAnimationFrame ); - window.addEventListener( 'resize', refresh ); - window.addEventListener( 'scroll', refresh, true ); + defaultView.addEventListener( 'click', refreshOnAnimationFrame ); + defaultView.addEventListener( 'resize', refresh ); + defaultView.addEventListener( 'scroll', refresh, true ); + + const anchorDocument = getAnchorDocument( anchorRef ); + + // If the anchor is within an iframe, the popover position also needs + // to refrest when the iframe content is scrolled or resized. + if ( anchorDocument && anchorDocument !== ownerDocument ) { + anchorDocument.defaultView.addEventListener( 'resize', refresh ); + anchorDocument.defaultView.addEventListener( + 'scroll', + refresh, + true + ); + } let observer; if ( __unstableObserveElement ) { - observer = new window.MutationObserver( refresh ); + observer = new defaultView.MutationObserver( refresh ); observer.observe( __unstableObserveElement, { attributes: true } ); } return () => { - window.clearInterval( intervalHandle ); - window.removeEventListener( 'resize', refresh ); - window.removeEventListener( 'scroll', refresh, true ); - window.removeEventListener( 'click', refreshOnAnimationFrame ); - window.cancelAnimationFrame( rafId ); + defaultView.clearInterval( intervalHandle ); + defaultView.removeEventListener( 'resize', refresh ); + defaultView.removeEventListener( 'scroll', refresh, true ); + defaultView.removeEventListener( 'click', refreshOnAnimationFrame ); + defaultView.cancelAnimationFrame( rafId ); + + if ( anchorDocument && anchorDocument !== ownerDocument ) { + anchorDocument.defaultView.removeEventListener( + 'resize', + refresh + ); + anchorDocument.defaultView.removeEventListener( + 'scroll', + refresh, + true + ); + } if ( observer ) { observer.disconnect(); @@ -509,6 +601,7 @@ const Popover = ( { className, animateClassName, { + 'is-spanned-over': __unstableSpanOverAnchor, 'is-expanded': isExpanded, 'is-without-arrow': noArrow, 'is-alternate': isAlternate, @@ -533,7 +626,9 @@ const Popover = ( { ) }
diff --git a/packages/components/src/popover/style.scss b/packages/components/src/popover/style.scss index 44446118161c6..c324c9e834137 100644 --- a/packages/components/src/popover/style.scss +++ b/packages/components/src/popover/style.scss @@ -12,6 +12,7 @@ $arrow-size: 8px; // position depends on the size of the popover. opacity: 0; + &.is-spanned-over, &.is-expanded, &[data-x-axis][data-y-axis] { opacity: 1; @@ -161,19 +162,26 @@ $arrow-size: 8px; &.is-from-right:not(.is-from-top):not(.is-from-bottom) { margin-right: $grid-unit-15; } + + &.is-spanned-over .wp-block { + margin: 0; + } } .components-popover__content { height: 100%; - background: $white; - border: $border-width solid $gray-400; - box-shadow: $shadow-popover; - border-radius: $radius-block-ui; - - // Alternate treatment for popovers that put them at elevation zero with high contrast. - .is-alternate & { - border: $border-width solid $gray-900; - box-shadow: none; + + &:not(.is-transparent) { + background: $white; + border: $border-width solid $gray-400; + box-shadow: $shadow-popover; + border-radius: $radius-block-ui; + + // Alternate treatment for popovers that put them at elevation zero with high contrast. + .is-alternate & { + border: $border-width solid $gray-900; + box-shadow: none; + } } .components-popover & { diff --git a/packages/components/src/popover/utils.js b/packages/components/src/popover/utils.js index 57c697322e821..5e5fbfa798d3e 100644 --- a/packages/components/src/popover/utils.js +++ b/packages/components/src/popover/utils.js @@ -264,6 +264,7 @@ export function computePopoverYAxisPosition( * relative positioned parent container. * @param {Element} boundaryElement Boundary element. * @param {boolean} forcePosition Don't adjust position based on anchor. + * @param {boolean} __unstableSpanOverAnchor * * @return {Object} Popover position and constraints. */ @@ -275,8 +276,17 @@ export function computePopoverPosition( anchorRef, relativeOffsetTop, boundaryElement, - forcePosition + forcePosition, + __unstableSpanOverAnchor ) { + if ( __unstableSpanOverAnchor ) { + return { + popoverWidth: anchorRect.width, + popoverTop: anchorRect.top, + popoverLeft: anchorRect.left, + }; + } + const [ yAxis, xAxis = 'center', corner ] = position.split( ' ' ); const yAxisPosition = computePopoverYAxisPosition( diff --git a/packages/e2e-test-utils/README.md b/packages/e2e-test-utils/README.md index 29e2074224857..5dacfd2c2231e 100644 --- a/packages/e2e-test-utils/README.md +++ b/packages/e2e-test-utils/README.md @@ -40,6 +40,10 @@ _Returns_ - `Promise`: Boolean which represents the state of prepublish checks. +# **canvas** + +Gets the editor canvas frame. + # **changeSiteTimezone** Visits general settings page and changes the timezone to the given value. @@ -76,6 +80,7 @@ Clicks a button based on the text on the button. _Parameters_ - _buttonText_ `string`: The text that appears on the button to click. +- _frame_ `Object`: # **clickMenuItem** diff --git a/packages/e2e-test-utils/src/canvas.js b/packages/e2e-test-utils/src/canvas.js new file mode 100644 index 0000000000000..6b1719513129d --- /dev/null +++ b/packages/e2e-test-utils/src/canvas.js @@ -0,0 +1,6 @@ +/** + * Gets the editor canvas frame. + */ +export function canvas() { + return page.frames().find( ( f ) => f.name() === 'editor-canvas' ); +} diff --git a/packages/e2e-test-utils/src/click-block-appender.js b/packages/e2e-test-utils/src/click-block-appender.js index 26e8b9162dcb4..a8080d63e6ebd 100644 --- a/packages/e2e-test-utils/src/click-block-appender.js +++ b/packages/e2e-test-utils/src/click-block-appender.js @@ -1,8 +1,13 @@ +/** + * Internal dependencies + */ +import { canvas } from './canvas'; + /** * Clicks the default block appender. */ export async function clickBlockAppender() { - const appender = await page.waitForSelector( + const appender = await canvas().waitForSelector( '.block-editor-default-block-appender__content' ); await appender.click(); diff --git a/packages/e2e-test-utils/src/click-block-toolbar-button.js b/packages/e2e-test-utils/src/click-block-toolbar-button.js index 3aa431bfe29ff..cb5cd1ed1b80a 100644 --- a/packages/e2e-test-utils/src/click-block-toolbar-button.js +++ b/packages/e2e-test-utils/src/click-block-toolbar-button.js @@ -26,6 +26,12 @@ export async function clickBlockToolbarButton( label, type = 'ariaLabel' ) { ); } + if ( type === 'label' ) { + button = await page.waitForXPath( + `//*[@class='${ BLOCK_TOOLBAR_SELECTOR }']//label[contains(text(), '${ label }')]` + ); + } + await button.evaluate( ( element ) => element.scrollIntoView() ); await button.click(); } diff --git a/packages/e2e-test-utils/src/click-button.js b/packages/e2e-test-utils/src/click-button.js index 634319101e5d0..ff7d8980b9dd6 100644 --- a/packages/e2e-test-utils/src/click-button.js +++ b/packages/e2e-test-utils/src/click-button.js @@ -2,10 +2,12 @@ * Clicks a button based on the text on the button. * * @param {string} buttonText The text that appears on the button to click. + * @param {Object} frame */ -export async function clickButton( buttonText ) { - const button = await page.waitForXPath( +export async function clickButton( buttonText, frame = page ) { + const button = await frame.waitForXPath( `//button[contains(text(), '${ buttonText }')]` ); + await button.evaluate( ( element ) => element.scrollIntoView() ); await button.click(); } diff --git a/packages/e2e-test-utils/src/drag-and-resize.js b/packages/e2e-test-utils/src/drag-and-resize.js index f3c45eec479ec..ac4a21711877a 100644 --- a/packages/e2e-test-utils/src/drag-and-resize.js +++ b/packages/e2e-test-utils/src/drag-and-resize.js @@ -1,3 +1,8 @@ +/** + * Internal dependencies + */ +import { canvas } from './canvas'; + /** * Clicks an element, drags a particular distance and releases the mouse button. * @@ -16,8 +21,20 @@ export async function dragAndResize( element, delta ) { height: elementHeight, } = await element.boundingBox(); - const originX = elementX + elementWidth / 2; - const originY = elementY + elementHeight / 2; + const windowRect = await canvas().evaluate( () => { + if ( window.frameElement ) { + return { x: 0, y: 0 }; + } + + const winRect = window.frameElement.getBoundingClientRect(); + return { + x: winRect.x, + y: winRect.y, + }; + } ); + + const originX = windowRect.x + elementX + elementWidth / 2; + const originY = windowRect.y + elementY + elementHeight / 2; await page.mouse.move( originX, originY ); await page.mouse.down(); diff --git a/packages/e2e-test-utils/src/index.js b/packages/e2e-test-utils/src/index.js index c70f7fd15f69c..06899b154c983 100644 --- a/packages/e2e-test-utils/src/index.js +++ b/packages/e2e-test-utils/src/index.js @@ -2,6 +2,7 @@ export { activatePlugin } from './activate-plugin'; export { activateTheme } from './activate-theme'; export { arePrePublishChecksEnabled } from './are-pre-publish-checks-enabled'; export { changeSiteTimezone } from './change-site-timezone'; +export { canvas } from './canvas'; export { clearLocalStorage } from './clear-local-storage'; export { clickBlockAppender } from './click-block-appender'; export { clickBlockToolbarButton } from './click-block-toolbar-button'; diff --git a/packages/e2e-test-utils/src/inserter.js b/packages/e2e-test-utils/src/inserter.js index c3d31299f3e42..e6a108ea92358 100644 --- a/packages/e2e-test-utils/src/inserter.js +++ b/packages/e2e-test-utils/src/inserter.js @@ -2,6 +2,7 @@ * Internal dependencies */ import { pressKeyWithModifier } from './press-key-with-modifier'; +import { canvas } from './canvas'; // This selector is written to support the current and old inserter markup // because the performance tests need to be able to run across versions. @@ -57,12 +58,11 @@ export async function toggleGlobalBlockInserter() { * Retrieves the document container by css class and checks to make sure the document's active element is within it */ async function waitForInserterCloseAndContentFocus() { - await page.waitForFunction( () => - document.body - .querySelector( - '.interface-interface-skeleton__content .block-editor-block-list__layout' - ) - .contains( document.activeElement ) + await canvas().waitForFunction( + () => + document.activeElement.closest( + '.block-editor-block-list__layout' + ) !== null ); } @@ -171,7 +171,7 @@ export async function insertReusableBlock( searchTerm ) { // We should wait until the inserter closes and the focus moves to the content. await waitForInserterCloseAndContentFocus(); // We should wait until the block is loaded - await page.waitForXPath( + await canvas().waitForXPath( '//*[@class="block-library-block__reusable-block-container"]' ); } diff --git a/packages/e2e-test-utils/src/is-in-default-block.js b/packages/e2e-test-utils/src/is-in-default-block.js index 21d9a19bf22dd..a2ea80230f3b1 100644 --- a/packages/e2e-test-utils/src/is-in-default-block.js +++ b/packages/e2e-test-utils/src/is-in-default-block.js @@ -1,26 +1,30 @@ +/** + * Internal dependencies + */ +import { canvas } from './canvas'; + /** * Checks if the block that is focused is the default block. * * @return {Promise} Promise resolving with a boolean indicating if the focused block is the default block. */ -export function isInDefaultBlock() { - return page.evaluate( () => { - const activeElement = document.activeElement; +export async function isInDefaultBlock() { + const defaultBlockName = await page.evaluate( () => + window.wp.blocks.getDefaultBlockName() + ); + const activeBlockName = await canvas().evaluate( () => { + const { activeElement } = document; // activeElement may be null in that case we should return false if ( ! activeElement ) { return false; } - const closestElementWithDataTpe = activeElement.closest( + const closestElementWithDataType = activeElement.closest( '[data-type]' ); - if ( ! closestElementWithDataTpe ) { + if ( ! closestElementWithDataType ) { return false; } - const activeBlockName = closestElementWithDataTpe.getAttribute( - 'data-type' - ); - const defaultBlockName = window.wp.blocks.getDefaultBlockName(); - - return activeBlockName === defaultBlockName; + return closestElementWithDataType.getAttribute( 'data-type' ); } ); + return defaultBlockName === activeBlockName; } 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 b79f27c1d4a72..20dce3fabbe39 100644 --- a/packages/e2e-test-utils/src/press-key-with-modifier.js +++ b/packages/e2e-test-utils/src/press-key-with-modifier.js @@ -25,7 +25,24 @@ async function emulateSelectAll() { await page.evaluate( () => { const isMac = /Mac|iPod|iPhone|iPad/.test( window.navigator.platform ); - document.activeElement.dispatchEvent( + function getActiveElement( { activeElement } ) { + if ( activeElement.nodeName === 'IFRAME' ) { + return getActiveElement( activeElement.contentDocument ); + } + return activeElement; + } + + function getActiveDocument( doc ) { + const { activeElement } = doc; + + if ( activeElement.nodeName === 'IFRAME' ) { + return getActiveDocument( activeElement.contentDocument ); + } + + return doc; + } + + getActiveElement( document ).dispatchEvent( new KeyboardEvent( 'keydown', { bubbles: true, cancelable: true, @@ -58,14 +75,18 @@ async function emulateSelectAll() { } ); const wasPrevented = - ! document.activeElement.dispatchEvent( preventableEvent ) || + ! getActiveElement( document ).dispatchEvent( preventableEvent ) || preventableEvent.defaultPrevented; if ( ! wasPrevented ) { - document.execCommand( 'selectall', false, null ); + getActiveDocument( document ).execCommand( + 'selectall', + false, + null + ); } - document.activeElement.dispatchEvent( + getActiveElement( document ).dispatchEvent( new KeyboardEvent( 'keyup', { bubbles: true, cancelable: true, @@ -92,6 +113,18 @@ async function emulateSelectAll() { export async function setClipboardData( { plainText = '', html = '' } ) { await page.evaluate( ( _plainText, _html ) => { + function getActiveWindow( doc ) { + const { activeElement } = doc; + + if ( activeElement.nodeName === 'IFRAME' ) { + return getActiveWindow( activeElement.contentDocument ); + } + + return doc.defaultView; + } + + const window = getActiveWindow( document ); + window._clipboardData = new DataTransfer(); window._clipboardData.setData( 'text/plain', _plainText ); window._clipboardData.setData( 'text/html', _html ); @@ -103,6 +136,25 @@ export async function setClipboardData( { plainText = '', html = '' } ) { async function emulateClipboard( type ) { await page.evaluate( ( _type ) => { + function getActiveElement( { activeElement } ) { + if ( activeElement.nodeName === 'IFRAME' ) { + return getActiveElement( activeElement.contentDocument ); + } + return activeElement; + } + + function getActiveWindow( doc ) { + const { activeElement } = doc; + + if ( activeElement.nodeName === 'IFRAME' ) { + return getActiveWindow( activeElement.contentDocument ); + } + + return doc.defaultView; + } + + const window = getActiveWindow( document ); + if ( _type !== 'paste' ) { window._clipboardData = new DataTransfer(); @@ -123,7 +175,7 @@ async function emulateClipboard( type ) { window._clipboardData.setData( 'text/html', html ); } - document.activeElement.dispatchEvent( + getActiveElement( document ).dispatchEvent( new ClipboardEvent( _type, { bubbles: true, clipboardData: window._clipboardData, diff --git a/packages/e2e-test-utils/src/show-block-toolbar.js b/packages/e2e-test-utils/src/show-block-toolbar.js index f1ac720e028d4..3d91232f8800e 100644 --- a/packages/e2e-test-utils/src/show-block-toolbar.js +++ b/packages/e2e-test-utils/src/show-block-toolbar.js @@ -3,7 +3,11 @@ * Call this function to reveal it. */ export async function showBlockToolbar() { - // Move the mouse to disable the isTyping mode + // Move the mouse to disable the isTyping mode. We need at least three + // mousemove events for it to work across windows (iframe). With three + // moves, it's a guarantee that at least two will be in the same window. + // Two events are required for the flag to be unset. await page.mouse.move( 50, 50 ); + await page.mouse.move( 75, 75 ); await page.mouse.move( 100, 100 ); } diff --git a/packages/e2e-test-utils/src/transform-block-to.js b/packages/e2e-test-utils/src/transform-block-to.js index 4a6968c684904..f39839d32d5d3 100644 --- a/packages/e2e-test-utils/src/transform-block-to.js +++ b/packages/e2e-test-utils/src/transform-block-to.js @@ -2,6 +2,7 @@ * Internal dependencies */ import { showBlockToolbar } from './show-block-toolbar'; +import { canvas } from './canvas'; /** * Converts editor's block type. @@ -33,5 +34,7 @@ export async function transformBlockTo( name ) { // Wait for the transformed block to appear. const BLOCK_SELECTOR = '.block-editor-block-list__block'; const BLOCK_NAME_SELECTOR = `[data-title="${ name }"]`; - await page.waitForSelector( `${ BLOCK_SELECTOR }${ BLOCK_NAME_SELECTOR }` ); + await canvas().waitForSelector( + `${ BLOCK_SELECTOR }${ BLOCK_NAME_SELECTOR }` + ); } diff --git a/packages/e2e-tests/specs/editor/blocks/buttons.test.js b/packages/e2e-tests/specs/editor/blocks/buttons.test.js index 9253d29b1cbd4..dd736ddf49d28 100644 --- a/packages/e2e-tests/specs/editor/blocks/buttons.test.js +++ b/packages/e2e-tests/specs/editor/blocks/buttons.test.js @@ -6,6 +6,7 @@ import { getEditedPostContent, createNewPost, pressKeyWithModifier, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Buttons', () => { @@ -28,7 +29,7 @@ describe( 'Buttons', () => { () => !! document.activeElement.closest( '.block-editor-url-input' ) ); await page.keyboard.press( 'Escape' ); - await page.waitForFunction( + await canvas().waitForFunction( () => document.activeElement === document.querySelector( '.block-editor-rich-text__editable' ) diff --git a/packages/e2e-tests/specs/editor/blocks/classic.test.js b/packages/e2e-tests/specs/editor/blocks/classic.test.js index d48cd0b826784..e4dc4f461b35e 100644 --- a/packages/e2e-tests/specs/editor/blocks/classic.test.js +++ b/packages/e2e-tests/specs/editor/blocks/classic.test.js @@ -12,10 +12,10 @@ import { v4 as uuid } from 'uuid'; import { getEditedPostContent, createNewPost, - insertBlock, pressKeyWithModifier, clickBlockToolbarButton, saveDraft, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Classic', () => { @@ -24,7 +24,9 @@ describe( 'Classic', () => { } ); it( 'should be inserted', async () => { - await insertBlock( 'Classic' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( '/classic' ); + await page.keyboard.press( 'Enter' ); // Wait for TinyMCE to initialise. await page.waitForSelector( '.mce-content-body' ); // Ensure there is focus. @@ -37,7 +39,9 @@ describe( 'Classic', () => { } ); it( 'should insert media, convert to blocks, and undo in one step', async () => { - await insertBlock( 'Classic' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( '/classic' ); + await page.keyboard.press( 'Enter' ); // Wait for TinyMCE to initialise. await page.waitForSelector( '.mce-content-body' ); // Ensure there is focus. @@ -86,7 +90,7 @@ describe( 'Classic', () => { // Convert to blocks and verify it worked correctly. await clickBlockToolbarButton( 'Convert to blocks', 'content' ); - await page.waitForSelector( '.wp-block[data-type="core/gallery"]' ); + await canvas().waitForSelector( '.wp-block[data-type="core/gallery"]' ); expect( await getEditedPostContent() ).toMatch( /\\s*
<\\/figure>\\s*` + `\\s*
<\\/figure>\\s*` ); expect( await getEditedPostContent() ).toMatch( regex2 ); - await clickButton( 'Replace' ); + await clickBlockToolbarButton( 'Replace', 'content' ); const filename2 = await upload( - '.block-editor-media-replace-flow__options input[type="file"]' + '.block-editor-media-replace-flow__options input[type="file"]', + page ); await waitForImage( filename2 ); @@ -104,7 +107,7 @@ describe( 'Image', () => { ); expect( await getEditedPostContent() ).toMatch( regex3 ); - await page.click( '.wp-block-image img' ); + await canvas().click( '.wp-block-image img' ); await page.keyboard.press( 'Backspace' ); expect( await getEditedPostContent() ).toBe( '' ); @@ -120,7 +123,7 @@ describe( 'Image', () => { await page.keyboard.type( '2' ); expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await canvas().evaluate( () => document.activeElement.innerHTML ) ).toBe( '12' ); } ); @@ -133,7 +136,7 @@ describe( 'Image', () => { await page.keyboard.press( 'Enter' ); expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await canvas().evaluate( () => document.activeElement.innerHTML ) ).toBe( '1
2' ); } ); @@ -144,7 +147,7 @@ describe( 'Image', () => { // Confirm correct setup. expect( await getEditedPostContent() ).toMatchSnapshot(); - const image = await page.$( '[data-type="core/image"]' ); + const image = await canvas().$( '[data-type="core/image"]' ); await image.evaluate( () => { const input = document.createElement( 'input' ); @@ -186,7 +189,7 @@ describe( 'Image', () => { await waitForImage( filename ); // Assert that the image is initially unscaled and unedited. - const initialImage = await page.$( '.wp-block-image img' ); + const initialImage = await canvas().$( '.wp-block-image img' ); const initialImageSrc = await getSrc( initialImage ); const initialImageDataURL = await getDataURL( initialImage ); expect( initialImageDataURL ).toMatchSnapshot(); @@ -211,12 +214,12 @@ describe( 'Image', () => { await clickBlockToolbarButton( 'Apply', 'content' ); // Wait for the cropping tools to disappear. - await page.waitForSelector( + await canvas().waitForSelector( '.wp-block-image img:not( .reactEasyCrop_Image )' ); // Assert that the image is edited. - const updatedImage = await page.$( '.wp-block-image img' ); + const updatedImage = await canvas().$( '.wp-block-image img' ); const updatedImageSrc = await getSrc( updatedImage ); expect( initialImageSrc ).not.toEqual( updatedImageSrc ); const updatedImageDataURL = await getDataURL( updatedImage ); @@ -231,7 +234,7 @@ describe( 'Image', () => { await waitForImage( filename ); // Assert that the image is initially unscaled and unedited. - const initialImage = await page.$( '.wp-block-image img' ); + const initialImage = await canvas().$( '.wp-block-image img' ); const initialImageSrc = await getSrc( initialImage ); const initialImageDataURL = await getDataURL( initialImage ); expect( initialImageDataURL ).toMatchSnapshot(); @@ -248,12 +251,12 @@ describe( 'Image', () => { await clickBlockToolbarButton( 'Apply', 'content' ); // Wait for the cropping tools to disappear. - await page.waitForSelector( + await canvas().waitForSelector( '.wp-block-image img:not( .reactEasyCrop_Image )' ); // Assert that the image is edited. - const updatedImage = await page.$( '.wp-block-image img' ); + const updatedImage = await canvas().$( '.wp-block-image img' ); const updatedImageSrc = await getSrc( updatedImage ); expect( initialImageSrc ).not.toEqual( updatedImageSrc ); const updatedImageDataURL = await getDataURL( updatedImage ); @@ -268,22 +271,24 @@ describe( 'Image', () => { await waitForImage( filename ); // Assert that the image is initially unscaled and unedited. - const initialImage = await page.$( '.wp-block-image img' ); + const initialImage = await canvas().$( '.wp-block-image img' ); const initialImageDataURL = await getDataURL( initialImage ); expect( initialImageDataURL ).toMatchSnapshot(); // Double the image's size using the zoom input. await clickBlockToolbarButton( 'Crop' ); - await page.waitForSelector( '.wp-block-image img.reactEasyCrop_Image' ); + await canvas().waitForSelector( + '.wp-block-image img.reactEasyCrop_Image' + ); await clickBlockToolbarButton( 'Rotate' ); await clickBlockToolbarButton( 'Apply', 'content' ); - await page.waitForSelector( + await canvas().waitForSelector( '.wp-block-image img:not( .reactEasyCrop_Image )' ); // Assert that the image is edited. - const updatedImage = await page.$( '.wp-block-image img' ); + const updatedImage = await canvas().$( '.wp-block-image img' ); const updatedImageDataURL = await getDataURL( updatedImage ); expect( initialImageDataURL ).not.toEqual( updatedImageDataURL ); expect( updatedImageDataURL ).toMatchSnapshot(); diff --git a/packages/e2e-tests/specs/editor/blocks/list.test.js b/packages/e2e-tests/specs/editor/blocks/list.test.js index bba09376edfa6..015ab9b141e45 100644 --- a/packages/e2e-tests/specs/editor/blocks/list.test.js +++ b/packages/e2e-tests/specs/editor/blocks/list.test.js @@ -11,6 +11,7 @@ import { pressKeyWithModifier, insertBlock, showBlockToolbar, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'List', () => { @@ -148,7 +149,7 @@ describe( 'List', () => { await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); await page.keyboard.down( 'Shift' ); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.keyboard.up( 'Shift' ); await transformBlockTo( 'List' ); @@ -173,7 +174,7 @@ describe( 'List', () => { await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); await page.keyboard.down( 'Shift' ); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.keyboard.up( 'Shift' ); await transformBlockTo( 'List' ); diff --git a/packages/e2e-tests/specs/editor/blocks/quote.test.js b/packages/e2e-tests/specs/editor/blocks/quote.test.js index e185c9e3c7cd7..1457e7d7f1722 100644 --- a/packages/e2e-tests/specs/editor/blocks/quote.test.js +++ b/packages/e2e-tests/specs/editor/blocks/quote.test.js @@ -8,6 +8,7 @@ import { pressKeyTimes, transformBlockTo, insertBlock, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Quote', () => { @@ -64,7 +65,7 @@ describe( 'Quote', () => { await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); await page.keyboard.down( 'Shift' ); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.keyboard.up( 'Shift' ); await transformBlockTo( 'Quote' ); @@ -161,10 +162,10 @@ describe( 'Quote', () => { await page.keyboard.type( 'cite' ); await transformBlockTo( 'Heading' ); expect( await getEditedPostContent() ).toMatchSnapshot(); - await page.click( '[data-type="core/quote"]' ); + await canvas().click( '[data-type="core/quote"]' ); await transformBlockTo( 'Heading' ); expect( await getEditedPostContent() ).toMatchSnapshot(); - await page.click( '[data-type="core/quote"]' ); + await canvas().click( '[data-type="core/quote"]' ); await transformBlockTo( 'Heading' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); diff --git a/packages/e2e-tests/specs/editor/blocks/spacer.test.js b/packages/e2e-tests/specs/editor/blocks/spacer.test.js index 258fc59a6d1ee..650882cc6045c 100644 --- a/packages/e2e-tests/specs/editor/blocks/spacer.test.js +++ b/packages/e2e-tests/specs/editor/blocks/spacer.test.js @@ -5,7 +5,7 @@ import { clickBlockAppender, getEditedPostContent, createNewPost, - dragAndResize, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Spacer', () => { @@ -34,13 +34,32 @@ describe( 'Spacer', () => { ); await page.keyboard.press( 'Enter' ); - const resizableHandle = await page.$( - '.block-library-spacer__resize-container .components-resizable-box__handle' - ); - await dragAndResize( resizableHandle, { x: 0, y: 50 } ); + const [ coord1, coord2 ] = await canvas().evaluate( () => { + const element = document.querySelector( + '.block-library-spacer__resize-container .components-resizable-box__handle' + ); + const rect = element.getBoundingClientRect(); + const winRect = window.frameElement.getBoundingClientRect(); + return [ + { + x: winRect.x + rect.x + rect.width / 2, + y: winRect.y + rect.y + rect.height / 2, + }, + { + x: winRect.x + rect.x + rect.width / 2, + y: winRect.y + rect.y + rect.height / 2 + 50, + }, + ]; + } ); + + await page.mouse.move( coord1.x, coord1.y ); + await page.mouse.down(); + await page.mouse.move( coord2.x, coord2.y ); + await page.mouse.up(); + expect( await getEditedPostContent() ).toMatchSnapshot(); - const selectedSpacer = await page.$( + const selectedSpacer = await canvas().$( '[data-type="core/spacer"].is-selected' ); expect( selectedSpacer ).not.toBe( null ); diff --git a/packages/e2e-tests/specs/editor/blocks/table.test.js b/packages/e2e-tests/specs/editor/blocks/table.test.js index 1b8273159b2ba..c64bfee7005da 100644 --- a/packages/e2e-tests/specs/editor/blocks/table.test.js +++ b/packages/e2e-tests/specs/editor/blocks/table.test.js @@ -8,6 +8,7 @@ import { getEditedPostContent, insertBlock, openDocumentSettingsSidebar, + canvas, } from '@wordpress/e2e-test-utils'; const createButtonLabel = 'Create Table'; @@ -31,14 +32,14 @@ describe( 'Table', () => { await insertBlock( 'Table' ); // Check for existence of the column count field. - const columnCountLabel = await page.$x( + const columnCountLabel = await canvas().$x( "//figure[@data-type='core/table']//label[text()='Column count']" ); expect( columnCountLabel ).toHaveLength( 1 ); // Modify the column count. await columnCountLabel[ 0 ].click(); - const currentColumnCount = await page.evaluate( + const currentColumnCount = await canvas().evaluate( () => document.activeElement.value ); expect( currentColumnCount ).toBe( '2' ); @@ -46,14 +47,14 @@ describe( 'Table', () => { await page.keyboard.type( '5' ); // Check for existence of the row count field. - const rowCountLabel = await page.$x( + const rowCountLabel = await canvas().$x( "//figure[@data-type='core/table']//label[text()='Row count']" ); expect( rowCountLabel ).toHaveLength( 1 ); // Modify the row count. await rowCountLabel[ 0 ].click(); - const currentRowCount = await page.evaluate( + const currentRowCount = await canvas().evaluate( () => document.activeElement.value ); expect( currentRowCount ).toBe( '2' ); @@ -61,7 +62,7 @@ describe( 'Table', () => { await page.keyboard.type( '10' ); // Create the table. - await clickButton( createButtonLabel ); + await clickButton( createButtonLabel, canvas() ); // Expect the post content to have a correctly sized table. expect( await getEditedPostContent() ).toMatchSnapshot(); @@ -71,10 +72,10 @@ describe( 'Table', () => { await insertBlock( 'Table' ); // Create the table. - await clickButton( createButtonLabel ); + await clickButton( createButtonLabel, canvas() ); - // Click the first cell and add some text. - await page.click( 'td' ); + // Tab to the first cell and add some text. + await page.keyboard.press( 'Tab' ); await page.keyboard.type( 'This' ); // Tab to the next cell and add some text. @@ -107,7 +108,7 @@ describe( 'Table', () => { expect( footerSwitch ).toHaveLength( 0 ); // Create the table. - await clickButton( createButtonLabel ); + await clickButton( createButtonLabel, canvas() ); // Expect the header and footer switches to be present now that the table has been created. headerSwitch = await page.$x( headerSwitchSelector ); @@ -119,13 +120,13 @@ describe( 'Table', () => { await headerSwitch[ 0 ].click(); await footerSwitch[ 0 ].click(); - await page.click( 'thead th' ); + await canvas().click( 'thead th' ); await page.keyboard.type( 'header' ); - await page.click( 'tbody td' ); + await canvas().click( 'tbody td' ); await page.keyboard.type( 'body' ); - await page.click( 'tfoot td' ); + await canvas().click( 'tfoot td' ); await page.keyboard.type( 'footer' ); // Expect the table to have a header, body and footer with written content. @@ -144,7 +145,7 @@ describe( 'Table', () => { await openDocumentSettingsSidebar(); // Create the table. - await clickButton( createButtonLabel ); + await clickButton( createButtonLabel, canvas() ); // Toggle on the switches and add some content. const headerSwitch = await page.$x( @@ -156,7 +157,7 @@ describe( 'Table', () => { await headerSwitch[ 0 ].click(); await footerSwitch[ 0 ].click(); - await page.click( 'td' ); + await canvas().click( 'td' ); // Add a column. await clickBlockToolbarButton( 'Edit table' ); @@ -165,7 +166,7 @@ describe( 'Table', () => { // Expect the table to have 3 columns across the header, body and footer. expect( await getEditedPostContent() ).toMatchSnapshot(); - await page.click( 'td' ); + await canvas().click( 'td' ); // Delete a column. await clickBlockToolbarButton( 'Edit table' ); @@ -178,7 +179,7 @@ describe( 'Table', () => { it( 'allows columns to be aligned', async () => { await insertBlock( 'Table' ); - const [ columnCountLabel ] = await page.$x( + const [ columnCountLabel ] = await canvas().$x( "//figure[@data-type='core/table']//label[text()='Column count']" ); await columnCountLabel.click(); @@ -186,10 +187,10 @@ describe( 'Table', () => { await page.keyboard.type( '4' ); // Create the table. - await clickButton( createButtonLabel ); + await clickButton( createButtonLabel, canvas() ); // Click the first cell and add some text. Don't align. - const cells = await page.$$( 'td,th' ); + const cells = await canvas().$$( 'td,th' ); await cells[ 0 ].click(); await page.keyboard.type( 'None' ); @@ -218,7 +219,7 @@ describe( 'Table', () => { await openDocumentSettingsSidebar(); // Create the table. - await clickButton( createButtonLabel ); + await clickButton( createButtonLabel, canvas() ); // Enable fixed width as it exascerbates the amount of empty space around the RichText. const [ fixedWidthSwitch ] = await page.$x( @@ -227,20 +228,23 @@ describe( 'Table', () => { await fixedWidthSwitch.click(); // Add multiple new lines to the first cell to make it taller. - await page.click( 'td' ); + await canvas().click( 'td' ); await page.keyboard.type( '\n\n\n\n' ); // Get the bounding client rect for the second cell. - const { x: secondCellX, y: secondCellY } = await page.evaluate( () => { - const secondCell = document.querySelectorAll( - '.wp-block-table td' - )[ 1 ]; - // Page.evaluate can only return a serializable value to the - // parent process, so destructure and restructure the result - // into an object. - const { x, y } = secondCell.getBoundingClientRect(); - return { x, y }; - } ); + const { x: secondCellX, y: secondCellY } = await canvas().evaluate( + () => { + const secondCell = document.querySelectorAll( + '.wp-block-table td' + )[ 1 ]; + // Page.evaluate can only return a serializable value to the + // parent process, so destructure and restructure the result + // into an object. + const { x, y } = secondCell.getBoundingClientRect(); + const winRect = window.frameElement.getBoundingClientRect(); + return { x: x + winRect.x, y: y + winRect.y }; + } + ); // Click in the top left corner of the second cell and type some text. await page.mouse.click( secondCellX, secondCellY ); @@ -254,10 +258,10 @@ describe( 'Table', () => { await insertBlock( 'Table' ); // Create the table. - await clickButton( createButtonLabel ); + await clickButton( createButtonLabel, canvas() ); // Click the first cell and add some text. - await page.click( '.wp-block-table figcaption' ); + await canvas().click( '.wp-block-table figcaption' ); await page.keyboard.type( 'Caption!' ); expect( await getEditedPostContent() ).toMatchSnapshot(); @@ -267,7 +271,7 @@ describe( 'Table', () => { await insertBlock( 'Table' ); // Create the table. - await clickButton( createButtonLabel ); + await clickButton( createButtonLabel, canvas() ); await page.keyboard.press( 'Tab' ); await page.keyboard.type( '1' ); diff --git a/packages/e2e-tests/specs/editor/plugins/annotations.test.js b/packages/e2e-tests/specs/editor/plugins/annotations.test.js index 14cfbcaa1e7c4..eec8287b8bdd9 100644 --- a/packages/e2e-tests/specs/editor/plugins/annotations.test.js +++ b/packages/e2e-tests/specs/editor/plugins/annotations.test.js @@ -8,6 +8,7 @@ import { clickOnMoreMenuItem, createNewPost, deactivatePlugin, + canvas, } from '@wordpress/e2e-test-utils'; const clickOnBlockSettingsMenuItem = async ( buttonLabel ) => { @@ -51,7 +52,7 @@ describe( 'Using Plugins API', () => { await page.$x( "//button[contains(text(), 'Add annotation')]" ) )[ 0 ]; await addAnnotationButton.click(); - await page.evaluate( () => + await canvas().evaluate( () => document.querySelector( '[contenteditable]' ).focus() ); } @@ -67,7 +68,7 @@ describe( 'Using Plugins API', () => { await page.$x( "//button[contains(text(), 'Remove annotations')]" ) )[ 0 ]; await addAnnotationButton.click(); - await page.evaluate( () => + await canvas().evaluate( () => document.querySelector( '[contenteditable]' ).focus() ); } @@ -78,11 +79,11 @@ describe( 'Using Plugins API', () => { * @return {Promise} The annotated text. */ async function getAnnotatedText() { - const annotations = await page.$$( ANNOTATIONS_SELECTOR ); + const annotations = await canvas().$$( ANNOTATIONS_SELECTOR ); const annotation = annotations[ 0 ]; - return await page.evaluate( ( el ) => el.innerText, annotation ); + return await canvas().evaluate( ( el ) => el.innerText, annotation ); } /** @@ -91,8 +92,8 @@ describe( 'Using Plugins API', () => { * @return {Promise} Inner HTML. */ async function getRichTextInnerHTML() { - const htmlContent = await page.$$( '*[contenteditable]' ); - return await page.evaluate( ( el ) => { + const htmlContent = await canvas().$$( '*[contenteditable]' ); + return await canvas().evaluate( ( el ) => { return el.innerHTML; }, htmlContent[ 0 ] ); } @@ -105,12 +106,12 @@ describe( 'Using Plugins API', () => { await clickOnMoreMenuItem( 'Annotations Sidebar' ); - let annotations = await page.$$( ANNOTATIONS_SELECTOR ); + let annotations = await canvas().$$( ANNOTATIONS_SELECTOR ); expect( annotations ).toHaveLength( 0 ); await annotateFirstBlock( 9, 13 ); - annotations = await page.$$( ANNOTATIONS_SELECTOR ); + annotations = await canvas().$$( ANNOTATIONS_SELECTOR ); expect( annotations ).toHaveLength( 1 ); const text = await getAnnotatedText(); @@ -118,10 +119,10 @@ describe( 'Using Plugins API', () => { await clickOnBlockSettingsMenuItem( 'Edit as HTML' ); - const htmlContent = await page.$$( + const htmlContent = await canvas().$$( '.block-editor-block-list__block-html-textarea' ); - const html = await page.evaluate( ( el ) => { + const html = await canvas().evaluate( ( el ) => { return el.innerHTML; }, htmlContent[ 0 ] ); @@ -139,8 +140,8 @@ describe( 'Using Plugins API', () => { await page.keyboard.type( 'D' ); await removeAnnotations(); - const htmlContent = await page.$$( '*[contenteditable]' ); - const html = await page.evaluate( ( el ) => { + const htmlContent = await canvas().$$( '*[contenteditable]' ); + const html = await canvas().evaluate( ( el ) => { return el.innerHTML; }, htmlContent[ 0 ] ); diff --git a/packages/e2e-tests/specs/editor/plugins/block-context.test.js b/packages/e2e-tests/specs/editor/plugins/block-context.test.js index f09df529e70ce..000e925af2da2 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-context.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-context.test.js @@ -8,6 +8,7 @@ import { insertBlock, saveDraft, openPreviewPage, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Block context', () => { @@ -28,7 +29,7 @@ describe( 'Block context', () => { // Inserting the context provider block should select the first inner // block of the template. Verify the contents of the consumer. - let innerBlockText = await page.evaluate( + let innerBlockText = await canvas().evaluate( () => document.activeElement.textContent ); expect( innerBlockText ).toBe( 'The record ID is: 0' ); @@ -39,7 +40,7 @@ describe( 'Block context', () => { // Verify propagated context changes. await page.keyboard.press( 'ArrowDown' ); - innerBlockText = await page.evaluate( + innerBlockText = await canvas().evaluate( () => document.activeElement.textContent ); expect( innerBlockText ).toBe( 'The record ID is: 123' ); @@ -60,7 +61,7 @@ describe( 'Block context', () => { // Return to editor to change context value to non-default. await editorPage.bringToFront(); - await editorPage.focus( + await canvas().focus( '[data-type="gutenberg/test-context-provider"] input' ); await editorPage.keyboard.press( 'ArrowRight' ); diff --git a/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js b/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js index dde952f627477..576beefec22de 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-directory-add.test.js @@ -8,6 +8,7 @@ import { setUpResponseMocking, getEditedPostContent, createJSONResponse, + canvas, } from '@wordpress/e2e-test-utils'; // Urls to mock @@ -181,7 +182,9 @@ describe( 'adding blocks from block directory', () => { // Search for the block via the inserter await insertBlockDirectoryBlock( MOCK_BLOCK1.title ); - await page.waitForSelector( `div[data-type="${ MOCK_BLOCK1.name }"]` ); + await canvas().waitForSelector( + `div[data-type="${ MOCK_BLOCK1.name }"]` + ); // The block will auto select and get added, make sure we see it in the content expect( await getEditedPostContent() ).toMatchSnapshot(); diff --git a/packages/e2e-tests/specs/editor/plugins/block-icons.test.js b/packages/e2e-tests/specs/editor/plugins/block-icons.test.js index d8fc23bf64e86..cbb4af9615ac8 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-icons.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-icons.test.js @@ -9,6 +9,7 @@ import { pressKeyWithModifier, searchForBlock, openDocumentSettingsSidebar, + canvas, } from '@wordpress/e2e-test-utils'; const INSERTER_BUTTON_SELECTOR = @@ -17,8 +18,8 @@ const INSERTER_ICON_WRAPPER_SELECTOR = `${ INSERTER_BUTTON_SELECTOR } .block-edi const INSERTER_ICON_SELECTOR = `${ INSERTER_BUTTON_SELECTOR } .block-editor-block-icon`; const INSPECTOR_ICON_SELECTOR = '.edit-post-sidebar .block-editor-block-icon'; -async function getInnerHTML( selector ) { - return await page.$eval( selector, ( element ) => element.innerHTML ); +async function getInnerHTML( selector, frame = page ) { + return await frame.$eval( selector, ( element ) => element.innerHTML ); } async function getBackgroundColor( selector ) { @@ -83,7 +84,8 @@ describe( 'Correctly Renders Block Icons on Inserter and Inspector', () => { await insertBlock( blockTitle ); expect( await getInnerHTML( - `[data-type="${ blockName }"] [data-type="core/paragraph"]` + `[data-type="${ blockName }"] [data-type="core/paragraph"]`, + canvas() ) ).toEqual( blockTitle ); } ); diff --git a/packages/e2e-tests/specs/editor/plugins/block-variations.js b/packages/e2e-tests/specs/editor/plugins/block-variations.js index ef4a17360284a..4d892ff0128c3 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-variations.js +++ b/packages/e2e-tests/specs/editor/plugins/block-variations.js @@ -7,6 +7,7 @@ import { deactivatePlugin, insertBlock, searchForBlock, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Block variations', () => { @@ -52,7 +53,7 @@ describe( 'Block variations', () => { await insertBlock( 'Large Quote' ); expect( - await page.$( + await canvas().$( '.wp-block[data-type="core/quote"] blockquote.is-style-large' ) ).toBeDefined(); @@ -82,7 +83,7 @@ describe( 'Block variations', () => { test( 'Insert the Success Message block variation', async () => { await insertBlock( 'Success Message' ); - const successMessageBlock = await page.$( + const successMessageBlock = await canvas().$( '.wp-block[data-type="core/paragraph"]' ); expect( successMessageBlock ).toBeDefined(); @@ -93,12 +94,12 @@ describe( 'Block variations', () => { test( 'Pick the additional variation in the inserted Columns block', async () => { await insertBlock( 'Columns' ); - const fourColumnsVariation = await page.waitForSelector( + const fourColumnsVariation = await canvas().waitForSelector( '.wp-block[data-type="core/columns"] .block-editor-block-variation-picker__variation[aria-label="Four columns"]' ); await fourColumnsVariation.click(); expect( - await page.$$( + await canvas().$$( '.wp-block[data-type="core/columns"] .wp-block[data-type="core/column"]' ) ).toHaveLength( 4 ); diff --git a/packages/e2e-tests/specs/editor/plugins/child-blocks.test.js b/packages/e2e-tests/specs/editor/plugins/child-blocks.test.js index 183813a951136..f47be8ff4d60a 100644 --- a/packages/e2e-tests/specs/editor/plugins/child-blocks.test.js +++ b/packages/e2e-tests/specs/editor/plugins/child-blocks.test.js @@ -9,6 +9,7 @@ import { getAllBlockInserterItemTitles, insertBlock, openGlobalBlockInserter, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Child Blocks', () => { @@ -34,10 +35,10 @@ describe( 'Child Blocks', () => { it( 'shows up in a parent block', async () => { await insertBlock( 'Child Blocks Unrestricted Parent' ); await closeGlobalBlockInserter(); - await page.waitForSelector( + await canvas().waitForSelector( '[data-type="test/child-blocks-unrestricted-parent"] .block-editor-default-block-appender' ); - await page.click( + await canvas().click( '[data-type="test/child-blocks-unrestricted-parent"] .block-editor-default-block-appender' ); await openGlobalBlockInserter(); @@ -49,10 +50,10 @@ describe( 'Child Blocks', () => { it( 'display in a parent block with allowedItems', async () => { await insertBlock( 'Child Blocks Restricted Parent' ); await closeGlobalBlockInserter(); - await page.waitForSelector( + await canvas().waitForSelector( '[data-type="test/child-blocks-restricted-parent"] .block-editor-default-block-appender' ); - await page.click( + await canvas().click( '[data-type="test/child-blocks-restricted-parent"] .block-editor-default-block-appender' ); await openGlobalBlockInserter(); diff --git a/packages/e2e-tests/specs/editor/plugins/container-blocks.test.js b/packages/e2e-tests/specs/editor/plugins/container-blocks.test.js index e6d162eb18520..40c0785e2a9c1 100644 --- a/packages/e2e-tests/specs/editor/plugins/container-blocks.test.js +++ b/packages/e2e-tests/specs/editor/plugins/container-blocks.test.js @@ -9,6 +9,7 @@ import { insertBlock, switchEditorModeTo, pressKeyWithModifier, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'InnerBlocks Template Sync', () => { @@ -99,7 +100,7 @@ describe( 'Container block without paragraph support', () => { await insertBlock( 'Container without paragraph' ); // Open the specific appender used when there's no paragraph support. - await page.click( + await canvas().click( '.block-editor-inner-blocks .block-list-appender .block-list-appender__toggle' ); diff --git a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js index 1eefa0a69ebbf..de6616ed5c64b 100644 --- a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js +++ b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js @@ -12,6 +12,7 @@ import { pressKeyTimes, pressKeyWithModifier, setPostContent, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'cpt locking', () => { @@ -35,7 +36,7 @@ describe( 'cpt locking', () => { }; const shouldNotAllowBlocksToBeRemoved = async () => { - await page.type( + await canvas().type( '.block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); @@ -46,12 +47,12 @@ describe( 'cpt locking', () => { }; const shouldAllowBlocksToBeMoved = async () => { - await page.click( + await canvas().click( '.block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).not.toBeNull(); await page.click( 'button[aria-label="Move up"]' ); - await page.type( + await canvas().type( '.block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); @@ -71,14 +72,14 @@ describe( 'cpt locking', () => { ); it( 'should not allow blocks to be moved', async () => { - await page.click( + await canvas().click( '.block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).toBeNull(); } ); it( 'should not error when deleting the cotents of a paragraph', async () => { - await page.click( + await canvas().click( '.block-editor-block-list__block[data-type="core/paragraph"]' ); const textToType = 'Paragraph'; @@ -88,7 +89,7 @@ describe( 'cpt locking', () => { } ); it( 'should insert line breaks when using enter and shift-enter', async () => { - await page.click( + await canvas().click( '.block-editor-block-list__block[data-type="core/paragraph"]' ); await page.keyboard.type( 'First line' ); @@ -119,8 +120,10 @@ describe( 'cpt locking', () => { } ); it( 'can use the global inserter in inner blocks', async () => { - await page.click( 'button[aria-label="Two columns; equal split"]' ); - await page.click( + await canvas().click( + 'button[aria-label="Two columns; equal split"]' + ); + await canvas().click( '.wp-block-column .block-editor-button-block-appender' ); await page.type( '.block-editor-inserter__search-input', 'image' ); @@ -133,7 +136,7 @@ describe( 'cpt locking', () => { ); await pressKeyTimes( 'Tab', 2 ); await page.keyboard.press( 'Enter' ); - expect( await page.$( '.wp-block-gallery' ) ).not.toBeNull(); + expect( await canvas().$( '.wp-block-gallery' ) ).not.toBeNull(); } ); } ); @@ -167,7 +170,7 @@ describe( 'cpt locking', () => { } ); it( 'should allow blocks to be removed', async () => { - await page.type( + await canvas().type( '.block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); @@ -187,7 +190,7 @@ describe( 'cpt locking', () => { } ); it( 'should allow blocks to be removed', async () => { - await page.type( + await canvas().type( '.block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); @@ -213,7 +216,7 @@ describe( 'cpt locking', () => { ); it( 'should not allow blocks to be moved', async () => { - await page.click( + await canvas().click( '.block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).toBeNull(); @@ -233,7 +236,7 @@ describe( 'cpt locking', () => { ); it( 'should not allow blocks to be moved', async () => { - await page.click( + await canvas().click( '.block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).toBeNull(); diff --git a/packages/e2e-tests/specs/editor/plugins/custom-post-types.test.js b/packages/e2e-tests/specs/editor/plugins/custom-post-types.test.js index 062d8b56c0725..d2bc0d673ce3b 100644 --- a/packages/e2e-tests/specs/editor/plugins/custom-post-types.test.js +++ b/packages/e2e-tests/specs/editor/plugins/custom-post-types.test.js @@ -7,6 +7,7 @@ import { deactivatePlugin, publishPost, findSidebarPanelWithTitle, + canvas, } from '@wordpress/e2e-test-utils'; const openPageAttributesPanel = async () => { @@ -40,7 +41,7 @@ describe( 'Test Custom Post Types', () => { // Create a parent post. await createNewPost( { postType: 'hierar-no-title' } ); - await page.click( '.block-editor-writing-flow' ); + await canvas().click( '.block-editor-writing-flow' ); await page.keyboard.type( 'Parent Post' ); await publishPost(); // Create a post that is a child of the previously created post. @@ -55,7 +56,7 @@ describe( 'Test Custom Post Types', () => { ( element ) => element.textContent ); await optionToSelect.click(); - await page.click( '.block-editor-writing-flow' ); + await canvas().click( '.block-editor-writing-flow' ); await page.keyboard.type( 'Child Post' ); await publishPost(); // Reload the child post and verify it is still correctly selected as a child post. @@ -71,11 +72,12 @@ describe( 'Test Custom Post Types', () => { [ valueToSelect, PARENT_PAGE_INPUT ] ); } ); + it( 'should create a cpt with a legacy block in its template without WSOD', async () => { await createNewPost( { postType: 'leg_block_in_tpl' } ); - await page.click( '.block-editor-writing-flow' ); + await canvas().click( '.block-editor-writing-flow' ); await page.keyboard.type( 'Hello there' ); - await page.waitForSelector( '[data-type="core/embed"]' ); + await canvas().waitForSelector( '[data-type="core/embed"]' ); await publishPost(); } ); } ); diff --git a/packages/e2e-tests/specs/editor/plugins/hooks-api.test.js b/packages/e2e-tests/specs/editor/plugins/hooks-api.test.js index e015de70257c7..736658cf32346 100644 --- a/packages/e2e-tests/specs/editor/plugins/hooks-api.test.js +++ b/packages/e2e-tests/specs/editor/plugins/hooks-api.test.js @@ -7,6 +7,7 @@ import { createNewPost, deactivatePlugin, getEditedPostContent, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Using Hooks API', () => { @@ -33,7 +34,7 @@ describe( 'Using Hooks API', () => { it( 'Pressing reset block button resets the block', async () => { await clickBlockAppender(); await page.keyboard.type( 'First paragraph' ); - const paragraphContent = await page.$eval( + const paragraphContent = await canvas().$eval( 'p[data-type="core/paragraph"]', ( element ) => element.textContent ); diff --git a/packages/e2e-tests/specs/editor/plugins/image-size.test.js b/packages/e2e-tests/specs/editor/plugins/image-size.test.js index a92ae63046550..aa6e24d8f7b85 100644 --- a/packages/e2e-tests/specs/editor/plugins/image-size.test.js +++ b/packages/e2e-tests/specs/editor/plugins/image-size.test.js @@ -16,6 +16,7 @@ import { deactivatePlugin, insertBlock, openDocumentSettingsSidebar, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'changing image size', () => { @@ -30,7 +31,7 @@ describe( 'changing image size', () => { it( 'should insert and change my image size', async () => { await insertBlock( 'Image' ); - await clickButton( 'Media Library' ); + await clickButton( 'Media Library', canvas() ); // Wait for media modal to appear and upload image. await page.waitForSelector( '.media-modal input[type=file]' ); @@ -68,7 +69,9 @@ describe( 'changing image size', () => { await imageSizeSelect.select( 'custom-size-one' ); // Verify that the custom size was applied to the image. - await page.waitForSelector( '.wp-block-image.size-custom-size-one' ); + await canvas().waitForSelector( + '.wp-block-image.size-custom-size-one' + ); await page.waitForFunction( () => document.querySelector( diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js index 1e02d4369f1b3..6af995ef5e149 100644 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js +++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js @@ -9,6 +9,7 @@ import { insertBlock, openGlobalBlockInserter, closeGlobalBlockInserter, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Allowed Blocks Setting on InnerBlocks ', () => { @@ -31,8 +32,8 @@ describe( 'Allowed Blocks Setting on InnerBlocks ', () => { const childParagraphSelector = `${ parentBlockSelector } ${ paragraphSelector }`; await insertBlock( 'Allowed Blocks Unset' ); await closeGlobalBlockInserter(); - await page.waitForSelector( childParagraphSelector ); - await page.click( childParagraphSelector ); + await canvas().waitForSelector( childParagraphSelector ); + await canvas().click( childParagraphSelector ); await openGlobalBlockInserter(); await expect( ( await getAllBlockInserterItemTitles() ).length @@ -44,8 +45,8 @@ describe( 'Allowed Blocks Setting on InnerBlocks ', () => { const childParagraphSelector = `${ parentBlockSelector } ${ paragraphSelector }`; await insertBlock( 'Allowed Blocks Set' ); await closeGlobalBlockInserter(); - await page.waitForSelector( childParagraphSelector ); - await page.click( childParagraphSelector ); + await canvas().waitForSelector( childParagraphSelector ); + await canvas().click( childParagraphSelector ); await openGlobalBlockInserter(); expect( await getAllBlockInserterItemTitles() ).toEqual( [ 'Button', @@ -62,8 +63,8 @@ describe( 'Allowed Blocks Setting on InnerBlocks ', () => { const parentBlockSelector = '[data-type="test/allowed-blocks-dynamic"]'; const blockAppender = '.block-list-appender button'; const appenderSelector = `${ parentBlockSelector } ${ blockAppender }`; - await page.waitForSelector( appenderSelector ); - await page.click( appenderSelector ); + await canvas().waitForSelector( appenderSelector ); + await canvas().click( appenderSelector ); expect( await getAllBlockInserterItemTitles() ).toEqual( [ 'Image', 'List', @@ -74,8 +75,10 @@ describe( 'Allowed Blocks Setting on InnerBlocks ', () => { await insertButton.click(); await insertBlock( 'Image' ); await closeGlobalBlockInserter(); - await page.waitForSelector( '.product[data-number-of-children="2"]' ); - await page.click( appenderSelector ); + await canvas().waitForSelector( + '.product[data-number-of-children="2"]' + ); + await canvas().click( appenderSelector ); expect( await getAllBlockInserterItemTitles() ).toEqual( [ 'Gallery', 'Video', diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js index 182f224d0976f..c89c31bcaa0ec 100644 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js +++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js @@ -9,6 +9,7 @@ import { getEditedPostContent, insertBlock, closeGlobalBlockInserter, + canvas, } from '@wordpress/e2e-test-utils'; const INSERTER_RESULTS_SELECTOR = @@ -35,17 +36,17 @@ describe( 'RenderAppender prop of InnerBlocks ', () => { await insertBlock( 'InnerBlocks renderAppender' ); await closeGlobalBlockInserter(); // Wait for the custom block appender to appear. - await page.waitForSelector( APPENDER_SELECTOR ); + await canvas().waitForSelector( APPENDER_SELECTOR ); // Verify if the custom block appender text is the expected one. expect( - await page.evaluate( + await canvas().evaluate( ( el ) => el.innerText, - await page.$( `${ APPENDER_SELECTOR } > span` ) + await canvas().$( `${ APPENDER_SELECTOR } > span` ) ) ).toEqual( 'My custom awesome appender' ); // Open the inserter of our custom block appender and expand all the categories. - await page.click( + await canvas().click( `${ APPENDER_SELECTOR } .block-editor-button-block-appender` ); // Verify if the blocks the custom inserter is rendering are the expected ones. @@ -72,16 +73,16 @@ describe( 'RenderAppender prop of InnerBlocks ', () => { await closeGlobalBlockInserter(); // Wait for the custom dynamic block appender to appear. - await page.waitForSelector( '.' + DYNAMIC_APPENDER_SELECTOR ); + await canvas().waitForSelector( '.' + DYNAMIC_APPENDER_SELECTOR ); // Verify if the custom block appender text is the expected one. - await page.waitForXPath( + await canvas().waitForXPath( `//*[contains(@class, "${ DYNAMIC_APPENDER_SELECTOR }")]/span[contains(@class, "empty-blocks-appender")][contains(text(), "Empty Blocks Appender")]` ); // Open the inserter of our custom block appender and expand all the categories. const blockAppenderButtonSelector = `.${ DYNAMIC_APPENDER_SELECTOR } .block-editor-button-block-appender`; - await page.click( blockAppenderButtonSelector ); + await canvas().click( blockAppenderButtonSelector ); // Verify if the blocks the custom inserter is rendering are the expected ones. expect( await getAllBlockInserterItemTitles() ).toEqual( [ @@ -99,23 +100,23 @@ describe( 'RenderAppender prop of InnerBlocks ', () => { await quoteButton.click(); // Verify if the custom block appender text changed as expected. - await page.waitForXPath( + await canvas().waitForXPath( `//*[contains(@class, "${ DYNAMIC_APPENDER_SELECTOR }")]/span[contains(@class, "single-blocks-appender")][contains(text(), "Single Blocks Appender")]` ); // Verify that the custom appender button is still being rendered. - expect( await page.$( blockAppenderButtonSelector ) ).toBeTruthy(); + expect( await canvas().$( blockAppenderButtonSelector ) ).toBeTruthy(); // Insert a video block. await insertBlock( 'Video' ); // Verify if the custom block appender text changed as expected. - await page.waitForXPath( + await canvas().waitForXPath( `//*[contains(@class, "${ DYNAMIC_APPENDER_SELECTOR }")]/span[contains(@class, "multiple-blocks-appender")][contains(text(), "Multiple Blocks Appender")]` ); // Verify that the custom appender button is now not being rendered. - expect( await page.$( blockAppenderButtonSelector ) ).toBeFalsy(); + expect( await canvas().$( blockAppenderButtonSelector ) ).toBeFalsy(); // Verify that final block markup is the expected one. expect( await getEditedPostContent() ).toMatchSnapshot(); diff --git a/packages/e2e-tests/specs/editor/plugins/innerblocks-locking-all-embed.js b/packages/e2e-tests/specs/editor/plugins/innerblocks-locking-all-embed.js index a0a83fbf90e61..2ad250ff72e62 100644 --- a/packages/e2e-tests/specs/editor/plugins/innerblocks-locking-all-embed.js +++ b/packages/e2e-tests/specs/editor/plugins/innerblocks-locking-all-embed.js @@ -9,6 +9,7 @@ import { createEmbeddingMatcher, createJSONResponse, setUpResponseMocking, + canvas, } from '@wordpress/e2e-test-utils'; const MOCK_RESPONSES = [ @@ -45,12 +46,12 @@ describe( 'Embed block inside a locked all parent', () => { await insertBlock( 'Test Inner Blocks Locking All Embed' ); const embedInputSelector = '.components-placeholder__input[aria-label="Embed URL"]'; - await page.waitForSelector( embedInputSelector ); - await page.click( embedInputSelector ); + await canvas().waitForSelector( embedInputSelector ); + await canvas().click( embedInputSelector ); // This URL should not have a trailing slash. await page.keyboard.type( 'https://twitter.com/wordpress' ); await page.keyboard.press( 'Enter' ); // The twitter block should appear correctly. - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); } ); } ); diff --git a/packages/e2e-tests/specs/editor/plugins/meta-attribute-block.test.js b/packages/e2e-tests/specs/editor/plugins/meta-attribute-block.test.js index a11cbb1f6872e..792271623a3c5 100644 --- a/packages/e2e-tests/specs/editor/plugins/meta-attribute-block.test.js +++ b/packages/e2e-tests/specs/editor/plugins/meta-attribute-block.test.js @@ -9,6 +9,7 @@ import { insertBlock, saveDraft, pressKeyTimes, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Block with a meta attribute', () => { @@ -44,7 +45,7 @@ describe( 'Block with a meta attribute', () => { await page.waitForSelector( '.edit-post-layout' ); expect( await getEditedPostContent() ).toMatchSnapshot(); - const persistedValue = await page.evaluate( + const persistedValue = await canvas().evaluate( () => document.querySelector( '.my-meta-input' ).value ); expect( persistedValue ).toBe( 'Meta Value' ); @@ -56,7 +57,7 @@ describe( 'Block with a meta attribute', () => { await insertBlock( `Test Meta Attribute Block (${ variant })` ); await page.keyboard.type( 'Meta Value' ); - const inputs = await page.$$( '.my-meta-input' ); + const inputs = await canvas().$$( '.my-meta-input' ); await Promise.all( inputs.map( async ( input ) => { // Clicking the input selects the block, @@ -90,7 +91,7 @@ describe( 'Block with a meta attribute', () => { await page.waitForSelector( '.edit-post-layout' ); expect( await getEditedPostContent() ).toMatchSnapshot(); - const persistedValue = await page.evaluate( + const persistedValue = await canvas().evaluate( () => document.querySelector( '.my-meta-input' ).value ); expect( persistedValue ).toBe( 'Meta Value' ); diff --git a/packages/e2e-tests/specs/editor/plugins/meta-boxes.test.js b/packages/e2e-tests/specs/editor/plugins/meta-boxes.test.js index b7b13a4be08da..07dc140f11adc 100644 --- a/packages/e2e-tests/specs/editor/plugins/meta-boxes.test.js +++ b/packages/e2e-tests/specs/editor/plugins/meta-boxes.test.js @@ -10,6 +10,7 @@ import { openDocumentSettingsSidebar, publishPost, saveDraft, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Meta boxes', () => { @@ -30,7 +31,7 @@ describe( 'Meta boxes', () => { expect( await page.$( '.editor-post-save-draft' ) ).toBe( null ); // Add title to enable valid non-empty post save. - await page.type( '.editor-post-title__input', 'Hello Meta' ); + await canvas().type( '.editor-post-title__input', 'Hello Meta' ); expect( await page.$( '.editor-post-save-draft' ) ).not.toBe( null ); await saveDraft(); @@ -41,14 +42,17 @@ describe( 'Meta boxes', () => { it( 'Should render dynamic blocks when the meta box uses the excerpt for front end rendering', async () => { // Publish a post so there's something for the latest posts dynamic block to render. - await page.type( '.editor-post-title__input', 'A published post' ); + await canvas().type( '.editor-post-title__input', 'A published post' ); await insertBlock( 'Paragraph' ); await page.keyboard.type( 'Hello there!' ); await publishPost(); // Publish a post with the latest posts dynamic block. await createNewPost(); - await page.type( '.editor-post-title__input', 'Dynamic block test' ); + await canvas().type( + '.editor-post-title__input', + 'Dynamic block test' + ); await insertBlock( 'Latest Posts' ); await publishPost(); @@ -66,7 +70,7 @@ describe( 'Meta boxes', () => { it( 'Should render the excerpt in meta based on post content if no explicit excerpt exists', async () => { await insertBlock( 'Paragraph' ); await page.keyboard.type( 'Excerpt from content.' ); - await page.type( '.editor-post-title__input', 'A published post' ); + await canvas().type( '.editor-post-title__input', 'A published post' ); await publishPost(); // View the post. @@ -89,7 +93,7 @@ describe( 'Meta boxes', () => { it( 'Should render the explicitly set excerpt in meta instead of the content based one', async () => { await insertBlock( 'Paragraph' ); await page.keyboard.type( 'Excerpt from content.' ); - await page.type( '.editor-post-title__input', 'A published post' ); + await canvas().type( '.editor-post-title__input', 'A published post' ); // Open the excerpt panel await openDocumentSettingsSidebar(); diff --git a/packages/e2e-tests/specs/editor/plugins/templates.test.js b/packages/e2e-tests/specs/editor/plugins/templates.test.js index 173acdff8c031..862025e629788 100644 --- a/packages/e2e-tests/specs/editor/plugins/templates.test.js +++ b/packages/e2e-tests/specs/editor/plugins/templates.test.js @@ -12,6 +12,7 @@ import { switchUserToAdmin, switchUserToTest, visitAdminPage, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'templates', () => { @@ -35,7 +36,7 @@ describe( 'templates', () => { it( 'Should respect user edits to not re-apply template after save (single block removal)', async () => { // Remove a block from the template to verify that it's not // re-added after saving and reloading the editor. - await page.click( '.editor-post-title__input' ); + await canvas().click( '.editor-post-title__input' ); await page.keyboard.press( 'ArrowDown' ); await page.keyboard.press( 'Backspace' ); await saveDraft(); @@ -48,7 +49,7 @@ describe( 'templates', () => { it( 'Should respect user edits to not re-apply template after save (full delete)', async () => { // Remove all blocks from the template to verify that they're not // re-added after saving and reloading the editor. - await page.type( '.editor-post-title__input', 'My Empty Book' ); + await canvas().type( '.editor-post-title__input', 'My Empty Book' ); await page.keyboard.press( 'ArrowDown' ); await pressKeyWithModifier( 'primary', 'A' ); await page.keyboard.press( 'Backspace' ); @@ -99,7 +100,10 @@ describe( 'templates', () => { // Remove the default block template to verify that it's not // re-added after saving and reloading the editor. - await page.type( '.editor-post-title__input', 'My Image Format' ); + await canvas().type( + '.editor-post-title__input', + 'My Image Format' + ); await clickBlockAppender(); await page.keyboard.press( 'Backspace' ); await page.keyboard.press( 'Backspace' ); diff --git a/packages/e2e-tests/specs/editor/plugins/wp-editor-meta-box.test.js b/packages/e2e-tests/specs/editor/plugins/wp-editor-meta-box.test.js index 761830e8481c7..8d7d78e69f382 100644 --- a/packages/e2e-tests/specs/editor/plugins/wp-editor-meta-box.test.js +++ b/packages/e2e-tests/specs/editor/plugins/wp-editor-meta-box.test.js @@ -6,6 +6,7 @@ import { createNewPost, deactivatePlugin, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'WP Editor Meta Boxes', () => { @@ -20,7 +21,7 @@ describe( 'WP Editor Meta Boxes', () => { it( 'Should save the changes', async () => { // Add title to enable valid non-empty post save. - await page.type( '.editor-post-title__input', 'Hello Meta' ); + await canvas().type( '.editor-post-title__input', 'Hello Meta' ); // Type something await expect( page ).toClick( '#test_tinymce_id-html' ); diff --git a/packages/e2e-tests/specs/editor/various/adding-blocks.test.js b/packages/e2e-tests/specs/editor/various/adding-blocks.test.js index 5f71713055595..a9cc9f402baa2 100644 --- a/packages/e2e-tests/specs/editor/various/adding-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/adding-blocks.test.js @@ -10,6 +10,7 @@ import { closeGlobalBlockInserter, searchForBlock, showBlockToolbar, + canvas, } from '@wordpress/e2e-test-utils'; /** @typedef {import('puppeteer').ElementHandle} ElementHandle */ @@ -71,7 +72,7 @@ describe( 'adding blocks', () => { await page.$( '.interface-interface-skeleton__content' ) ); expect( - await page.waitForSelector( '[data-type="core/paragraph"]' ) + await canvas().waitForSelector( '[data-type="core/paragraph"]' ) ).not.toBeNull(); await page.keyboard.type( 'Paragraph block' ); @@ -125,11 +126,11 @@ describe( 'adding blocks', () => { await page.keyboard.type( 'lines preserved[/myshortcode]' ); // Unselect blocks to avoid conflicts with the inbetween inserter - await page.click( '.editor-post-title__input' ); + await canvas().click( '.editor-post-title__input' ); await closeGlobalBlockInserter(); // Using the between inserter - const insertionPoint = await page.$( '[data-type="core/quote"]' ); + const insertionPoint = await canvas().$( '[data-type="core/quote"]' ); const rect = await insertionPoint.boundingBox(); await page.mouse.move( rect.x + rect.width / 2, rect.y - 10, { steps: 10, @@ -225,13 +226,13 @@ describe( 'adding blocks', () => { await page.keyboard.type( '1.1' ); // After inserting the Buttons block the inner button block should be selected. - const selectedButtonBlocks = await page.$$( + const selectedButtonBlocks = await canvas().$$( '.wp-block-button.is-selected' ); expect( selectedButtonBlocks.length ).toBe( 1 ); // Specifically click the root container appender. - await page.click( + await canvas().click( '.block-editor-block-list__layout.is-root-container > .block-list-appender .block-editor-inserter__toggle' ); @@ -268,7 +269,7 @@ describe( 'adding blocks', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); // Using the between inserter - const insertionPoint = await page.$( '[data-type="core/heading"]' ); + const insertionPoint = await canvas().$( '[data-type="core/heading"]' ); const rect = await insertionPoint.boundingBox(); await page.mouse.move( rect.x + rect.width / 2, rect.y - 10, { steps: 10, @@ -308,10 +309,10 @@ describe( 'adding blocks', () => { await page.keyboard.type( 'First paragraph' ); await insertBlock( 'Image' ); await showBlockToolbar(); - const paragraphBlock = await page.$( + const paragraphBlock = await canvas().$( 'p[aria-label="Paragraph block"]' ); - paragraphBlock.click(); + await paragraphBlock.click(); await showBlockToolbar(); // Open the global inserter and search for the Heading block. @@ -341,7 +342,9 @@ describe( 'adding blocks', () => { await insertBlock( 'Group' ); await insertBlock( 'Paragraph' ); await page.keyboard.type( 'Paragraph after group' ); - await page.click( '[data-type="core/group"] [aria-label="Add block"]' ); + await canvas().click( + '[data-type="core/group"] [aria-label="Add block"]' + ); const browseAll = await page.waitForXPath( '//button[text()="Browse all"]' ); diff --git a/packages/e2e-tests/specs/editor/various/autosave.test.js b/packages/e2e-tests/specs/editor/various/autosave.test.js index 6608b286980ba..d9e5ac60728d7 100644 --- a/packages/e2e-tests/specs/editor/various/autosave.test.js +++ b/packages/e2e-tests/specs/editor/various/autosave.test.js @@ -9,6 +9,7 @@ import { publishPost, saveDraft, toggleOfflineMode, + canvas, } from '@wordpress/e2e-test-utils'; // Constant to override editor preference @@ -258,7 +259,7 @@ describe( 'autosave', () => { await page.keyboard.type( 'before publish' ); await publishPost(); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.keyboard.type( ' after publish' ); // Trigger remote autosave diff --git a/packages/e2e-tests/specs/editor/various/block-deletion.test.js b/packages/e2e-tests/specs/editor/various/block-deletion.test.js index 80d9d3a11e19b..f68934c6c4560 100644 --- a/packages/e2e-tests/specs/editor/various/block-deletion.test.js +++ b/packages/e2e-tests/specs/editor/various/block-deletion.test.js @@ -10,6 +10,7 @@ import { pressKeyWithModifier, pressKeyTimes, insertBlock, + canvas, } from '@wordpress/e2e-test-utils'; const addThreeParagraphsToNewPost = async () => { @@ -110,10 +111,10 @@ describe( 'block deletion -', () => { await page.keyboard.press( 'Enter' ); // Click on something that's not a block. - await page.click( '.editor-post-title' ); + await canvas().click( '.editor-post-title' ); // Click on the image block so that its wrapper is selected and backspace to delete it. - await page.click( + await canvas().click( '.wp-block[data-type="core/image"] .components-placeholder__label' ); await page.keyboard.press( 'Backspace' ); @@ -158,7 +159,7 @@ describe( 'deleting all blocks', () => { // There is a default block: expect( - await page.$$( '.block-editor-block-list__block' ) + await canvas().$$( '.block-editor-block-list__block' ) ).toHaveLength( 1 ); // But the effective saved content is still empty: @@ -189,7 +190,7 @@ describe( 'deleting all blocks', () => { // Add and remove a block. await insertBlock( 'Image' ); - await page.waitForSelector( 'figure[data-type="core/image"]' ); + await canvas().waitForSelector( 'figure[data-type="core/image"]' ); await page.keyboard.press( 'Backspace' ); // Verify there is no selected block. diff --git a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js index 919a10bebe0f1..877d91af83947 100644 --- a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js +++ b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js @@ -8,6 +8,7 @@ import { pressKeyTimes, pressKeyWithModifier, openDocumentSettingsSidebar, + canvas, } from '@wordpress/e2e-test-utils'; async function openBlockNavigator() { @@ -39,7 +40,7 @@ describe( 'Navigating the block hierarchy', () => { it( 'should navigate using the block hierarchy dropdown menu', async () => { await insertBlock( 'Columns' ); - await page.click( '[aria-label="Two columns; equal split"]' ); + await canvas().click( '[aria-label="Two columns; equal split"]' ); // Add a paragraph in the first column. await page.keyboard.press( 'Tab' ); // Tab to inserter. @@ -91,7 +92,7 @@ describe( 'Navigating the block hierarchy', () => { it( 'should navigate block hierarchy using only the keyboard', async () => { await insertBlock( 'Columns' ); await openDocumentSettingsSidebar(); - await page.click( '[aria-label="Two columns; equal split"]' ); + await canvas().click( '[aria-label="Two columns; equal split"]' ); // Add a paragraph in the first column. await page.keyboard.press( 'Tab' ); // Tab to inserter. @@ -118,7 +119,9 @@ describe( 'Navigating the block hierarchy', () => { await openBlockNavigator(); await pressKeyTimes( 'ArrowDown', 4 ); await page.keyboard.press( 'Enter' ); - await page.waitForSelector( '.is-selected[data-type="core/column"]' ); + await canvas().waitForSelector( + '.is-selected[data-type="core/column"]' + ); // Insert text in the last column block await page.keyboard.press( 'Tab' ); // Tab to inserter. @@ -160,7 +163,7 @@ describe( 'Navigating the block hierarchy', () => { // Insert some random blocks. // The last block shouldn't be a textual block. - await page.click( '.block-list-appender .block-editor-inserter' ); + await canvas().click( '.block-list-appender .block-editor-inserter' ); const paragraphMenuItem = ( await page.$x( `//button//span[contains(text(), 'Paragraph')]` ) )[ 0 ]; @@ -172,7 +175,7 @@ describe( 'Navigating the block hierarchy', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); // Unselect the blocks - await page.click( '.editor-post-title' ); + await canvas().click( '.editor-post-title' ); // Try selecting the group block using the Outline await page.click( '[aria-label="Outline"]' ); @@ -184,7 +187,7 @@ describe( 'Navigating the block hierarchy', () => { await groupMenuItem.click(); // The group block's wrapper should be selected. - const isGroupBlockSelected = await page.evaluate( + const isGroupBlockSelected = await canvas().evaluate( () => document.activeElement.getAttribute( 'data-type' ) === 'core/group' diff --git a/packages/e2e-tests/specs/editor/various/block-mover.test.js b/packages/e2e-tests/specs/editor/various/block-mover.test.js index c3a04f6f3a6c4..b239b378f4aea 100644 --- a/packages/e2e-tests/specs/editor/various/block-mover.test.js +++ b/packages/e2e-tests/specs/editor/various/block-mover.test.js @@ -1,7 +1,11 @@ /** * WordPress dependencies */ -import { createNewPost, showBlockToolbar } from '@wordpress/e2e-test-utils'; +import { + createNewPost, + showBlockToolbar, + canvas, +} from '@wordpress/e2e-test-utils'; describe( 'block mover', () => { beforeEach( async () => { @@ -10,13 +14,13 @@ describe( 'block mover', () => { it( 'should show block mover when more than one block exists', async () => { // Create a two blocks on the page. - await page.click( '.block-editor-default-block-appender' ); + await canvas().click( '.block-editor-default-block-appender' ); await page.keyboard.type( 'First Paragraph' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'Second Paragraph' ); // Select a block so the block mover is rendered. - await page.focus( '.block-editor-block-list__block' ); + await canvas().focus( '.block-editor-block-list__block' ); await showBlockToolbar(); @@ -27,11 +31,11 @@ describe( 'block mover', () => { it( 'should hide block mover when only one block exists', async () => { // Create a single block on the page. - await page.click( '.block-editor-default-block-appender' ); + await canvas().click( '.block-editor-default-block-appender' ); await page.keyboard.type( 'First Paragraph' ); // Select a block so the block mover has the possibility of being rendered. - await page.focus( '.block-editor-block-list__block' ); + await canvas().focus( '.block-editor-block-list__block' ); await showBlockToolbar(); diff --git a/packages/e2e-tests/specs/editor/various/change-detection.test.js b/packages/e2e-tests/specs/editor/various/change-detection.test.js index 8bac378e8aaa1..e27c60e467345 100644 --- a/packages/e2e-tests/specs/editor/various/change-detection.test.js +++ b/packages/e2e-tests/specs/editor/various/change-detection.test.js @@ -10,6 +10,7 @@ import { saveDraft, openDocumentSettingsSidebar, isCurrentURL, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Change detection', () => { @@ -77,7 +78,7 @@ describe( 'Change detection', () => { } ); it( 'Should autosave post', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Force autosave to occur immediately. await Promise.all( [ @@ -93,7 +94,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt to confirm unsaved changes for autosaved draft for non-content fields', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Toggle post as needing review (not persisted for autosave). await ensureSidebarOpened(); @@ -116,7 +117,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt to confirm unsaved changes for autosaved published post', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await publishPost(); @@ -129,7 +130,7 @@ describe( 'Change detection', () => { ] ); // Should be dirty after autosave change of published post. - await page.type( '.editor-post-title__input', '!' ); + await canvas().type( '.editor-post-title__input', '!' ); await Promise.all( [ page.waitForSelector( '.editor-post-publish-button.is-busy' ), @@ -159,7 +160,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if property changed without save', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await assertIsDirty( true ); } ); @@ -172,7 +173,7 @@ describe( 'Change detection', () => { } ); it( 'Should not prompt if changes saved', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await saveDraft(); @@ -189,7 +190,7 @@ describe( 'Change detection', () => { } ); it( 'Should not save if all changes saved', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await saveDraft(); @@ -202,7 +203,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if save failed', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await page.setOfflineMode( true ); @@ -228,7 +229,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if changes and save is in-flight', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Hold the posts request so we don't deal with race conditions of the // save completing early. Other requests should be allowed to continue, @@ -244,7 +245,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if changes made while save is in-flight', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Hold the posts request so we don't deal with race conditions of the // save completing early. Other requests should be allowed to continue, @@ -254,7 +255,7 @@ describe( 'Change detection', () => { // Keyboard shortcut Ctrl+S save. await pressKeyWithModifier( 'primary', 'S' ); - await page.type( '.editor-post-title__input', '!' ); + await canvas().type( '.editor-post-title__input', '!' ); await page.waitForSelector( '.editor-post-save-draft' ); await releaseSaveIntercept(); @@ -263,7 +264,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if property changes made while save is in-flight, and save completes', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Hold the posts request so we don't deal with race conditions of the // save completing early. @@ -273,7 +274,7 @@ describe( 'Change detection', () => { await pressKeyWithModifier( 'primary', 'S' ); // Dirty post while save is in-flight. - await page.type( '.editor-post-title__input', '!' ); + await canvas().type( '.editor-post-title__input', '!' ); // Allow save to complete. Disabling interception flushes pending. await Promise.all( [ @@ -285,7 +286,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if block revision is made while save is in-flight, and save completes', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Hold the posts request so we don't deal with race conditions of the // save completing early. @@ -315,7 +316,7 @@ describe( 'Change detection', () => { await saveDraft(); // Verify that the title is empty. - const title = await page.$eval( + const title = await canvas().$eval( '.editor-post-title__input', ( element ) => element.innerHTML ); @@ -327,7 +328,7 @@ describe( 'Change detection', () => { it( 'should not prompt to confirm unsaved changes when trashing an existing post', async () => { // Enter title. - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Save await saveDraft(); @@ -371,12 +372,12 @@ describe( 'Change detection', () => { ] ); // Increase the paragraph's font size. - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.click( '.components-font-size-picker__select' ); await page.click( '.components-custom-select-control__item:nth-child(3)' ); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); // Check that the post is dirty. await page.waitForSelector( '.editor-post-save-draft' ); @@ -388,12 +389,12 @@ describe( 'Change detection', () => { ] ); // Increase the paragraph's font size again. - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.click( '.components-font-size-picker__select' ); await page.click( '.components-custom-select-control__item:nth-child(4)' ); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); // Check that the post is dirty. await page.waitForSelector( '.editor-post-save-draft' ); diff --git a/packages/e2e-tests/specs/editor/various/draggable-block.test.js b/packages/e2e-tests/specs/editor/various/draggable-block.test.js index 2d0ebc0bb8974..8e362ebc3e714 100644 --- a/packages/e2e-tests/specs/editor/various/draggable-block.test.js +++ b/packages/e2e-tests/specs/editor/various/draggable-block.test.js @@ -7,6 +7,7 @@ import { deactivatePlugin, activatePlugin, showBlockToolbar, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Draggable block', () => { @@ -59,37 +60,28 @@ describe( 'Draggable block', () => { await page.mouse.move( x + 10, y + 10, { steps: 10 } ); // Confirm dragged state. - await page.waitForSelector( '.block-editor-block-mover__drag-clone' ); - - const paragraph = await page.$( '[data-type="core/paragraph"]' ); - - const paragraphRect = await paragraph.boundingBox(); - const pX = paragraphRect.x + paragraphRect.width / 2; - const pY = paragraphRect.y + paragraphRect.height / 3; - - // Move over upper side of the first paragraph. - await page.mouse.move( pX, pY, { steps: 10 } ); + await page.waitForSelector( '.components-draggable__clone' ); // Puppeteer fires the initial `dragstart` event, but no further events. // Simulating the drop event works. - await paragraph.evaluate( - ( element, clientX, clientY ) => { - const dataTransfer = new DataTransfer(); - dataTransfer.setData( - 'text/plain', - JSON.stringify( window._dataTransfer ) - ); - const event = new DragEvent( 'drop', { - bubbles: true, - clientX, - clientY, - dataTransfer, - } ); - element.dispatchEvent( event ); - }, - pX, - pY - ); + await canvas().evaluate( () => { + const paragraph = document.querySelector( + '[data-type="core/paragraph"]' + ); + const paragraphRect = paragraph.getBoundingClientRect(); + const dataTransfer = new DataTransfer(); + dataTransfer.setData( + 'text/plain', + JSON.stringify( window.parent._dataTransfer ) + ); + const event = new DragEvent( 'drop', { + bubbles: true, + clientX: paragraphRect.x + paragraphRect.width / 2, + clientY: paragraphRect.y + paragraphRect.height / 3, + dataTransfer, + } ); + paragraph.dispatchEvent( event ); + } ); await page.mouse.up(); diff --git a/packages/e2e-tests/specs/editor/various/editor-modes.test.js b/packages/e2e-tests/specs/editor/various/editor-modes.test.js index 82e481ead2da2..3c343ebbdebb4 100644 --- a/packages/e2e-tests/specs/editor/various/editor-modes.test.js +++ b/packages/e2e-tests/specs/editor/various/editor-modes.test.js @@ -10,6 +10,7 @@ import { switchEditorModeTo, pressKeyTimes, pressKeyWithModifier, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Editing modes (visual/HTML)', () => { @@ -21,7 +22,7 @@ describe( 'Editing modes (visual/HTML)', () => { it( 'should switch between visual and HTML modes', async () => { // This block should be in "visual" mode by default. - let visualBlock = await page.$$( + let visualBlock = await canvas().$$( '.block-editor-block-list__layout .block-editor-block-list__block.rich-text' ); expect( visualBlock ).toHaveLength( 1 ); @@ -31,7 +32,7 @@ describe( 'Editing modes (visual/HTML)', () => { await clickMenuItem( 'Edit as HTML' ); // Wait for the block to be converted to HTML editing mode. - const htmlBlock = await page.$$( + const htmlBlock = await canvas().$$( '.block-editor-block-list__layout .block-editor-block-list__block .block-editor-block-list__block-html-textarea' ); expect( htmlBlock ).toHaveLength( 1 ); @@ -41,7 +42,7 @@ describe( 'Editing modes (visual/HTML)', () => { await clickMenuItem( 'Edit visually' ); // This block should be in "visual" mode by default. - visualBlock = await page.$$( + visualBlock = await canvas().$$( '.block-editor-block-list__layout .block-editor-block-list__block.rich-text' ); expect( visualBlock ).toHaveLength( 1 ); @@ -66,7 +67,7 @@ describe( 'Editing modes (visual/HTML)', () => { await clickMenuItem( 'Edit as HTML' ); // Make sure the paragraph content is rendered as expected. - let htmlBlockContent = await page.$eval( + let htmlBlockContent = await canvas().$eval( '.block-editor-block-list__layout .block-editor-block-list__block .block-editor-block-list__block-html-textarea', ( node ) => node.textContent ); @@ -82,7 +83,7 @@ describe( 'Editing modes (visual/HTML)', () => { ); // Make sure the HTML content updated. - htmlBlockContent = await page.$eval( + htmlBlockContent = await canvas().$eval( '.block-editor-block-list__layout .block-editor-block-list__block .block-editor-block-list__block-html-textarea', ( node ) => node.textContent ); diff --git a/packages/e2e-tests/specs/editor/various/embedding.test.js b/packages/e2e-tests/specs/editor/various/embedding.test.js index 170965215eceb..9b3d9304c982f 100644 --- a/packages/e2e-tests/specs/editor/various/embedding.test.js +++ b/packages/e2e-tests/specs/editor/various/embedding.test.js @@ -12,6 +12,7 @@ import { insertBlock, publishPost, setUpResponseMocking, + canvas, } from '@wordpress/e2e-test-utils'; const MOCK_EMBED_WORDPRESS_SUCCESS_RESPONSE = { @@ -171,24 +172,24 @@ describe( 'Embedding content', () => { it( 'should render embeds in the correct state', async () => { // Valid embed. Should render valid figure element. await insertEmbed( 'https://twitter.com/notnownikki' ); - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); // Valid provider; invalid content. Should render failed, edit state. await insertEmbed( 'https://twitter.com/wooyaygutenberg123454312' ); - await page.waitForSelector( + await canvas().waitForSelector( 'input[value="https://twitter.com/wooyaygutenberg123454312"]' ); // WordPress invalid content. Should render failed, edit state. await insertEmbed( 'https://wordpress.org/gutenberg/handbook/' ); - await page.waitForSelector( + await canvas().waitForSelector( 'input[value="https://wordpress.org/gutenberg/handbook/"]' ); // Provider whose oembed API has gone wrong. Should render failed, edit // state. await insertEmbed( 'https://twitter.com/thatbunty' ); - await page.waitForSelector( + await canvas().waitForSelector( 'input[value="https://twitter.com/thatbunty"]' ); @@ -197,12 +198,12 @@ describe( 'Embedding content', () => { await insertEmbed( 'https://wordpress.org/gutenberg/handbook/block-api/attributes/' ); - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); // Video content. Should render valid figure element, and include the // aspect ratio class. await insertEmbed( 'https://www.youtube.com/watch?v=lXMskKTw3Bc' ); - await page.waitForSelector( + await canvas().waitForSelector( 'figure.wp-block-embed.is-type-video.wp-embed-aspect-16-9' ); @@ -219,18 +220,18 @@ describe( 'Embedding content', () => { // has styles applied which depend on resize observer, wait for the // expected size class to settle before clicking, since otherwise a race // condition could occur on the placeholder layout vs. click intent. - await page.waitForSelector( + await canvas().waitForSelector( '.components-placeholder.is-large .components-placeholder__error' ); - await clickButton( 'Convert to link' ); + await clickButton( 'Convert to link', canvas() ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); it( 'should retry embeds that could not be embedded with trailing slashes, without the trailing slashes', async () => { await insertEmbed( 'https://twitter.com/notnownikki/' ); // The twitter block should appear correctly. - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); @@ -242,7 +243,7 @@ describe( 'Embedding content', () => { // has styles applied which depend on resize observer, wait for the // expected size class to settle before clicking, since otherwise a race // condition could occur on the placeholder layout vs. click intent. - await page.waitForSelector( + await canvas().waitForSelector( '.components-placeholder.is-large .components-placeholder__error' ); @@ -257,8 +258,8 @@ describe( 'Embedding content', () => { ), }, ] ); - await clickButton( 'Try again' ); - await page.waitForSelector( 'figure.wp-block-embed' ); + await clickButton( 'Try again', canvas() ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); @@ -281,6 +282,6 @@ describe( 'Embedding content', () => { await insertEmbed( postUrl ); // Check the block has become a WordPress block. - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); } ); } ); diff --git a/packages/e2e-tests/specs/editor/various/invalid-block.test.js b/packages/e2e-tests/specs/editor/various/invalid-block.test.js index 3313e819d752c..4be4e49c74be8 100644 --- a/packages/e2e-tests/specs/editor/various/invalid-block.test.js +++ b/packages/e2e-tests/specs/editor/various/invalid-block.test.js @@ -6,6 +6,7 @@ import { createNewPost, clickBlockAppender, clickBlockToolbarButton, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'invalid blocks', () => { @@ -24,7 +25,7 @@ describe( 'invalid blocks', () => { await clickMenuItem( 'Edit as HTML' ); // Focus on the textarea and enter an invalid paragraph - await page.click( + await canvas().click( '.block-editor-block-list__layout .block-editor-block-list__block .block-editor-block-list__block-html-textarea' ); await page.keyboard.type( '

invalid paragraph' ); @@ -35,7 +36,7 @@ describe( 'invalid blocks', () => { expect( console ).toHaveWarned(); // Click on the 'three-dots' menu toggle - await page.click( + await canvas().click( '.block-editor-warning__actions button[aria-label="More options"]' ); diff --git a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js index 2b092c9b46690..c6758c5a7dcd8 100644 --- a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js @@ -8,13 +8,24 @@ import { clickBlockAppender, getEditedPostContent, showBlockToolbar, + canvas, + clickButton, } from '@wordpress/e2e-test-utils'; async function getActiveLabel() { return await page.evaluate( () => { + function getActiveElement( { activeElement } ) { + if ( activeElement.nodeName === 'IFRAME' ) { + return getActiveElement( activeElement.contentDocument ); + } + return activeElement; + } + + const activeElement = getActiveElement( document ); + return ( - document.activeElement.getAttribute( 'aria-label' ) || - document.activeElement.innerHTML + activeElement.getAttribute( 'aria-label' ) || + activeElement.innerHTML ); } ); } @@ -23,6 +34,7 @@ const navigateToContentEditorTop = async () => { // Use 'Ctrl+`' to return to the top of the editor await pressKeyWithModifier( 'ctrl', '`' ); await pressKeyWithModifier( 'ctrl', '`' ); + await expect( await getActiveLabel() ).toBe( 'Editor content' ); }; const tabThroughParagraphBlock = async ( paragraphText ) => { @@ -34,7 +46,7 @@ const tabThroughParagraphBlock = async ( paragraphText ) => { await page.keyboard.press( 'Tab' ); await expect( await getActiveLabel() ).toBe( 'Paragraph block' ); await expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await canvas().evaluate( () => document.activeElement.innerHTML ) ).toBe( paragraphText ); await page.keyboard.press( 'Tab' ); @@ -109,13 +121,18 @@ describe( 'Order of block keyboard navigation', () => { } // Clear the selected block. - const paragraph = await page.$( '[data-type="core/paragraph"]' ); - const box = await paragraph.boundingBox(); - await page.mouse.click( box.x - 1, box.y ); + await clickButton( 'Document' ); + + // Put focus in front of the block list. + await page.evaluate( () => { + document + .querySelector( '.interface-interface-skeleton__content' ) + .focus(); + } ); await page.keyboard.press( 'Tab' ); await expect( - await page.evaluate( () => { + await canvas().evaluate( () => { return document.activeElement.placeholder; } ) ).toBe( 'Add title' ); @@ -144,9 +161,7 @@ describe( 'Order of block keyboard navigation', () => { } // Clear the selected block. - const paragraph = await page.$( '[data-type="core/paragraph"]' ); - const box = await paragraph.boundingBox(); - await page.mouse.click( box.x - 1, box.y ); + await clickButton( 'Document' ); // Put focus behind the block list. await page.evaluate( () => { @@ -167,10 +182,13 @@ describe( 'Order of block keyboard navigation', () => { await pressKeyWithModifier( 'shift', 'Tab' ); await expect( - await page.evaluate( () => { + await canvas().evaluate( () => { return document.activeElement.placeholder; } ) ).toBe( 'Add title' ); + + await pressKeyWithModifier( 'shift', 'Tab' ); + await expect( await getActiveLabel() ).toBe( 'Options' ); } ); it( 'should navigate correctly with multi selection', async () => { diff --git a/packages/e2e-tests/specs/editor/various/links.test.js b/packages/e2e-tests/specs/editor/various/links.test.js index 21c50094a0d1f..481e4dbecb567 100644 --- a/packages/e2e-tests/specs/editor/various/links.test.js +++ b/packages/e2e-tests/specs/editor/various/links.test.js @@ -8,6 +8,7 @@ import { createNewPost, pressKeyWithModifier, showBlockToolbar, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Links', () => { @@ -49,7 +50,7 @@ describe( 'Links', () => { await page.keyboard.press( 'Enter' ); - const actualText = await page.evaluate( + const actualText = await canvas().evaluate( () => document.querySelector( '.block-editor-rich-text__editable a' ) .textContent @@ -182,7 +183,7 @@ describe( 'Links', () => { await page.keyboard.type( 'https://wordpress.org/gutenberg' ); // Click somewhere else - it doesn't really matter where - await page.click( '.editor-post-title' ); + await canvas().click( '.editor-post-title' ); } ); const createAndReselectLink = async () => { @@ -312,7 +313,7 @@ describe( 'Links', () => { const createPostWithTitle = async ( titleText ) => { await createNewPost(); - await page.type( '.editor-post-title__input', titleText ); + await canvas().type( '.editor-post-title__input', titleText ); await page.click( '.editor-post-publish-panel__toggle' ); // Disable reason: Wait for the animation to complete, since otherwise the @@ -510,7 +511,7 @@ describe( 'Links', () => { await page.keyboard.press( 'Enter' ); // Wait for Gutenberg to finish the job. - await page.waitForXPath( + await canvas().waitForXPath( '//a[contains(@href,"w.org") and @target="_blank"]' ); @@ -551,7 +552,7 @@ describe( 'Links', () => { await page.keyboard.press( 'Space' ); // Wait for Gutenberg to finish the job. - await page.waitForXPath( + await canvas().waitForXPath( '//a[contains(@href,"wordpress.org") and not(@target)]' ); diff --git a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js index bfa098f7f4240..9bb642a0cfbf0 100644 --- a/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js +++ b/packages/e2e-tests/specs/editor/various/multi-block-selection.test.js @@ -9,10 +9,11 @@ import { getEditedPostContent, clickBlockToolbarButton, clickButton, + canvas, } from '@wordpress/e2e-test-utils'; async function getSelectedFlatIndices() { - return await page.evaluate( () => { + return await canvas().evaluate( () => { const indices = []; let single; @@ -38,7 +39,7 @@ async function getSelectedFlatIndices() { async function testNativeSelection() { // Wait for the selection to update. await page.evaluate( () => new Promise( window.requestAnimationFrame ) ); - await page.evaluate( () => { + await canvas().evaluate( () => { const selection = window.getSelection(); const elements = Array.from( document.querySelectorAll( '.is-multi-selected' ) @@ -263,7 +264,7 @@ describe( 'Multi-block selection', () => { await page.keyboard.press( 'Enter' ); await page.keyboard.type( '2' ); await page.keyboard.down( 'Shift' ); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.keyboard.up( 'Shift' ); await testNativeSelection(); @@ -277,20 +278,21 @@ describe( 'Multi-block selection', () => { await page.keyboard.type( '2' ); await page.keyboard.press( 'ArrowUp' ); - const [ coord1, coord2 ] = await page.evaluate( () => { + const [ coord1, coord2 ] = await canvas().evaluate( () => { const elements = Array.from( document.querySelectorAll( '[data-type="core/paragraph"]' ) ); const rect1 = elements[ 0 ].getBoundingClientRect(); const rect2 = elements[ 1 ].getBoundingClientRect(); + const winRect = window.frameElement.getBoundingClientRect(); return [ { - x: rect1.x + rect1.width / 2, - y: rect1.y + rect1.height / 2, + x: winRect.x + rect1.x + rect1.width / 2, + y: winRect.y + rect1.y + rect1.height / 2, }, { - x: rect2.x + rect2.width / 2, - y: rect2.y + rect2.height / 2, + x: winRect.x + rect2.x + rect2.width / 2, + y: winRect.y + rect2.y + rect2.height / 2, }, ]; } ); @@ -314,7 +316,7 @@ describe( 'Multi-block selection', () => { ); await page.keyboard.press( 'Enter' ); - const groupAppender = await page.waitForSelector( + const groupAppender = await canvas().waitForSelector( '.block-editor-button-block-appender' ); await groupAppender.click(); @@ -326,21 +328,22 @@ describe( 'Multi-block selection', () => { await page.keyboard.type( '2' ); - const [ coord1, coord2 ] = await page.evaluate( () => { + const [ coord1, coord2 ] = await canvas().evaluate( () => { const elements = Array.from( document.querySelectorAll( '[data-type="core/paragraph"]' ) ); + elements[ 0 ].scrollIntoView(); const rect1 = elements[ 0 ].getBoundingClientRect(); const rect2 = elements[ 1 ].getBoundingClientRect(); - + const winRect = window.frameElement.getBoundingClientRect(); return [ { - x: rect1.x + rect1.width / 2, - y: rect1.y + rect1.height / 2, + x: winRect.x + rect1.x + rect1.width / 2, + y: winRect.y + rect1.y + rect1.height / 2, }, { - x: rect2.x + rect2.width / 2, - y: rect2.y + rect2.height / 2, + x: winRect.x + rect2.x + rect2.width / 2, + y: winRect.y + rect2.y + rect2.height / 2, }, ]; } ); @@ -396,7 +399,7 @@ describe( 'Multi-block selection', () => { await page.keyboard.type( '2' ); await page.keyboard.press( 'ArrowLeft' ); - const [ coord1, coord2 ] = await page.evaluate( () => { + const [ coord1, coord2 ] = await canvas().evaluate( () => { const selection = window.getSelection(); if ( ! selection.rangeCount ) { @@ -409,16 +412,17 @@ describe( 'Multi-block selection', () => { '[data-type="core/paragraph"]' ); const rect2 = element.getBoundingClientRect(); + const winRect = window.frameElement.getBoundingClientRect(); return [ { - x: rect1.x, - y: rect1.y + rect1.height / 2, + x: winRect.x + rect1.x, + y: winRect.y + rect1.y + rect1.height / 2, }, { // Move a bit outside the paragraph. - x: rect2.x - 10, - y: rect2.y + rect2.height / 2, + x: winRect.x + rect2.x - 10, + y: winRect.y + rect2.y + rect2.height / 2, }, ]; } ); @@ -447,20 +451,21 @@ describe( 'Multi-block selection', () => { await page.keyboard.press( 'Enter' ); await page.keyboard.type( '3' ); - const [ coord1, coord2 ] = await page.evaluate( () => { + const [ coord1, coord2 ] = await canvas().evaluate( () => { const elements = Array.from( document.querySelectorAll( '[data-type="core/paragraph"]' ) ); const rect1 = elements[ 2 ].getBoundingClientRect(); const rect2 = elements[ 1 ].getBoundingClientRect(); + const winRect = window.frameElement.getBoundingClientRect(); return [ { - x: rect1.x + rect1.width / 2, - y: rect1.y + rect1.height / 2, + x: winRect.x + rect1.x + rect1.width / 2, + y: winRect.y + rect1.y + rect1.height / 2, }, { - x: rect2.x + rect2.width / 2, - y: rect2.y + rect2.height / 2, + x: winRect.x + rect2.x + rect2.width / 2, + y: winRect.y + rect2.y + rect2.height / 2, }, ]; } ); @@ -491,14 +496,15 @@ describe( 'Multi-block selection', () => { await testNativeSelection(); expect( await getSelectedFlatIndices() ).toEqual( [ 1, 2 ] ); - const coord = await page.evaluate( () => { + const coord = await canvas().evaluate( () => { const element = document.querySelector( '[data-type="core/paragraph"]' ); const rect = element.getBoundingClientRect(); + const winRect = window.frameElement.getBoundingClientRect(); return { - x: rect.x - 1, - y: rect.y + rect.height / 2, + x: winRect.x + rect.x - 1, + y: winRect.y + rect.y + rect.height / 2, }; } ); diff --git a/packages/e2e-tests/specs/editor/various/navigable-toolbar.test.js b/packages/e2e-tests/specs/editor/various/navigable-toolbar.test.js index e108828c31e63..d50807177427e 100644 --- a/packages/e2e-tests/specs/editor/various/navigable-toolbar.test.js +++ b/packages/e2e-tests/specs/editor/various/navigable-toolbar.test.js @@ -1,7 +1,11 @@ /** * WordPress dependencies */ -import { createNewPost, pressKeyWithModifier } from '@wordpress/e2e-test-utils'; +import { + createNewPost, + pressKeyWithModifier, + canvas, +} from '@wordpress/e2e-test-utils'; describe.each( [ [ 'unified', true ], @@ -49,32 +53,21 @@ describe.each( [ if ( ! isUnifiedToolbar ) { it( 'should not scroll page', async () => { - while ( - await page.evaluate( () => { - const scrollable = wp.dom.getScrollContainer( - document.activeElement - ); - return ! scrollable || scrollable.scrollTop === 0; - } ) - ) { + while ( await canvas().evaluate( () => window.scrollY === 0 ) ) { await page.keyboard.press( 'Enter' ); } await page.keyboard.type( 'a' ); - const scrollTopBefore = await page.evaluate( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop + const scrollTopBefore = await canvas().evaluate( + () => window.scrollY ); await pressKeyWithModifier( 'alt', 'F10' ); expect( await isInBlockToolbar() ).toBe( true ); - const scrollTopAfter = await page.evaluate( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop + const scrollTopAfter = await canvas().evaluate( + () => window.scrollY ); expect( scrollTopBefore ).toBe( scrollTopAfter ); diff --git a/packages/e2e-tests/specs/editor/various/new-post-default-content.test.js b/packages/e2e-tests/specs/editor/various/new-post-default-content.test.js index 4c917f265eaf3..857f1b7a5dfd6 100644 --- a/packages/e2e-tests/specs/editor/various/new-post-default-content.test.js +++ b/packages/e2e-tests/specs/editor/various/new-post-default-content.test.js @@ -8,6 +8,8 @@ import { findSidebarPanelToggleButtonWithTitle, getEditedPostContent, openDocumentSettingsSidebar, + canvas, + clickButton, } from '@wordpress/e2e-test-utils'; describe( 'new editor filtered state', () => { @@ -25,7 +27,7 @@ describe( 'new editor filtered state', () => { it( 'should respect default content', async () => { // get the values that should have their defaults changed. - const title = await page.$eval( + const title = await canvas().$eval( '.editor-post-title__input', ( element ) => element.innerHTML ); @@ -33,6 +35,7 @@ describe( 'new editor filtered state', () => { // open the sidebar, we want to see the excerpt. await openDocumentSettingsSidebar(); + await clickButton( 'Post' ); const excerptButton = await findSidebarPanelToggleButtonWithTitle( 'Excerpt' ); diff --git a/packages/e2e-tests/specs/editor/various/new-post.test.js b/packages/e2e-tests/specs/editor/various/new-post.test.js index e8baff2d573fb..a24fc390d21b4 100644 --- a/packages/e2e-tests/specs/editor/various/new-post.test.js +++ b/packages/e2e-tests/specs/editor/various/new-post.test.js @@ -5,6 +5,7 @@ import { activatePlugin, createNewPost, deactivatePlugin, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'new editor state', () => { @@ -25,7 +26,7 @@ describe( 'new editor state', () => { expect.stringContaining( 'post-new.php' ) ); // Should display the blank title. - const title = await page.$( '[placeholder="Add title"]' ); + const title = await canvas().$( '[placeholder="Add title"]' ); expect( title ).not.toBeNull(); expect( title.innerHTML ).toBeFalsy(); // Should display the Preview button. @@ -51,10 +52,10 @@ describe( 'new editor state', () => { } ); it( 'should focus the title if the title is empty', async () => { - const activeElementClasses = await page.evaluate( () => { + const activeElementClasses = await canvas().evaluate( () => { return Object.values( document.activeElement.classList ); } ); - const activeElementTagName = await page.evaluate( () => { + const activeElementTagName = await canvas().evaluate( () => { return document.activeElement.tagName.toLowerCase(); } ); @@ -64,7 +65,7 @@ describe( 'new editor state', () => { it( 'should not focus the title if the title exists', async () => { // Enter a title for this post. - await page.type( '.editor-post-title__input', 'Here is the title' ); + await canvas().type( '.editor-post-title__input', 'Here is the title' ); // Save the post as a draft. await page.click( '.editor-post-save-draft' ); await page.waitForSelector( '.editor-post-saved-state.is-saved' ); @@ -72,10 +73,10 @@ describe( 'new editor state', () => { await page.reload(); await page.waitForSelector( '.edit-post-layout' ); - const activeElementClasses = await page.evaluate( () => { + const activeElementClasses = await canvas().evaluate( () => { return Object.values( document.activeElement.classList ); } ); - const activeElementTagName = await page.evaluate( () => { + const activeElementTagName = await canvas().evaluate( () => { return document.activeElement.tagName.toLowerCase(); } ); diff --git a/packages/e2e-tests/specs/editor/various/post-visibility.test.js b/packages/e2e-tests/specs/editor/various/post-visibility.test.js index 6844b9bd97345..84ef7ce75af32 100644 --- a/packages/e2e-tests/specs/editor/various/post-visibility.test.js +++ b/packages/e2e-tests/specs/editor/various/post-visibility.test.js @@ -5,6 +5,7 @@ import { setBrowserViewport, createNewPost, openDocumentSettingsSidebar, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Post visibility', () => { @@ -40,7 +41,7 @@ describe( 'Post visibility', () => { await createNewPost(); // Enter a title for this post. - await page.type( '.editor-post-title__input', 'Title' ); + await canvas().type( '.editor-post-title__input', 'Title' ); await openDocumentSettingsSidebar(); @@ -61,7 +62,7 @@ describe( 'Post visibility', () => { await privateLabel.click(); // Enter a title for this post. - await page.type( '.editor-post-title__input', ' Changed' ); + await canvas().type( '.editor-post-title__input', ' Changed' ); // Wait for the button to be clickable before attempting to click. // This could cause errors when we try to click before changes are registered. diff --git a/packages/e2e-tests/specs/editor/various/preview.test.js b/packages/e2e-tests/specs/editor/various/preview.test.js index d0996211a512c..d2761365c30d3 100644 --- a/packages/e2e-tests/specs/editor/various/preview.test.js +++ b/packages/e2e-tests/specs/editor/various/preview.test.js @@ -11,6 +11,7 @@ import { publishPost, saveDraft, openPreviewPage, + canvas, } from '@wordpress/e2e-test-utils'; /** @typedef {import('puppeteer').Page} Page */ @@ -95,7 +96,7 @@ describe( 'Preview', () => { ); expect( isPreviewDisabled ).toBe( true ); - await editorPage.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); const previewPage = await openPreviewPage( editorPage ); await previewPage.waitForSelector( '.entry-title' ); @@ -123,7 +124,7 @@ describe( 'Preview', () => { // Return to editor to change title. await editorPage.bringToFront(); - await editorPage.type( '.editor-post-title__input', '!' ); + await canvas().type( '.editor-post-title__input', '!' ); await waitForPreviewDropdownOpen( editorPage ); await waitForPreviewNavigation( previewPage ); @@ -150,7 +151,7 @@ describe( 'Preview', () => { // Return to editor to change title. await editorPage.bringToFront(); - await editorPage.type( '.editor-post-title__input', ' And more.' ); + await canvas().type( '.editor-post-title__input', ' And more.' ); await waitForPreviewDropdownOpen( editorPage ); await waitForPreviewNavigation( previewPage ); @@ -189,7 +190,7 @@ describe( 'Preview', () => { const editorPage = page; // Type aaaaa in the title filed. - await editorPage.type( '.editor-post-title__input', 'aaaaa' ); + await canvas().type( '.editor-post-title__input', 'aaaaa' ); await editorPage.keyboard.press( 'Tab' ); // Save the post as a draft. @@ -211,7 +212,7 @@ describe( 'Preview', () => { await editorPage.bringToFront(); // Append bbbbb to the title, and tab away from the title so blur event is triggered. - await editorPage.type( '.editor-post-title__input', 'bbbbb' ); + await canvas().type( '.editor-post-title__input', 'bbbbb' ); await editorPage.keyboard.press( 'Tab' ); // Save draft and open the preview page right after. @@ -246,9 +247,9 @@ describe( 'Preview with Custom Fields enabled', () => { const editorPage = page; // Make sure input is mounted in editor before adding content. - await editorPage.waitForSelector( '.editor-post-title__input' ); + await canvas().waitForSelector( '.editor-post-title__input' ); // Add an initial title and content. - await editorPage.type( '.editor-post-title__input', 'title 1' ); + await canvas().type( '.editor-post-title__input', 'title 1' ); await editorPage.keyboard.press( 'Tab' ); await editorPage.keyboard.type( 'content 1' ); @@ -275,7 +276,7 @@ describe( 'Preview with Custom Fields enabled', () => { // Return to editor and modify the title and content. await editorPage.bringToFront(); - await editorPage.click( '.editor-post-title__input' ); + await canvas().click( '.editor-post-title__input' ); await editorPage.keyboard.press( 'End' ); await editorPage.keyboard.press( 'Backspace' ); await editorPage.keyboard.type( '2' ); @@ -318,7 +319,7 @@ describe( 'Preview with private custom post type', () => { await createNewPost( { postType: 'not_public' } ); // Type in the title filed. - await page.type( '.editor-post-title__input', 'aaaaa' ); + await canvas().type( '.editor-post-title__input', 'aaaaa' ); await page.keyboard.press( 'Tab' ); // Open the preview menu. diff --git a/packages/e2e-tests/specs/editor/various/publish-button.test.js b/packages/e2e-tests/specs/editor/various/publish-button.test.js index d9396b7f48c38..26e6cdb0532fc 100644 --- a/packages/e2e-tests/specs/editor/various/publish-button.test.js +++ b/packages/e2e-tests/specs/editor/various/publish-button.test.js @@ -6,6 +6,7 @@ import { disablePrePublishChecks, enablePrePublishChecks, createNewPost, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'PostPublishButton', () => { @@ -32,7 +33,7 @@ describe( 'PostPublishButton', () => { } ); it( 'should be disabled when post is being saved', async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); // Make it saveable + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); // Make it saveable expect( await page.$( '.editor-post-publish-button[aria-disabled="true"]' ) ).toBeNull(); @@ -44,7 +45,7 @@ describe( 'PostPublishButton', () => { } ); it( 'should be disabled when metabox is being saved', async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); // Make it saveable + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); // Make it saveable expect( await page.$( '.editor-post-publish-button[aria-disabled="true"]' ) ).toBeNull(); diff --git a/packages/e2e-tests/specs/editor/various/publish-panel.test.js b/packages/e2e-tests/specs/editor/various/publish-panel.test.js index 3a6aefd8f6687..333f2f1c2a8b3 100644 --- a/packages/e2e-tests/specs/editor/various/publish-panel.test.js +++ b/packages/e2e-tests/specs/editor/various/publish-panel.test.js @@ -9,6 +9,7 @@ import { openPublishPanel, pressKeyWithModifier, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'PostPublishPanel', () => { @@ -28,7 +29,7 @@ describe( 'PostPublishPanel', () => { } ); it( 'PrePublish: publish button should have the focus', async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); await openPublishPanel(); const focusedElementClassList = await page.$eval( @@ -44,7 +45,7 @@ describe( 'PostPublishPanel', () => { it( 'PostPublish: post link should have the focus', async () => { const postTitle = 'E2E Test Post'; - await page.type( '.editor-post-title__input', postTitle ); + await canvas().type( '.editor-post-title__input', postTitle ); await publishPost(); const focusedElementTag = await page.$eval( @@ -64,7 +65,7 @@ describe( 'PostPublishPanel', () => { } ); it( 'should retain focus within the panel', async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); await openPublishPanel(); await pressKeyWithModifier( 'shift', 'Tab' ); diff --git a/packages/e2e-tests/specs/editor/various/publishing.test.js b/packages/e2e-tests/specs/editor/various/publishing.test.js index 745008a0a15f1..b86a06c50118b 100644 --- a/packages/e2e-tests/specs/editor/various/publishing.test.js +++ b/packages/e2e-tests/specs/editor/various/publishing.test.js @@ -9,6 +9,7 @@ import { disablePrePublishChecks, arePrePublishChecksEnabled, setBrowserViewport, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Publishing', () => { @@ -30,7 +31,7 @@ describe( 'Publishing', () => { } ); it( `should publish the ${ postType } and close the panel once we start editing again.`, async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); await publishPost(); @@ -40,7 +41,7 @@ describe( 'Publishing', () => { ).not.toBeNull(); // Start editing again. - await page.type( '.editor-post-title__input', ' (Updated)' ); + await canvas().type( '.editor-post-title__input', ' (Updated)' ); // The post-publishing panel is not visible anymore. expect( await page.$( '.editor-post-publish-panel' ) ).toBeNull(); @@ -67,7 +68,10 @@ describe( 'Publishing', () => { } ); it( `should publish the ${ postType } without opening the post-publish sidebar.`, async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); + await canvas().type( + '.editor-post-title__input', + 'E2E Test Post' + ); // The "Publish" button should be shown instead of the "Publish..." toggle expect( diff --git a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js index 0d7c6d8baf236..e438a722ce71a 100644 --- a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js @@ -12,6 +12,7 @@ import { trashAllPosts, visitAdminPage, toggleGlobalBlockInserter, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Reusable blocks', () => { @@ -44,7 +45,7 @@ describe( 'Reusable blocks', () => { await page.waitForXPath( '//*[contains(@class, "components-snackbar")]/*[text()="Block created."]' ); - await page.waitForXPath( + await canvas().waitForXPath( '//*[@class="block-library-block__reusable-block-container"]' ); @@ -55,24 +56,20 @@ describe( 'Reusable blocks', () => { await page.keyboard.type( 'Greeting block' ); // Save the reusable block - const [ saveButton ] = await page.$x( '//button[text()="Save"]' ); + const [ saveButton ] = await canvas().$x( '//button[text()="Save"]' ); await saveButton.click(); // Wait for saving to finish - await page.waitForXPath( '//button[text()="Edit"]' ); + await canvas().waitForXPath( '//button[text()="Edit"]' ); // Check that we have a reusable block on the page - const block = await page.$( + const block = await canvas().$( '.block-editor-block-list__block[data-type="core/block"]' ); expect( block ).not.toBeNull(); // Check that its title is displayed - const title = await page.$eval( - '.reusable-block-edit-panel__info', - ( element ) => element.innerText - ); - expect( title ).toBe( 'Greeting block' ); + await canvas().waitForXPath( '//b[text()="Greeting block"]' ); } ); it( 'can be created with no title', async () => { @@ -87,29 +84,25 @@ describe( 'Reusable blocks', () => { await page.waitForXPath( '//*[contains(@class, "components-snackbar")]/*[text()="Block created."]' ); - await page.waitForXPath( + await canvas().waitForXPath( '//*[@class="block-library-block__reusable-block-container"]' ); // Save the reusable block - const [ saveButton ] = await page.$x( '//button[text()="Save"]' ); + const [ saveButton ] = await canvas().$x( '//button[text()="Save"]' ); await saveButton.click(); // Wait for saving to finish - await page.waitForXPath( '//button[text()="Edit"]' ); + await canvas().waitForXPath( '//button[text()="Edit"]' ); // Check that we have a reusable block on the page - const block = await page.$( + const block = await canvas().$( '.block-editor-block-list__block[data-type="core/block"]' ); expect( block ).not.toBeNull(); // Check that it is untitled - const title = await page.$eval( - '.reusable-block-edit-panel__info', - ( element ) => element.innerText - ); - expect( title ).toBe( 'Untitled Reusable Block' ); + await canvas().waitForXPath( '//b[text()="Untitled Reusable Block"]' ); } ); it( 'can be inserted and edited', async () => { @@ -117,9 +110,10 @@ describe( 'Reusable blocks', () => { await insertReusableBlock( 'Greeting block' ); // Put the reusable block in edit mode - const editButton = await page.waitForXPath( + const editButton = await canvas().waitForXPath( '//button[text()="Edit" and not(@disabled)]' ); + await editButton.click(); // Change the block's title @@ -137,27 +131,23 @@ describe( 'Reusable blocks', () => { await page.keyboard.type( 'Oh! ' ); // Save the reusable block - const [ saveButton ] = await page.$x( '//button[text()="Save"]' ); + const [ saveButton ] = await canvas().$x( '//button[text()="Save"]' ); await saveButton.click(); // Wait for saving to finish - await page.waitForXPath( '//button[text()="Edit"]' ); + await canvas().waitForXPath( '//button[text()="Edit"]' ); // Check that we have a reusable block on the page - const block = await page.$( + const block = await canvas().$( '.block-editor-block-list__block[data-type="core/block"]' ); expect( block ).not.toBeNull(); // Check that its title is displayed - const title = await page.$eval( - '.reusable-block-edit-panel__info', - ( element ) => element.innerText - ); - expect( title ).toBe( 'Surprised greeting block' ); + await canvas().waitForXPath( '//b[text()="Surprised greeting block"]' ); // Check that its content is up to date - const text = await page.$eval( + const text = await canvas().$eval( '.block-editor-block-list__block[data-type="core/block"] p', ( element ) => element.innerText ); @@ -177,7 +167,7 @@ describe( 'Reusable blocks', () => { await page.waitForXPath( '//*[contains(@class, "components-snackbar")]/*[text()="Block created."]' ); - await page.waitForXPath( + await canvas().waitForXPath( '//*[@class="block-library-block__reusable-block-container"]' ); @@ -188,7 +178,7 @@ describe( 'Reusable blocks', () => { await page.keyboard.type( 'Awesome block' ); // Save the reusable block - const [ saveButton ] = await page.$x( '//button[text()="Save"]' ); + const [ saveButton ] = await canvas().$x( '//button[text()="Save"]' ); await saveButton.click(); // Step 2. Create new post. @@ -200,17 +190,13 @@ describe( 'Reusable blocks', () => { await insertReusableBlock( 'Awesome block' ); // Check that we have a reusable block on the page - const block = await page.$( + const block = await canvas().$( '.block-editor-block-list__block[data-type="core/block"]' ); expect( block ).not.toBeNull(); // Check that its title is displayed - const title = await page.$eval( - '.reusable-block-edit-panel__info', - ( element ) => element.innerText - ); - expect( title ).toBe( 'Awesome block' ); + await canvas().waitForXPath( '//b[text()="Awesome block"]' ); } ); it( 'can be converted to a regular block', async () => { @@ -221,13 +207,13 @@ describe( 'Reusable blocks', () => { await clickBlockToolbarButton( 'Convert to regular blocks', 'content' ); // Check that we have a paragraph block on the page - const block = await page.$( + const block = await canvas().$( '.block-editor-block-list__block[data-type="core/paragraph"]' ); expect( block ).not.toBeNull(); // Check that its content is up to date - const text = await page.$eval( + const text = await canvas().$eval( '.block-editor-block-list__block[data-type="core/paragraph"]', ( element ) => element.innerText ); @@ -255,7 +241,7 @@ describe( 'Reusable blocks', () => { await page.waitForXPath( '//*[contains(@class, "components-snackbar")]/*[text()="Block created."]' ); - await page.waitForXPath( + await canvas().waitForXPath( '//*[@class="block-library-block__reusable-block-container"]' ); @@ -266,24 +252,22 @@ describe( 'Reusable blocks', () => { await page.keyboard.type( 'Multi-selection reusable block' ); // Save the reusable block - const [ saveButton ] = await page.$x( '//button[text()="Save"]' ); + const [ saveButton ] = await canvas().$x( '//button[text()="Save"]' ); await saveButton.click(); // Wait for saving to finish - await page.waitForXPath( '//button[text()="Edit"]' ); + await canvas().waitForXPath( '//button[text()="Edit"]' ); // Check that we have a reusable block on the page - const block = await page.$( + const block = await canvas().$( '.block-editor-block-list__block[data-type="core/block"]' ); expect( block ).not.toBeNull(); // Check that its title is displayed - const title = await page.$eval( - '.reusable-block-edit-panel__info', - ( element ) => element.innerText + await canvas().waitForXPath( + '//b[text()="Multi-selection reusable block"]' ); - expect( title ).toBe( 'Multi-selection reusable block' ); } ); it( 'multi-selection reusable block can be converted back to regular blocks', async () => { @@ -309,10 +293,12 @@ describe( 'Reusable blocks', () => { await page.waitForNavigation(); + await page.waitForSelector( 'iframe[title="Editor canvas"]' ); + // Click the block to give it focus const blockSelector = 'p[data-title="Paragraph"]'; - await page.waitForSelector( blockSelector ); - await page.click( blockSelector ); + await canvas().waitForSelector( blockSelector ); + await canvas().click( blockSelector ); // Delete the block, leaving the reusable block empty await clickBlockToolbarButton( 'More options' ); diff --git a/packages/e2e-tests/specs/editor/various/rich-text.test.js b/packages/e2e-tests/specs/editor/various/rich-text.test.js index 17e064b7c5852..eda4c58d9b700 100644 --- a/packages/e2e-tests/specs/editor/various/rich-text.test.js +++ b/packages/e2e-tests/specs/editor/various/rich-text.test.js @@ -8,6 +8,7 @@ import { clickBlockAppender, pressKeyWithModifier, showBlockToolbar, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'RichText', () => { @@ -73,7 +74,7 @@ describe( 'RichText', () => { await pressKeyWithModifier( 'shift', 'ArrowLeft' ); await pressKeyWithModifier( 'primary', 'b' ); - const count = await page.evaluate( + const count = await canvas().evaluate( () => document.querySelectorAll( '*[data-rich-text-format-boundary]' ) .length @@ -155,7 +156,7 @@ describe( 'RichText', () => { await pressKeyWithModifier( 'primary', 'b' ); await page.keyboard.type( '3' ); - await page.evaluate( () => { + await canvas().evaluate( () => { let called; const { body } = document; const config = { @@ -215,7 +216,7 @@ describe( 'RichText', () => { await page.keyboard.type( '4' ); - await page.evaluate( () => { + await canvas().evaluate( () => { // The selection change event should be called once. If there's only // one item in `window.unsubscribes`, it means that only one // function is present to disconnect the `mutationObserver`. @@ -256,7 +257,7 @@ describe( 'RichText', () => { await page.keyboard.press( 'Enter' ); // Wait for rich text editor to load. - await page.waitForSelector( '.block-editor-rich-text__editable' ); + await canvas().waitForSelector( '.block-editor-rich-text__editable' ); await pressKeyWithModifier( 'primary', 'b' ); await page.keyboard.type( '12' ); @@ -288,7 +289,14 @@ describe( 'RichText', () => { // Simulate moving focus to a different app, then moving focus back, // without selection being changed. await page.evaluate( () => { - const activeElement = document.activeElement; + function getActiveElement( { activeElement } ) { + if ( activeElement.nodeName === 'IFRAME' ) { + return getActiveElement( activeElement.contentDocument ); + } + return activeElement; + } + + const activeElement = getActiveElement( document ); activeElement.blur(); activeElement.focus(); } ); diff --git a/packages/e2e-tests/specs/editor/various/rtl.test.js b/packages/e2e-tests/specs/editor/various/rtl.test.js index 67f66ee77cc63..8667a65384127 100644 --- a/packages/e2e-tests/specs/editor/various/rtl.test.js +++ b/packages/e2e-tests/specs/editor/various/rtl.test.js @@ -5,6 +5,7 @@ import { createNewPost, getEditedPostContent, pressKeyWithModifier, + canvas, } from '@wordpress/e2e-test-utils'; // Avoid using three, as it looks too much like two with some fonts. @@ -15,7 +16,7 @@ const ARABIC_TWO = '٢'; describe( 'RTL', () => { beforeEach( async () => { await createNewPost(); - await page.evaluate( () => { + await canvas().evaluate( () => { document.querySelector( '.is-root-container' ).dir = 'rtl'; } ); } ); @@ -102,7 +103,7 @@ describe( 'RTL', () => { await page.keyboard.press( 'Enter' ); // Wait for rich text editor to load. - await page.waitForSelector( '.block-editor-rich-text__editable' ); + await canvas().waitForSelector( '.block-editor-rich-text__editable' ); await pressKeyWithModifier( 'primary', 'b' ); await page.keyboard.type( ARABIC_ONE ); diff --git a/packages/e2e-tests/specs/editor/various/sidebar-permalink-panel.test.js b/packages/e2e-tests/specs/editor/various/sidebar-permalink-panel.test.js index 35b51001788cd..075325966bce5 100644 --- a/packages/e2e-tests/specs/editor/various/sidebar-permalink-panel.test.js +++ b/packages/e2e-tests/specs/editor/various/sidebar-permalink-panel.test.js @@ -7,6 +7,7 @@ import { deactivatePlugin, findSidebarPanelWithTitle, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; const permalinkPanelXPath = `//div[contains(@class, "edit-post-sidebar")]//button[contains(@class, "components-panel__body-toggle") and contains(text(),"Permalink")]`; @@ -38,7 +39,7 @@ describe( 'Sidebar Permalink Panel', () => { await page.keyboard.type( 'aaaaa' ); await publishPost(); // Start editing again. - await page.type( '.editor-post-title__input', ' (Updated)' ); + await canvas().type( '.editor-post-title__input', ' (Updated)' ); expect( await page.$x( permalinkPanelXPath ) ).toEqual( [] ); } ); @@ -47,7 +48,7 @@ describe( 'Sidebar Permalink Panel', () => { await page.keyboard.type( 'aaaaa' ); await publishPost(); // Start editing again. - await page.type( '.editor-post-title__input', ' (Updated)' ); + await canvas().type( '.editor-post-title__input', ' (Updated)' ); expect( await page.$x( permalinkPanelXPath ) ).toEqual( [] ); } ); @@ -56,7 +57,7 @@ describe( 'Sidebar Permalink Panel', () => { await page.keyboard.type( 'aaaaa' ); await publishPost(); // Start editing again. - await page.type( '.editor-post-title__input', ' (Updated)' ); + await canvas().type( '.editor-post-title__input', ' (Updated)' ); expect( await findSidebarPanelWithTitle( 'Permalink' ) ).toBeDefined(); } ); } ); diff --git a/packages/e2e-tests/specs/editor/various/splitting-merging.test.js b/packages/e2e-tests/specs/editor/various/splitting-merging.test.js index 05e08db82afce..aadfb9e43efed 100644 --- a/packages/e2e-tests/specs/editor/various/splitting-merging.test.js +++ b/packages/e2e-tests/specs/editor/various/splitting-merging.test.js @@ -8,6 +8,7 @@ import { getEditedPostContent, pressKeyTimes, pressKeyWithModifier, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'splitting and merging blocks', () => { @@ -195,7 +196,7 @@ describe( 'splitting and merging blocks', () => { // There is a default block: expect( - await page.$$( '.block-editor-block-list__block' ) + await canvas().$$( '.block-editor-block-list__block' ) ).toHaveLength( 1 ); // But the effective saved content is still empty: diff --git a/packages/e2e-tests/specs/editor/various/taxonomies.test.js b/packages/e2e-tests/specs/editor/various/taxonomies.test.js index 2ed1c18d2c361..8784ee051b26c 100644 --- a/packages/e2e-tests/specs/editor/various/taxonomies.test.js +++ b/packages/e2e-tests/specs/editor/various/taxonomies.test.js @@ -11,6 +11,7 @@ import { findSidebarPanelWithTitle, openDocumentSettingsSidebar, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; /** @@ -108,7 +109,7 @@ describe( 'Taxonomies', () => { expect( selectedCategories[ 0 ] ).toEqual( 'z rand category 1' ); // Type something in the title so we can publish the post. - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Publish the post. await publishPost(); @@ -166,7 +167,7 @@ describe( 'Taxonomies', () => { expect( tags[ 0 ] ).toEqual( tagName ); // Type something in the title so we can publish the post. - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Publish the post. await publishPost(); @@ -225,7 +226,7 @@ describe( 'Taxonomies', () => { expect( tags[ 0 ] ).toEqual( tagName ); // Type something in the title so we can publish the post. - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Publish the post. await publishPost(); diff --git a/packages/e2e-tests/specs/editor/various/toolbar-roving-tabindex.test.js b/packages/e2e-tests/specs/editor/various/toolbar-roving-tabindex.test.js index b31c088352a63..d490cb9c37c7b 100644 --- a/packages/e2e-tests/specs/editor/various/toolbar-roving-tabindex.test.js +++ b/packages/e2e-tests/specs/editor/various/toolbar-roving-tabindex.test.js @@ -6,15 +6,16 @@ import { pressKeyWithModifier, clickBlockToolbarButton, insertBlock, + canvas, } from '@wordpress/e2e-test-utils'; async function focusBlockToolbar() { await pressKeyWithModifier( 'alt', 'F10' ); } -async function expectLabelToHaveFocus( label ) { +async function expectLabelToHaveFocus( label, p = page ) { await expect( - await page.evaluate( () => + await p.evaluate( () => document.activeElement.getAttribute( 'aria-label' ) ) ).toBe( label ); @@ -26,7 +27,7 @@ async function testBlockToolbarKeyboardNavigation( currentBlockLabel ) { await page.keyboard.press( 'ArrowRight' ); await expectLabelToHaveFocus( 'Move up' ); await page.keyboard.press( 'Tab' ); - await expectLabelToHaveFocus( currentBlockLabel ); + await expectLabelToHaveFocus( currentBlockLabel, canvas() ); await pressKeyWithModifier( 'shift', 'Tab' ); await expectLabelToHaveFocus( 'Move up' ); } @@ -39,9 +40,9 @@ async function wrapCurrentBlockWithGroup() { } async function testGroupKeyboardNavigation( currentBlockLabel ) { - await expectLabelToHaveFocus( 'Block: Group' ); + await expectLabelToHaveFocus( 'Block: Group', canvas() ); await page.keyboard.press( 'Tab' ); - await expectLabelToHaveFocus( currentBlockLabel ); + await expectLabelToHaveFocus( currentBlockLabel, canvas() ); await pressKeyWithModifier( 'shift', 'Tab' ); await expectLabelToHaveFocus( 'Select parent (Group)' ); await page.keyboard.press( 'ArrowRight' ); @@ -92,7 +93,7 @@ describe( 'Toolbar roving tabindex', () => { // Move focus to the first toolbar item await page.keyboard.press( 'Home' ); await expectLabelToHaveFocus( 'Change block type or style' ); - await page.click( '.blocks-table__placeholder-button' ); + await canvas().click( '.blocks-table__placeholder-button' ); await testBlockToolbarKeyboardNavigation( 'Block: Table' ); await wrapCurrentBlockWithGroup(); await testGroupKeyboardNavigation( 'Block: Table' ); diff --git a/packages/e2e-tests/specs/editor/various/typewriter.test.js b/packages/e2e-tests/specs/editor/various/typewriter.test.js index d1983e465e785..60daf820bb279 100644 --- a/packages/e2e-tests/specs/editor/various/typewriter.test.js +++ b/packages/e2e-tests/specs/editor/various/typewriter.test.js @@ -1,15 +1,18 @@ /** * WordPress dependencies */ -import { createNewPost } from '@wordpress/e2e-test-utils'; +import { createNewPost, canvas } from '@wordpress/e2e-test-utils'; describe( 'TypeWriter', () => { beforeEach( async () => { await createNewPost(); } ); - const getCaretPosition = async () => - await page.evaluate( () => wp.dom.computeCaretRect( window ).y ); + async function getCaretPosition() { + return await canvas().evaluate( () => { + return window.top.wp.dom.computeCaretRect( window ).top; + } ); + } // Allow the scroll position to be 1px off. const BUFFER = 1; @@ -21,9 +24,6 @@ describe( 'TypeWriter', () => { // Create first block. await page.keyboard.press( 'Enter' ); - // Create second block. - await page.keyboard.press( 'Enter' ); - const initialPosition = await getCaretPosition(); // The page shouldn't be scrolled when it's being filled. @@ -32,13 +32,7 @@ describe( 'TypeWriter', () => { expect( await getCaretPosition() ).toBeGreaterThan( initialPosition ); // Create blocks until the the typewriter effect kicks in. - while ( - await page.evaluate( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop === 0 - ) - ) { + while ( await canvas().evaluate( () => window.scrollY === 0 ) ) { await page.keyboard.press( 'Enter' ); } @@ -51,7 +45,7 @@ describe( 'TypeWriter', () => { // Type until the text wraps. while ( - await page.evaluate( + await canvas().evaluate( () => document.activeElement.clientHeight <= parseInt( @@ -91,19 +85,16 @@ describe( 'TypeWriter', () => { await page.keyboard.press( 'Enter' ); // Create blocks until there is a scrollable container. - while ( - await page.evaluate( - () => ! wp.dom.getScrollContainer( document.activeElement ) - ) - ) { + while ( await canvas().evaluate( () => window.scrollY === 0 ) ) { await page.keyboard.press( 'Enter' ); } + await page.evaluate( () => { + window.scrollY = 1; + } ); + await page.evaluate( - () => - ( wp.dom.getScrollContainer( - document.activeElement - ).scrollTop = 1 ) + () => new Promise( window.requestAnimationFrame ) ); const initialPosition = await getCaretPosition(); @@ -142,11 +133,7 @@ describe( 'TypeWriter', () => { await page.keyboard.press( 'Enter' ); // Create blocks until there is a scrollable container. - while ( - await page.evaluate( - () => ! wp.dom.getScrollContainer( document.activeElement ) - ) - ) { + while ( await canvas().evaluate( () => window.scrollY === 0 ) ) { await page.keyboard.press( 'Enter' ); } @@ -154,24 +141,16 @@ describe( 'TypeWriter', () => { // Create blocks until the the typewriter effect kicks in, create at // least 10 blocks to properly test the . - while ( - ( await page.evaluate( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop === 0 - ) ) || - count < 10 - ) { + while ( count < 10 ) { await page.keyboard.press( 'Enter' ); count++; } // Scroll the active element to the very bottom of the scroll container, // then scroll up, so the caret is partially hidden. - await page.evaluate( () => { + await canvas().evaluate( () => { document.activeElement.scrollIntoView( false ); - wp.dom.getScrollContainer( document.activeElement ).scrollTop -= - document.activeElement.offsetHeight + 10; + window.scrollBy( 0, -document.activeElement.offsetHeight + 10 ); } ); const bottomPostition = await getCaretPosition(); @@ -198,10 +177,9 @@ describe( 'TypeWriter', () => { // Scroll the active element to the very top of the scroll container, // then scroll down, so the caret is partially hidden. - await page.evaluate( () => { + await canvas().evaluate( () => { document.activeElement.scrollIntoView(); - wp.dom.getScrollContainer( document.activeElement ).scrollTop += - document.activeElement.offsetHeight + 10; + window.scrollBy( 0, document.activeElement.offsetHeight + 10 ); } ); const topPostition = await getCaretPosition(); diff --git a/packages/e2e-tests/specs/editor/various/undo.test.js b/packages/e2e-tests/specs/editor/various/undo.test.js index 30b3a4c80d494..b6476e703a8f9 100644 --- a/packages/e2e-tests/specs/editor/various/undo.test.js +++ b/packages/e2e-tests/specs/editor/various/undo.test.js @@ -10,10 +10,11 @@ import { getAllBlocks, saveDraft, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; const getSelection = async () => { - return await page.evaluate( () => { + return await canvas().evaluate( () => { const selectedBlock = document.activeElement.closest( '.wp-block' ); const blocks = Array.from( document.querySelectorAll( '.wp-block' ) ); const blockIndex = blocks.indexOf( selectedBlock ); @@ -174,12 +175,12 @@ describe( 'undo', () => { await saveDraft(); await page.reload(); await page.waitForSelector( '.edit-post-layout' ); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await pressKeyWithModifier( 'primary', 'a' ); await pressKeyWithModifier( 'primary', 'b' ); await pressKeyWithModifier( 'primary', 'z' ); - const visibleResult = await page.evaluate( + const visibleResult = await canvas().evaluate( () => document.activeElement.innerHTML ); expect( visibleResult ).toBe( 'test' ); @@ -363,7 +364,7 @@ describe( 'undo', () => { // regression present was accurate, it would produce the correct // content. The issue had manifested in the form of what was shown to // the user since the blocks state failed to sync to block editor. - const visibleContent = await page.evaluate( + const visibleContent = await canvas().evaluate( () => document.activeElement.textContent ); expect( visibleContent ).toBe( 'original' ); @@ -400,7 +401,7 @@ describe( 'undo', () => { await page.$( '.editor-history__undo[aria-disabled="true"]' ) ).not.toBeNull(); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.keyboard.type( '2' ); diff --git a/packages/e2e-tests/specs/editor/various/writing-flow.test.js b/packages/e2e-tests/specs/editor/various/writing-flow.test.js index f7d8b031f2911..ee65d03533780 100644 --- a/packages/e2e-tests/specs/editor/various/writing-flow.test.js +++ b/packages/e2e-tests/specs/editor/various/writing-flow.test.js @@ -10,6 +10,7 @@ import { insertBlock, clickBlockToolbarButton, clickButton, + canvas, } from '@wordpress/e2e-test-utils'; const getActiveBlockName = async () => @@ -27,8 +28,8 @@ const addParagraphsAndColumnsDemo = async () => { `//*[contains(@class, "components-autocomplete__result") and contains(@class, "is-selected") and contains(text(), 'Columns')]` ); await page.keyboard.press( 'Enter' ); - await page.click( ':focus [aria-label="Two columns; equal split"]' ); - await page.click( ':focus .block-editor-button-block-appender' ); + await canvas().click( ':focus [aria-label="Two columns; equal split"]' ); + await canvas().click( ':focus .block-editor-button-block-appender' ); await page.waitForSelector( ':focus.block-editor-inserter__search-input' ); await page.keyboard.type( 'Paragraph' ); await pressKeyTimes( 'Tab', 2 ); // Tab to paragraph result. @@ -38,8 +39,8 @@ const addParagraphsAndColumnsDemo = async () => { // TODO: ArrowDown should traverse into the second column. In slower // CPUs, it can sometimes remain in the first column paragraph. This // is a temporary solution. - await page.focus( '.wp-block[data-type="core/column"]:nth-child(2)' ); - await page.click( ':focus .block-editor-button-block-appender' ); + await canvas().focus( '.wp-block[data-type="core/column"]:nth-child(2)' ); + await canvas().click( ':focus .block-editor-button-block-appender' ); await page.waitForSelector( ':focus.block-editor-inserter__search-input' ); await page.keyboard.type( 'Paragraph' ); await pressKeyTimes( 'Tab', 2 ); // Tab to paragraph result. @@ -75,7 +76,7 @@ describe( 'Writing Flow', () => { await page.keyboard.press( 'ArrowUp' ); activeBlockName = await getActiveBlockName(); expect( activeBlockName ).toBe( 'core/paragraph' ); - activeElementText = await page.evaluate( + activeElementText = await canvas().evaluate( () => document.activeElement.textContent ); expect( activeElementText ).toBe( '2nd col' ); @@ -86,7 +87,7 @@ describe( 'Writing Flow', () => { activeBlockName = await getActiveBlockName(); expect( activeBlockName ).toBe( 'core/column' ); await page.keyboard.press( 'ArrowUp' ); - const activeElementBlockType = await page.evaluate( () => + const activeElementBlockType = await canvas().evaluate( () => document.activeElement.getAttribute( 'data-type' ) ); expect( activeElementBlockType ).toBe( 'core/columns' ); @@ -98,7 +99,7 @@ describe( 'Writing Flow', () => { await page.keyboard.press( 'ArrowUp' ); activeBlockName = await getActiveBlockName(); expect( activeBlockName ).toBe( 'core/paragraph' ); - activeElementText = await page.evaluate( + activeElementText = await canvas().evaluate( () => document.activeElement.textContent ); expect( activeElementText ).toBe( 'First paragraph' ); @@ -290,25 +291,25 @@ describe( 'Writing Flow', () => { // See: https://github.com/WordPress/gutenberg/issues/9626 // Title is within the editor's writing flow, and is a