Repository: cordova-plugin-camera
Updated Branches:
  refs/heads/master a9c18710f -> 82c9f4524


CB-11073 Appium tests stability improvements


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/commit/82c9f452
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/tree/82c9f452
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/diff/82c9f452

Branch: refs/heads/master
Commit: 82c9f4524a4720242d7572e479c533b498be0751
Parents: a9c1871
Author: Alexander Sorokin <alexander.soro...@akvelon.com>
Authored: Wed Apr 13 12:42:51 2016 +0300
Committer: Alexander Sorokin <alexander.soro...@akvelon.com>
Committed: Wed Apr 13 12:42:51 2016 +0300

----------------------------------------------------------------------
 appium-tests/android/android.spec.js     | 505 +++++++++-----------------
 appium-tests/helpers/cameraHelper.js     |  19 +
 appium-tests/helpers/screenshotHelper.js |  58 ---
 appium-tests/helpers/wdHelper.js         |  68 ----
 appium-tests/ios/ios.spec.js             | 234 ++++++------
 5 files changed, 286 insertions(+), 598 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/82c9f452/appium-tests/android/android.spec.js
----------------------------------------------------------------------
diff --git a/appium-tests/android/android.spec.js 
b/appium-tests/android/android.spec.js
index 37485ca..a011941 100644
--- a/appium-tests/android/android.spec.js
+++ b/appium-tests/android/android.spec.js
@@ -1,4 +1,5 @@
 /*jshint node: true, jasmine: true */
