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 block insertion tests #1139

Merged
merged 27 commits into from Jul 12, 2019
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9df6cdf
Add block insertion tests with html verification
JavonDavis Jun 14, 2019
ceb5a72
fix issue caused by not properly deleting blocks
JavonDavis Jun 18, 2019
ff1650c
clicking on middle of element to avoid ios new block creation
JavonDavis Jun 18, 2019
3b980c9
Merge branch 'develop' of https://github.com/wordpress-mobile/gutenbe…
JavonDavis Jun 18, 2019
9fbe8aa
Use non default device on Sauce
JavonDavis Jun 21, 2019
610da4e
use branch specific app files
JavonDavis Jun 21, 2019
05ee1b6
add a prestep for creating sage filename
JavonDavis Jun 24, 2019
7a9f12f
use correct name in utils
JavonDavis Jun 24, 2019
b7b7ac5
Merge branch 'develop' of https://github.com/wordpress-mobile/gutenbe…
JavonDavis Jun 24, 2019
b232607
update cache keys
JavonDavis Jun 24, 2019
ad97bd9
upgrade circleci image to api 29
JavonDavis Jun 24, 2019
041127f
upgrade circleci image to api 29
JavonDavis Jun 24, 2019
1ac420a
delete differently
JavonDavis Jun 24, 2019
41a18be
delete differently
JavonDavis Jun 24, 2019
e5da2df
delete differently on ios vs android
JavonDavis Jun 24, 2019
5797732
Merge branch 'develop' into add/tests-add-block-insertion
JavonDavis Jul 5, 2019
5ab6353
resolved test issues with merge
JavonDavis Jul 11, 2019
d28a01f
resolve ci changes
JavonDavis Jul 11, 2019
e44f34e
remove "its" from test data
JavonDavis Jul 11, 2019
c6a979b
try no cache option with jest to fix issue with tests not running in …
JavonDavis Jul 11, 2019
07a675d
try no cache option with jest to fix issue with tests not running in …
JavonDavis Jul 11, 2019
0a371c2
add max workers to jest command
JavonDavis Jul 11, 2019
987bb4a
remove detect open handles
JavonDavis Jul 11, 2019
b70ce37
Merge branch 'develop' of https://github.com/wordpress-mobile/gutenbe…
JavonDavis Jul 11, 2019
2cf5fe7
rename test to match new scenario
JavonDavis Jul 12, 2019
560efc2
update submodule
JavonDavis Jul 12, 2019
849a315
reduce max workers and increase timeout length to reduce driver colli…
JavonDavis Jul 12, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 12 additions & 10 deletions .circleci/config.yml
Expand Up @@ -6,13 +6,13 @@ commands:
- restore_cache:
name: Restore Yarn Cache
keys:
- yarn-i18n-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "yarn.lock" }}
- yarn-i18n-v3-{{ .Environment.CIRCLE_JOB }}-{{ checksum "yarn.lock" }}
- run:
name: Yarn Install
command: yarn install --frozen-lockfile --prefer-offline
- save_cache:
name: Save Yarn Cache
key: yarn-i18n-v1-{{ .Environment.CIRCLE_JOB }}-{{ checksum "yarn.lock" }}
key: yarn-i18n-v3-{{ .Environment.CIRCLE_JOB }}-{{ checksum "yarn.lock" }}
paths:
- node_modules
- i18n-cache/data
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:
path: ./reports/test-results
android-device-checks:
docker:
- image: circleci/android:api-28-node8-alpha
- image: circleci/android:api-29-node
steps:
- checkout
- run:
Expand All @@ -80,7 +80,8 @@ jobs:
- run:
name: Upload apk to sauce labs
command: |
curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" -X POST -H "Content-Type: application/octet-stream" https://saucelabs.com/rest/v1/storage/automattic/Gutenberg.apk?overwrite=true --data-binary @./android/app/build/outputs/apk/debug/app-debug.apk
source bin/sauce-pre-upload.sh
curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" -X POST -H "Content-Type: application/octet-stream" https://saucelabs.com/rest/v1/storage/automattic/Gutenberg-$SAUCE_FILENAME.apk?overwrite=true --data-binary @./android/app/build/outputs/apk/debug/app-debug.apk
- run:
name: Run Device Tests
command: yarn device-tests
Expand Down Expand Up @@ -111,21 +112,21 @@ jobs:
- restore_cache:
name: Restore Dependencies Cache
keys:
- dependencies-{{ checksum "react-native-aztec/ios/Cartfile.resolved" }}-{{
- dependencies-v2-{{ checksum "react-native-aztec/ios/Cartfile.resolved" }}-{{
checksum "yarn.lock" }}
- dependencies-{{ checksum "react-native-aztec/ios/Cartfile.resolved" }}
- dependencies-
- dependencies-v2-{{ checksum "react-native-aztec/ios/Cartfile.resolved" }}
- dependencies-v2-
- run:
name: Yarn preios (if needed)
command: test -e ios/build/gutenberg/Build/Products/Release-iphonesimulator/gutenberg.app || yarn preios
- save_cache:
name: Save Dependencies Cache
key: dependencies-{{ checksum "react-native-aztec/ios/Cartfile.resolved" }}-{{
key: dependencies-v2-{{ checksum "react-native-aztec/ios/Cartfile.resolved" }}-{{
checksum "yarn.lock" }}
paths:
- react-native-aztec/ios/Carthage
- ~/.rncache
- run:
- run:
name: Build (if needed)
command: test -e ios/build/gutenberg/Build/Products/Release-iphonesimulator/gutenberg.app || yarn react-native run-ios --configuration Release --no-packager
- run:
Expand All @@ -137,7 +138,8 @@ jobs:
- run:
name: Upload .app to sauce labs
command: |
curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" -X POST -H "Content-Type: application/octet-stream" https://saucelabs.com/rest/v1/storage/automattic/Gutenberg.app.zip?overwrite=true --data-binary @./ios/Gutenberg.app.zip
source bin/sauce-pre-upload.sh
curl -u "$SAUCE_USERNAME:$SAUCE_ACCESS_KEY" -X POST -H "Content-Type: application/octet-stream" https://saucelabs.com/rest/v1/storage/automattic/Gutenberg-$SAUCE_FILENAME.app.zip?overwrite=true --data-binary @./ios/Gutenberg.app.zip
- run:
name: Run Device Tests
command: |
Expand Down
114 changes: 114 additions & 0 deletions __device-tests__/gutenberg-editor-block-insertion.test.js
@@ -0,0 +1,114 @@
/**
* @format
* */

/**
* Internal dependencies
*/
import EditorPage from './pages/editor-page';
import {
setupDriver,
isLocalEnvironment,
stopDriver,
isAndroid,
clickMiddleOfElement,
} from './helpers/utils';
import testData from './helpers/test-data';

jasmine.DEFAULT_TIMEOUT_INTERVAL = 240000;

describe( 'Gutenberg Editor tests for Block insertion', () => {
let driver;
let editorPage;
let allPassed = true;

// Use reporter for setting status for saucelabs Job
if ( ! isLocalEnvironment() ) {
const reporter = {
specDone: async ( result ) => {
allPassed = allPassed && result.status !== 'failed';
},
};

jasmine.getEnv().addReporter( reporter );
}

beforeAll( async () => {
driver = await setupDriver();
editorPage = new EditorPage( driver );
} );

it( 'should be able to see visual editor', async () => {
await expect( editorPage.getBlockList() ).resolves.toBe( true );
} );

it( 'should be able to insert block into post', async () => {
await editorPage.addNewParagraphBlock();
let paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 1 );
if ( isAndroid() ) {
await paragraphBlockElement.click();
}
await editorPage.sendTextToParagraphBlockAtPosition( 1, testData.longText );
// Should have 3 paragraph blocks at this point

paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 2 );
await paragraphBlockElement.click();

await editorPage.addNewParagraphBlock();
paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 3 );
await paragraphBlockElement.click();
await editorPage.sendTextToParagraphBlockAtPosition( 3, testData.mediumText );

await editorPage.verifyHtmlContent( testData.blockInsertionHtml );

// Workaround for now since deleting the first element causes a crash on CI for Android
if ( isAndroid() ) {
paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 3 );
await paragraphBlockElement.click();
await editorPage.removeParagraphBlockAtPosition( 3 );
for ( let i = 3; i > 0; i-- ) {
paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( i );
await paragraphBlockElement.click();
await editorPage.removeParagraphBlockAtPosition( i );
}
} else {
for ( let i = 4; i > 0; i-- ) {
paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 1 );
await clickMiddleOfElement( driver, paragraphBlockElement );
await editorPage.removeParagraphBlockAtPosition( 1 );
}
}
} );

it( 'should be able to insert block at the end of post from the title', async () => {
mchowning marked this conversation as resolved.
Show resolved Hide resolved
await editorPage.addNewParagraphBlock();
let paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 1 );
if ( isAndroid() ) {
await paragraphBlockElement.click();
}
await editorPage.sendTextToParagraphBlockAtPosition( 1, testData.longText );
// Should have 3 paragraph blocks at this point

if ( isAndroid() ) {
await driver.hideDeviceKeyboard();
}

const titleElement = await editorPage.getTitleElement();
await titleElement.click();
await titleElement.click();

await editorPage.addNewParagraphBlock();
paragraphBlockElement = await editorPage.getParagraphBlockAtPosition( 1 );
await clickMiddleOfElement( driver, paragraphBlockElement );
await editorPage.sendTextToParagraphBlockAtPosition( 1, testData.mediumText );
await paragraphBlockElement.click();
await editorPage.verifyHtmlContent( testData.blockInsertionHtmlFromTitle );
} );

