Skip to content

Commit

Permalink
where it can change to use clickIfClickable(), add new param for wait…
Browse files Browse the repository at this point in the history
…ForVisible() to control return value (#41367)

Co-authored-by: jos <[email protected]>
  • Loading branch information
2 people authored and dcalhoun committed Jul 7, 2022
1 parent aee2a06 commit c7a740c
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,9 @@ describe( 'Gutenberg Editor tests for Block insertion 2', () => {
} );

it( 'inserts between 2 existing blocks', async () => {
const headingBlockElement = await editorPage.getBlockAtPosition(
blockNames.heading
);
const firstBlock = await editorPage.getFirstBlockVisible();
await firstBlock.click();

await headingBlockElement.click();
await editorPage.addNewBlock( blockNames.separator );

const expectedHtml = [
Expand Down
31 changes: 9 additions & 22 deletions packages/react-native-editor/__device-tests__/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import testData from './helpers/test-data';

describe( 'Gutenberg Editor Image Block tests', () => {
it( 'should be able to add an image block', async () => {
await editorPage.addNewBlock( blockNames.image );
await editorPage.closePicker();
// iOS only test - Can only add image from media library on iOS
if ( ! isAndroid() ) {
await editorPage.addNewBlock( blockNames.image );
await editorPage.closePicker();

const imageBlock = await editorPage.getBlockAtPosition(
blockNames.image
);
const imageBlock = await editorPage.getBlockAtPosition(
blockNames.image
);

// Can only add image from media library on iOS
if ( ! isAndroid() ) {
await editorPage.selectEmptyImageBlock( imageBlock );
await editorPage.chooseMediaLibrary();

Expand All @@ -31,27 +31,14 @@ describe( 'Gutenberg Editor Image Block tests', () => {
true
);
await editorPage.dismissKeyboard();
}
await editorPage.addNewBlock( blockNames.paragraph );
const paragraphBlockElement = await editorPage.getTextBlockAtPosition(
blockNames.paragraph,
2
);
if ( isAndroid() ) {
await paragraphBlockElement.click();
}

await editorPage.sendTextToParagraphBlock( 2, testData.shortText );

// skip HTML check for Android since we couldn't add image from media library
/* eslint-disable jest/no-conditional-expect */
if ( ! isAndroid() ) {
await editorPage.addNewBlock( blockNames.paragraph );
await editorPage.sendTextToParagraphBlock( 2, testData.shortText );
const html = await editorPage.getHtmlContent();

expect( html.toLowerCase() ).toBe(
testData.imageShorteHtml.toLowerCase()
);
}
/* eslint-enable jest/no-conditional-expect */
} );
} );
27 changes: 22 additions & 5 deletions packages/react-native-editor/__device-tests__/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -516,13 +516,15 @@ const waitForMediaLibrary = async ( driver ) => {
* @param {string} driver
* @param {string} elementLocator
* @param {number} maxIteration - Default value is 25
* @param {string} elementToReturn - Options are allElements, lastElement, firstElement. Defaults to "firstElement"
* @param {number} iteration - Default value is 0
* @return {string} - Returns the first element found, empty string if not found
*/
const waitForVisible = async (
driver,
elementLocator,
maxIteration = 25,
elementToReturn = 'firstElement',
iteration = 0
) => {
const timeout = 1000;
Expand All @@ -539,35 +541,47 @@ const waitForVisible = async (
await driver.sleep( timeout );
}

const element = await driver.elementsByXPath( elementLocator );
if ( element.length === 0 ) {
const elements = await driver.elementsByXPath( elementLocator );
if ( elements.length === 0 ) {
// if locator is not visible, try again
return waitForVisible(
driver,
elementLocator,
maxIteration,
elementToReturn,
iteration + 1
);
}

return element[ 0 ];
switch ( elementToReturn ) {
case 'allElements':
return elements;
case 'lastElement':
return elements[ elements.length - 1 ];
default:
// Default is to return first element
return elements[ 0 ];
}
};

/**
* @param {string} driver
* @param {string} elementLocator
* @param {number} maxIteration - Default value is 25, can be adjusted to be less to wait for element to not be visible
* @param {string} elementToReturn - Options are allElements, lastElement, firstElement. Defaults to "firstElement"
* @return {boolean} - Returns true if element is found, false otherwise
*/
const isElementVisible = async (
driver,
elementLocator,
maxIteration = 25
maxIteration = 25,
elementToReturn = 'firstElement'
) => {
const element = await waitForVisible(
driver,
elementLocator,
maxIteration
maxIteration,
elementToReturn
);

// if there is no element, return false
Expand All @@ -582,12 +596,14 @@ const clickIfClickable = async (
driver,
elementLocator,
maxIteration = 25,
elementToReturn = 'firstElement',
iteration = 0
) => {
const element = await waitForVisible(
driver,
elementLocator,
maxIteration,
elementToReturn,
iteration
);

Expand All @@ -606,6 +622,7 @@ const clickIfClickable = async (
driver,
elementLocator,
maxIteration,
elementToReturn,
iteration + 1
);
}
Expand Down
59 changes: 21 additions & 38 deletions packages/react-native-editor/__device-tests__/pages/editor-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,7 @@ class EditorPage {
if ( ! isAndroid() ) {
const textBlockLocator = `(//XCUIElementTypeButton[contains(@name, "${ blockName } Block. Row ${ position }")])`;

const textBlock = await waitForVisible(
this.driver,
textBlockLocator
);
await textBlock.click();
await clickIfClickable( this.driver, textBlockLocator );
}

const blockLocator = isAndroid()
Expand Down Expand Up @@ -151,9 +147,12 @@ class EditorPage {

async getLastBlockVisible() {
const firstBlockLocator = `//*[contains(@${ this.accessibilityIdXPathAttrib }, " Block. Row ")]`;
await waitForVisible( this.driver, firstBlockLocator );
const elements = await this.driver.elementsByXPath( firstBlockLocator );
return elements[ elements.length - 1 ];
return await waitForVisible(
this.driver,
firstBlockLocator,
25,
'lastElement'
);
}

async hasBlockAtPosition( position = 1, blockName = '' ) {
Expand Down Expand Up @@ -243,12 +242,10 @@ class EditorPage {
// Sometimes double tap is not enough for paste menu to appear, so we also long press.
await longPressMiddleOfElement( this.driver, htmlContentView );

const pasteButton = await waitForVisible(
await clickIfClickable(
this.driver,
'//XCUIElementTypeMenuItem[@name="Paste"]'
);

await pasteButton.click();
}

await toggleHtmlMode( this.driver, false );
Expand All @@ -262,10 +259,11 @@ class EditorPage {
if ( isAndroid() ) {
return await this.driver.hideDeviceKeyboard();
}
const hideKeyboardToolbarButton = await this.driver.elementByXPath(

await clickIfClickable(
this.driver,
'//XCUIElementTypeButton[@name="Hide keyboard"]'
);
await hideKeyboardToolbarButton.click();
}

async dismissAndroidClipboardSmartSuggestion() {
Expand Down Expand Up @@ -645,11 +643,7 @@ class EditorPage {
? `//android.widget.Button[@content-desc="WordPress Media Library"]`
: `//XCUIElementTypeButton[@name="WordPress Media Library"]`;

const mediaLibraryButton = await waitForVisible(
this.driver,
mediaLibraryLocator
);
await mediaLibraryButton.click();
await clickIfClickable( this.driver, mediaLibraryLocator );
}

async enterCaptionToSelectedImageBlock( caption, clear = true ) {
Expand All @@ -669,11 +663,10 @@ class EditorPage {

await swipeDown( this.driver );
} else {
const cancelButton = await waitForVisible(
await clickIfClickable(
this.driver,
'//XCUIElementTypeButton[@name="Cancel"]'
);
await cancelButton.click();
}
}

Expand Down Expand Up @@ -703,42 +696,32 @@ class EditorPage {

const elementName = isAndroid() ? '//*' : '//XCUIElementTypeOther';

const locator = `${ elementName }[starts-with(@${ this.accessibilityIdXPathAttrib }, "Hide search heading")]`;
const hideSearchHeadingToggle = await waitForVisible(
const hideSearchHeadingToggleLocator = `${ elementName }[starts-with(@${ this.accessibilityIdXPathAttrib }, "Hide search heading")]`;
return await clickIfClickable(
this.driver,
locator
hideSearchHeadingToggleLocator
);

return await hideSearchHeadingToggle.click();
}

async changeSearchButtonPositionSetting( block, buttonPosition ) {
await this.openBlockSettings( block );

const elementName = isAndroid() ? '//*' : '//XCUIElementTypeButton';

const locator = `${ elementName }[starts-with(@${ this.accessibilityIdXPathAttrib }, "Button position")]`;
let optionMenuButton = await waitForVisible( this.driver, locator );
await optionMenuButton.click();
const optionMenuLocator = `${ elementName }[starts-with(@${ this.accessibilityIdXPathAttrib }, "Button position")]`;
await clickIfClickable( this.driver, optionMenuLocator );

const optionMenuButtonLocator = `${ elementName }[contains(@${ this.accessibilityIdXPathAttrib }, "${ buttonPosition }")]`;
optionMenuButton = await waitForVisible(
this.driver,
optionMenuButtonLocator
);

return await optionMenuButton.click();
return await clickIfClickable( this.driver, optionMenuButtonLocator );
}

async toggleSearchIconOnlySetting( block ) {
await this.openBlockSettings( block );

const elementName = isAndroid() ? '//*' : '//XCUIElementTypeOther';

const locator = `${ elementName }[starts-with(@${ this.accessibilityIdXPathAttrib }, "Use icon button")]`;
const useIconButton = await waitForVisible( this.driver, locator );

return await useIconButton.click();
const useIconButtonLocator = `${ elementName }[starts-with(@${ this.accessibilityIdXPathAttrib }, "Use icon button")]`;
return await clickIfClickable( this.driver, useIconButtonLocator );
}

async isSearchSettingsVisible() {
Expand Down

0 comments on commit c7a740c

Please sign in to comment.