+/* global navigator, Q */
 /*
  *
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -27,18 +28,18 @@
 
 'use strict';
 
-var wdHelper = require('../helpers/wdHelper');
+var wdHelper = global.WD_HELPER;
+var screenshotHelper = global.SCREENSHOT_HELPER;
 var wd = wdHelper.getWD();
 var cameraConstants = require('../../www/CameraConstants');
 var cameraHelper = require('../helpers/cameraHelper');
-var screenshotHelper = require('../helpers/screenshotHelper');
 
-var STARTING_MESSAGE = 'Ready for action!';
-var RETRY_COUNT = 3; // how many times to retry taking a picture before failing
 var MINUTE = 60 * 1000;
+var BACK_BUTTON = 4;
 var DEFAULT_SCREEN_WIDTH = 360;
 var DEFAULT_SCREEN_HEIGHT = 567;
 var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW';
+var PROMISE_PREFIX = 'appium_camera_promise_';
 
 describe('Camera tests Android.', function () {
     var driver;
@@ -46,33 +47,29 @@ describe('Camera tests Android.', function () {
     var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
     // this indicates that the device library has the test picture:
     var isTestPictureSaved = false;
-    // this indicates that there was a critical error and we should try to 
recover:
-    var errorFlag = false;
-    // this indicates that we couldn't restore Appium session and should fail 
fast:
-    var stopFlag = false;
     // we need to know the screen width and height to properly click on an 
image in the gallery:
     var screenWidth = DEFAULT_SCREEN_WIDTH;
     var screenHeight = DEFAULT_SCREEN_HEIGHT;
+    // promise count to use in promise ID
+    var promiseCount = 0;
 
-    function win() {
-        expect(true).toBe(true);
+    function getNextPromiseId() {
+        promiseCount += 1;
+        return getCurrentPromiseId();
     }
 
-    function fail(error) {
-        screenshotHelper.saveScreenshot(driver);
-        if (error && error.message) {
-            console.log('An error occured: ' + error.message);
-            expect(true).toFailWithMessage(error.message);
-            throw error.message;
-        }
-        if (error) {
-            console.log('Failed expectation: ' + error);
-            expect(true).toFailWithMessage(error);
-            throw error;
-        }
-        // no message provided :(
-        expect(true).toBe(false);
-        throw 'An error without description occured';
+    function getCurrentPromiseId() {
+        return PROMISE_PREFIX + promiseCount;
+    }
+
+    function saveScreenshotAndFail(error) {
+        fail(error);
+        return screenshotHelper
+            .saveScreenshot(driver)
+            .quit()
+            .then(function () {
+                return getDriver();
+            });
     }
 
     // generates test specs by combining all the specified options
@@ -95,152 +92,110 @@ describe('Camera tests Android.', function () {
         return cameraHelper.generateSpecs(sourceTypes, destinationTypes, 
encodingTypes, allowEditOptions);
     }
 
-    function getPicture(options, skipUiInteractions, retry) {
+    // invokes Camera.getPicture() with the specified options
+    // and goes through all UI interactions unless 'skipUiInteractions' is true
+    function getPicture(options, skipUiInteractions) {
+        var promiseId = getNextPromiseId();
         if (!options) {
             options = {};
         }
-        if (typeof retry === 'undefined') {
-            retry = 1;
-        }
 
-        var command = "navigator.camera.getPicture(function (result) { 
document.getElementById('info').innerHTML = result.slice(0, 100); }, " +
-                      "function (err) { 
document.getElementById('info').innerHTML = 'ERROR: ' + err; }," + 
JSON.stringify(options) + ");";
         return driver
             .context(webviewContext)
-            .execute(command)
-            .sleep(7000)
+            .execute(cameraHelper.getPicture, [options, promiseId])
             .context('NATIVE_APP')
-            .sleep(5000)
             .then(function () {
                 if (skipUiInteractions) {
                     return;
                 }
+                // selecting a picture from gallery
                 if (options.hasOwnProperty('sourceType') &&
                         (options.sourceType === 
cameraConstants.PictureSourceType.PHOTOLIBRARY ||
                         options.sourceType === 
cameraConstants.PictureSourceType.SAVEDPHOTOALBUM)) {
-                    var touchTile = new wd.TouchAction(),
-                        swipeRight = new wd.TouchAction();
-                    touchTile.press({x: Math.round(screenWidth / 4), y: 
Math.round(screenHeight / 5)}).release();
-                    swipeRight.press({x: 10, y: Math.round(screenHeight * 
0.8)})
+                    var tapTile = new wd.TouchAction();
+                    var swipeRight = new wd.TouchAction();
+                    tapTile.tap({x: Math.round(screenWidth / 4), y: 
Math.round(screenHeight / 5)});
+                    swipeRight.press({x: 10, y: 100})
                         .wait(300)
-                        .moveTo({x: Math.round(screenWidth / 2), y: 
Math.round(screenHeight / 2)})
+                        .moveTo({x: Math.round(screenWidth / 2), y: 100})
                         .release();
                     return driver
-                        .performTouchAction(swipeRight)
-                        .sleep(3000)
-                        .elementByXPath('//*[@text="Gallery"]')
+                        
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
+                        .fail(function () {
+                            return driver
+                                .performTouchAction(swipeRight)
+                                
.elementByXPath('//android.widget.TextView[@text="Gallery"]');
+                        })
                         .then(function (element) {
-                            return element.click().sleep(5000);
+                            return element
+                                .click()
+                                // we need to sleep here to give a sidebar 
some time to close
+                                // if we don't sleep here, sometimes we would 
click on a sidebar
+                                // in the next step
+                                .sleep(3000);
                         }, function () {
-                            // if the gallery is already opened, we'd just go 
on:
+                            // the gallery is already opened, just go on:
                             return driver;
                         })
-                        .performTouchAction(touchTile);
+                        .performTouchAction(tapTile);
                 }
+                // taking a picture from camera
                 return driver
-                    
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
-                    .click()
-                    .sleep(3000)
-                    
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
+                    
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]',
 MINUTE)
                     .click()
-                    .sleep(10000);
+                    
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]',
 MINUTE)
+                    .click();
             })
             .then(function () {
                 if (skipUiInteractions) {
                     return;
                 }
-                if (options.hasOwnProperty('allowEdit') && options.allowEdit 
=== true) {
+                if (options.allowEdit) {
                     return driver
-                        .elementByXPath('//*[contains(@resource-id,\'save\')]')
+                        
.waitForElementByXPath('//*[contains(@resource-id,\'save\')]', MINUTE)
                         .click();
                 }
             })
-            .then(function () {
-                if (!skipUiInteractions) {
-                    return driver.sleep(10000);
-                }
-            })
-            .fail(function (error) {
-                if (retry < RETRY_COUNT) {
-                    console.log('Failed to get a picture. Let\'s try it 
again... ');
-                    return getPicture(options, skipUiInteractions, ++retry);
-                } else {
-                    console.log('Tried ' + RETRY_COUNT + ' times but couldn\'t 
get the picture. Failing...');
-                    fail(error);
-                }
-            });
-    }
-
-    function enterTest() {
-        return driver
-            // trying to determine where we are
-            .context(webviewContext)
-            .fail(function (error) {
-                fail(error);
-            })
-            .elementById('info')
-            .then(function () {
-                return driver; //we're already on the test screen
-            }, function () {
-                return driver
-                    .elementById('middle')
-                    .then(function () {
-                        return driver
-                            // we're on autotests page, we should go to start 
page
-                            .execute('window.location = "../index.html"')
-                            .sleep(5000)
-                            .fail(function () {
-                                errorFlag = true;
-                                throw 'Couldn\'t find start page.';
-                            });
-                    }, function () {
-                        return; // no-op
-                    })
-                    // unknown starting page: no 'info' div
-                    // adding it manually
-                    .execute('var info = document.createElement("div"); ' +
-                             'info.id = "info"; ' +
-                             'document.body.appendChild(info);');
-            })
-            .sleep(5000);
+            .fail(fail);
     }
 
+    // checks if the picture was successfully taken
+    // if shouldLoad is falsy, ensures that the error callback was called
     function checkPicture(shouldLoad) {
         return driver
             .context(webviewContext)
-            .elementById('info')
-            .getAttribute('innerHTML')
-            .then(function (html) {
-                if (html.indexOf(STARTING_MESSAGE) >= 0) {
-                    expect(true).toFailWithMessage('No callback was fired');
-                } else if (shouldLoad) {
-                    expect(html.length).toBeGreaterThan(0);
-                    if (html.indexOf('ERROR') >= 0) {
-                        fail(html);
+            .setAsyncScriptTimeout(MINUTE)
+            .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId()])
+            .then(function (result) {
+                if (shouldLoad) {
+                    expect(result.length).toBeGreaterThan(0);
+                    if (result.indexOf('ERROR') >= 0) {
+                        return fail(result);
                     }
                 } else {
-                    if (html.indexOf('ERROR') === -1) {
-                        fail('Unexpected success callback with result: ' + 
html);
+                    if (result.indexOf('ERROR') === -1) {
+                        return fail('Unexpected success callback with result: 
' + result);
                     }
-                    expect(html.indexOf('ERROR')).toBe(0);
+                    expect(result.indexOf('ERROR')).toBe(0);
                 }
             });
     }
 
     function runCombinedSpec(spec) {
-        return enterTest()
+        return driver
             .then(function () {
                 return getPicture(spec.options);
             })
             .then(function () {
                 return checkPicture(true);
             })
-            .then(win, fail);
+            .fail(saveScreenshotAndFail);
     }
 
+    // deletes the latest image from the gallery
     function deleteImage() {
         var holdTile = new wd.TouchAction();
-        holdTile.press({x: Math.round(screenWidth / 3), 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
             .performTouchAction(holdTile)
             .elementByXPath('//android.widget.TextView[@text="Delete"]')
@@ -251,141 +206,48 @@ describe('Camera tests Android.', function () {
                     .click();
             }, function () {
                 // couldn't find Delete menu item. Possibly there is no image.
-                return;
+                return driver;
             });
     }
 
     function getDriver() {
         driver = wdHelper.getDriver('Android');
-        return driver;
-    }
-
-    function checkStopFlag() {
-        if (stopFlag) {
-            fail('Something went wrong: the stopFlag is on. Please see the log 
for more details.');
-        }
-        return stopFlag;
+        return wdHelper.getWebviewContext(driver)
+            .then(function(context) {
+                webviewContext = context;
+                return driver.context(webviewContext);
+            })
+            .then(function () {
+                return wdHelper.waitForDeviceReady(driver);
+            })
+            .then(function () {
+                return wdHelper.injectLibraries(driver);
+            });
     }
 
-    beforeEach(function () {
-        jasmine.addMatchers({
-            toFailWithMessage : function () {
-                return {
-                    compare: function (actual, msg) {
-                        console.log('Failing with message: ' + msg);
-                        var result = {
-                            pass: false,
-                            message: msg
-                        };
-                        // status 6 means that we've lost the session
-                        // status 7 means that Appium couldn't find an element
-                        // both these statuses mean that the test has failed 
but
-                        // we should try to recreate the session for the 
following tests
-                        if (msg.indexOf('Error response status: 6') >= 0 ||
-                            msg.indexOf('Error response status: 7') >= 0) {
-                            errorFlag = true;
-                        }
-                        return result;
-                    }
-                };
-            }
-        });
-    });
-
     it('camera.ui.util configuring driver and starting a session', function 
(done) {
-        stopFlag = true; // just in case of timeout
-        getDriver().then(function () {
-            stopFlag = false;
-        }, function (error) {
-            fail(error);
-        })
-        .finally(done);
+        getDriver()
+            .fail(fail)
+            .done(done);
     }, 5 * MINUTE);
 
-    it('camera.ui.util determine webview context name', function (done) {
-        var i = 0;
-        return driver
-            .contexts(function (err, contexts) {
-                if (err) {
-                    console.log(err);
-                }
-                for (i = 0; i < contexts.length; i++) {
-                    if (contexts[i].indexOf('mobilespec') >= 0) {
-                        webviewContext = contexts[i];
-                    }
-                }
-                done();
-            });
-    }, MINUTE);
-
     it('camera.ui.util determine screen dimensions', function (done) {
-        return enterTest()
-            .execute('document.getElementById(\'info\').innerHTML = 
window.innerWidth;')
-            .sleep(5000)
-            .elementById('info')
-            .getAttribute('innerHTML')
-            .then(function (html) {
-                if (html !== STARTING_MESSAGE) {
-                    screenWidth = Number(html);
-                }
+        return driver
+            .context(webviewContext)
+            .execute(function () {
+                return {
+                    'width': window.innerWidth,
+                    'height': window.innerHeight
+                };
+            }, [])
+            .then(function (size) {
+                screenWidth = Number(size.width);
+                screenHeight = Number(size.height);
             })
-            .execute('document.getElementById(\'info\').innerHTML = \'' + 
STARTING_MESSAGE + '\';')
-            .execute('document.getElementById(\'info\').innerHTML = 
window.innerHeight;')
-            .sleep(5000)
-            .elementById('info')
-            .getAttribute('innerHTML')
-            .then(function (html) {
-                if (html !== STARTING_MESSAGE) {
-                    screenHeight = Number(html);
-                }
-                done();
-            });
+            .done(done);
     }, MINUTE);
 
     describe('Specs.', function () {
-        beforeEach(function (done) {
-            // prepare the app for the test
-            if (!stopFlag) {
-                return driver
-                    .context(webviewContext)
-                    .then(function () {
-                        return driver; // no-op
-                    }, function (error) {
-                        expect(true).toFailWithMessage(error);
-                    })
-                    .execute('document.getElementById("info").innerHTML = "' + 
STARTING_MESSAGE + '";')
-                    .finally(done);
-            }
-            done();
-        }, 3 * MINUTE);
-
-        afterEach(function (done) {
-            if (!errorFlag || stopFlag) {
-                // either there's no error or we've failed irrecoverably
-                // nothing to worry about!
-                done();
-                return;
-            }
-            // recreate the session if there was a critical error in a 
previous spec
-            stopFlag = true; // we're going to set this to false if we're able 
to restore the session
-            return driver
-                .quit()
-                .then(function () {
-                    return getDriver()
-                        .then(function () {
-                            errorFlag = false;
-                            stopFlag = false;
-                        }, function (error) {
-                            fail(error);
-                            stopFlag = true;
-                        });
-                }, function (error) {
-                    fail(error);
-                    stopFlag = true;
-                })
-                .finally(done);
-        }, 3 * MINUTE);
-
         // getPicture() with saveToPhotoLibrary = true
         it('camera.ui.spec.1 Saving the picture to photo library', function 
(done) {
             var options = {
@@ -394,8 +256,7 @@ describe('Camera tests Android.', function () {
                 sourceType: cameraConstants.PictureSourceType.CAMERA,
                 saveToPhotoAlbum: true
             };
-            enterTest()
-                .context(webviewContext)
+            driver
                 .then(function () {
                     return getPicture(options);
                 })
@@ -403,40 +264,26 @@ describe('Camera tests Android.', function () {
                     isTestPictureSaved = true;
                     return checkPicture(true);
                 })
-                .then(win, fail)
-                .finally(done);
+                .fail(saveScreenshotAndFail)
+                .done(done);
         }, 3 * MINUTE);
 
         // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY
         it('camera.ui.spec.2 Selecting only videos', function (done) {
-            if (checkStopFlag()) {
-                done();
-                return;
-            }
             var options = { sourceType: 
cameraConstants.PictureSourceType.PHOTOLIBRARY,
                             mediaType: cameraConstants.MediaType.VIDEO };
-            enterTest()
+            driver
                 .then(function () {
                     return getPicture(options, true);
                 })
-                .sleep(5000)
-                .context(webviewContext)
-                .elementById('info')
-                .getAttribute('innerHTML')
-                .then(function (html) {
-                    if (html.indexOf('ERROR') >= 0) {
-                        throw html;
-                    }
-                })
                 .context('NATIVE_APP')
-                .sleep(5000)
                 .then(function () {
                     // try to find "Gallery" menu item
                     // if there's none, the gallery should be already opened
                     return driver
-                        .elementByXPath('//*[@text="Gallery"]')
+                        
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
                         .then(function (element) {
-                            return element.click().sleep(2000);
+                            return element.click();
                         }, function () {
                             return driver;
                         });
@@ -450,143 +297,115 @@ describe('Camera tests Android.', function () {
                             throw 'Couldn\'t find "Choose video" element.';
                         });
                 })
-                .then(win, fail)
-                .deviceKeyEvent(4)
-                .sleep(2000)
-                .deviceKeyEvent(4)
-                .sleep(2000)
-                .elementById('action_bar_title')
-                .then(function () {
-                    // success means we're still in native app
+                .deviceKeyEvent(BACK_BUTTON)
+                .elementByXPath('//android.widget.TextView[@text="Gallery"]')
+                .deviceKeyEvent(BACK_BUTTON)
+                .finally(function () {
                     return driver
-                        .deviceKeyEvent(4)
-                        .sleep(2000);
-                }, function () {
-                    // error means we're already in webview
-                    return driver;
+                        .elementById('action_bar_title')
+                        .then(function () {
+                            // success means we're still in native app
+                            return driver
+                                .deviceKeyEvent(BACK_BUTTON);
+                        }, function () {
+                            // error means we're already in webview
+                            return driver;
+                        });
                 })
-                .finally(done);
+                .fail(saveScreenshotAndFail)
+                .done(done);
         }, 3 * MINUTE);
 
         // getPicture(), then dismiss
-        // wait for the error callback to bee called
+        // wait for the error callback to be called
         it('camera.ui.spec.3 Dismissing the camera', function (done) {
-            if (checkStopFlag()) {
-                done();
-                return;
-            }
             var options = { quality: 50,
                             allowEdit: true,
                             sourceType: 
cameraConstants.PictureSourceType.CAMERA,
                             destinationType: 
cameraConstants.DestinationType.FILE_URI };
-            enterTest()
-                .context(webviewContext)
+            driver
                 .then(function () {
                     return getPicture(options, true);
                 })
-                .sleep(5000)
                 .context("NATIVE_APP")
-                
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]')
+                
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]',
 MINUTE / 2)
                 .click()
-                .context(webviewContext)
                 .then(function () {
-                    return driver
-                        .elementByXPath('//*[contains(text(),"Camera 
cancelled")]')
-                        .then(function () {
-                            return checkPicture(false);
-                        }, function () {
-                            throw 'Couldn\'t find "Camera cancelled" message.';
-                        });
+                    return checkPicture(false);
                 })
-                .then(win, fail)
-                .finally(done);
+                .fail(saveScreenshotAndFail)
+                .done(done);
         }, 3 * MINUTE);
 
         // getPicture(), then take picture but dismiss the edit
-        // wait for the error cllback to be called
+        // wait for the error callback to be called
         it('camera.ui.spec.4 Dismissing the edit', function (done) {
-            if (checkStopFlag()) {
-                done();
-                return;
-            }
             var options = { quality: 50,
                             allowEdit: true,
                             sourceType: 
cameraConstants.PictureSourceType.CAMERA,
                             destinationType: 
cameraConstants.DestinationType.FILE_URI };
-            enterTest()
-                .context(webviewContext)
+            driver
                 .then(function () {
                     return getPicture(options, true);
                 })
-                .sleep(5000)
                 .context('NATIVE_APP')
-                
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]')
+                
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]',
 MINUTE / 2)
                 .click()
-                
.elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]')
+                
.waitForElementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]',
 MINUTE / 2)
                 .click()
-                .elementByXPath('//*[contains(@resource-id,\'discard\')]')
+                
.waitForElementByXPath('//*[contains(@resource-id,\'discard\')]', MINUTE / 2)
                 .click()
-                .sleep(5000)
-                .context(webviewContext)
                 .then(function () {
-                    return driver
-                        .elementByXPath('//*[contains(text(),"Camera 
cancelled")]')
-                        .then(function () {
-                            return checkPicture(false);
-                        }, function () {
-                            throw 'Couldn\'t find "Camera cancelled" message.';
-                        });
+                    return checkPicture(false);
                 })
-                .then(win, fail)
-                .finally(done);
+                .fail(saveScreenshotAndFail)
+                .done(done);
         }, 3 * MINUTE);
 
         // combine various options for getPicture()
         generateSpecs().forEach(function (spec) {
             it('camera.ui.spec.5.' + spec.id + ' Combining options', function 
(done) {
-                if (checkStopFlag()) {
-                    done();
-                    return;
-                }
-                runCombinedSpec(spec).then(done);
+                runCombinedSpec(spec)
+                    .done(done);
             }, 3 * MINUTE);
         });
 
 
         it('camera.ui.util Delete test image from device library', function 
(done) {
-            if (checkStopFlag()) {
+            if (!isTestPictureSaved) {
+                // couldn't save test picture earlier, so nothing to delete 
here
                 done();
                 return;
             }
-            if (isTestPictureSaved) {
-                // delete exactly one last picture
-                // this should be the picture we've taken in the first spec
-                return driver
-                    .context('NATIVE_APP')
-                    .deviceKeyEvent(3)
-                    .sleep(5000)
-                    .elementByName('Apps')
-                    .click()
-                    
.elementByXPath('//android.widget.TextView[@text="Gallery"]')
-                    .click()
-                    
.elementByXPath('//android.widget.TextView[contains(@text,"Pictures")]')
-                    .then(function (element) {
-                        return element
-                            .click()
-                            .sleep(3000)
-                            .then(deleteImage)
-                            .then(function () { done(); }, function () { 
done(); });
-                    }, function () {
-                        done();
-                    });
-            }
-            // couldn't save test picture earlier, so nothing to delete here
-            done();
+            // delete exactly one latest picture
+            // this should be the picture we've taken in the first spec
+            return driver
+                .context('NATIVE_APP')
+                .deviceKeyEvent(BACK_BUTTON)
+                .sleep(1000)
+                .deviceKeyEvent(BACK_BUTTON)
+                .sleep(1000)
+                .deviceKeyEvent(BACK_BUTTON)
+                .elementById('Apps')
+                .click()
+                .elementByXPath('//android.widget.TextView[@text="Gallery"]')
+                .click()
+                
.elementByXPath('//android.widget.TextView[contains(@text,"Pictures")]')
+                .click()
+                .then(deleteImage)
+                .deviceKeyEvent(BACK_BUTTON)
+                .sleep(1000)
+                .deviceKeyEvent(BACK_BUTTON)
+                .sleep(1000)
+                .deviceKeyEvent(BACK_BUTTON)
+                .fail(fail)
+                .finally(done);
         }, 3 * MINUTE);
-
     });
 
     it('camera.ui.util Destroy the session', function (done) {
-        return driver.quit(done);
+        driver
+            .quit()
+            .done(done);
     }, MINUTE);
 });

http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/82c9f452/appium-tests/helpers/cameraHelper.js
----------------------------------------------------------------------
diff --git a/appium-tests/helpers/cameraHelper.js 
b/appium-tests/helpers/cameraHelper.js
index 9342a30..8a746f3 100644
--- a/appium-tests/helpers/cameraHelper.js
+++ b/appium-tests/helpers/cameraHelper.js
@@ -1,4 +1,5 @@
 /*jshint node: true */
