Skip to content

Commit

Permalink
Avoid using adb for inserting text in Android e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mchowning committed Jan 24, 2020
1 parent 5276ed2 commit db104b1
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 23 deletions.
2 changes: 1 addition & 1 deletion __device-tests__/gutenberg-editor-paragraph.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe( 'Gutenberg Editor tests for Paragraph Block', () => {
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, testData.shortText );
const textViewElement = await editorPage.getTextViewForParagraphBlock( paragraphBlockElement );
await clickMiddleOfElement( driver, textViewElement );
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, '\n' );
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, '\n', false );
expect( await editorPage.hasParagraphBlockAtPosition( 1 ) && await editorPage.hasParagraphBlockAtPosition( 2 ) )
.toBe( true );

Expand Down
45 changes: 40 additions & 5 deletions __device-tests__/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,51 @@ const stopDriver = async ( driver: wd.PromiseChainWebdriver ) => {
}
};

const typeString = async ( driver: wd.PromiseChainWebdriver, element: wd.PromiseChainWebdriver.Element, str: string, clear: boolean = false ) => {
/*
* The 'clear' parameter is defaulted to true because not clearing the text requires Android to use ADB, which
* has demonstrated itself to be very flaky, particularly on CI. In other words, clear the view unless you absolutely
* have to append the new text and, in that case, append fewest number of characters possible.
*/
const typeString = async ( driver: wd.PromiseChainWebdriver, element: wd.PromiseChainWebdriver.Element, str: string, clear: boolean = true ) => {
if ( isAndroid() ) {
await typeStringAndroid( driver, element, str, clear );
} else {
await typeStringIos( driver, element, str, clear );
}
};

const typeStringIos = async ( driver: wd.PromiseChainWebdriver, element: wd.PromiseChainWebdriver.Element, str: string, clear: boolean ) => {
if ( clear ) {
await element.clear();
}
await element.type( str );
};

if ( isAndroid() ) {
const paragraphs = str.split( '\n' );
const typeStringAndroid = async ( driver: wd.PromiseChainWebdriver, element: wd.PromiseChainWebdriver.Element, str: string, clear: boolean ) => {
if ( str in strToKeycode ) {
return await driver.pressKeycode( strToKeycode[ str ] );
} else if ( clear ) {
/*
* On Android `element.type` deletes the contents of the EditText before typing and, unfortunately,
* with our blocks it also deletes the block entirely. We used to avoid this by using adb to enter
* long text along these lines:
* await driver.execute( 'mobile: shell', { command: 'input',
* args: [ 'text', 'text I want to enter...' ] } )
* but using adb in this way proved to be very flakey (frequently all of the text would not get entered,
* particularly on CI). We are now using the `type` approach again, but adding a space to the block to
* insure it is not empty, which avoids the deletion of the block when `type` executes.
*
* Note that this approach does not allow appending text to the text in a block on account
* of `type` always clearing the block (on Android).
*/

await driver.execute( 'mobile: shell', { command: 'input', args: [ 'text', '%s' ] } );
await element.type( str );
} else {
// eslint-disable-next-line no-console
console.log( 'Warning: Using `adb shell input text` on Android which is rather flaky.' );

const paragraphs = str.split( '\n' );
for ( let i = 0; i < paragraphs.length; i++ ) {
const paragraph = paragraphs[ i ].replace( /[ ]/g, '%s' );
if ( paragraph in strToKeycode ) {
Expand All @@ -181,8 +218,6 @@ const typeString = async ( driver: wd.PromiseChainWebdriver, element: wd.Promise
await driver.pressKeycode( strToKeycode[ '\n' ] );
}
}
} else {
return await element.type( str );
}
};

Expand Down
24 changes: 14 additions & 10 deletions __device-tests__/pages/editor-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,22 +256,22 @@ export default class EditorPage {
return await this.driver.elementByXPath( blockLocator );
}

async sendTextToParagraphBlock( block: wd.PromiseChainWebdriver.Element, text: string ) {
async sendTextToParagraphBlock( block: wd.PromiseChainWebdriver.Element, text: string, clear: boolean = true ) {
const textViewElement = await this.getTextViewForParagraphBlock( block );
await typeString( this.driver, textViewElement, text );
await typeString( this.driver, textViewElement, text, clear );
await this.driver.sleep( 1000 ); // Give time for the block to rerender (such as for accessibility)
}

async sendTextToParagraphBlockAtPosition( position: number, text: string ) {
async sendTextToParagraphBlockAtPosition( position: number, text: string, clear: boolean = true ) {
const paragraphs = text.split( '\n' );
for ( let i = 0; i < paragraphs.length; i++ ) {
// Select block first
const block = await this.getParagraphBlockAtPosition( position + i );
await block.click();

await this.sendTextToParagraphBlock( block, paragraphs[ i ] );
await this.sendTextToParagraphBlock( block, paragraphs[ i ], clear );
if ( i !== paragraphs.length - 1 ) {
await this.sendTextToParagraphBlock( block, '\n' );
await this.sendTextToParagraphBlock( block, '\n', false );
}
}
}
Expand Down Expand Up @@ -325,7 +325,11 @@ export default class EditorPage {

async sendTextToListBlock( block: wd.PromiseChainWebdriver.Element, text: string ) {
const textViewElement = await this.getTextViewForListBlock( block );
return await typeString( this.driver, textViewElement, text );

// Cannot clear list blocks because it messes up the list bullet
const clear = false;

return await typeString( this.driver, textViewElement, text, clear );
}

async getTextForListBlock( block: wd.PromiseChainWebdriver.Element ) {
Expand Down Expand Up @@ -368,10 +372,10 @@ export default class EditorPage {
await mediaLibraryButton.click();
}

async enterCaptionToSelectedImageBlock( caption: string ) {
async enterCaptionToSelectedImageBlock( caption: string, clear: boolean = true ) {
const imageBlockCaptionField = await this.driver.elementByXPath( '//XCUIElementTypeButton[@name="Image caption. Empty"]' );
await imageBlockCaptionField.click();
await typeString( this.driver, imageBlockCaptionField, caption );
await typeString( this.driver, imageBlockCaptionField, caption, clear );
}

async removeImageBlockAtPosition( position: number ) {
Expand Down Expand Up @@ -417,9 +421,9 @@ export default class EditorPage {
return await this.driver.elementByXPath( blockLocator );
}

async sendTextToHeadingBlock( block: wd.PromiseChainWebdriver.Element, text: string ) {
async sendTextToHeadingBlock( block: wd.PromiseChainWebdriver.Element, text: string, clear: boolean = true ) {
const textViewElement = await this.getTextViewForHeadingBlock( block, true );
return await typeString( this.driver, textViewElement, text );
return await typeString( this.driver, textViewElement, text, clear );
}

async getTextForHeadingBlock( block: wd.PromiseChainWebdriver.Element ) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@wordpress/babel-preset-default": "^4.0.0",
"@wordpress/eslint-plugin": "^2.0.0",
"@wordpress/jest-preset-default": "^4.0.0",
"appium": "1.16.0-rc.1",
"appium": "1.16.0",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^8.2.2",
"babel-jest": "^24.1.0",
Expand Down
11 changes: 5 additions & 6 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2795,7 +2795,7 @@ appium-remote-debugger@^5.7.0:
lodash "^4.17.11"
source-map-support "^0.5.5"

appium-remote-debugger@^7.0.0, appium-remote-debugger@^7.3.0:
appium-remote-debugger@^7.0.0:
version "7.3.0"
resolved "https://registry.yarnpkg.com/appium-remote-debugger/-/appium-remote-debugger-7.3.0.tgz#a512e7dc7fb5c187f00538f39e996580cea6c759"
integrity sha512-3dMEvuOpql2B2SXJZ25o+rW4JkQe+1AFh+xIM4ArsLjn9FzHnTr9uRlhTUOgogrzNzJ8UJDVCAWIL+IbutwsfQ==
Expand Down Expand Up @@ -3131,10 +3131,10 @@ appium-youiengine-driver@^1.2.0:
source-map-support "^0.5.9"
teen_process "^1.14.1"

[email protected]-rc.1:
version "1.16.0-rc.1"
resolved "https://registry.yarnpkg.com/appium/-/appium-1.16.0-rc.1.tgz#78b5d25937f2c89acfbcdf940902395b721b47fb"
integrity sha512-VxwbfZi1WTAXqQPVj0a+u+f4kc0IMoQSTewiny6xUyLvr56MBd+xxoQws5ipIOiDQiQB6QkQ7/OWw+r/lUGp9g==
[email protected]:
version "1.16.0"
resolved "https://registry.yarnpkg.com/appium/-/appium-1.16.0.tgz#fb58a6cec93636892749c42d25d4396450223260"
integrity sha512-wOTmJTWPGvGV0I8rGZpJl+dPiJ6V05qkIrifn4SLWeR0WAp4Zlm0hyYeQO3Mqwbf0KDgwOc4SJd2sU7yytE2Tw==
dependencies:
"@babel/runtime" "^7.6.0"
appium-android-driver "^4.21.0"
Expand All @@ -3144,7 +3144,6 @@ [email protected]:
appium-flutter-driver "^0"
appium-ios-driver "4.x"
appium-mac-driver "1.x"
appium-remote-debugger "^7.3.0"
appium-support "2.x"
appium-tizen-driver "^1.1.1-beta.4"
appium-uiautomator2-driver "^1.40.0"
Expand Down

0 comments on commit db104b1

Please sign in to comment.