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

Add paragraph block writing flow tests #821

Merged
merged 69 commits into from
May 21, 2019
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
6d1b407
include code for handling paragraph block with multiple newlines
JavonDavis Apr 3, 2019
be25642
Merge branch 'revert-803-revert-676-try/e2e-tests-appium' of https://…
JavonDavis Apr 3, 2019
0f52256
start restructuring functions to editor page
JavonDavis Apr 3, 2019
c7eec61
moved most of block functionality to editor page
JavonDavis Apr 4, 2019
284ecde
Merge branch 'revert-803-revert-676-try/e2e-tests-appium' of https://…
JavonDavis Apr 4, 2019
9bce282
completely removed blockinteraction and moved actual interactions to …
JavonDavis Apr 4, 2019
188436c
add getText function for paragraph blocks
JavonDavis Apr 4, 2019
4654a26
included flow for splitting paragraph blocks
JavonDavis Apr 4, 2019
f1ccfd2
include all current paragraph flow tests
JavonDavis Apr 4, 2019
fbc6fe9
resolve linter errors
JavonDavis Apr 4, 2019
97588dc
fixed path to iOS app in circle config
JavonDavis Apr 5, 2019
9757529
append branch to path
JavonDavis Apr 5, 2019
212df48
remove branch from file path
JavonDavis Apr 5, 2019
9441c7b
revert platform version removal
JavonDavis Apr 5, 2019
f05d9c9
include test for merging paragraph blocks
JavonDavis Apr 5, 2019
eed3b95
device_test: include jest exectation for second block deletion
JavonDavis Apr 5, 2019
cc8e999
increase timeout to account for time to type long text
JavonDavis Apr 5, 2019
4272d85
remove unused branch variable
JavonDavis Apr 5, 2019
7a557de
include null check for linter
JavonDavis Apr 5, 2019
b669430
merge develop
JavonDavis Apr 8, 2019
7f9e48e
revert initial html
JavonDavis Apr 8, 2019
c227250
Testing: Merge appium improvements
JavonDavis Apr 8, 2019
72928aa
fix flow errors
JavonDavis Apr 9, 2019
0856bac
focus on block before removing
JavonDavis Apr 9, 2019
60d5970
include additional comments and update zip path
JavonDavis Apr 9, 2019
28ba568
merge develop
JavonDavis Apr 15, 2019
013fe27
using row number in toolbar accessibility
JavonDavis Apr 15, 2019
6b5441f
update gitignore
JavonDavis Apr 15, 2019
dff6090
change out label for blocks in block list
JavonDavis Apr 15, 2019
aea1257
update test identifiers and positions to match with row numbers
JavonDavis Apr 16, 2019
26769c1
switched out android text entry to use adb shell command due to https…
JavonDavis Apr 16, 2019
1d8e18f
switched out android text entry to use adb shell command due to https…
JavonDavis Apr 16, 2019
5c69b1a
switched out android text entry to use adb shell command due to https…
JavonDavis Apr 16, 2019
8e1849c
revert Depency graph delete
JavonDavis Apr 16, 2019
f0cd38d
add function to swipe up to show remove icon
JavonDavis Apr 17, 2019
5c896f4
swipe up before each removal for small screens
JavonDavis Apr 17, 2019
89d61fc
update swipe
JavonDavis Apr 17, 2019
a67a5c7
update swipe
JavonDavis Apr 17, 2019
be18d5f
update swipe
JavonDavis Apr 17, 2019
c866ee5
moved swiping into remove block function
JavonDavis Apr 17, 2019
478c8a7
connect InlineToolbar to store and include additional expect condition
JavonDavis Apr 18, 2019
2a06e92
fix linter error
JavonDavis Apr 18, 2019
8278d49
fix typo in utils
JavonDavis Apr 18, 2019
76d7e94
merge in changes from develop
JavonDavis Apr 19, 2019
3a9966f
include comment on adb shell
JavonDavis Apr 19, 2019
73c406f
Add basic test for list blocks
hypest May 7, 2019
ffd57d1
Add local e2e script that supports attaching debugger
hypest May 7, 2019
94e5b05
Adjust code style
hypest May 7, 2019
243385d
Add dev menu item to toggle html mode
hypest May 7, 2019
d0e56b2
Verify list block's html
hypest May 8, 2019
f303bc0
Block's html verification only on Android for now
hypest May 10, 2019
d65b6fa
Minor code cleanup
hypest May 10, 2019
60b3d06
merged in develop and resolved issues sending text to the paragraph b…
JavonDavis May 16, 2019
af3bc23
resolve conflicts with develop
JavonDavis May 16, 2019
ca0a861
resolve issue with translator using sprintf
JavonDavis May 16, 2019
f0a5ccc
resolved issue with remove block identifier on Android
JavonDavis May 16, 2019
2bde312
merge in updates from add/paragraph-flow-tests
JavonDavis May 17, 2019
48b46a9
merge in develop
JavonDavis May 20, 2019
dfe8851
improve accessibility text for translators
JavonDavis May 20, 2019
85fc10e
fixed gutnberg submmodule version
JavonDavis May 20, 2019
14977c1
update interface methods in MainApplication.java
JavonDavis May 21, 2019
83c779d
sync gutenberg version
JavonDavis May 21, 2019
036a28c
improve accessibility text
JavonDavis May 21, 2019
ba18700
improve accessibility text
JavonDavis May 21, 2019
41adacc
Update src/block-management/inline-toolbar/index.js
JavonDavis May 21, 2019
7acefbc
Merge branch 'develop' of https://github.com/wordpress-mobile/gutenbe…
JavonDavis May 21, 2019
548f324
resolve identifier changes in UI tests
JavonDavis May 21, 2019
a74af6a
Merge branch 'add/paragraph-flow-tests' of https://github.com/wordpre…
JavonDavis May 21, 2019
fabc73c
Merge pull request #970 from wordpress-mobile/tests/add-list-test
JavonDavis May 21, 2019
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
72 changes: 0 additions & 72 deletions __device-tests__/blocks/block-interaction.js