afterAll( async () => {
if ( ! isLocalEnvironment() ) {
driver.sauceJobStatus( allPassed );
}
await stopDriver( driver );
} );
} );
1 change: 1 addition & 0 deletions __device-tests__/gutenberg-editor-image.test.js
Expand Up @@ -63,6 +63,7 @@ describe( 'Gutenberg Editor Image Block tests', () => {
await swipeUp( driver, imageBlock );
await editorPage.enterCaptionToSelectedImageBlock( testData.imageCaption );
await editorPage.dismissKeyboard();
imageBlock = await editorPage.getImageBlockAtPosition( 1 );
await imageBlock.click();
}
await editorPage.removeImageBlockAtPosition( 1 );
Expand Down
4 changes: 2 additions & 2 deletions __device-tests__/helpers/caps.js
Expand Up @@ -13,8 +13,8 @@ exports.ios12 = {
exports.android8 = {
browserName: '',
platformName: 'Android',
platformVersion: '8.0',
deviceName: 'Android Emulator',
platformVersion: '9.0',
deviceName: 'Google Pixel 3 GoogleAPI Emulator',
mchowning marked this conversation as resolved.
Show resolved Hide resolved
automationName: 'UiAutomator2',
os: 'Android',
appPackage: 'com.gutenberg',
Expand Down
46 changes: 39 additions & 7 deletions __device-tests__/helpers/test-data.js
@@ -1,10 +1,10 @@
exports.shortText = `Rock music approaches at high velocity.`;

exports.mediumText = `The finer continuum interprets the polynomial rabbit. When can the geology cheat? An astronomer runs. Should a communist consent?`;
exports.mediumText = `The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?`;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changes here were made to avoid autocomplete causing validation errors.


exports.longText = `Beneath the busy continuum blinks the ineffective husband. Why a metric bow outside the official subway? How can the prompt crop exhaust his tree
exports.longText = `Beneath the busy continuum blinks the ineffective husband. Why a metric now outside the official subway? How can the prompt crop exhaust his tree
Does this chord crowd my emptied search? A theory bubbles under the cartoon. The discontinued speaker cracks every thick epic. Its extraordinary twin shifts behind
The finer continuum interprets the polynomial rabbit. When can the geology cheat? An astronomer runs. Should a communist consent?`;
The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?`;

exports.listItem1 = `Milk`;
exports.listItem2 = `Honey`;
Expand All @@ -31,11 +31,43 @@ exports.pasteHtmlText = pastedHtmlText;
exports.pasteHtmlTextResult = `${ pastedHtmlText }\n\n${ pastedHtmlText }`;

exports.deviceRotationHtml = `<!-- wp:paragraph -->
<p>The finer continuum interprets the polynomial rabbit. When can the geology cheat? An astronomer runs. Should a communist consent?</p>
<p>The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The finer continuum interprets the polynomial rabbit. When can the geology cheat? An astronomer runs. Should a communist consent?</p>
<p>The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?</p>
<!-- /wp:paragraph -->`;

exports.blockInsertionHtml = `<!-- wp:paragraph -->
<p>Beneath the busy continuum blinks the ineffective husband. Why a metric now outside the official subway? How can the prompt crop exhaust his tree </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Does this chord crowd my emptied search? A theory bubbles under the cartoon. The discontinued speaker cracks every thick epic. Its extraordinary twin shifts behind</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?</p>
<!-- /wp:paragraph -->`;

exports.blockInsertionHtmlFromTitle = `<!-- wp:paragraph -->
<p>The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Beneath the busy continuum blinks the ineffective husband. Why a metric now outside the official subway? How can the prompt crop exhaust his tree </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Does this chord crowd my emptied search? A theory bubbles under the cartoon. The discontinued speaker cracks every thick epic. Its extraordinary twin shifts behind</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?</p>
<!-- /wp:paragraph -->`;

exports.imageCaption = `C'est la vie my friends`;
Expand All @@ -45,13 +77,13 @@ exports.imageCompletehtml = `<!-- wp:image {"id":1} -->
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>Beneath the busy continuum blinks the ineffective husband. Why a metric bow outside the official subway? How can the prompt crop exhaust his tree </p>
<p>Beneath the busy continuum blinks the ineffective husband. Why a metric now outside the official subway? How can the prompt crop exhaust his tree </p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Does this chord crowd my emptied search? A theory bubbles under the cartoon. The discontinued speaker cracks every thick epic. Its extraordinary twin shifts behind</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The finer continuum interprets the polynomial rabbit. When can the geology cheat? An astronomer runs. Should a communist consent?</p>
<p>The finer continuum interprets the polynomial rabbit. When can the geology runs? An astronomer runs. Should a communist consent?</p>
<!-- /wp:paragraph -->`;
16 changes: 8 additions & 8 deletions __device-tests__/helpers/utils.js
Expand Up @@ -56,6 +56,8 @@ const isLocalEnvironment = () => {

// Initialises the driver and desired capabilities for appium
const setupDriver = async () => {
const branch = process.env.CIRCLE_BRANCH || '';
const safeBranchName = branch.replace( '/', '-' );
if ( isLocalEnvironment() ) {
try {
appiumProcess = await AppiumLocal.start( localAppiumPort );
Expand All @@ -79,28 +81,26 @@ const setupDriver = async () => {
.execSync( 'adb shell getprop ro.build.version.release' )
.toString()
.replace( /^\s+|\s+$/g, '' );
if ( ! isNaN( androidVersion ) ) {
delete desiredCaps.platformVersion;
// eslint-disable-next-line no-console
console.log( 'Detected Android device running Android %s', androidVersion );
}
delete desiredCaps.platformVersion;
desiredCaps.deviceName = 'Android Emulator';
// eslint-disable-next-line no-console
console.log( 'Detected Android device running Android %s', androidVersion );
} catch ( error ) {
// ignore error
}
} else {
desiredCaps.app = 'sauce-storage:Gutenberg.apk'; // App should be preloaded to sauce storage, this can also be a URL
desiredCaps.app = `sauce-storage:Gutenberg-${ safeBranchName }.apk`; // App should be preloaded to sauce storage, this can also be a URL
}
} else {
desiredCaps = _.clone( ios12 );
if ( isLocalEnvironment() ) {
desiredCaps.app = path.resolve( localIOSAppPath );
} else {
desiredCaps.app = 'sauce-storage:Gutenberg.app.zip'; // App should be preloaded to sauce storage, this can also be a URL
desiredCaps.app = `sauce-storage:Gutenberg-${ safeBranchName }.app.zip`; // App should be preloaded to sauce storage, this can also be a URL
}
}

if ( ! isLocalEnvironment() ) {
const branch = process.env.CIRCLE_BRANCH || '';
desiredCaps.name = `Gutenberg Editor Tests[${ rnPlatform }]-${ branch }`;
desiredCaps.tags = [ 'Gutenberg', branch ];
}
Expand Down
18 changes: 11 additions & 7 deletions __device-tests__/pages/editor-page.js
Expand Up @@ -49,6 +49,12 @@ export default class EditorPage {
return undefined !== await this.getBlockAtPosition( position, blockName );
}

async getTitleElement() {
//TODO: Improve the identifier for this element
const elements = await this.driver.elementsByXPath( `//*[contains(@${ this.accessibilityIdXPathAttrib }, "Post title.")]` );
return elements[ elements.length - 1 ];
}

async getTextViewForHtmlViewContent() {
const accessibilityId = 'html-view-content';
let blockLocator = `//*[@${ this.accessibilityIdXPathAttrib }="${ accessibilityId }"]`;
Expand All @@ -59,13 +65,6 @@ export default class EditorPage {
return await this.driver.elementByXPath( blockLocator );
}

async getTitleElement() {
//TODO: Improve the identifier for this element
const titleIdentifier = isAndroid() ? '//android.view.ViewGroup[@content-desc="Post title. Welcome to Gutenberg!"]/android.widget.EditText' :
'//XCUIElementTypeOther[@name="Add title"]/XCUIElementTypeTextView';
return await this.driver.elementByXPath( titleIdentifier );
}

// Converts to lower case and checks for a match to lowercased html content
// Ensure to take additional steps to handle text being changed by auto correct
async verifyHtmlContent( html: string ) {
Expand All @@ -89,6 +88,11 @@ export default class EditorPage {
}

async dismissKeyboard() {
await this.driver.sleep( 1000 ); /// wait for any keyboard animations
const keyboardShown = await this.driver.isKeyboardShown();
if ( ! keyboardShown ) {
return;
}
if ( isAndroid() ) {
return await this.driver.hideDeviceKeyboard();
}
Expand Down
9 changes: 9 additions & 0 deletions bin/sauce-pre-upload.sh
@@ -0,0 +1,9 @@
#!/bin/sh

# check if CIRCLE_BRANCH variable is set
if [[ -n "$CIRCLE_BRANCH" ]] ; then
# replace / with - and assign to new var SAUCE_FILENAME
export SAUCE_FILENAME=${CIRCLE_BRANCH//[\/]/-};
else
echo "Expected CIRCLE_BRANCH env variable";
mchowning marked this conversation as resolved.
Show resolved Hide resolved
fi