Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RNMobile - Update clicks to use clickIfClickable() when possible #41367

Merged
merged 1 commit into from
Jun 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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() ) {
Comment on lines +10 to +11
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This test was failing when tested locally on Android then realized that it's actually an iOS-only test, moving the condition to the start of the test so it doesn't have to run anything on Android.

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 @@ -473,13 +473,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 @@ -496,35 +498,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 @@ -539,12 +553,14 @@ const clickIfClickable = async (
driver,
elementLocator,
maxIteration = 25,
elementToReturn = 'firstElement',
iteration = 0
) => {
const element = await waitForVisible(
driver,
elementLocator,
maxIteration,
elementToReturn,
iteration
);

Expand All @@ -563,6 +579,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 @@ -56,11 +56,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 @@ -150,9 +146,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 @@ -244,12 +243,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 @@ -263,10 +260,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 @@ -637,11 +635,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 @@ -661,11 +655,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 @@ -695,42 +688,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