This file was deleted.

53 changes: 0 additions & 53 deletions __device-tests__/blocks/paragraph-block-interaction.js

This file was deleted.

73 changes: 65 additions & 8 deletions __device-tests__/gutenberg-editor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@
* Internal dependencies
*/
import EditorPage from './pages/editor-page';
import ParagraphBlockInteraction from './blocks/paragraph-block-interaction';
import { setupDriver, isLocalEnvironment, timer, stopDriver } from './helpers/utils';
import {
setupDriver,
isLocalEnvironment,
clickMiddleOfElement,
clickBeginningOfElement,
stopDriver } from './helpers/utils';
import testData from './helpers/test-data';

jasmine.DEFAULT_TIMEOUT_INTERVAL = 120000;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 240000;

describe( 'Gutenberg Editor tests', () => {
let driver;
Expand Down Expand Up @@ -37,11 +42,63 @@ describe( 'Gutenberg Editor tests', () => {
} );

it( 'should be able to add a new Paragraph block', async () => {
const paragraphBlockInteraction = new ParagraphBlockInteraction( driver );
await editorPage.addNewBlock( paragraphBlockInteraction );
await paragraphBlockInteraction.sendText( 'Hello Gutenberg!' );
await timer( 3000 );
expect( await paragraphBlockInteraction.getText() ).toBe( 'Hello Gutenberg!' );
await editorPage.addNewParagraphBlock();
const paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 1 );
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, testData.shortText );
await editorPage.removeParagraphBlockAtPosition( 1 );
} );

it( 'should be able to split one paragraph block into two', async () => {
await editorPage.addNewParagraphBlock();
const paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 1 );
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, testData.shortText );
const textViewElement = await editorPage.getTextViewForParagraphBlock( paragraphBlockElement );
await clickMiddleOfElement( driver, textViewElement );
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, '\n' );
expect( await editorPage.hasParagraphBlockAtPosition( 1 ) && await editorPage.hasParagraphBlockAtPosition( 2 ) )
.toBe( true );

const text0 = await editorPage.getTextForParagraphBlockAtPosition( 1 );
const text1 = await editorPage.getTextForParagraphBlockAtPosition( 2 );
expect( text0 ).not.toBe( '' );
expect( text1 ).not.toBe( '' );
expect( testData.shortText ).toMatch( new RegExp( `${ text0 + text1 }|${ text0 } ${ text1 }` ) );

await editorPage.removeParagraphBlockAtPosition( 2 );
await editorPage.removeParagraphBlockAtPosition( 1 );
} );

