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

UI Tests for Block Mover #27883

Closed
wants to merge 4 commits into from
Closed
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
@@ -0,0 +1,158 @@
/**
* Internal dependencies
*/
import { isAndroid } from './helpers/utils';
import { blockNames } from './pages/editor-page';

describe( 'Gutenberg Editor Block Mover tests', () => {
const cancelButtonName = 'Cancel';
const buttonIosType = 'Button';
const moveTopButtonName = 'Move to top';
const moveBottomButtonName = 'Move to bottom';

async function setupBlocks( text = 'p1' ) {
await editorPage.addNewBlock( blockNames.paragraph );
const paragraphBlock = await editorPage.getBlockAtPosition(
blockNames.paragraph
);
await editorPage.typeTextToParagraphBlock( paragraphBlock, text );

await editorPage.addNewBlock( blockNames.heading );
const headerBlock = await editorPage.getBlockAtPosition(
blockNames.heading,
2
);
await editorPage.typeTextToParagraphBlock( headerBlock, text );
}

async function removeBlocks( blockOrder ) {
for ( let i = blockOrder.length; i > 0; i-- ) {
await editorPage.removeBlockAtPosition( blockOrder[ i - 1 ], i );
}
}

async function cancelActionSheet( ePage ) {
if ( isAndroid() ) {
await ePage.tapCoordinates( 100, 100 );
} else {
await ePage.selectElement( cancelButtonName, buttonIosType );
}
}

it( 'should be able to see move block to top when long pressing up and change nothing when pressing cancel', async () => {
await setupBlocks( 'p1-up-cancel' );

await editorPage.longPressToolBarButton(
'Move block up from row 2 to row 1'
);
const moveUpAction = await editorPage.findElementByXPath(
moveTopButtonName,
buttonIosType
);

expect( moveUpAction ).toBeTruthy();

await cancelActionSheet( editorPage );
const paragraphIsFirst = await editorPage.hasBlockAtPosition(
1,
blockNames.paragraph
);

expect( paragraphIsFirst ).toBe( true );

await removeBlocks( [ blockNames.paragraph, blockNames.heading ] );
} );

it( 'should be able to move block to first block when pressing move block to top', async () => {
await setupBlocks( 'p1-up' );

await editorPage.longPressToolBarButton(
'Move block up from row 2 to row 1'
);
await editorPage.selectElement( moveTopButtonName, buttonIosType );
const headerIsFirst = await editorPage.hasBlockAtPosition(
1,
blockNames.heading
);

expect( headerIsFirst ).toBe( true );

await editorPage.selectBlock( blockNames.paragraph, 2 );
await removeBlocks( [ blockNames.heading, blockNames.paragraph ] );
} );

it( 'should have move up disabled when on top', async () => {
await setupBlocks( 'p1-disabled-top' );
await editorPage.selectBlock( blockNames.paragraph );

await editorPage.longPressToolBarButton( 'Move block up' );
const moveUpAction = await editorPage.findElementByXPath(
moveTopButtonName,
buttonIosType
);

expect( moveUpAction ).toBe( undefined );

await editorPage.selectBlock( blockNames.heading, 2 );
await removeBlocks( [ blockNames.paragraph, blockNames.heading ] );
} );

it( 'should be able to see move block to bottom when long pressing down and change nothing when pressing cancel', async () => {
await setupBlocks( 'p1-down-cancel' );
await editorPage.selectBlock( blockNames.paragraph );

await editorPage.longPressToolBarButton(
'Move block down from row 1 to row 2'
);
const moveDownAction = await editorPage.findElementByXPath(
moveBottomButtonName,
buttonIosType
);

expect( moveDownAction ).toBeTruthy();

await cancelActionSheet( editorPage );
const paragraphIsFirst = await editorPage.hasBlockAtPosition(
1,
blockNames.paragraph
);

expect( paragraphIsFirst ).toBe( true );

await editorPage.selectBlock( blockNames.heading, 2 );
await removeBlocks( [ blockNames.paragraph, blockNames.heading ] );
} );

it( 'should be able to move block to last block when pressing move block to bottom', async () => {
await setupBlocks( 'p1-down' );
await editorPage.selectBlock( blockNames.paragraph );

await editorPage.longPressToolBarButton(
'Move block down from row 1 to row 2'
);

await editorPage.selectElement( moveBottomButtonName, buttonIosType );
const headerIsFirst = await editorPage.hasBlockAtPosition(
1,
blockNames.heading
);

expect( headerIsFirst ).toBe( true );

await removeBlocks( [ blockNames.heading, blockNames.paragraph ] );
} );

it( 'should have move down disabled when on bottom', async () => {
await setupBlocks( 'p1-disabled-down' );

await editorPage.longPressToolBarButton( 'Move block down' );
const moveDownAction = await editorPage.findElementByXPath(
moveBottomButtonName,
buttonIosType
);

expect( moveDownAction ).toBe( undefined );

await removeBlocks( [ blockNames.paragraph, blockNames.heading ] );
} );
} );
76 changes: 70 additions & 6 deletions packages/react-native-editor/__device-tests__/pages/editor-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@ const {
setupDriver,
stopDriver,
isAndroid,
longPressMiddleOfElement,
swipeUp,
swipeDown,
typeString,
toggleHtmlMode,
swipeFromTo,
longPressMiddleOfElement,
} = require( '../helpers/utils' );

