The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?
`; -exports.imageShorteHtml = ` +exports.imageShortHtml = ` - - - -rock music approaches at high velocity.
-`; +`; exports.unsupportedBlockHtml = ``; diff --git a/packages/react-native-editor/__device-tests__/pages/editor-page.js b/packages/react-native-editor/__device-tests__/pages/editor-page.js index c78cc135c06ba..57490584cb3b9 100644 --- a/packages/react-native-editor/__device-tests__/pages/editor-page.js +++ b/packages/react-native-editor/__device-tests__/pages/editor-page.js @@ -1,3 +1,9 @@ +/** + * External dependencies + */ +// eslint-disable-next-line import/no-extraneous-dependencies +const wd = require( 'wd' ); + /** * Internal dependencies */ @@ -5,7 +11,6 @@ const { doubleTap, isAndroid, isEditorVisible, - isElementVisible, longPressMiddleOfElement, setClipboard, setupDriver, @@ -168,15 +173,21 @@ class EditorPage { } async getTitleElement( options = { autoscroll: false } ) { - // TODO: Improve the identifier for this element - const elements = await this.driver.elementsByXPath( - `//*[contains(@${ this.accessibilityIdXPathAttrib }, "Post title.")]` + const titleElement = isAndroid() + ? 'Post title. Welcome to Gutenberg!, Updates the title.' + : 'post-title'; + const elements = await this.driver.elementsByAccessibilityId( + titleElement ); - if ( elements.length === 0 && options.autoscroll ) { + + if ( + ( elements.length === 0 || ! elements[ 0 ].isDisplayed() ) && + options.autoscroll + ) { await swipeDown( this.driver ); return this.getTitleElement( options ); } - return elements[ elements.length - 1 ]; + return elements[ 0 ]; } // iOS loads the block list more eagerly compared to Android. @@ -278,15 +289,32 @@ class EditorPage { } } - async openBlockSettings( block ) { - await block.click(); - - const settingsButton = await block.elementByAccessibilityId( - 'Open Settings' + async openBlockSettings() { + const settingsButtonElement = 'Open Settings'; + const settingsButton = await this.waitForElementToBeDisplayedById( + settingsButtonElement ); + await settingsButton.click(); } + async removeBlock() { + const blockActionsButtonElement = isAndroid() + ? 'Open Block Actions Menu, Double tap to open Bottom Sheet with available options' + : 'Open Block Actions Menu'; + const blockActionsMenu = await this.waitForElementToBeDisplayedById( + blockActionsButtonElement + ); + await blockActionsMenu.click(); + + const removeElement = 'Remove block'; + const removeBlockButton = await this.waitForElementToBeDisplayedById( + removeElement, + 4000 + ); + return await removeBlockButton.click(); + } + async dismissBottomSheet() { return await swipeDown( this.driver ); } @@ -296,13 +324,12 @@ class EditorPage { // ========================= async addNewBlock( blockName, relativePosition ) { - const addBlockButtonLocator = isAndroid() - ? '//android.widget.Button[@content-desc="Add block, Double tap to add a block"]' - : '//XCUIElementTypeButton[@name="add-block-button"]'; - - const addButton = await waitForVisible( - this.driver, - addBlockButtonLocator + const addBlockElement = isAndroid() + ? 'Add block, Double tap to add a block' + : 'Add block'; + const addButton = await this.waitForElementToBeDisplayedById( + addBlockElement, + 3000 ); if ( relativePosition === 'before' ) { @@ -346,14 +373,19 @@ class EditorPage { return screenHeight * 0.82; } + async waitForInserter() { + const inserterElement = isAndroid() + ? 'Blocks menu' + : 'InserterUI-Blocks'; + return await this.waitForElementToBeDisplayedById( + inserterElement, + 4000 + ); + } + // Attempts to find the given block button in the block inserter control. async findBlockButton( blockName ) { - // Wait for the first block, Paragraph block, to load before looking for other blocks - const paragraphBlockLocator = isAndroid() - ? '//android.widget.Button[@content-desc="Paragraph block"]/android.widget.TextView' - : '//XCUIElementTypeButton[@name="Paragraph block"]'; - - await waitForVisible( this.driver, paragraphBlockLocator ); + await this.waitForInserter(); const blockAccessibilityLabel = `${ blockName } block`; const blockAccessibilityLabelNewBlock = `${ blockAccessibilityLabel }, newly available`; @@ -555,11 +587,20 @@ class EditorPage { } async assertSlashInserterPresent() { - const slashInserterLocator = isAndroid() - ? '//android.widget.HorizontalScrollView[@content-desc="Slash inserter results"]/android.view.ViewGroup' - : '(//XCUIElementTypeOther[@name="Slash inserter results"])[1]'; + let isPresent = false; + const autocompleterElementId = isAndroid() + ? 'Slash inserter results' + : 'autocompleter'; + const autocompleterElement = + await this.driver.elementsByAccessibilityId( + autocompleterElementId + ); + + if ( autocompleterElement?.[ 0 ] ) { + isPresent = await autocompleterElement[ 0 ].isDisplayed(); + } - return await isElementVisible( this.driver, slashInserterLocator, 5 ); + return isPresent; } // ========================= @@ -700,8 +741,8 @@ class EditorPage { return await typeString( this.driver, textViewElement, text ); } - async toggleHideSearchLabelSetting( block ) { - await this.openBlockSettings( block ); + async toggleHideSearchLabelSetting() { + await this.openBlockSettings(); const elementName = isAndroid() ? '//*' : '//XCUIElementTypeOther'; @@ -712,8 +753,8 @@ class EditorPage { ); } - async changeSearchButtonPositionSetting( block, buttonPosition ) { - await this.openBlockSettings( block ); + async changeSearchButtonPositionSetting( buttonPosition ) { + await this.openBlockSettings(); const elementName = isAndroid() ? '//*' : '//XCUIElementTypeButton'; @@ -724,8 +765,8 @@ class EditorPage { return await clickIfClickable( this.driver, optionMenuButtonLocator ); } - async toggleSearchIconOnlySetting( block ) { - await this.openBlockSettings( block ); + async toggleSearchIconOnlySetting() { + await this.openBlockSettings(); const elementName = isAndroid() ? '//*' : '//XCUIElementTypeOther'; @@ -800,6 +841,16 @@ class EditorPage { return await waitForVisible( this.driver, blockLocator ); } + + async waitForElementToBeDisplayedById( id, timeout = 2000 ) { + await this.driver.waitForElementByAccessibilityId( + id, + wd.asserters.isDisplayed, + timeout + ); + + return await this.driver.elementByAccessibilityId( id ); + } } const blockNames = { diff --git a/packages/react-native-editor/package.json b/packages/react-native-editor/package.json index 2601a1871f580..065fe844249a9 100644 --- a/packages/react-native-editor/package.json +++ b/packages/react-native-editor/package.json @@ -108,7 +108,7 @@ "test": "cross-env NODE_ENV=test jest --verbose --config ../../test/native/jest.config.js", "test:debug": "cross-env NODE_ENV=test node --inspect-brk ../../node_modules/.bin/jest --runInBand --verbose --config ../../test/native/jest.config.js", "test:update": "npm run test -- --updateSnapshot", - "device-tests": "cross-env NODE_ENV=test jest --forceExit --detectOpenHandles --no-cache --maxWorkers=3 --testPathIgnorePatterns=@canary --verbose --config ./jest_ui.config.js", + "device-tests": "cross-env NODE_ENV=test jest --forceExit --detectOpenHandles --no-cache --maxWorkers=3 --testPathIgnorePatterns='canary|gutenberg-editor-rendering' --verbose --config ./jest_ui.config.js", "device-tests-canary": "cross-env NODE_ENV=test jest --forceExit --detectOpenHandles --no-cache --maxWorkers=2 --testPathPattern=@canary --verbose --config ./jest_ui.config.js", "device-tests:local": "cross-env NODE_ENV=test jest --runInBand --detectOpenHandles --verbose --forceExit --config ./jest_ui.config.js", "device-tests:debug": "cross-env NODE_ENV=test node $NODE_DEBUG_OPTION --inspect-brk node_modules/jest/bin/jest --runInBand --detectOpenHandles --verbose --config ./jest_ui.config.js",