зеркало из https://github.com/mozilla/gecko-dev.git
Bug 872229 - Add an add_task API for mochitest. r=ted
This commit is contained in:
Родитель
f535093ab0
Коммит
8f97970e9c
|
@ -7,10 +7,9 @@
|
|||
|
||||
let tmp = {};
|
||||
Cu.import("resource://gre/modules/osfile.jsm", tmp);
|
||||
Cu.import("resource://gre/modules/Task.jsm", tmp);
|
||||
Cu.import("resource:///modules/sessionstore/_SessionFile.jsm", tmp);
|
||||
|
||||
const {OS, Task, _SessionFile} = tmp;
|
||||
const {OS, _SessionFile} = tmp;
|
||||
|
||||
const PREF_SS_INTERVAL = "browser.sessionstore.interval";
|
||||
// Full paths for sessionstore.js and sessionstore.bak.
|
||||
|
|
|
@ -73,10 +73,14 @@ function Tester(aTests, aDumper, aCallback) {
|
|||
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/SimpleTest.js", simpleTestScope);
|
||||
this._scriptLoader.loadSubScript("chrome://mochikit/content/chrome-harness.js", simpleTestScope);
|
||||
this.SimpleTest = simpleTestScope.SimpleTest;
|
||||
this.Task = Components.utils.import("resource://gre/modules/Task.jsm", null).Task;
|
||||
this.Promise = Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js", null).Promise;
|
||||
}
|
||||
Tester.prototype = {
|
||||
EventUtils: {},
|
||||
SimpleTest: {},
|
||||
Task: null,
|
||||
Promise: null,
|
||||
|
||||
repeat: 0,
|
||||
runUntilFailure: false,
|
||||
|
@ -398,6 +402,8 @@ Tester.prototype = {
|
|||
this.currentTest.scope.EventUtils = this.EventUtils;
|
||||
this.currentTest.scope.SimpleTest = this.SimpleTest;
|
||||
this.currentTest.scope.gTestPath = this.currentTest.path;
|
||||
this.currentTest.scope.Task = this.Task;
|
||||
this.currentTest.scope.Promise = this.Promise;
|
||||
|
||||
// Override SimpleTest methods with ours.
|
||||
["ok", "is", "isnot", "ise", "todo", "todo_is", "todo_isnot", "info"].forEach(function(m) {
|
||||
|
@ -431,9 +437,34 @@ Tester.prototype = {
|
|||
|
||||
// Run the test
|
||||
this.lastStartTime = Date.now();
|
||||
if ("generatorTest" in this.currentTest.scope) {
|
||||
if ("test" in this.currentTest.scope)
|
||||
if (this.currentTest.scope.__tasks) {
|
||||
// This test consists of tasks, added via the `add_task()` API.
|
||||
if ("test" in this.currentTest.scope) {
|
||||
throw "Cannot run both a add_task test and a normal test at the same time.";
|
||||
}
|
||||
let testScope = this.currentTest.scope;
|
||||
let currentTest = this.currentTest;
|
||||
this.Task.spawn(function() {
|
||||
let task;
|
||||
while ((task = this.__tasks.shift())) {
|
||||
this.SimpleTest.info("Entering test " + task.name);
|
||||
try {
|
||||
yield task();
|
||||
} catch (ex) {
|
||||
let isExpected = !!this.SimpleTest.isExpectingUncaughtException();
|
||||
let stack = (typeof ex == "object" && "stack" in ex)?ex.stack:null;
|
||||
let name = "Uncaught exception";
|
||||
let result = new testResult(isExpected, name, ex, false, stack);
|
||||
currentTest.addResult(result);
|
||||
}
|
||||
this.SimpleTest.info("Leaving test " + task.name);
|
||||
}
|
||||
this.finish();
|
||||
}.bind(testScope));
|
||||
} else if ("generatorTest" in this.currentTest.scope) {
|
||||
if ("test" in this.currentTest.scope) {
|
||||
throw "Cannot run both a generator test and a normal test at the same time.";
|
||||
}
|
||||
|
||||
// This test is a generator. It will not finish immediately.
|
||||
this.currentTest.scope.waitForExplicitFinish();
|
||||
|
@ -444,7 +475,7 @@ Tester.prototype = {
|
|||
this.currentTest.scope.test();
|
||||
}
|
||||
} catch (ex) {
|
||||
var isExpected = !!this.SimpleTest.isExpectingUncaughtException();
|
||||
let isExpected = !!this.SimpleTest.isExpectingUncaughtException();
|
||||
if (!this.SimpleTest.isIgnoringAllUncaughtExceptions()) {
|
||||
this.currentTest.addResult(new testResult(isExpected, "Exception thrown", ex, false));
|
||||
this.SimpleTest.expectUncaughtException(false);
|
||||
|
@ -668,12 +699,58 @@ function testScope(aTester, aTest) {
|
|||
testScope.prototype = {
|
||||
__done: true,
|
||||
__generator: null,
|
||||
__tasks: null,
|
||||
__waitTimer: null,
|
||||
__cleanupFunctions: [],
|
||||
__timeoutFactor: 1,
|
||||
|
||||
EventUtils: {},
|
||||
SimpleTest: {},
|
||||
Task: null,
|
||||
Promise: null,
|
||||
|
||||
/**
|
||||
* Add a test function which is a Task function.
|
||||
*
|
||||
* Task functions are functions fed into Task.jsm's Task.spawn(). They are
|
||||
* generators that emit promises.
|
||||
*
|
||||
* If an exception is thrown, an assertion fails, or if a rejected
|
||||
* promise is yielded, the test function aborts immediately and the test is
|
||||
* reported as a failure. Execution continues with the next test function.
|
||||
*
|
||||
* To trigger premature (but successful) termination of the function, simply
|
||||
* return or throw a Task.Result instance.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* add_task(function test() {
|
||||
* let result = yield Promise.resolve(true);
|
||||
*
|
||||
* ok(result);
|
||||
*
|
||||
* let secondary = yield someFunctionThatReturnsAPromise(result);
|
||||
* is(secondary, "expected value");
|
||||
* });
|
||||
*
|
||||
* add_task(function test_early_return() {
|
||||
* let result = yield somethingThatReturnsAPromise();
|
||||
*
|
||||
* if (!result) {
|
||||
* // Test is ended immediately, with success.
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* is(result, "foo");
|
||||
* });
|
||||
*/
|
||||
add_task: function(aFunction) {
|
||||
if (!this.__tasks) {
|
||||
this.waitForExplicitFinish();
|
||||
this.__tasks = [];
|
||||
}
|
||||
this.__tasks.push(aFunction.bind(this));
|
||||
},
|
||||
|
||||
destroy: function test_destroy() {
|
||||
for (let prop in this)
|
||||
|
|
|
@ -14,6 +14,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||
head.js \
|
||||
browser_head.js \
|
||||
browser_pass.js \
|
||||
browser_add_task.js \
|
||||
browser_async.js \
|
||||
browser_privileges.js \
|
||||
browser_popupNode.js \
|
||||
|
@ -25,6 +26,7 @@ MOCHITEST_BROWSER_FILES = \
|
|||
# Disabled, these are only good for testing the harness' failure reporting
|
||||
# browser_zz_fail_openwindow.js \
|
||||
# browser_fail.js \
|
||||
# browser_fail_add_task.js \
|
||||
# browser_fail_async_throw.js \
|
||||
# browser_fail_fp.js \
|
||||
# browser_fail_pf.js \
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let test1Complete = false;
|
||||
let test2Complete = false;
|
||||
|
||||
function executeWithTimeout() {
|
||||
let deferred = Promise.defer();
|
||||
executeSoon(function() {
|
||||
ok(true, "we get here after a timeout");
|
||||
deferred.resolve();
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
add_task(function asyncTest_no1() {
|
||||
yield executeWithTimeout();
|
||||
test1Complete = true;
|
||||
});
|
||||
|
||||
add_task(function asyncTest_no2() {
|
||||
yield executeWithTimeout();
|
||||
test2Complete = true;
|
||||
});
|
||||
|
||||
add_task(function() {
|
||||
ok(test1Complete, "We have been through test 1");
|
||||
ok(test2Complete, "We have been through test 2");
|
||||
});
|
|
@ -0,0 +1,57 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// This test is designed to fail.
|
||||
// It ensures that throwing an asynchronous error from add_task will
|
||||
// fail the test.
|
||||
|
||||
let passedTests = 0;
|
||||
|
||||
function rejectWithTimeout(error = undefined) {
|
||||
let deferred = Promise.defer();
|
||||
executeSoon(function() {
|
||||
ok(true, "we get here after a timeout");
|
||||
deferred.reject(error);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
add_task(function failWithoutError() {
|
||||
try {
|
||||
yield rejectWithTimeout();
|
||||
} finally {
|
||||
++passedTests;
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function failWithString() {
|
||||
try {
|
||||
yield rejectWithTimeout("Meaningless error");
|
||||
} finally {
|
||||
++passedTests;
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function failWithoutInt() {
|
||||
try {
|
||||
yield rejectWithTimeout(42);
|
||||
} finally {
|
||||
++passedTests;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// This one should display a stack trace
|
||||
add_task(function failWithError() {
|
||||
try {
|
||||
yield rejectWithTimeout(new Error("This is an error"));
|
||||
} finally {
|
||||
++passedTests;
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function done() {
|
||||
is(passedTests, 4, "Passed all tests");
|
||||
});
|
Загрузка…
Ссылка в новой задаче