From a060fb36f38b5dcf9daab64bbbfcda0b1646a817 Mon Sep 17 00:00:00 2001 From: Alexander Sorokin Date: Thu, 4 Feb 2016 18:55:57 +0300 Subject: [PATCH] CB-10397 Added Appium tests --- appium-tests/android/android.spec.js | 451 +++++++++++++++++++++++++++ appium-tests/helpers/cameraHelper.js | 65 ++++ appium-tests/helpers/wdHelper.js | 45 +++ appium-tests/ios/ios.spec.js | 256 +++++++++++++++ tests/tests.js | 8 +- 5 files changed, 822 insertions(+), 3 deletions(-) create mode 100644 appium-tests/android/android.spec.js create mode 100644 appium-tests/helpers/cameraHelper.js create mode 100644 appium-tests/helpers/wdHelper.js create mode 100644 appium-tests/ios/ios.spec.js diff --git a/appium-tests/android/android.spec.js b/appium-tests/android/android.spec.js new file mode 100644 index 0000000..b99e978 --- /dev/null +++ b/appium-tests/android/android.spec.js @@ -0,0 +1,451 @@ +/*jslint node: true, plusplus: true */ +/*global beforeEach, afterEach */ +/*global describe, it, xit, expect, jasmine */ +'use strict'; + +// these tests are meant to be executed by Cordova Medic Appium runner +// you can find it here: https://github.com/apache/cordova-medic/ +// 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" + +var wdHelper = require('../helpers/wdHelper'); +var wd = wdHelper.getWD(); +var cameraConstants = require('../../www/CameraConstants'); +var cameraHelper = require('../helpers/cameraHelper'); + +describe('Camera tests Android.', function () { + var driver, + startingMessage = 'Ready for action!', + isTestPictureSaved = false, // this indicates if device library has test picture + stopFlag = false; // this indecates that there was critical error and tests cannot go on + + function win() { + expect(true).toBe(true); + } + + function fail(error) { + 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 :( + console.log('An error without description occured'); + expect(true).toBe(false); + throw 'An error without description occured'; + } + + function generateSpecs() { + var sourceTypes = [ + cameraConstants.PictureSourceType.CAMERA, + cameraConstants.PictureSourceType.PHOTOLIBRARY + ], + destinationTypes = cameraConstants.DestinationType, + encodingTypes = [ + cameraConstants.EncodingType.JPEG, + cameraConstants.EncodingType.PNG + ], + allowEditOptions = [ + true, + false + ]; + + return cameraHelper.generateSpecs(sourceTypes, destinationTypes, encodingTypes, allowEditOptions); + } + + function getPicture(options, skipUiInteractions) { + if (!options) { + options = {}; + } + 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('WEBVIEW') + .execute(command) + .sleep(5000) + .context('NATIVE_APP') + .then(function () { + if (skipUiInteractions) { + return; + } + 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: 50, y: 50}).release(); + swipeRight.press({x: 3, y: 100}).moveTo({x: 100, y: 100}).release(); + return driver + .performTouchAction(swipeRight) + .sleep(1000) + .elementByXPath('//*[@text="Gallery"]') + .then(function (element) { + return element.click().sleep(5000); + }, function () { + // if the gallery is already opened, we'd just go on: + return driver; + }) + .performTouchAction(touchTile); + } + return driver + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') + .click() + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') + .click(); + }) + .then(function () { + if (skipUiInteractions) { + return; + } + if (options.hasOwnProperty('allowEdit') && options.allowEdit === true) { + return driver + .elementByXPath('//*[contains(@resource-id,\'save\')]') + .click(); + } + }) + .then(function () { + if (!skipUiInteractions) { + return driver.sleep(10000); + } + }); + } + + function enterTest() { + if (stopFlag) { + return driver + .context('WEBVIEW') + .then(function () { + throw 'stopFlag is on!'; + }); + } + return driver + // trying to determine where we are + .context('WEBVIEW') + .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 () { + stopFlag = 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); + } + + function checkPicture(shouldLoad) { + return driver + .context('WEBVIEW') + .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); + } + } else { + if (html.indexOf('ERROR') === -1) { + expect(true).toFailWithMessage('Unexpected success callback with result: ' + html); + } + expect(html.indexOf('ERROR')).toBe(0); + } + }); + } + + function runCombinedSpec(spec) { + return enterTest() + .then(function () { + return getPicture(spec.options); + }) + .then(function () { + return checkPicture(true); + }) + .then(win, fail); + } + + function deleteImage() { + var holdTile = new wd.TouchAction(); + holdTile.press({x: 50, y: 50}).wait(1000).release(); + return driver + .performTouchAction(holdTile) + .elementByXPath('//android.widget.TextView[@text="Delete"]') + .then(function (element) { + return element + .click() + .elementByXPath('//android.widget.Button[@text="OK"]') + .click(); + }, function () { + // couldn't find Delete menu item. Possibly there is no image. + return; + }); + } + + beforeEach(function () { + jasmine.addMatchers({ + toFailWithMessage : function () { + return { + compare: function (actual, msg) { + console.log('Failing with message: ' + msg); + var result = { + pass: false, + message: msg + }; + if (msg.indexOf('Error response status: 6') >= 0) { + stopFlag = true; + } + return result; + } + }; + } + }); + }); + + it('camera.ui.util configuring driver and starting a session', function (done) { + driver = wdHelper.getDriver('Android', function () { + return driver + .sleep(10000) + .finally(done); + }); + }, 240000); + + describe('Specs.', function () { + beforeEach(function (done) { + if (!stopFlag) { + return driver + .context('WEBVIEW') + .execute('document.getElementById("info").innerHTML = "' + startingMessage + '";') + .finally(done); + } + }, 20000); + + // getPicture() with saveToPhotoLibrary = true + it('camera.ui.spec.1 Saving the picture to photo library', function (done) { + var options = { + quality: 50, + allowEdit: false, + sourceType: cameraConstants.PictureSourceType.CAMERA, + saveToPhotoAlbum: true + }; + enterTest() + .context('WEBVIEW') + .then(function () { + return getPicture(options); + }) + .then(function () { + isTestPictureSaved = true; + return checkPicture(true); + }) + .then(win, fail) + .finally(done); + }, 300000); + + // getPicture() with mediaType: VIDEO, sourceType: PHOTOLIBRARY + it('camera.ui.spec.2 Selecting only videos', function (done) { + if (stopFlag) { + expect(true).toFailWithMessage('Couldn\'t start tests execution.'); + done(); + return; + } + var options = { sourceType: cameraConstants.PictureSourceType.PHOTOLIBRARY, + mediaType: cameraConstants.MediaType.VIDEO }; + enterTest() + .then(function () { + return getPicture(options, true); + }) + .sleep(5000) + .context('WEBVIEW') + .elementById('info') + .getAttribute('innerHTML') + .then(function (html) { + if (html.indexOf('ERROR') >= 0) { + throw html; + } + }) + .context('NATIVE_APP') + .then(function () { + // try to find "Gallery" menu item + // if there's none, the gallery should be already opened + return driver + .elementByXPath('//*[@text="Gallery"]') + .then(function (element) { + return element.click().sleep(2000); + }, function () { + return driver; + }); + }) + .then(function () { + // if the gallery is opened on the videos page, + // there should be a "Choose video" caption + return driver + .elementByXPath('//*[@text="Choose video"]') + .fail(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 + return driver + .deviceKeyEvent(4) + .sleep(2000); + }, function () { + // error means we're already in webview + return driver; + }) + .finally(done); + }, 300000); + + // getPicture(), then dismiss + // wait for the error callback to bee called + it('camera.ui.spec.3 Dismissing the camera', function (done) { + if (stopFlag) { + expect(true).toFailWithMessage('Couldn\'t start tests execution.'); + done(); + return; + } + var options = { quality: 50, + allowEdit: true, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.FILE_URI }; + enterTest() + .context('WEBVIEW') + .then(function () { + return getPicture(options, true); + }) + .sleep(5000) + .context("NATIVE_APP") + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'cancel\')]') + .click() + .context('WEBVIEW') + .then(function () { + return driver + .elementByXPath('//*[contains(text(),"Camera cancelled")]') + .then(function () { + return checkPicture(false); + }, function () { + throw 'Couldn\'t find "Camera cancelled" message.'; + }); + }) + .then(win, fail) + .finally(done); + }, 300000); + + // getPicture(), then take picture but dismiss the edit + // wait for the error cllback to be called + it('camera.ui.spec.4 Dismissing the edit', function (done) { + if (stopFlag) { + expect(true).toFailWithMessage('Couldn\'t start tests execution.'); + done(); + return; + } + var options = { quality: 50, + allowEdit: true, + sourceType: cameraConstants.PictureSourceType.CAMERA, + destinationType: cameraConstants.DestinationType.FILE_URI }; + enterTest() + .context('WEBVIEW') + .then(function () { + return getPicture(options, true); + }) + .sleep(5000) + .context('NATIVE_APP') + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'shutter\')]') + .click() + .elementByXPath('//android.widget.ImageView[contains(@resource-id,\'done\')]') + .click() + .elementByXPath('//*[contains(@resource-id,\'discard\')]') + .click() + .sleep(5000) + .context('WEBVIEW') + .then(function () { + return driver + .elementByXPath('//*[contains(text(),"Camera cancelled")]') + .then(function () { + return checkPicture(false); + }, function () { + throw 'Couldn\'t find "Camera cancelled" message.'; + }); + }) + .then(win, fail) + .finally(done); + }, 300000); + + // combine various options for getPicture() + generateSpecs().forEach(function (spec) { + it('camera.ui.spec.5.' + spec.id + ' Combining options', function (done) { + if (stopFlag) { + expect(true).toFailWithMessage('Couldn\'t start tests execution.'); + done(); + return; + } + runCombinedSpec(spec).then(done); + }, 3 * 60 * 1000); + }); + + + it('camera.ui.util Delete test image from device library', function (done) { + if (stopFlag) { + expect(true).toFailWithMessage('Couldn\'t start tests executeion.'); + 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(); + }, 300000); + + }); + + it('camera.ui.util Destroy the session', function (done) { + return driver.quit(done); + }, 10000); +}); diff --git a/appium-tests/helpers/cameraHelper.js b/appium-tests/helpers/cameraHelper.js new file mode 100644 index 0000000..b2a631a --- /dev/null +++ b/appium-tests/helpers/cameraHelper.js @@ -0,0 +1,65 @@ +/*jslint node: true, plusplus: true */ +'use strict'; + +var cameraConstants = require('../../www/CameraConstants'); + +module.exports.generateSpecs = function (sourceTypes, destinationTypes, encodingTypes, allowEditOptions) { + var destinationType, + sourceType, + encodingType, + allowEdit, + specs = [], + id = 1; + for (destinationType in destinationTypes) { + if (destinationTypes.hasOwnProperty(destinationType)) { + for (sourceType in sourceTypes) { + if (sourceTypes.hasOwnProperty(sourceType)) { + for (encodingType in encodingTypes) { + if (encodingTypes.hasOwnProperty(encodingType)) { + for (allowEdit in allowEditOptions) { + if (allowEditOptions.hasOwnProperty(allowEdit)) { + // if taking picture from photolibrary, don't vary 'correctOrientation' option + if (sourceTypes[sourceType] === cameraConstants.PictureSourceType.PHOTOLIBRARY) { + specs.push({ + 'id': id++, + 'options': { + 'destinationType': destinationTypes[destinationType], + 'sourceType': sourceTypes[sourceType], + 'encodingType': encodingTypes[encodingType], + 'allowEdit': allowEditOptions[allowEdit], + 'saveToPhotoAlbum': false, + } + }); + } else { + specs.push({ + 'id': id++, + 'options': { + 'destinationType': destinationTypes[destinationType], + 'sourceType': sourceTypes[sourceType], + 'encodingType': encodingTypes[encodingType], + 'correctOrientation': true, + 'allowEdit': allowEditOptions[allowEdit], + 'saveToPhotoAlbum': false, + } + }, { + 'id': id++, + 'options': { + 'destinationType': destinationTypes[destinationType], + 'sourceType': sourceTypes[sourceType], + 'encodingType': encodingTypes[encodingType], + 'correctOrientation': false, + 'allowEdit': allowEditOptions[allowEdit], + 'saveToPhotoAlbum': false, + } + }); + } + } + } + } + } + } + } + } + } + return specs; +}; diff --git a/appium-tests/helpers/wdHelper.js b/appium-tests/helpers/wdHelper.js new file mode 100644 index 0000000..ad3a9e4 --- /dev/null +++ b/appium-tests/helpers/wdHelper.js @@ -0,0 +1,45 @@ +/*jslint node: true, plusplus: true */ +'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.3', + platformName: platform, + platformVersion: global.PLATFORM_VERSION || '', + deviceName: global.DEVICE_NAME || '', + app: global.PACKAGE_PATH, + autoAcceptAlerts: true + }; + + driver = wd.promiseChainRemote(serverConfig); + module.exports.configureLogging(driver); + driver.init(driverConfig).setImplicitWaitTimeout(10000) + .sleep(20000) // wait for the app to load + .then(callback); + + return driver; +}; + +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 || ''); + }); +}; diff --git a/appium-tests/ios/ios.spec.js b/appium-tests/ios/ios.spec.js new file mode 100644 index 0000000..c880413 --- /dev/null +++ b/appium-tests/ios/ios.spec.js @@ -0,0 +1,256 @@ +/*jslint node: true, plusplus: true */ +/*global beforeEach, afterEach */ +/*global describe, it, xit, expect, jasmine, pending */ +'use strict'; + +var wdHelper = require('../helpers/wdHelper'); +var wd = wdHelper.getWD(); +var isDevice = global.DEVICE; +var cameraConstants = require('../../www/CameraConstants'); +var cameraHelper = require('../helpers/cameraHelper'); + +describe('Camera tests iOS.', function () { + var driver, + webviewContext = 'WEBVIEW_1', + startingMessage = 'Ready for action!'; + + function win() { + expect(true).toBe(true); + } + + function fail(error) { + if (error && error.message) { + console.log('An error occured: ' + error.message); + expect(true).toFailWithMessage(error.message); + return; + } + if (error) { + console.log('Failed expectation: ' + error); + expect(true).toFailWithMessage(error); + return; + } + // no message provided :( + console.log('An error without description occured'); + expect(true).toBe(false); + } + + function generateSpecs() { + var sourceTypes = [ + cameraConstants.PictureSourceType.CAMERA, + cameraConstants.PictureSourceType.PHOTOLIBRARY + ], + destinationTypes = cameraConstants.DestinationType, + encodingTypes = [ + cameraConstants.EncodingType.JPEG, + cameraConstants.EncodingType.PNG + ], + allowEditOptions = [ + true, + false + ]; + + return cameraHelper.generateSpecs(sourceTypes, destinationTypes, encodingTypes, allowEditOptions); + } + + function getPicture(options, cancelCamera, skipUiInteractions) { + 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) + .context('NATIVE_APP') + .then(function () { + if (skipUiInteractions) { + return; + } + if (options.hasOwnProperty('sourceType') && options.sourceType === cameraConstants.PictureSourceType.PHOTOLIBRARY) { + return driver + .elementByName('Camera Roll') + .click() + .elementByXPath('//UIACollectionCell') + .click() + .then(function () { + if (options.hasOwnProperty('allowEdit') && options.allowEdit === true) { + return driver + .elementByName('Use') + .click(); + } + return driver; + }); + } + if (options.hasOwnProperty('sourceType') && options.sourceType === cameraConstants.PictureSourceType.SAVEDPHOTOALBUM) { + return driver + .elementByXPath('//UIACollectionCell') + .click() + .then(function () { + if (options.hasOwnProperty('allowEdit') && options.allowEdit === true) { + return driver + .elementByName('Use') + .click(); + } + return driver; + }); + } + if (cancelCamera) { + return driver + .elementByName('Cancel') + .click(); + } + return driver + .elementByName('PhotoCapture') + .click() + .elementByName('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); + } + + 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); + } + } else { + if (html.indexOf('ERROR') === -1) { + expect(true).toFailWithMessage('Unexpected success callback with result: ' + html); + } + expect(html.indexOf('ERROR')).toBe(0); + } + }) + .context('NATIVE_APP'); + } + + function runCombinedSpec(spec) { + return enterTest() + .then(function () { + return getPicture(spec.options); + }) + .then(function () { + return checkPicture(true); + }) + .then(win, fail); + } + + 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; + } + }; + } + }); + }); + + it('camera.ui.util Configuring driver and starting a session', function (done) { + driver = wdHelper.getDriver('iOS', done); + }, 240000); + + 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') + .click() + .finally(done); + }, 300000); + + // getPicture(), then dismiss + // wait for the error callback to bee called + it('camera.ui.spec.2 Dismissing the camera', function (done) { + // camera is not available on iOS simulator + if (!isDevice) { + pending(); + } + var options = { sourceType: cameraConstants.PictureSourceType.CAMERA }; + enterTest() + .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); + }, 300000); + + // 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) { + pending(); + } + runCombinedSpec(spec).then(done); + }, 3 * 60 * 1000); + }); + + }); + + it('camera.ui.util.4 Destroy the session', function (done) { + driver.quit(done); + }, 10000); +}); diff --git a/tests/tests.js b/tests/tests.js index fd97ec2..868140c 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -121,8 +121,8 @@ exports.defineManualTests = function (contentEl, createActionButton) { url = "data:image/jpeg;base64," + url; } catch (e) { // not DATA_URL - log('URL: ' + url.slice(0, 100)); } + log('URL: "' + url.slice(0, 90) + '"'); pictureUrl = url; var img = document.getElementById('camera_image'); @@ -141,10 +141,11 @@ exports.defineManualTests = function (contentEl, createActionButton) { function getPictureWin(data) { setPicture(data); // TODO: Fix resolveLocalFileSystemURI to work with native-uri. - if (pictureUrl.indexOf('file:') == 0 || pictureUrl.indexOf('content:') == 0 || pictureUrl.indexOf('ms-appdata:') === 0) { + if (pictureUrl.indexOf('file:') == 0 || pictureUrl.indexOf('content:') == 0 || pictureUrl.indexOf('ms-appdata:') === 0 || pictureUrl.indexOf('assets-library:') === 0) { resolveLocalFileSystemURI(data, function (e) { fileEntry = e; logCallback('resolveLocalFileSystemURI()', true)(e.toURL()); + readFile(); }, logCallback('resolveLocalFileSystemURI()', false)); } else if (pictureUrl.indexOf('data:image/jpeg;base64') == 0) { // do nothing @@ -217,6 +218,7 @@ exports.defineManualTests = function (contentEl, createActionButton) { log('FileReader.readAsDataURL() - length = ' + reader.result.length); }; reader.onerror = logCallback('FileReader.readAsDataURL', false); + reader.onloadend = onFileReadAsDataURL; reader.readAsDataURL(file); }; // Test out onFileReceived when the file object was set via a native elements. @@ -361,7 +363,7 @@ exports.defineManualTests = function (contentEl, createActionButton) { function createOptionsEl(name, values, selectionDefault) { var openDiv = '
' + name + ': '; - var select = ''; var defaultOption = ''; if (selectionDefault == undefined) {