Async timeout support

This commit is contained in:
JR Boyens
2013-07-26 11:27:40 -07:00
parent 984074ec95
commit 98fa58ee49
4 changed files with 97 additions and 6 deletions
+24 -3
View File
@@ -239,6 +239,8 @@ getJasmineRequireObj().Spec = function() {
this.queueRunner = attrs.queueRunner || function() {}; this.queueRunner = attrs.queueRunner || function() {};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout};
if (!this.fn) { if (!this.fn) {
this.pend(); this.pend();
} }
@@ -274,9 +276,26 @@ getJasmineRequireObj().Spec = function() {
return; return;
} }
function timeoutable(fn) {
return function(done) {
var timeout = Function.prototype.apply.apply(self.timer.setTimeout, [window, [function() {
onException(new Error('timeout'));
done();
}, 10000]]);
var callDone = function() {
Function.prototype.apply.apply(self.timer.clearTimeout, [window, [timeout]]);
done();
};
fn(callDone); //TODO: do we care about more than 1 arg?
};
}
var befores = this.beforeFns() || [], var befores = this.beforeFns() || [],
afters = this.afterFns() || []; afters = this.afterFns() || [],
var allFns = befores.concat(this.fn).concat(afters); thisOne = (this.fn.length) ? timeoutable(this.fn) : this.fn;
var allFns = befores.concat(thisOne).concat(afters);
this.queueRunner({ this.queueRunner({
fns: allFns, fns: allFns,
@@ -360,6 +379,7 @@ getJasmineRequireObj().Env = function(j$) {
var catchExceptions = true; var catchExceptions = true;
var realSetTimeout = j$.getGlobal().setTimeout; var realSetTimeout = j$.getGlobal().setTimeout;
var realClearTimeout = j$.getGlobal().clearTimeout;
this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler()); this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler());
var spies = []; var spies = [];
@@ -495,7 +515,8 @@ getJasmineRequireObj().Env = function(j$) {
description: description, description: description,
expectationResultFactory: expectationResultFactory, expectationResultFactory: expectationResultFactory,
queueRunner: queueRunnerFactory, queueRunner: queueRunnerFactory,
fn: fn fn: fn,
timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
}); });
if (!self.specFilter(spec)) { if (!self.specFilter(spec)) {
+49
View File
@@ -292,6 +292,55 @@ describe("Env integration", function() {
env.execute(); env.execute();
}); });
describe("with a mock clock", function() {
beforeEach(function() {
jasmine.getEnv().clock.install();
});
afterEach(function() {
jasmine.getEnv().clock.uninstall();
});
it("should not hang on async specs that forget to call done()", function(done) {
var env = new j$.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
env.addReporter(reporter);
env.describe("tests", function() {
env.it("async spec that will hang", function(underTestCallback) {
env.expect(true).toBeTruthy();
});
env.it("after async spec", function() {
env.expect(true).toBeTruthy();
});
});
env.execute();
reporter.jasmineDone.and.callFake(function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 2
});
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({status: 'passed'}));
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({status: 'failed'}));
done();
});
jasmine.getEnv().clock.tick(60001);
});
});
// TODO: something is wrong with this spec // TODO: something is wrong with this spec
it("should report as expected", function(done) { it("should report as expected", function(done) {
var env = new j$.Env(), var env = new j$.Env(),
+3 -1
View File
@@ -8,6 +8,7 @@ getJasmineRequireObj().Env = function(j$) {
var catchExceptions = true; var catchExceptions = true;
var realSetTimeout = j$.getGlobal().setTimeout; var realSetTimeout = j$.getGlobal().setTimeout;
var realClearTimeout = j$.getGlobal().clearTimeout;
this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler()); this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler());
var spies = []; var spies = [];
@@ -143,7 +144,8 @@ getJasmineRequireObj().Env = function(j$) {
description: description, description: description,
expectationResultFactory: expectationResultFactory, expectationResultFactory: expectationResultFactory,
queueRunner: queueRunnerFactory, queueRunner: queueRunnerFactory,
fn: fn fn: fn,
timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
}); });
if (!self.specFilter(spec)) { if (!self.specFilter(spec)) {
+21 -2
View File
@@ -16,6 +16,8 @@ getJasmineRequireObj().Spec = function() {
this.queueRunner = attrs.queueRunner || function() {}; this.queueRunner = attrs.queueRunner || function() {};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; }; this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout};
if (!this.fn) { if (!this.fn) {
this.pend(); this.pend();
} }
@@ -51,9 +53,26 @@ getJasmineRequireObj().Spec = function() {
return; return;
} }
function timeoutable(fn) {
return function(done) {
var timeout = Function.prototype.apply.apply(self.timer.setTimeout, [window, [function() {
onException(new Error('timeout'));
done();
}, 10000]]);
var callDone = function() {
Function.prototype.apply.apply(self.timer.clearTimeout, [window, [timeout]]);
done();
};
fn(callDone); //TODO: do we care about more than 1 arg?
};
}
var befores = this.beforeFns() || [], var befores = this.beforeFns() || [],
afters = this.afterFns() || []; afters = this.afterFns() || [],
var allFns = befores.concat(this.fn).concat(afters); thisOne = (this.fn.length) ? timeoutable(this.fn) : this.fn;
var allFns = befores.concat(thisOne).concat(afters);
this.queueRunner({ this.queueRunner({
fns: allFns, fns: allFns,