+/* global Q */
 /*
  *
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -84,3 +85,21 @@ module.exports.generateSpecs = function (sourceTypes, 
destinationTypes, encoding
     }
     return specs;
 };
+
+module.exports.getPicture = function (opts, pid) {
+    navigator._appiumPromises[pid] = Q.defer();
+    navigator.camera.getPicture(function (result) {
+        navigator._appiumPromises[pid].resolve(result);
+    }, function (err) {
+        navigator._appiumPromises[pid].reject(err);
+    }, opts);
+};
+
+module.exports.checkPicture = function (pid, cb) {
+    navigator._appiumPromises[pid].promise
+        .then(function (result) {
+            cb(result);
+        }, function (err) {
+            cb('ERROR: ' + err);
+        });
+};

http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/82c9f452/appium-tests/helpers/screenshotHelper.js
----------------------------------------------------------------------
diff --git a/appium-tests/helpers/screenshotHelper.js 
b/appium-tests/helpers/screenshotHelper.js
deleted file mode 100644
index e3cf136..0000000
--- a/appium-tests/helpers/screenshotHelper.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/* jshint node: true */
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
-*/
-
-'use strict';
-
-var path = require('path');
-var screenshotPath = global.SCREENSHOT_PATH || path.join(__dirname, 
'../../../appium_screenshots/');
-
-function generateScreenshotName() {
-    var date = new Date();
-
-    var month = date.getMonth() + 1;
-    var day = date.getDate();
-    var hour = date.getHours();
-    var min = date.getMinutes();
-    var sec = date.getSeconds();
-
-    month = (month < 10 ? "0" : "") + month;
-    day = (day < 10 ? "0" : "") + day;
-    hour = (hour < 10 ? "0" : "") + hour;
-    min = (min < 10 ? "0" : "") + min;
-    sec = (sec < 10 ? "0" : "") + sec;
-
-    return date.getFullYear() + '-' + month + '-' + day + '_' +  hour + '.' + 
min + '.' + sec + '.png';
-}
-
-module.exports.saveScreenshot = function (driver) {
-    var oldContext;
-    return driver
-        .currentContext()
-        .then(function (cc) {
-            oldContext = cc;
-        })
-        .context('NATIVE_APP')
-        .saveScreenshot(path.join(screenshotPath, generateScreenshotName()))
-        .then(function () {
-            return driver.context(oldContext);
-        });
-};

