|
@@ -1,7 +1,31 @@
|
|
|
+import haxe.Constraints;
|
|
|
+import haxe.*;
|
|
|
import js.Node.*;
|
|
|
using Reflect;
|
|
|
using Lambda;
|
|
|
|
|
|
+/**
|
|
|
+ Promise interface of [Q](https://github.com/kriskowal/q).
|
|
|
+ Incomplete.
|
|
|
+*/
|
|
|
+private typedef Promise = {
|
|
|
+ public function then(onResolve:Function, ?onReject:Function):Promise;
|
|
|
+ public function fail(onReject:Function):Promise;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ Run tests on SauceLabs.
|
|
|
+
|
|
|
+ Usage: npm install wd q && node RunSauceLabs.js testFile.html [...testFile2.html] [options]
|
|
|
+ Options:
|
|
|
+ -serve-domain <domain> Domain of the server that serves the test files. Default: localhost
|
|
|
+ -serve-port <port> Port number of the server that serves the test files. Default: 2000
|
|
|
+ -connect-domain <domain> Domain of the remote testing server. Default: localhost (using Sauce Connect)
|
|
|
+ -connect-port <port> Port number of remote testing server. Default: 4445 (using Sauce Connect)
|
|
|
+ -browsers <browsers> A list of browsers to test with in JSON format. Default: refer to source code
|
|
|
+
|
|
|
+ Tests should log "SUCCESS: true" or "SUCCESS: false" to the console when it is done.
|
|
|
+*/
|
|
|
class RunSauceLabs {
|
|
|
static function successMsg(msg:String):Void {
|
|
|
console.log('\x1b[32m' + msg + '\x1b[0m');
|
|
@@ -14,19 +38,11 @@ class RunSauceLabs {
|
|
|
}
|
|
|
|
|
|
static function main():Void {
|
|
|
- var allSuccess = true;
|
|
|
- var q:Dynamic = require("q");
|
|
|
- var webdriver:Dynamic = require("wd");
|
|
|
- var browser:Dynamic = webdriver.promiseRemote(
|
|
|
- "localhost",
|
|
|
- 4445,
|
|
|
- Sys.getEnv("SAUCE_USERNAME"),
|
|
|
- Sys.getEnv("SAUCE_ACCESS_KEY")
|
|
|
- );
|
|
|
-
|
|
|
- var tags = [];
|
|
|
- if (Sys.getEnv("TRAVIS") != null)
|
|
|
- tags.push("TravisCI");
|
|
|
+ var serveDomain = "localhost";
|
|
|
+ var servePort = "2000";
|
|
|
+ var connectDomain = "localhost";
|
|
|
+ var connectPort = "4445";
|
|
|
+ var urls = [];
|
|
|
|
|
|
//https://saucelabs.com/platforms
|
|
|
var browsers:Array<Dynamic> = [
|
|
@@ -94,6 +110,12 @@ class RunSauceLabs {
|
|
|
"version": "6.1",
|
|
|
"device-orientation": "portrait"
|
|
|
},
|
|
|
+ {
|
|
|
+ "browserName": "iphone",
|
|
|
+ "platform": "OS X 10.9",
|
|
|
+ "version": "8.1",
|
|
|
+ "device-orientation": "portrait"
|
|
|
+ },
|
|
|
{
|
|
|
"browserName": "android",
|
|
|
"platform": "Linux",
|
|
@@ -108,11 +130,44 @@ class RunSauceLabs {
|
|
|
}
|
|
|
];
|
|
|
|
|
|
+ var arg, args = process.argv.slice(2);
|
|
|
+ while ((arg = args.shift()) != null) {
|
|
|
+ switch (arg) {
|
|
|
+ case "-serve-domain":
|
|
|
+ serveDomain = args.shift();
|
|
|
+ case "-serve-port":
|
|
|
+ servePort = args.shift();
|
|
|
+ case "-connect-domain":
|
|
|
+ connectDomain = args.shift();
|
|
|
+ case "-connect-port":
|
|
|
+ connectPort = args.shift();
|
|
|
+ case "-browsers":
|
|
|
+ browsers = Json.parse(args.shift());
|
|
|
+ case _:
|
|
|
+ urls.push(arg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var allSuccess = true;
|
|
|
+ var q:Dynamic = require("q");
|
|
|
+ var webdriver:Dynamic = require("wd");
|
|
|
+ var browser:Dynamic = webdriver.promiseRemote(
|
|
|
+ connectDomain,
|
|
|
+ connectPort,
|
|
|
+ Sys.getEnv("SAUCE_USERNAME"),
|
|
|
+ Sys.getEnv("SAUCE_ACCESS_KEY")
|
|
|
+ );
|
|
|
+
|
|
|
+ var tags = [];
|
|
|
+ if (Sys.getEnv("TRAVIS") != null)
|
|
|
+ tags.push("TravisCI");
|
|
|
+
|
|
|
var timeout = 30000; //30s
|
|
|
|
|
|
function testBrowser(caps:Dynamic, trials = 3):Dynamic {
|
|
|
console.log('========================================================');
|
|
|
- console.log('Requesting: ${caps.browserName} ${caps.version} on ${caps.platform}');
|
|
|
+ var browserName = caps.hasField("version") ? '${caps.browserName} ${caps.version}' : caps.browserName;
|
|
|
+ console.log('Requesting: ${browserName} on ${caps.platform}');
|
|
|
|
|
|
caps.setField("name", Sys.getEnv("TRAVIS") != null ? Sys.getEnv("TRAVIS_REPO_SLUG") : "haxe");
|
|
|
caps.setField("tags", tags);
|
|
@@ -124,7 +179,8 @@ class RunSauceLabs {
|
|
|
trials--;
|
|
|
|
|
|
function onErrored(err):Dynamic {
|
|
|
- console.log(err);
|
|
|
+ console.log(Std.string(err));
|
|
|
+ console.log("detail: " + Json.stringify(err, " "));
|
|
|
if (trials > 0) {
|
|
|
return browser
|
|
|
.sauceJobUpdate({ passed: true, tags: tags.concat(["errored"]) })
|
|
@@ -150,6 +206,8 @@ class RunSauceLabs {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ var browserSuccess = true;
|
|
|
+
|
|
|
return browser
|
|
|
.init(caps)
|
|
|
.then(function() {
|
|
@@ -162,47 +220,53 @@ class RunSauceLabs {
|
|
|
.then(function()
|
|
|
return browser.setAsyncScriptTimeout(timeout))
|
|
|
.then(function(){
|
|
|
- console.log("[debug] opening test page");
|
|
|
- return browser.get("http://localhost:2000/unit-js.html");
|
|
|
- })
|
|
|
- .then(function() {
|
|
|
- console.log("[debug] waiting for test to exit");
|
|
|
- return
|
|
|
- until("return (typeof unit != 'undefined') && unit.Test && (typeof unit.Test.success === 'boolean')")
|
|
|
- .timeout(timeout);
|
|
|
- })
|
|
|
- .then(function() {
|
|
|
- console.log("[debug] test exited");
|
|
|
- return browser.text("body");
|
|
|
- })
|
|
|
- .then(function(resultText:String) {
|
|
|
- //check if test is successful or not
|
|
|
- var success = false;
|
|
|
- for (line in resultText.split("\n")) {
|
|
|
- infoMsg(line);
|
|
|
- if (line.indexOf("SUCCESS: ") >= 0) {
|
|
|
- success = line.indexOf("SUCCESS: true") >= 0;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- allSuccess = allSuccess && success;
|
|
|
-
|
|
|
- if (success) {
|
|
|
- successMsg('${caps.browserName} ${caps.version} on ${caps.platform}: SUCCESS');
|
|
|
- } else {
|
|
|
- failMsg('${caps.browserName} ${caps.version} on ${caps.platform}: FAIL');
|
|
|
- }
|
|
|
-
|
|
|
- return browser.sauceJobUpdate({ passed: success });
|
|
|
+ return urls.fold(function(url:String, promise:Promise):Promise {
|
|
|
+ return promise.then(function(){
|
|
|
+ var url = 'http://${serveDomain}:${servePort}/${url}';
|
|
|
+ console.log('[debug] opening $url');
|
|
|
+ return browser.get(url)
|
|
|
+ .then(function() {
|
|
|
+ console.log("[debug] waiting for test to exit");
|
|
|
+ return
|
|
|
+ until("return (typeof unit != 'undefined') && unit.Test && (typeof unit.Test.success === 'boolean')")
|
|
|
+ .timeout(timeout);
|
|
|
+ })
|
|
|
+ .then(function() {
|
|
|
+ console.log("[debug] test exited");
|
|
|
+ return browser.text("body");
|
|
|
+ })
|
|
|
+ .then(function(resultText:String) {
|
|
|
+ //check if test is successful or not
|
|
|
+ var success = false;
|
|
|
+ for (line in resultText.split("\n")) {
|
|
|
+ infoMsg(line);
|
|
|
+ if (line.indexOf("SUCCESS: ") >= 0) {
|
|
|
+ success = line.indexOf("SUCCESS: true") >= 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ browserSuccess = browserSuccess && success;
|
|
|
+ allSuccess = allSuccess && browserSuccess;
|
|
|
+
|
|
|
+ if (success) {
|
|
|
+ successMsg('$url in ${caps.browserName} ${caps.version} on ${caps.platform}: SUCCESS');
|
|
|
+ } else {
|
|
|
+ failMsg('$url in ${caps.browserName} ${caps.version} on ${caps.platform}: FAIL');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .timeout(60000 * 5); //5 min
|
|
|
+ });
|
|
|
+ }, q());
|
|
|
})
|
|
|
+ .then(function()
|
|
|
+ return browser.sauceJobUpdate({ passed: browserSuccess }))
|
|
|
.then(function()
|
|
|
return browser.quit())
|
|
|
- .timeout(60000 * 5) //5 min
|
|
|
.fail(onErrored);
|
|
|
}
|
|
|
|
|
|
browsers
|
|
|
- .fold(function(caps:Dynamic, promise:Dynamic):Dynamic {
|
|
|
+ .fold(function(caps:Dynamic, promise:Promise):Promise {
|
|
|
return promise.then(function () return testBrowser(caps));
|
|
|
}, q())
|
|
|
.then(function() {
|