You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by al...@apache.org on 2017/07/21 11:06:03 UTC
cordova-paramedic git commit: CB-13028 Run tests for browser platform
on Sauce
Repository: cordova-paramedic
Updated Branches:
refs/heads/master 76dc9e637 -> 0c9f8517c
CB-13028 Run tests for browser platform on Sauce
Project: http://git-wip-us.apache.org/repos/asf/cordova-paramedic/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-paramedic/commit/0c9f8517
Tree: http://git-wip-us.apache.org/repos/asf/cordova-paramedic/tree/0c9f8517
Diff: http://git-wip-us.apache.org/repos/asf/cordova-paramedic/diff/0c9f8517
Branch: refs/heads/master
Commit: 0c9f8517c9087a61583ca5dc7b12d63949137169
Parents: 76dc9e6
Author: Alexander Sorokin <al...@akvelon.com>
Authored: Fri Jul 21 14:05:42 2017 +0300
Committer: Alexander Sorokin <al...@akvelon.com>
Committed: Fri Jul 21 14:05:42 2017 +0300
----------------------------------------------------------------------
README.md | 16 +++-
conf/pr/browser-chrome.config.json | 8 ++
conf/pr/browser-edge.config.json | 8 ++
conf/pr/browser-firefox.config.json | 8 ++
conf/pr/browser-safari.config.json | 8 ++
lib/LocalServer.js | 6 +-
lib/ParamedicConfig.js | 28 +++++-
lib/appium/AppiumRunner.js | 79 ++--------------
lib/appium/helpers/appPatcher.js | 112 +++++++++++++++++++++++
lib/appium/helpers/wdHelper.js | 9 +-
lib/paramedic.js | 149 ++++++++++++++++++++++---------
main.js | 9 +-
12 files changed, 312 insertions(+), 128 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 4fcf712..c915426 100644
--- a/README.md
+++ b/README.md
@@ -104,6 +104,14 @@ Verbose mode. Display more information output
cordova-paramedic --platform ios --plugin cordova-plugin-inappbrowser --verbose
```
+####--cli (optional)
+
+A path to Cordova CLI. Useful when you're testing against locally installed Cordova version.
+
+```
+cordova-paramedic --platform android --plugin cordova-plugin-device --cli ./cordova-cli/bin/cordova
+```
+
####--timeout (optional)
Time in millisecs to wait for tests to pass|fail (defaults to 10 minutes).
@@ -148,11 +156,11 @@ cordova-paramedic --platform ios --plugin cordova-plugin-contacts --tccDbPath tc
####--shouldUseSauce (optional)
-Run tests on [Sauce Labs](https://saucelabs.com/). You'll need to specify Sauce Labs username and access key using either --sauceUser and --sauceKey arguments or SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables.
+Run tests on [Sauce Labs](https://saucelabs.com/). You'll need to specify Sauce Labs username and access key using either --sauceUser and --sauceKey arguments or `SAUCE_USERNAME` and `SAUCE_ACCESS_KEY` environment variables.
####--buildName (optional)
-Build name to show on Sauce Labs dashboard.
+Build name to show on Sauce Labs dashboard. If omitted, will use "Paramedic sauce test" and a timestamp.
####--sauceUser (optional)
@@ -168,11 +176,11 @@ cordova-paramedic --platform ios --plugin cordova-plugin-contacts --shouldUseSau
####--sauceDeviceName (optional)
-Name of the Sauce Labs emulator. For example, "iPhone Simulator". Please refer to the [Sauce Labs platforms list](https://saucelabs.com/platforms) to see available device names.
+Name of the Sauce Labs emulator or browser. For example, "iPhone Simulator" or "firefox". Please refer to the [Sauce Labs platforms list](https://saucelabs.com/platforms) to see available device names.
####--saucePlatformVersion (optional)
-Platform version of the Sauce Labs emulator. For example, "9.3". Please refer to the [Sauce Labs platforms list](https://saucelabs.com/platforms) to see available platform versions.
+Platform version of the Sauce Labs emulator OS, or version of the browser (if testing `browser` platform). For example, "9.3" or "54.0". Please refer to the [Sauce Labs platforms list](https://saucelabs.com/platforms) to see available platform versions.
####--sauceAppiumVersion (optional)
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/conf/pr/browser-chrome.config.json
----------------------------------------------------------------------
diff --git a/conf/pr/browser-chrome.config.json b/conf/pr/browser-chrome.config.json
new file mode 100644
index 0000000..89cf4d5
--- /dev/null
+++ b/conf/pr/browser-chrome.config.json
@@ -0,0 +1,8 @@
+{
+ "platform": "browser",
+ "action": "run",
+ "cleanUpAfterRun": true,
+ "verbose": true,
+ "sauceDeviceName": "chrome",
+ "saucePlatformVersion": "59.0"
+}
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/conf/pr/browser-edge.config.json
----------------------------------------------------------------------
diff --git a/conf/pr/browser-edge.config.json b/conf/pr/browser-edge.config.json
new file mode 100644
index 0000000..07fe98e
--- /dev/null
+++ b/conf/pr/browser-edge.config.json
@@ -0,0 +1,8 @@
+{
+ "platform": "browser",
+ "action": "run",
+ "cleanUpAfterRun": true,
+ "verbose": true,
+ "sauceDeviceName": "MicrosoftEdge",
+ "saucePlatformVersion": "15.15063"
+}
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/conf/pr/browser-firefox.config.json
----------------------------------------------------------------------
diff --git a/conf/pr/browser-firefox.config.json b/conf/pr/browser-firefox.config.json
new file mode 100644
index 0000000..769ef94
--- /dev/null
+++ b/conf/pr/browser-firefox.config.json
@@ -0,0 +1,8 @@
+{
+ "platform": "browser",
+ "action": "run",
+ "cleanUpAfterRun": true,
+ "verbose": true,
+ "sauceDeviceName": "firefox",
+ "saucePlatformVersion": "54.0"
+}
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/conf/pr/browser-safari.config.json
----------------------------------------------------------------------
diff --git a/conf/pr/browser-safari.config.json b/conf/pr/browser-safari.config.json
new file mode 100644
index 0000000..9c90238
--- /dev/null
+++ b/conf/pr/browser-safari.config.json
@@ -0,0 +1,8 @@
+{
+ "platform": "browser",
+ "action": "run",
+ "cleanUpAfterRun": true,
+ "verbose": true,
+ "sauceDeviceName": "safari",
+ "saucePlatformVersion": "10.0"
+}
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/lib/LocalServer.js
----------------------------------------------------------------------
diff --git a/lib/LocalServer.js b/lib/LocalServer.js
index 4c5fbc1..4f92dcc 100644
--- a/lib/LocalServer.js
+++ b/lib/LocalServer.js
@@ -46,7 +46,7 @@ function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
-LocalServer.startServer = function (ports, externalServerUrl, useTunnel) {
+LocalServer.startServer = function (ports, externalServerUrl, useTunnel, noListener) {
logger.normal("local-server: scanning ports from " + ports.start + " to " + ports.end);
return LocalServer.getAvailablePort(ports.start, ports.end)
@@ -55,7 +55,9 @@ LocalServer.startServer = function (ports, externalServerUrl, useTunnel) {
logger.info("local-server: starting local medic server");
var localServer = new LocalServer(port, externalServerUrl);
- localServer.createSocketListener();
+ if (!noListener) {
+ localServer.createSocketListener();
+ }
if (useTunnel) {
return localServer.createTunnel();
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/lib/ParamedicConfig.js
----------------------------------------------------------------------
diff --git a/lib/ParamedicConfig.js b/lib/ParamedicConfig.js
index c6b2360..cdb955a 100644
--- a/lib/ParamedicConfig.js
+++ b/lib/ParamedicConfig.js
@@ -36,11 +36,23 @@ function ParamedicConfig(json) {
}
ParamedicConfig.prototype.getDefaultSauceDeviceName = function () {
- return this.getPlatformId() === 'android' ? DEFAULT_SAUCE_DEVICE_NAME_ANDROID : DEFAULT_SAUCE_DEVICE_NAME_IOS;
+ if (this.getPlatformId() === util.ANDROID) {
+ return DEFAULT_SAUCE_DEVICE_NAME_ANDROID;
+ } else if (this.getPlatformId() === util.IOS) {
+ return DEFAULT_SAUCE_DEVICE_NAME_IOS;
+ } else {
+ throw new Error('Don\'t know a default device name for platform: ' + this.getPlatformId());
+ }
};
ParamedicConfig.prototype.getDefaultSaucePlatformVersion = function () {
- return this.getPlatformId() === 'android' ? DEFAULT_SAUCE_PLATFORM_VERSION_ANDROID : DEFAULT_SAUCE_PLATFORM_VERSION_IOS;
+ if (this.getPlatformId() === util.ANDROID) {
+ return DEFAULT_SAUCE_PLATFORM_VERSION_ANDROID;
+ } else if (this.getPlatformId() === util.IOS) {
+ return DEFAULT_SAUCE_PLATFORM_VERSION_IOS;
+ } else {
+ throw new Error('Don\'t know a default platform version for platform: ' + this.getPlatformId());
+ }
};
ParamedicConfig.parseFromArguments = function (argv) {
@@ -65,6 +77,7 @@ ParamedicConfig.parseFromArguments = function (argv) {
sauceDeviceName: argv.sauceDeviceName && argv.sauceDeviceName.toString(),
saucePlatformVersion: argv.saucePlatformVersion && argv.saucePlatformVersion.toString(),
sauceAppiumVersion: argv.sauceAppiumVersion && argv.sauceAppiumVersion.toString(),
+ sauceTunnelId: argv.sauceTunnelId,
skipAppiumTests: argv.skipAppium,
skipMainTests: argv.skipMainTests,
ci: argv.ci,
@@ -210,6 +223,17 @@ ParamedicConfig.prototype.setSauceAppiumVersion = function (sauceAppiumVersion)
this._config.sauceAppiumVersion = sauceAppiumVersion.toString();
};
+ParamedicConfig.prototype.getSauceTunnelId = function () {
+ if (typeof this._config.sauceTunnelId === 'boolean') {
+ this._config.sauceTunnelId = undefined;
+ }
+ return this._config.sauceTunnelId;
+};
+
+ParamedicConfig.prototype.setSauceTunnelId = function (tid) {
+ this._config.sauceTunnelId = tid;
+};
+
ParamedicConfig.prototype.runMainTests = function () {
return !this._config.skipMainTests;
};
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/lib/appium/AppiumRunner.js
----------------------------------------------------------------------
diff --git a/lib/appium/AppiumRunner.js b/lib/appium/AppiumRunner.js
index 2157b8c..dca23a4 100644
--- a/lib/appium/AppiumRunner.js
+++ b/lib/appium/AppiumRunner.js
@@ -30,13 +30,13 @@ var logger = require('../utils').logger;
var wd = require('wd');
var wdHelper = require('./helpers/wdHelper');
var screenshotHelper = require('./helpers/screenshotHelper');
+var appPatcher = require('./helpers/appPatcher.js');
var child_process = require('child_process');
var expectTelnet = require('expect-telnet');
var shell = require('shelljs');
var Jasmine = require('jasmine');
var unorm = require('unorm');
var Q = require('q');
-var ConfigParser = require('cordova-common').ConfigParser;
var Reporters = require('../Reporters');
var execPromise = require('../utils').execPromise;
var Reporters = require('../Reporters');
@@ -99,75 +99,6 @@ function getPluginDirs(appPath) {
return shell.ls(path.join(appPath, '/plugins/cordova-plugin-*'));
}
-function getConfigPath(appPath) {
- return path.join(appPath, 'config.xml');
-}
-
-function addCspSource(appPath, directive, source) {
- var cspInclFile = path.join(appPath, 'www/csp-incl.js');
- var indexFile = path.join(appPath, 'www/index.html');
- var cspFile = fs.existsSync(cspInclFile) ? cspInclFile : indexFile;
- var cspContent = fs.readFileSync(cspFile, util.DEFAULT_ENCODING);
- var cspTagOpening = '<meta http-equiv="Content-Security-Policy" content=\'';
- var cspRule = directive + ' ' + source;
- var cspRuleReg = new RegExp(directive + '[^;"]+' + source.replace('*', '\\*'));
-
- logger.normal('paramedic-appium: Adding CSP source "' + source + '" to directive "' + directive + '"');
-
- if (cspContent.match(cspRuleReg)) {
- logger.normal('paramedic-appium: It\'s already there.');
- } else if (util.contains(cspContent, directive)) {
- // if the directive is there, just add the source to it
- cspContent = cspContent.replace(directive, cspRule);
- fs.writeFileSync(cspFile, cspContent, util.DEFAULT_ENCODING);
- } else if (cspContent.match(/content=".*?default-src.+?"/)) {
- // needed directive is not there but there is default-src directive
- // creating needed directive and copying default-src sources to it
- var defaultSrcReg = /(content=".*?default-src)(.+?);/;
- cspContent = cspContent.replace(defaultSrcReg, '$1$2; ' + cspRule + '$2;');
- fs.writeFileSync(cspFile, cspContent, util.DEFAULT_ENCODING);
- } else if (util.contains(cspContent, cspTagOpening)) {
- // needed directive is not there and there is no default-src directive
- // but the CSP tag is till present
- // just adding needed directive to a start of CSP tag content
- cspContent = cspContent.replace(cspTagOpening, cspTagOpening + directive + ' ' + source + '; ');
- fs.writeFileSync(cspFile, cspContent, util.DEFAULT_ENCODING);
- } else {
- // no CSP tag, skipping
- logger.normal('paramedic-appium: WARNING: No CSP tag found.');
- }
-}
-
-function setPreference(appPath, preference, value) {
- var configFile = getConfigPath(appPath);
- var config = new ConfigParser(configFile);
-
- logger.normal('paramedic-appium: Setting "' + preference + '" preference to "' + value + '"');
- config.setGlobalPreference(preference, value);
- config.write();
-}
-
-function permitAccess(appPath, origin) {
- var configFile = getConfigPath(appPath);
- var config = new ConfigParser(configFile);
- var accesses = config.getAccesses();
- var accessPresent = false;
-
- logger.normal('paramedic-appium: Adding a whitelist "access" rule for origin: ' + origin);
- accesses.forEach(function (access) {
- if (access.origin == origin) {
- accessPresent = true;
- }
- });
-
- if (accessPresent) {
- logger.normal('paramedic-appium: It is already in place');
- } else {
- config.addElement('access', { origin: origin });
- config.write();
- }
-}
-
function runCommand(command, appPath) {
if (appPath) {
shell.pushd(appPath);
@@ -431,12 +362,12 @@ AppiumRunner.prototype.prepareApp = function () {
// set properties/CSP rules
if (self.options.platform === 'ios') {
- setPreference(fullAppPath, 'CameraUsesGeolocation', 'true');
+ appPatcher.setPreference(fullAppPath, 'CameraUsesGeolocation', 'true');
} else if (self.options.platform === 'android') {
- setPreference(fullAppPath, 'loadUrlTimeoutValue', 60000);
+ appPatcher.setPreference(fullAppPath, 'loadUrlTimeoutValue', 60000);
}
- addCspSource(fullAppPath, 'connect-src', 'http://*');
- permitAccess(fullAppPath, '*');
+ appPatcher.addCspSource(fullAppPath, 'connect-src', 'http://*');
+ appPatcher.permitAccess(fullAppPath, '*');
// add cordova-save-image-gallery plugin from npm to enable
// Appium tests for camera plugin to save test image to the gallery
runCommand(self.options.cli + ' plugin add cordova-save-image-gallery' + util.PARAMEDIC_COMMON_CLI_ARGS, fullAppPath);
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/lib/appium/helpers/appPatcher.js
----------------------------------------------------------------------
diff --git a/lib/appium/helpers/appPatcher.js b/lib/appium/helpers/appPatcher.js
new file mode 100644
index 0000000..a3beca8
--- /dev/null
+++ b/lib/appium/helpers/appPatcher.js
@@ -0,0 +1,112 @@
+/* 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 fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var util = require('../../utils').utilities;
+var logger = require('../../utils').logger;
+var ConfigParser = require('cordova-common').ConfigParser;
+
+function getConfigPath(appPath) {
+ return path.join(appPath, 'config.xml');
+}
+
+module.exports.permitAccess = function (appPath, origin) {
+ var configFile = getConfigPath(appPath);
+ var config = new ConfigParser(configFile);
+ var accesses = config.getAccesses();
+ var accessPresent = false;
+
+ logger.normal('paramedic-appium: Adding a whitelist "access" rule for origin: ' + origin);
+ accesses.forEach(function (access) {
+ if (access.origin == origin) {
+ accessPresent = true;
+ }
+ });
+
+ if (accessPresent) {
+ logger.normal('paramedic-appium: It is already in place');
+ } else {
+ config.addElement('access', { origin: origin });
+ config.write();
+ }
+};
+
+module.exports.addCspSource = function (appPath, directive, source) {
+ var cspInclFile = path.join(appPath, 'www/csp-incl.js');
+ var indexFile = path.join(appPath, 'www/index.html');
+ var cspFile = fs.existsSync(cspInclFile) ? cspInclFile : indexFile;
+ var cspContent = fs.readFileSync(cspFile, util.DEFAULT_ENCODING);
+ var cspTagOpening = '<meta http-equiv="Content-Security-Policy" content=\'';
+ var cspRule = directive + ' ' + source;
+ var cspRuleReg = new RegExp(directive + '[^;"]+' + source.replace('*', '\\*'));
+
+ logger.normal('paramedic-appium: Adding CSP source "' + source + '" to directive "' + directive + '"');
+
+ if (cspContent.match(cspRuleReg)) {
+ logger.normal('paramedic-appium: It\'s already there.');
+ } else if (util.contains(cspContent, directive)) {
+ // if the directive is there, just add the source to it
+ cspContent = cspContent.replace(directive, cspRule);
+ fs.writeFileSync(cspFile, cspContent, util.DEFAULT_ENCODING);
+ } else if (cspContent.match(/content=".*?default-src.+?"/)) {
+ // needed directive is not there but there is default-src directive
+ // creating needed directive and copying default-src sources to it
+ var defaultSrcReg = /(content=".*?default-src)(.+?);/;
+ cspContent = cspContent.replace(defaultSrcReg, '$1$2; ' + cspRule + '$2;');
+ fs.writeFileSync(cspFile, cspContent, util.DEFAULT_ENCODING);
+ } else if (util.contains(cspContent, cspTagOpening)) {
+ // needed directive is not there and there is no default-src directive
+ // but the CSP tag is till present
+ // just adding needed directive to a start of CSP tag content
+ cspContent = cspContent.replace(cspTagOpening, cspTagOpening + directive + ' ' + source + '; ');
+ fs.writeFileSync(cspFile, cspContent, util.DEFAULT_ENCODING);
+ } else {
+ // no CSP tag, skipping
+ logger.normal('paramedic-appium: WARNING: No CSP tag found.');
+ }
+};
+
+module.exports.setPreference = function (appPath, preference, value) {
+ var configFile = getConfigPath(appPath);
+ var config = new ConfigParser(configFile);
+
+ logger.normal('paramedic-appium: Setting "' + preference + '" preference to "' + value + '"');
+ config.setGlobalPreference(preference, value);
+ config.write();
+};
+
+module.exports.monkeyPatch = function (file, regex, replacement) {
+ try {
+ var sedResult = shell.sed('-i', regex, replacement, file);
+ if (sedResult.indexOf(replacement) >= 0) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (err) {
+ logger.warn('cordova-paramedic: something went wrong while monkey patching ' + file + ':\n' + err.stack);
+ }
+};
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/lib/appium/helpers/wdHelper.js
----------------------------------------------------------------------
diff --git a/lib/appium/helpers/wdHelper.js b/lib/appium/helpers/wdHelper.js
index 912a69b..70a239d 100644
--- a/lib/appium/helpers/wdHelper.js
+++ b/lib/appium/helpers/wdHelper.js
@@ -192,8 +192,9 @@ module.exports.tapElementByXPath = function (xpath, driver) {
};
module.exports.pollForEvents = function (driver, platform, skipBuster, windowOffset) {
- var isAndroid = platform === 'android';
- var isIOS = platform === 'ios';
+ var isAndroid = platform === util.ANDROID;
+ var isBrowser = platform === util.BROWSER;
+ var isIOS = platform === util.IOS;
if (!windowOffset) {
windowOffset = 0;
}
@@ -207,7 +208,7 @@ module.exports.pollForEvents = function (driver, platform, skipBuster, windowOff
return driver.bustAlert(platform);
})
.then(function() {
- if (isIOS) {
+ if (isIOS || isBrowser) {
return driver;
}
// for some reason inappbrowser tests tend to leave an active window on android
@@ -237,7 +238,7 @@ module.exports.pollForEvents = function (driver, platform, skipBuster, windowOff
return result;
}
if (!isAndroid) {
- throw new Error('Cannot get the event cache: it doesn\'t exist in the app.');
+ throw new Error('Cannot get the event cache: it doesn\'t exist in the app. Got this instead: ' + result);
}
// no luck finding the event cache in this window, let's try next
return module.exports.pollForEvents(driver, platform, skipBuster, windowOffset + 1);
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/lib/paramedic.js
----------------------------------------------------------------------
diff --git a/lib/paramedic.js b/lib/paramedic.js
index f91a992..6988646 100644
--- a/lib/paramedic.js
+++ b/lib/paramedic.js
@@ -36,6 +36,7 @@ var wd = require('wd');
var SauceLabs = require('saucelabs');
var randomstring = require('randomstring');
var AppiumRunner = require('./appium/AppiumRunner');
+var appPatcher = require('./appium/helpers/appPatcher');
var ParamediciOSPermissions = require('./ParamediciOSPermissions');
var ParamedicTargetChooser = require('./ParamedicTargetChooser');
var ParamedicAppUninstall = require('./ParamedicAppUninstall');
@@ -74,7 +75,8 @@ ParamedicRunner.prototype.run = function () {
})
.then(function () {
if (self.config.runMainTests()) {
- return Server.startServer(self.config.getPorts(), self.config.getExternalServerUrl(), self.config.getUseTunnel());
+ var isBrowser = self.config.getPlatformId() === util.BROWSER;
+ return Server.startServer(self.config.getPorts(), self.config.getExternalServerUrl(), self.config.getUseTunnel(), isBrowser);
}
})
.then(function (server) {
@@ -188,20 +190,23 @@ ParamedicRunner.prototype.installPlatform = function () {
logger.info('cordova-paramedic: successfully finished adding platform ' + platform);
if (platformId === util.ANDROID && self.config.isCI()) {
logger.info('cordova-paramedic: monkey patching Android platform to disable gradle daemon...');
- try {
- // comment out the line where the gradle daemon is forced on
- var gradleBuilderFile = path.join(self.tempFolder.name, 'platforms/android/cordova/lib/builders/GradleBuilder.js');
- var sedResult = shell.sed('-i',
- /args\.push\('\-Dorg\.gradle\.daemon=true'\);/,
- '//args.push(\'-Dorg.gradle.daemon=true\');',
- gradleBuilderFile);
- if (sedResult.indexOf('//args.push(\'-Dorg.gradle.daemon=true\');') >= 0) {
- logger.info('cordova-paramedic: success!');
- } else {
- logger.info('cordova-paramedic: couldn\'t apply the patch. It must be good news: does cordova-android not hard-code gradle daemon anymore?');
- }
- } catch (err) {
- logger.warn('cordova-paramedic: something went wrong while patching Android platform:' + err.message);
+ var gradleBuilderFile = path.join(self.tempFolder.name, 'platforms/android/cordova/lib/builders/GradleBuilder.js');
+ // remove the line where the gradle daemon is forced on
+ if (appPatcher.monkeyPatch(gradleBuilderFile, /args\.push\('\-Dorg\.gradle\.daemon=true'\);/, '')) {
+ logger.info('cordova-paramedic: success!');
+ } else {
+ logger.info('cordova-paramedic: couldn\'t apply the patch. It must be good news: does cordova-android not hard-code gradle daemon anymore?');
+ }
+ } else if (platformId === util.BROWSER && self.config.shouldUseSauce()) {
+ logger.info('cordova-paramedic: I like patching stuff, so...');
+ logger.info('cordova-paramedic: monkey patching browser platform to disable browser pop-up.');
+ var cordovaRunFile = path.join(self.tempFolder.name, 'platforms/browser/cordova/run');
+ if (appPatcher.monkeyPatch(cordovaRunFile, /return cordovaServe\.launchBrowser\(.*\)\;/, '')) {
+ logger.info('cordova-paramedic: success!');
+ self.browserPatched = true;
+ } else {
+ logger.info('cordova-paramedic: couldn\'t apply the patch. Not a big deal, though: things should work anyway.');
+ self.browserPatched = false;
}
}
});
@@ -340,7 +345,7 @@ ParamedicRunner.prototype.runLocalTests = function () {
return util.TEST_PASSED; // if we're not waiting for a test result, just report tests as passed
})
- .then(function (result) {
+ .fin(function (result) {
if (runProcess) {
return Q.promise(function (resolve, reject) {
util.killProcess(runProcess.pid, function () {
@@ -466,14 +471,15 @@ ParamedicRunner.prototype.waitForTests = function () {
};
ParamedicRunner.prototype.getCommandForStartingTests = function () {
+ var self = this;
+ var cmd = self.config.getCli() + ' ' + this.config.getAction() + ' ' + this.config.getPlatformId() + util.PARAMEDIC_COMMON_CLI_ARGS;
+
function addConfigArgs(cmd) {
if (self.config.getArgs()) {
cmd += ' ' + self.config.getArgs();
}
return cmd;
}
- var self = this;
- var cmd = self.config.getCli() + ' ' + this.config.getAction() + ' ' + this.config.getPlatformId() + util.PARAMEDIC_COMMON_CLI_ARGS;
if (self.config.getPlatformId() === util.BROWSER) {
return addConfigArgs(cmd);
@@ -545,8 +551,9 @@ ParamedicRunner.prototype.cleanUpProject = function () {
ParamedicRunner.prototype.checkSauceRequirements = function () {
if (this.config.shouldUseSauce()) {
- if (this.config.getPlatformId() !== util.ANDROID && this.config.getPlatformId() !== util.IOS) {
- logger.warn('Saucelabs only supports Android and iOS, falling back to testing locally.');
+ var platformId = this.config.getPlatformId();
+ if (platformId !== util.ANDROID && platformId !== util.IOS && platformId !== util.BROWSER) {
+ logger.warn('Saucelabs only supports Android and iOS (and browser), falling back to testing locally.');
this.config.setShouldUseSauce(false);
} else if (!this.config.getSauceKey()) {
throw new Error('Saucelabs key not set. Please set it via environmental variable ' +
@@ -582,8 +589,10 @@ ParamedicRunner.prototype.packageApp = function () {
}
case util.ANDROID:
break; // don't need to zip the app for Android
+ case util.BROWSER:
+ break; // don't need to bundle the app on Browser platform at all
default:
- throw new Error('Unsupported platform for sauce labs testing: ' + this.config.getPlatformId());
+ throw new Error('Don\'t know how to package the app for platform: ' + this.config.getPlatformId());
}
return Q.resolve();
};
@@ -640,7 +649,7 @@ ParamedicRunner.prototype.getPackageFolder = function () {
packageFolder = path.join(this.tempFolder.name, 'platforms/ios/build/emulator/');
break;
default:
- throw new Error('Unsupported platform for sauce labs testing: ' + this.config.getPlatformId());
+ throw new Error('Don\t know where the package foler is for platform: ' + this.config.getPlatformId());
}
return packageFolder;
};
@@ -655,7 +664,7 @@ ParamedicRunner.prototype.getPackageName = function () {
packageName = this.getBinaryName();
break;
default:
- throw new Error('Unsupported platform for sauce labs testing: ' + this.config.getPlatformId());
+ throw new Error('Don\'t know what the package name is for platform: ' + this.config.getPlatformId());
}
return packageName;
};
@@ -670,7 +679,7 @@ ParamedicRunner.prototype.getBinaryDir = function () {
binaryPath = path.join(this.tempFolder.name, 'platforms/ios/build/emulator/');
break;
default:
- throw new Error('Unsupported platform for sauce labs testing: ' + this.config.getPlatformId());
+ throw new Error('Don\'t know the binary folder for platform: ' + this.config.getPlatformId());
}
return binaryPath;
};
@@ -699,7 +708,7 @@ ParamedicRunner.prototype.getBinaryName = function () {
binaryName = 'HelloCordova.app';
break;
default:
- throw new Error('Unsupported platform for sauce labs testing: ' + this.config.getPlatformId());
+ throw new Error('Don\'t know the binary name for platform: ' + this.config.getPlatformId());
}
return binaryName;
};
@@ -718,7 +727,7 @@ ParamedicRunner.prototype.getAppName = function () {
appName += '.zip';
break;
default:
- throw new Error('Unsupported platform for sauce labs testing: ' + this.config.getPlatformId());
+ throw new Error('Don\'t know the app name for platform: ' + this.config.getPlatformId());
}
this.appName = appName;
return appName;
@@ -774,30 +783,48 @@ ParamedicRunner.prototype.getSauceCaps = function () {
this.sauceBuildName = this.sauceBuildName || this.config.getBuildName();
var caps = {
name: this.sauceBuildName,
- browserName: '',
- appiumVersion: this.config.getSauceAppiumVersion(),
- deviceOrientation: 'portrait',
- deviceType: 'phone',
idleTimeout: '100', // in seconds
- app: 'sauce-storage:' + this.getAppName(),
- deviceName: this.config.getSauceDeviceName(),
- platformVersion: this.config.getSaucePlatformVersion(),
maxDuration: util.SAUCE_MAX_DURATION
};
+ if (this.config.getSauceTunnelId()) {
+ caps.tunnelIdentifier = this.config.getSauceTunnelId();
+ }
switch(this.config.getPlatformId()) {
case util.ANDROID:
caps.platformName = 'Android';
caps.appPackage = 'io.cordova.hellocordova';
caps.appActivity = 'io.cordova.hellocordova.MainActivity';
+ caps.app = 'sauce-storage:' + this.getAppName();
+ caps.deviceType = 'phone';
+ caps.deviceOrientation = 'portrait';
+ caps.appiumVersion = this.config.getSauceAppiumVersion();
+ caps.deviceName = this.config.getSauceDeviceName();
+ caps.platformVersion = this.config.getSaucePlatformVersion();
break;
case util.IOS:
caps.platformName = 'iOS';
caps.autoAcceptAlerts = true;
caps.waitForAppScript = 'true;';
+ caps.app = 'sauce-storage:' + this.getAppName();
+ caps.deviceType = 'phone';
+ caps.deviceOrientation = 'portrait';
+ caps.appiumVersion = this.config.getSauceAppiumVersion();
+ caps.deviceName = this.config.getSauceDeviceName();
+ caps.platformVersion = this.config.getSaucePlatformVersion();
+ break;
+ case util.BROWSER:
+ caps.browserName = this.config.getSauceDeviceName() || 'chrome';
+ caps.version = this.config.getSaucePlatformVersion() || '45.0';
+ caps.platform = caps.browserName.indexOf('Edge') > 0 ? 'Windows 10' : 'macOS 10.12';
+ if (!caps.tunnelIdentifier && process.env.TRAVIS_JOB_NUMBER) {
+ caps.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
+ } else if (!caps.tunnelIdentifier) {
+ throw new Error('Testing browser platform on Sauce Labs requires Sauce Connect tunnel. Please specify tunnel identifier via --sauceTunnelId');
+ }
break;
default:
- throw new Error('Unsupported platform for sauce labs testing: ' + this.config.getPlatformId());
+ throw new Error('Don\'t know the Sauce caps for platform: ' + this.config.getPlatformId());
}
return caps;
};
@@ -836,6 +863,7 @@ ParamedicRunner.prototype.runSauceTests = function () {
var isTestPassed = false;
var pollForResults;
var driver;
+ var runProcess = null;
if (!self.config.runMainTests()) {
logger.normal('Skipping main tests...');
@@ -844,15 +872,37 @@ ParamedicRunner.prototype.runSauceTests = function () {
logger.info('cordova-paramedic: running tests with sauce');
- return this.buildApp()
- .then(self.packageApp.bind(self))
- .then(self.uploadApp.bind(self))
+ return Q().then(function () {
+ if (self.config.getPlatformId() === util.BROWSER) {
+ // for browser, we need to serve the app for Sauce Connect
+ // we do it by just running "cordova run" and ignoring the chrome instance that pops up
+ return Q()
+ .then(function() {
+ appPatcher.addCspSource(self.tempFolder.name, 'connect-src', 'http://*');
+ appPatcher.permitAccess(self.tempFolder.name, '*');
+ return self.getCommandForStartingTests();
+ })
+ .then(function (command) {
+ runProcess = cp.exec(command, function onExit() {
+ // a precaution not to try to kill some other process
+ runProcess = null;
+ });
+ });
+ } else {
+ return self.buildApp()
+ .then(self.packageApp.bind(self))
+ .then(self.uploadApp.bind(self));
+ }
+ })
.then(function () {
driver = self.connectWebdriver();
+ if (self.config.getPlatformId() === util.BROWSER) {
+ return driver.get('http://localhost:8000/cdvtests/index.html');
+ }
return driver;
})
.then(function () {
- if (self.config.getUseTunnel()) {
+ if (self.config.getUseTunnel() || self.config.getPlatformId() === util.BROWSER) {
return driver;
}
return driver
@@ -891,6 +941,9 @@ ParamedicRunner.prototype.runSauceTests = function () {
skipBuster = true;
}
}
+ if (platform === util.BROWSER) {
+ skipBuster = true;
+ }
if (!self.config.getUseTunnel()) {
var polling = false;
pollForResults = setInterval(function () {
@@ -917,13 +970,29 @@ ParamedicRunner.prototype.runSauceTests = function () {
logger.normal('cordova-paramedic: Tests finished');
isTestPassed = result;
}, function (error) {
- logger.normal('cordova-paramedic: Tests failed to complete; ending appium session. The error is:\n' + error);
+ logger.normal('cordova-paramedic: Tests failed to complete; ending appium session. The error is:\n' + error.stack);
})
.fin(function () {
if (pollForResults) {
clearInterval(pollForResults);
}
- return driver.quit();
+ if (driver && typeof driver.quit === 'function') {
+ return driver.quit();
+ }
+ })
+ .fin(function () {
+ if (self.config.getPlatformId() === util.BROWSER && !self.browserPatched) {
+ // we need to kill chrome
+ self.killEmulatorProcess();
+ }
+ if (runProcess) {
+ // as well as we need to kill the spawned node process serving our app
+ return Q.promise(function (resolve, reject) {
+ util.killProcess(runProcess.pid, function () {
+ resolve();
+ });
+ });
+ }
})
.then(function () {
return isTestPassed;
http://git-wip-us.apache.org/repos/asf/cordova-paramedic/blob/0c9f8517/main.js
----------------------------------------------------------------------
diff --git a/main.js b/main.js
index 943c19b..f9a778c 100755
--- a/main.js
+++ b/main.js
@@ -50,9 +50,10 @@ var USAGE = "Error missing args. \n" +
"--logMins : (optional) Windows only - specifies number of minutes to get logs\n" +
"--outputDir : (optional) path to save Junit results file & Device logs\n" +
"--sauceAppiumVersion : (optional) Appium version to use when running on Saucelabs. For example, \"1.5.3\"\n" +
- "--sauceDeviceName : (optional) Name of the SauceLabs emulator. For example, \"iPhone Simulator\"\n" +
+ "--sauceDeviceName : (optional) Name of the SauceLabs emulator/browser. For example, \"iPhone Simulator\" or \"firefox\"\n" +
"--sauceKey : (optional) Saucelabs access key\n" +
- "--saucePlatformVersion : (optional) Platform version of the SauceLabs emulator. For example, \"9.3\"\n" +
+ "--saucePlatformVersion : (optional) Version of the emulator OS or version of the browser. For example, \"9.3\" or \"54.0\"\n" +
+ "--sauceTunnelId : (optional) Tunnel identifier to use. Only usable if you have Sauce Connect up\n"
"--sauceUser : (optional) Saucelabs username\n" +
"--shouldUseSauce : (optional) run tests on Sauce Labs\n" +
"--skipAppiumTests : (optional) Do not run Appium tests\n" +
@@ -136,6 +137,10 @@ if (argv.version) {
paramedicConfig.setSauceAppiumVersion(argv.sauceAppiumVersion);
}
+ if (argv.sauceTunnelId) {
+ paramedicConfig.setSauceTunnelId(argv.sauceTunnelId);
+ }
+
if (argv.useTunnel) {
if (argv.useTunnel === 'false') {
argv.useTunnel = false;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org