http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/82c9f452/appium-tests/helpers/wdHelper.js
----------------------------------------------------------------------
diff --git a/appium-tests/helpers/wdHelper.js b/appium-tests/helpers/wdHelper.js
deleted file mode 100644
index f14c933..0000000
--- a/appium-tests/helpers/wdHelper.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/* jshint node: true */
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
-*/
-
-'use strict';
-
-var wd = global.WD || require('wd');
-var driver;
-
-module.exports.getDriver = function (platform, callback) {
-    var serverConfig = {
-        host: 'localhost',
-        port: 4723
-    },
-        driverConfig = {
-            browserName: '',
-            'appium-version': '1.5',
-            platformName: platform,
-            platformVersion: global.PLATFORM_VERSION || '',
-            deviceName: global.DEVICE_NAME || '',
-            app: global.PACKAGE_PATH,
-            autoAcceptAlerts: true,
-        };
-
-    if (process.env.CHROMEDRIVER_EXECUTABLE) {
-        driverConfig.chromedriverExecutable = 
process.env.CHROMEDRIVER_EXECUTABLE;
-    }
-    driver = wd.promiseChainRemote(serverConfig);
-    module.exports.configureLogging(driver);
-
-    return driver.init(driverConfig).setImplicitWaitTimeout(10000)
-        .sleep(20000) // wait for the app to load
-        .then(callback);
-};
-
-module.exports.getWD = function () {
-    return wd;
-};
-
-module.exports.configureLogging = function (driver) {
-    driver.on('status', function (info) {
-        console.log(info);
-    });
-    driver.on('command', function (meth, path, data) {
-        console.log(' > ' + meth, path, data || '');
-    });
-    driver.on('http', function (meth, path, data) {
-        console.log(' > ' + meth, path, data || '');
-    });
-};