it( 'should be able to merge 2 paragraph blocks into 1', async () => {
await editorPage.addNewParagraphBlock();
let paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 1 );
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, testData.shortText );
let textViewElement = await editorPage.getTextViewForParagraphBlock( paragraphBlockElement );
await clickMiddleOfElement( driver, textViewElement );
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, '\n' );
expect( await editorPage.hasParagraphBlockAtPosition( 1 ) && await editorPage.hasParagraphBlockAtPosition( 2 ) )
.toBe( true );

const text0 = await editorPage.getTextForParagraphBlockAtPosition( 1 );
const text1 = await editorPage.getTextForParagraphBlockAtPosition( 2 );
paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 2 );
textViewElement = await editorPage.getTextViewForParagraphBlock( paragraphBlockElement );
await clickBeginningOfElement( driver, textViewElement );
await editorPage.sendTextToParagraphBlock( paragraphBlockElement, '\u0008' );

const text = await editorPage.getTextForParagraphBlockAtPosition( 1 );
expect( text0 + text1 ).toMatch( text );

expect( await editorPage.hasParagraphBlockAtPosition( 2 ) ).toBe( false );
await editorPage.removeParagraphBlockAtPosition( 1 );
} );

it( 'should be able to create a post with multiple paragraph blocks', async () => {
await editorPage.addNewParagraphBlock();
await editorPage.sendTextToParagraphBlockAtPosition( 1, testData.longText );

for ( let i = 4; i > 0; i-- ) {
await editorPage.removeParagraphBlockAtPosition( i );
}
} );

afterAll( async () => {
Expand Down
1 change: 1 addition & 0 deletions __device-tests__/helpers/appium-local.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const start = ( localAppiumPort: number ) => new Promise < childProcess.C
'--port', localAppiumPort.toString(),
'--log', './appium-out.log',
'--log-no-colors',
'--relaxed-security', // Needed for mobile:shell commend for text entry on Android
] );

let appiumOutputBuffer = '';
Expand Down
6 changes: 6 additions & 0 deletions __device-tests__/helpers/test-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
exports.shortText = `Hello Gutenberg! My name is Appium`;

