/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ var {utils: Cu} = Components; Cu.import("chrome://marionette/content/error.js"); this.EXPORTED_SYMBOLS = ["Marionette"]; /* * The Marionette object, passed to the script context. */ this.Marionette = function(window, context, logObj, timeout, heartbeatCallback, testName) { this.window = window; this.tests = []; this.logObj = logObj; this.context = context; this.timeout = timeout; this.heartbeatCallback = heartbeatCallback; this.testName = testName; this.TEST_UNEXPECTED_FAIL = "TEST-UNEXPECTED-FAIL"; this.TEST_UNEXPECTED_PASS = "TEST-UNEXPECTED-PASS"; this.TEST_PASS = "TEST-PASS"; this.TEST_KNOWN_FAIL = "TEST-KNOWN-FAIL"; }; Marionette.prototype = { exports: [ "ok", "is", "isnot", "todo", "log", "getLogs", "generate_results", "waitFor", "TEST_PASS", "TEST_KNOWN_FAIL", "TEST_UNEXPECTED_FAIL", "TEST_UNEXPECTED_PASS" ], addTest: function Marionette__addTest(condition, name, passString, failString, diag, state) { let test = {'result': !!condition, 'name': name, 'diag': diag, 'state': state}; this.logResult(test, typeof(passString) == "undefined" ? this.TEST_PASS : passString, typeof(failString) == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString); this.tests.push(test); }, ok: function Marionette__ok(condition, name, passString, failString) { this.heartbeatCallback(); let diag = this.repr(condition) + " was " + !!condition + ", expected true"; this.addTest(condition, name, passString, failString, diag); }, is: function Marionette__is(a, b, name, passString, failString) { this.heartbeatCallback(); let pass = (a == b); let diag = pass ? this.repr(a) + " should equal " + this.repr(b) : "got " + this.repr(a) + ", expected " + this.repr(b); this.addTest(pass, name, passString, failString, diag); }, isnot: function Marionette__isnot (a, b, name, passString, failString) { this.heartbeatCallback(); let pass = (a != b); let diag = pass ? this.repr(a) + " should not equal " + this.repr(b) : "didn't expect " + this.repr(a) + ", but got it"; this.addTest(pass, name, passString, failString, diag); }, todo: function Marionette__todo(condition, name, passString, failString) { this.heartbeatCallback(); let diag = this.repr(condition) + " was expected false"; this.addTest(!condition, name, typeof(passString) == "undefined" ? this.TEST_KNOWN_FAIL : passString, typeof(failString) == "undefined" ? this.TEST_UNEXPECTED_FAIL : failString, diag, "todo"); }, log: function Marionette__log(msg, level) { this.heartbeatCallback(); dump("MARIONETTE LOG: " + (level ? level : "INFO") + ": " + msg + "\n"); if (this.logObj != null) { this.logObj.log(msg, level); } }, getLogs: function Marionette__getLogs() { this.heartbeatCallback(); if (this.logObj != null) { this.logObj.getLogs(); } }, generate_results: function Marionette__generate_results() { this.heartbeatCallback(); let passed = 0; let failures = []; let expectedFailures = []; let unexpectedSuccesses = []; for (let i in this.tests) { let isTodo = (this.tests[i].state == "todo"); if(this.tests[i].result) { if (isTodo) { expectedFailures.push({'name': this.tests[i].name, 'diag': this.tests[i].diag}); } else { passed++; } } else { if (isTodo) { unexpectedSuccesses.push({'name': this.tests[i].name, 'diag': this.tests[i].diag}); } else { failures.push({'name': this.tests[i].name, 'diag': this.tests[i].diag}); } } } // Reset state in case this object is reused for more tests. this.tests = []; return {"passed": passed, "failures": failures, "expectedFailures": expectedFailures, "unexpectedSuccesses": unexpectedSuccesses}; }, logToFile: function Marionette__logToFile(file) { this.heartbeatCallback(); //TODO }, logResult: function Marionette__logResult(test, passString, failString) { this.heartbeatCallback(); //TODO: dump to file let resultString = test.result ? passString : failString; let diagnostic = test.name + (test.diag ? " - " + test.diag : ""); let msg = resultString + " | " + this.testName + " | " + diagnostic; dump("MARIONETTE TEST RESULT:" + msg + "\n"); }, repr: function Marionette__repr(o) { if (typeof(o) == "undefined") { return "undefined"; } else if (o === null) { return "null"; } try { if (typeof(o.__repr__) == 'function') { return o.__repr__(); } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) { return o.repr(); } } catch (e) { } try { if (typeof(o.NAME) == 'string' && ( o.toString == Function.prototype.toString || o.toString == Object.prototype.toString )) { return o.NAME; } } catch (e) { } let ostring; try { ostring = (o + ""); } catch (e) { return "[" + typeof(o) + "]"; } if (typeof(o) == "function") { o = ostring.replace(/^\s+/, ""); let idx = o.indexOf("{"); if (idx != -1) { o = o.substr(0, idx) + "{...}"; } } return ostring; }, waitFor: function test_waitFor(callback, test, timeout) { this.heartbeatCallback(); if (test()) { callback(); return; } var now = new Date(); var deadline = (timeout instanceof Date) ? timeout : new Date(now.valueOf() + (typeof(timeout) == "undefined" ? this.timeout : timeout)) if (deadline <= now) { dump("waitFor timeout: " + test.toString() + "\n"); // the script will timeout here, so no need to raise a separate // timeout exception return; } this.window.setTimeout(this.waitFor.bind(this), 100, callback, test, deadline); }, };