http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/82c9f452/appium-tests/ios/ios.spec.js
----------------------------------------------------------------------
diff --git a/appium-tests/ios/ios.spec.js b/appium-tests/ios/ios.spec.js
index 4b82fb2..27644ef 100644
--- a/appium-tests/ios/ios.spec.js
+++ b/appium-tests/ios/ios.spec.js
@@ -1,4 +1,5 @@
 /*jshint node: true, jasmine: true */
+/* global navigator, Q */
 /*
  *
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -27,41 +28,40 @@
 
 'use strict';
 
-var wdHelper = require('../helpers/wdHelper');
+var wdHelper = global.WD_HELPER;
+var screenshotHelper = global.SCREENSHOT_HELPER;
 var wd = wdHelper.getWD();
 var isDevice = global.DEVICE;
 var cameraConstants = require('../../www/CameraConstants');
 var cameraHelper = require('../helpers/cameraHelper');
-var screenshotHelper = require('../helpers/screenshotHelper');
 
 var MINUTE = 60 * 1000;
 var DEFAULT_WEBVIEW_CONTEXT = 'WEBVIEW_1';
+var PROMISE_PREFIX = 'appium_camera_promise_';
 
 describe('Camera tests iOS.', function () {
-
     var driver;
     var webviewContext = DEFAULT_WEBVIEW_CONTEXT;
-    var startingMessage = 'Ready for action!';
+    // promise count to use in promise ID
+    var promiseCount = 0;
 
-    function win() {
-        expect(true).toBe(true);
+    function getNextPromiseId() {
+        promiseCount += 1;
+        return getCurrentPromiseId();
     }
 
-    function fail(error) {
-        screenshotHelper.saveScreenshot(driver);
-        if (error && error.message) {
-            console.log('An error occured: ' + error.message);
-            expect(true).toFailWithMessage(error.message);
-            throw error.message;
-        }
-        if (error) {
-            console.log('Failed expectation: ' + error);
-            expect(true).toFailWithMessage(error);
-            throw error;
-        }
-        // no message provided :(
-        expect(true).toBe(false);
-        throw 'An error without description occured';
+    function getCurrentPromiseId() {
+        return PROMISE_PREFIX + promiseCount;
+    }
+
+    function saveScreenshotAndFail(error) {
+        fail(error);
+        return screenshotHelper
+            .saveScreenshot(driver)
+            .quit()
+            .then(function () {
+                return getDriver();
+            });
     }
 
     // generates test specs by combining all the specified options
@@ -84,17 +84,34 @@ describe('Camera tests iOS.', function () {
         return cameraHelper.generateSpecs(sourceTypes, destinationTypes, 
encodingTypes, allowEditOptions);
     }
 
+    function usePicture() {
+        return driver
+            .elementByXPath('//*[@label="Use"]')
+            .click()
+            .fail(function () {
+                return driver
+                    // For some reason "Choose" element is not clickable by 
standard Appium methods
+                    // So getting its position and tapping there using 
TouchAction
+                    .elementByXPath('//UIAButton[@label="Choose"]')
+                    .getLocation()
+                    .then(function (loc) {
+                        var tapChoose = new wd.TouchAction();
+                        tapChoose.tap(loc);
+                        return driver
+                            .performTouchAction(tapChoose);
+                    });
+            });
+    }
+
     function getPicture(options, cancelCamera, skipUiInteractions) {
+        var promiseId = getNextPromiseId();
         if (!options) {
             options = {};
         }
-        var command = "navigator.camera.getPicture(function (result) { 
document.getElementById('info').innerHTML = 'Success: ' + result.slice(0, 100); 
}, " +
-                      "function (err) { 
document.getElementById('info').innerHTML = 'ERROR: ' + err; }," + 
JSON.stringify(options) + ");";
+
         return driver
-            .sleep(2000)
             .context(webviewContext)
-            .execute(command)
-            .sleep(5000)
+            .execute(cameraHelper.getPicture, [options, promiseId])
             .context('NATIVE_APP')
             .then(function () {
                 if (skipUiInteractions) {
@@ -102,187 +119,146 @@ describe('Camera tests iOS.', function () {
                 }
                 if (options.hasOwnProperty('sourceType') && options.sourceType 
=== cameraConstants.PictureSourceType.PHOTOLIBRARY) {
                     return driver
-                        .elementByName('Camera Roll')
+                        .waitForElementByXPath('//*[@label="Camera Roll"]', 
MINUTE / 2)
                         .click()
                         .elementByXPath('//UIACollectionCell')
                         .click()
                         .then(function () {
-                            if (options.hasOwnProperty('allowEdit') && 
options.allowEdit === true) {
-                                return driver
-                                    .elementByName('Use')
-                                    .click();
+                            if (!options.allowEdit) {
+                                return driver;
                             }
-                            return driver;
+                            return usePicture();
                         });
                 }
                 if (options.hasOwnProperty('sourceType') && options.sourceType 
=== cameraConstants.PictureSourceType.SAVEDPHOTOALBUM) {
                     return driver
-                        .elementByXPath('//UIACollectionCell')
+                        .waitForElementByXPath('//UIACollectionCell', MINUTE / 
2)
                         .click()
                         .then(function () {
-                            if (options.hasOwnProperty('allowEdit') && 
options.allowEdit === true) {
-                                return driver
-                                    .elementByName('Use')
-                                    .click();
+                            if (!options.allowEdit) {
+                                return driver;
                             }
-                            return driver;
+                            return usePicture();
                         });
                 }
                 if (cancelCamera) {
                     return driver
-                        .elementByName('Cancel')
+                        .waitForElementByXPath('//*[@label="Cancel"]', MINUTE 
/ 2)
                         .click();
                 }
                 return driver
-                    .elementByName('PhotoCapture')
+                    .waitForElementByXPath('//*[@label="Take Picture"]', 
MINUTE / 2)
                     .click()
-                    .elementByName('Use Photo')
+                    .elementByXPath('//*[@label="Use Photo"]')
                     .click();
             })
-            .sleep(3000);
-    }
-
-    function enterTest() {
-        return driver
-            .contexts(function (err, contexts) {
-                if (err) {
-                    fail(err);
-                } else {
-                    // if WEBVIEW context is available, use it
-                    // if not, use NATIVE_APP
-                    webviewContext = contexts[contexts.length - 1];
-                }
-            })
-            .then(function () {
-                return driver
-                    .context(webviewContext);
-            })
-            .fail(fail)
-            .elementById('info')
-            .fail(function () {
-                // unknown starting page: no 'info' div
-                // adding it manually
-                return driver
-                    .execute('var info = document.createElement("div"); ' +
-                             'info.id = "info"' +
-                             'document.body.appendChild(info);')
-                    .fail(fail);
-            })
-            .execute('document.getElementById("info").innerHTML = "' + 
startingMessage + '";')
             .fail(fail);
     }
 
+    // checks if the picture was successfully taken
+    // if shouldLoad is falsy, ensures that the error callback was called
     function checkPicture(shouldLoad) {
         return driver
-            .contexts(function (err, contexts) {
-                // if WEBVIEW context is available, use it
-                // if not, use NATIVE_APP
-                webviewContext = contexts[contexts.length - 1];
-            })
             .context(webviewContext)
-            .elementById('info')
-            .getAttribute('innerHTML')
-            .then(function (html) {
-                if (html.indexOf(startingMessage) >= 0) {
-                    expect(true).toFailWithMessage('No callback was fired');
-                } else if (shouldLoad) {
-                    expect(html.length).toBeGreaterThan(0);
-                    if (html.indexOf('ERROR') >= 0) {
-                        expect(true).toFailWithMessage(html);
+            .setAsyncScriptTimeout(MINUTE)
+            .executeAsync(cameraHelper.checkPicture, [getCurrentPromiseId()])
+            .then(function (result) {
+                if (shouldLoad) {
+                    expect(result.length).toBeGreaterThan(0);
+                    if (result.indexOf('ERROR') >= 0) {
+                        return fail(result);
                     }
                 } else {
-                    if (html.indexOf('ERROR') === -1) {
-                        expect(true).toFailWithMessage('Unexpected success 
callback with result: ' + html);
+                    if (result.indexOf('ERROR') === -1) {
+                        return fail('Unexpected success callback with result: 
' + result);
                     }
-                    expect(html.indexOf('ERROR')).toBe(0);
+                    expect(result.indexOf('ERROR')).toBe(0);
                 }
-            })
-            .context('NATIVE_APP');
+            });
     }
 
     function runCombinedSpec(spec) {
-        return enterTest()
+        return driver
             .then(function () {
                 return getPicture(spec.options);
             })
             .then(function () {
                 return checkPicture(true);
             })
-            .then(win, fail);
+            .fail(saveScreenshotAndFail);
     }
 
-    beforeEach(function () {
-        jasmine.addMatchers({
-            toFailWithMessage : function () {
-                return {
-                    compare: function (actual, msg) {
-                        console.log('Failing with message: ' + msg);
-                        var result = {
-                            pass: false,
-                            message: msg
-                        };
-                        return result;
-                    }
-                };
-            }
-        });
-    });
+    function getDriver() {
+        driver = wdHelper.getDriver('iOS');
+        return wdHelper.getWebviewContext(driver)
+            .then(function(context) {
+                webviewContext = context;
+                return driver.context(webviewContext);
+            })
+            .then(function () {
+                return wdHelper.waitForDeviceReady(driver);
+            })
+            .then(function () {
+                return wdHelper.injectLibraries(driver);
+            });
+    }
 
-    it('camera.ui.util Configuring driver and starting a session', function 
(done) {
-        driver = wdHelper.getDriver('iOS', done);
-    }, 3 * MINUTE);
+    it('camera.ui.util configure driver and start a session', function (done) {
+        getDriver()
+            .fail(fail)
+            .finally(done);
+    }, 5 * MINUTE);
 
     describe('Specs.', function () {
         // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY
         it('camera.ui.spec.1 Selecting only videos', function (done) {
             var options = { sourceType: 
cameraConstants.PictureSourceType.PHOTOLIBRARY,
                             mediaType: cameraConstants.MediaType.VIDEO };
-            enterTest()
-                .then(function () { return getPicture(options, false, true); 
}) // skip ui unteractions
-                .sleep(5000)
-                .elementByName('Videos')
-                .then(win, fail)
-                .elementByName('Cancel')
+            driver
+                // skip ui unteractions
+                .then(function () { return getPicture(options, false, true); })
+                .waitForElementByXPath('//*[contains(@label,"Videos")]', 
MINUTE / 2)
+                .elementByXPath('//*[@label="Cancel"]')
                 .click()
-                .finally(done);
+                .fail(saveScreenshotAndFail)
+                .done(done);
         }, 3 * MINUTE);
 
         // getPicture(), then dismiss
-        // wait for the error callback to bee called
+        // wait for the error callback to be called
         it('camera.ui.spec.2 Dismissing the camera', function (done) {
-            // camera is not available on iOS simulator
+            // camera is not available on the iOS simulator
             if (!isDevice) {
                 pending();
             }
             var options = { sourceType: 
cameraConstants.PictureSourceType.CAMERA };
-            enterTest()
+            driver
                 .then(function () {
                     return getPicture(options, true);
                 })
                 .then(function () {
                     return checkPicture(false);
                 })
-                .elementByXPath('//UIAStaticText[contains(@label,"no image 
selected")]')
-                .then(function () {
-                    return checkPicture(false);
-                }, fail)
-                .finally(done);
+                .fail(saveScreenshotAndFail)
+                .done(done);
         }, 3 * MINUTE);
 
         // combine various options for getPicture()
         generateSpecs().forEach(function (spec) {
             it('camera.ui.spec.3.' + spec.id + ' Combining options', function 
(done) {
                 // camera is not available on iOS simulator
-                if (!isDevice) {
+                if (!isDevice && spec.options.sourceType === 
cameraConstants.PictureSourceType.CAMERA) {
                     pending();
                 }
-                runCombinedSpec(spec).then(done);
+                runCombinedSpec(spec).done(done);
             }, 3 * MINUTE);
         });
 
     });
 
     it('camera.ui.util.4 Destroy the session', function (done) {
-        driver.quit(done);
+        driver
+            .quit()
+            .done(done);
     }, MINUTE);
 });


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cordova.apache.org
For additional commands, e-mail: commits-h...@cordova.apache.org

Reply via email to