CB-12312: [Appium] [Android] A few changes to the tests:

- updated comments on how to run the tests. extra comments around functionality at certain points in the automation.
 - stub of a resolution checker on test startup - still need to figure out acceptable values.
 - moved session shutdown to an afterAll clause.
 - changed resolution determiner from using webview-based values to using the native windows dimensions - this helps as the webview values may be scaled down intentionally by manufacturers (via changing devicePixelRatio). furthermore, since the screen dimension automation is used purely for native UI automation, better to use the dimensions reported by the native context rather than the web context.
 - when finding elements by XPath, use multiple calls to avoid a Windows emulator + Android bug. Made this pattern consistent in the entire test.
This commit is contained in:
filmaj 2016-12-16 14:33:59 -08:00
parent a364e79482
commit 05594c4646

View File

@ -21,10 +21,12 @@
* *
*/ */
// these tests are meant to be executed by Cordova Medic Appium runner // these tests are meant to be executed by Cordova ParaMedic Appium runner
// you can find it here: https://github.com/apache/cordova-medic/ // you can find it here: https://github.com/apache/cordova-paramedic/
// it is not necessary to do a full CI setup to run these tests // it is not necessary to do a full CI setup to run these tests
// just run "node cordova-medic/medic/medic.js appium --platform android --plugins cordova-plugin-camera" // Run:
// node cordova-paramedic/main.js --platform android --plugin cordova-plugin-camera --skipMainTests --target <emulator name>
// Please note only Android 5.1 and 4.4 are supported at this point.
'use strict'; 'use strict';
@ -56,6 +58,8 @@ describe('Camera tests Android.', function () {
var appiumSessionStarted = false; var appiumSessionStarted = false;
// determine if camera is present on the device/emulator // determine if camera is present on the device/emulator
var cameraAvailable = false; var cameraAvailable = false;
// determine if emulator is within a range of acceptable resolutions able to run these tests
var isResolutionBad = true;
// a path to the image we add to the gallery before test run // a path to the image we add to the gallery before test run
var fillerImagePath; var fillerImagePath;
@ -121,7 +125,7 @@ describe('Camera tests Android.', function () {
y: Math.round(screenHeight / 4) y: Math.round(screenHeight / 4)
}); });
swipeRight swipeRight
.press({x: 10, y: 150}) .press({x: 10, y: Math.round(screenHeight / 4)})
.wait(300) .wait(300)
.moveTo({x: Math.round(screenWidth - (screenWidth / 8)), y: 0}) .moveTo({x: Math.round(screenWidth - (screenWidth / 8)), y: 0})
.wait(1500) .wait(1500)
@ -135,18 +139,19 @@ describe('Camera tests Android.', function () {
} }
return driver return driver
.waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000) .waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000)
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]') // multiple calls here for an Android bug:
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]') // on Windows + Android emulator, element selection
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]') // is completely wonky. Unfortunately duplicating element()
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]') // calls is the only workaround identified thus far.
.fail(function () { .fail(function () {
// If the Gallery button is not present, swipe right to reveal the Gallery button!
return driver return driver
.performTouchAction(swipeRight) .performTouchAction(swipeRight)
.waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000) .waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000)
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]'); .elementByXPath('//android.widget.TextView[@text="Gallery"]')
}) })
.click() .click()
// always wait before performing touchAction // always wait before performing touchAction
@ -158,10 +163,14 @@ describe('Camera tests Android.', function () {
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE / 2) .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE / 2)
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
.click() .click()
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE / 2) .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE / 2)
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
.click(); .click();
}) })
.then(function () { .then(function () {
@ -203,16 +212,25 @@ describe('Camera tests Android.', function () {
// deletes the latest image from the gallery // deletes the latest image from the gallery
function deleteImage() { function deleteImage() {
var holdTile = new wd.TouchAction(); var holdTile = new wd.TouchAction();
holdTile.press({x: Math.round(screenWidth / 4), y: Math.round(screenHeight / 5)}).wait(1000).release(); holdTile
.press({x: Math.round(screenWidth / 4), y: Math.round(screenHeight / 5)})
.wait(1000)
.release();
return driver return driver
// always wait before performing touchAction // always wait before performing touchAction
.sleep(7000) .sleep(7000)
.performTouchAction(holdTile) .performTouchAction(holdTile)
.elementByXPath('//android.widget.TextView[@text="Delete"]') .elementByXPath('//android.widget.TextView[@text="Delete"]')
.elementByXPath('//android.widget.TextView[@text="Delete"]')
.elementByXPath('//android.widget.TextView[@text="Delete"]')
.elementByXPath('//android.widget.TextView[@text="Delete"]')
.then(function (element) { .then(function (element) {
return element return element
.click() .click()
.elementByXPath('//android.widget.Button[@text="OK"]') .elementByXPath('//android.widget.Button[@text="OK"]')
.elementByXPath('//android.widget.Button[@text="OK"]')
.elementByXPath('//android.widget.Button[@text="OK"]')
.elementByXPath('//android.widget.Button[@text="OK"]')
.click(); .click();
}, function () { }, function () {
// couldn't find Delete menu item. Possibly there is no image. // couldn't find Delete menu item. Possibly there is no image.
@ -280,18 +298,27 @@ describe('Camera tests Android.', function () {
}; };
} }
function checkSession(done) { function checkSession(done, skipResolutionCheck) {
if (!appiumSessionStarted) { if (!appiumSessionStarted) {
fail('Failed to start a session'); fail('Failed to start a session ' + (lastFailureReason ? lastFailureReason : ''));
done(); done();
} }
if (!skipResolutionCheck && isResolutionBad) {
fail('The resolution of this target device is not within the appropriate range of width: blah-blah and height: bleh-bleh. The target\'s current resolution is: ' + isResolutionBad);
}
} }
function checkCamera(pending) { function checkCamera(pending) {
if (!cameraAvailable) { if (!cameraAvailable) {
pending('This test requires camera'); pending('This test requires a functioning camera on the Android device/emulator, and this test suite\'s functional camera test failed on your target environment.');
} }
} }
afterAll(function (done) {
checkSession(done);
driver
.quit()
.done(done);
}, MINUTE);
it('camera.ui.util configuring driver and starting a session', function (done) { it('camera.ui.util configuring driver and starting a session', function (done) {
getDriver() getDriver()
@ -302,18 +329,19 @@ describe('Camera tests Android.', function () {
}, 10 * MINUTE); }, 10 * MINUTE);
it('camera.ui.util determine screen dimensions', function (done) { it('camera.ui.util determine screen dimensions', function (done) {
checkSession(done); checkSession(done, /*skipResolutionCheck?*/ true); // skip the resolution check here since we are about to find out in this spec!
driver driver
.context(webviewContext) .context('NATIVE_APP')
.execute(function () { .getWindowSize()
return {
'width': screen.availWidth,
'height': screen.availHeight
};
}, [])
.then(function (size) { .then(function (size) {
screenWidth = Number(size.width); screenWidth = Number(size.width);
screenHeight = Number(size.height); screenHeight = Number(size.height);
isResolutionBad = false;
/*
TODO: what are acceptable resolution values?
need to check what the emulators used in CI return.
and also what local device definitions work and dont
*/
}) })
.done(done); .done(done);
}, MINUTE); }, MINUTE);
@ -374,6 +402,8 @@ describe('Camera tests Android.', function () {
.waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000) .waitForElementByXPath('//android.widget.TextView[@text="Gallery"]', 20000)
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
.then(function (element) { .then(function (element) {
return element.click(); return element.click();
}, function () { }, function () {
@ -384,6 +414,9 @@ describe('Camera tests Android.', function () {
// if the gallery is opened on the videos page, // if the gallery is opened on the videos page,
// there should be a "Choose video" caption // there should be a "Choose video" caption
return driver return driver
.elementByXPath('//*[@text="Choose video"]')
.elementByXPath('//*[@text="Choose video"]')
.elementByXPath('//*[@text="Choose video"]')
.elementByXPath('//*[@text="Choose video"]') .elementByXPath('//*[@text="Choose video"]')
.fail(function () { .fail(function () {
throw 'Couldn\'t find "Choose video" element.'; throw 'Couldn\'t find "Choose video" element.';
@ -391,6 +424,9 @@ describe('Camera tests Android.', function () {
}) })
.deviceKeyEvent(BACK_BUTTON) .deviceKeyEvent(BACK_BUTTON)
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
.deviceKeyEvent(BACK_BUTTON) .deviceKeyEvent(BACK_BUTTON)
.finally(function () { .finally(function () {
return driver return driver
@ -441,6 +477,8 @@ describe('Camera tests Android.', function () {
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]', MINUTE / 2) .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]', MINUTE / 2)
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]')
.click() .click()
.then(function () { .then(function () {
return checkPicture(false); return checkPicture(false);
@ -470,14 +508,20 @@ describe('Camera tests Android.', function () {
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE / 2) .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]', MINUTE / 2)
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
.click() .click()
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE / 2) .waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]', MINUTE / 2)
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
.click() .click()
.waitForElementByXPath('//*[contains(@resource-id,\'discard\')]', MINUTE / 2) .waitForElementByXPath('//*[contains(@resource-id,\'discard\')]', MINUTE / 2)
.elementByXPath('//*[contains(@resource-id,\'discard\')]') .elementByXPath('//*[contains(@resource-id,\'discard\')]')
.elementByXPath('//*[contains(@resource-id,\'discard\')]') .elementByXPath('//*[contains(@resource-id,\'discard\')]')
.elementByXPath('//*[contains(@resource-id,\'discard\')]')
.elementByXPath('//*[contains(@resource-id,\'discard\')]')
.click() .click()
.then(function () { .then(function () {
return checkPicture(false); return checkPicture(false);
@ -616,8 +660,14 @@ describe('Camera tests Android.', function () {
.elementById('Apps') .elementById('Apps')
.click() .click()
.elementByXPath('//android.widget.TextView[@text="Gallery"]') .elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
.click() .click()
.elementByXPath('//android.widget.TextView[contains(@text,"Pictures")]') .elementByXPath('//android.widget.TextView[contains(@text,"Pictures")]')
.elementByXPath('//android.widget.TextView[contains(@text,"Pictures")]')
.elementByXPath('//android.widget.TextView[contains(@text,"Pictures")]')
.elementByXPath('//android.widget.TextView[contains(@text,"Pictures")]')
.click() .click()
.then(deleteImage) .then(deleteImage)
.deviceKeyEvent(BACK_BUTTON) .deviceKeyEvent(BACK_BUTTON)
@ -630,10 +680,4 @@ describe('Camera tests Android.', function () {
}, 3 * MINUTE); }, 3 * MINUTE);
}); });
it('camera.ui.util Destroy the session', function (done) {
checkSession(done);
driver
.quit()
.done(done);
}, 5 * MINUTE);
}); });