exports.longText = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam luctus velit et nunc tristique, ut tincidunt ipsum placerat. Maecenas placerat nec elit sit amet vulputate.
Nam suscipit dolor eu arcu efficitur, nec faucibus sapien ullamcorper. Etiam nibh risus, tincidunt quis purus a, dictum porta dui. Phasellus lacinia iaculis odio, et eleifend d
Nullam suscipit volutpat velit eget varius. Etiam diam ex, finibus eu turpis a, semper tempus ante. Vestibulum quis elit et felis sagittis mollis.
Nullam porta aliquam nisi, eu dapibus mauris dignissim at. Praesent ut congue sem. Nullam a rhoncus metus.`;
88 changes: 86 additions & 2 deletions __device-tests__/helpers/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ const localIOSAppPath = process.env.IOS_APP_PATH || defaultIOSAppPath;
const localAppiumPort = serverConfigs.local.port; // Port to spawn appium process for local runs
let appiumProcess: ?childProcess.ChildProcess;

// Used to map unicode and special values to keycodes on Android
// Docs for keycode values: https://developer.android.com/reference/android/view/KeyEvent.html
const strToKeycode = {
'\n': 66,
'\u0008': 67,
};

const timer = ( ms: number ) => new Promise < {} > ( ( res ) => setTimeout( res, ms ) );

const isAndroid = () => {
Expand Down Expand Up @@ -92,8 +99,9 @@ const setupDriver = async () => {
}

if ( ! isLocalEnvironment() ) {
desiredCaps.name = `Gutenberg Editor Tests[${ rnPlatform }]`;
desiredCaps.tags = [ 'Gutenberg' ];
const branch = process.env.CIRCLE_BRANCH || '';
desiredCaps.name = `Gutenberg Editor Tests[${ rnPlatform }]-${ branch }`;
desiredCaps.tags = [ 'Gutenberg', branch ];
}

await driver.init( desiredCaps );
Expand Down Expand Up @@ -129,10 +137,86 @@ const stopDriver = async ( driver: wd.PromiseChainWebdriver ) => {
}
};

// attempts to type a string to a given element, need for this stems from
// https://github.com/appium/appium/issues/12285#issuecomment-471872239
// https://github.com/facebook/WebDriverAgent/issues/1084
const typeString = async ( driver: wd.PromiseChainWebdriver, element: wd.PromiseChainWebdriver.Element, str: string, clear: boolean = false ) => {
if ( clear ) {
await element.clear();
}

if ( isAndroid() ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The need for this additional work for Android is because of how the type API works. It basically clears the field first before start typing. Although Appium implemented a workaround in their additional implementation on top of this to allow appending by copying the existing text before typing the new one, unfortunately, it still performs the 'clear' operation under the hood. Because of that when it clears it, it doesn't know when to stop properly and removes the block, as if the user had touched the backspace button on an empty block.

The workaround uses adb shell input <text> instead to send the text.

const paragraphs = str.split( '\n' );

for ( let i = 0; i < paragraphs.length; i++ ) {
const paragraph = paragraphs[ i ].replace( /[ ]/g, '%s' );
if ( paragraph in strToKeycode ) {
await driver.pressKeycode( strToKeycode[ paragraph ] );
} else {
// Execute with adb shell input <text> since normal type auto clears field on Android
await driver.execute( 'mobile: shell', { command: 'input', args: [ 'text', paragraph ] } );
}
if ( i !== paragraphs.length - 1 ) {
await driver.pressKeycode( strToKeycode[ '\n' ] );
}
}
} else {
return await element.type( str );
}
};

// Calculates middle x,y and clicks that position
const clickMiddleOfElement = async ( driver: wd.PromiseChainWebdriver, element: wd.PromiseChainWebdriver.Element ) => {
const location = await element.getLocation();
const size = await element.getSize();

const action = await new wd.TouchAction( driver );
action.press( { x: location.x + ( size.width / 2 ), y: location.y } );
action.release();
await action.perform();
};

// Clicks in the top left of an element
const clickBeginningOfElement = async ( driver: wd.PromiseChainWebdriver, element: wd.PromiseChainWebdriver.Element ) => {
const location = await element.getLocation();
const action = await new wd.TouchAction( driver );
action.press( { x: location.x, y: location.y } );
action.release();
await action.perform();
};

// Starts from the middle of the screen or the element(if specified)
// and swipes upwards
const swipeUp = async ( driver: wd.PromiseChainWebdriver, element: wd.PromiseChainWebdriver.Element = undefined ) => {
let size = await driver.getWindowSize();
let y = 0;
if ( element !== undefined ) {
size = await element.getSize();
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel this function could use an upgrade (maybe in another PR?) It seems to me that there are quite few edge cases where this approach would fail:

  • What if the element height is bigger than 3 times the height of the screen
  • What if element is not given and a single swipe is not enough
  • What if the screen is only showing the top of element? startY might be outside the screen boudaries. Also a swipe might not be enough to reveal the bottom of the element in this case

I think a "slightly" better approach would be to make this function a simple swipe up with an height parameter, it will try to center the swipe on the screen and do it in a loop if height is bigger than the size of the screen. We can also think of a swipeUpUntilElementIsVIsible() version which would do what its name says.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For sure! I was saving improving this for another PR, do you think it's good enough for now?

it will try to center the swipe on the screen

It originally just did this, but failed on the CI because the device it used was small and the keyboard took up more than half of the screen.

We can also think of a swipeUpUntilElementIsVIsible() version which would do what its name says.

Yep, for now I was hoping this was enough to use in a loop if needed before that get's implemented.

Copy link
Contributor Author

@JavonDavis JavonDavis Apr 17, 2019

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep it seems to work really smoothly for now (at least on the devices we tested :)). So I think we should be good 👍

const location = await element.getLocation();
y = location.y;
}

const startX = size.width / 2;
const startY = y + ( size.height / 3 );
const endX = startX;
const endY = startY + ( startY * -1 * 0.5 );

const action = await new wd.TouchAction( driver );
action.press( { x: startX, y: startY } );
action.wait( 3000 );
action.moveTo( { x: endX, y: endY } );
action.release();
await action.perform();
};

module.exports = {
timer,
setupDriver,
isLocalEnvironment,
isAndroid,
typeString,
clickMiddleOfElement,
clickBeginningOfElement,
swipeUp,
stopDriver,
};
Loading