/**
* External dependencies
*/
// eslint-disable-next-line import/no-extraneous-dependencies
const wd = require( 'wd' );

const initializeEditorPage = async () => {
const driver = await setupDriver();
return new EditorPage( driver );
Expand Down Expand Up @@ -288,6 +294,20 @@ class EditorPage {
await toolBarButton.click();
}

async longPressToolBarButton( buttonName ) {
let toolBarButton;
if ( isAndroid() ) {
const blockLocator = `//*[contains(@${ this.accessibilityIdXPathAttrib }, "${ buttonName }")]`;
toolBarButton = await this.driver.elementByXPath( blockLocator );
} else {
toolBarButton = await this.driver.elementByAccessibilityId(
buttonName
);
}

await longPressMiddleOfElement( this.driver, toolBarButton );
}

// =========================
// Inline toolbar functions
// =========================
Expand Down Expand Up @@ -384,11 +404,15 @@ class EditorPage {
}

async typeTextToParagraphBlock( block, text, clear ) {
const textViewElement = await this.getTextViewForParagraphBlock(
block
);
await typeString( this.driver, textViewElement, text, clear );
await this.driver.sleep( 1000 ); // Give time for the block to rerender (such as for accessibility)
if ( ! isAndroid() ) {
block.type( text );
Copy link
Member

Choose a reason for hiding this comment

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

This seemed to be the failure reason for some of the e2e tests. What was the reason behind this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed this because locally my machine wouldn't type anything on iOS with that function. Not sure if I have something set up wrong?

Copy link
Member

Choose a reason for hiding this comment

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

Which iOS simulator (version, device) were you using?

} else {
const textViewElement = await this.getTextViewForParagraphBlock(
block
);
await typeString( this.driver, textViewElement, text, clear );
await this.driver.sleep( 1000 ); // Give time for the block to rerender (such as for accessibility)
}
}

async sendTextToParagraphBlock( position, text, clear ) {
Expand Down Expand Up @@ -572,6 +596,46 @@ class EditorPage {
async sauceJobStatus( allPassed ) {
await this.driver.sauceJobStatus( allPassed );
}

// =============================
// Misc functions
// =============================
async findElementByXPath( name, iosElementType ) {
const elementName = isAndroid()
? '//*'
: `//XCUIElementType${ iosElementType }`;
const blockLocator = `${ elementName }[contains(@${ this.accessibilityIdXPathAttrib }, "${ name }")]`;
const elements = await this.driver.elementsByXPath( blockLocator );
return elements[ 0 ];
}

async selectElement( name, iosElementType ) {
const el = await this.findElementByXPath( name, iosElementType );
el.click();
}

async selectBlock(
blockName,
position = 1,
options = { autoscroll: false }
) {
const block = await this.getBlockAtPosition(
blockName,
position,
options
);
block.click();
}

async tapCoordinates( x, y, longPress = false ) {
Copy link
Member

Choose a reason for hiding this comment

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

If possible, using clickMiddleOfElement instead could be more robust. The device size, running locally or in the cloud, could be different and coordinates may not be the same between them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmmm. The problem is that I need to click outside of the alert and I can't get elements behind the alert.

Copy link
Member

Choose a reason for hiding this comment

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

Would pressing the back button instead on Android work?

const action = new wd.TouchAction( this.driver );
action.press( { x, y } );
if ( longPress ) {
action.wait( 1000 );
}
action.release();
await action.perform();
}
}

const blockNames = {
Expand Down