Skip to content

Commit

Permalink
Fix theintern#67, moved calling beforeEach and afterEach into Test.
Browse files Browse the repository at this point in the history
Also added more unit tests.
  • Loading branch information
edhager committed Aug 29, 2013
1 parent 3315695 commit 1dbc181
Show file tree
Hide file tree
Showing 4 changed files with 325 additions and 94 deletions.
76 changes: 35 additions & 41 deletions lib/Suite.js
Expand Up @@ -101,17 +101,39 @@ define([
},

/**
* By default, run the parent's beforeEach.
* Allows setup code to run before each test execution. Use one of the testing interfaces,
* see ./interfaces/*, to define one or more beforeEach functions for a suite or aspect after this function.

This comment has been minimized.

Copy link
@bitpshr

bitpshr Sep 19, 2013

If the purpose of this comment is to discourage people from overriding this method, we should just plainly tell them that (in addition to what you already have about using the test interfaces.) I would also remove the ./interfaces/* syntax, it looks odd.

*/
beforeEach: function() {
return this.parent && this.parent.beforeEach();
var parent = this.parent;
return parent && parent.beforeEach && parent.beforeEach();
},

/**
* By default, run the parent's afterEach.
* Allows tear down code to run after each test execution. Use one of the testing interfaces,
* see ./interfaces/*, to define one or more afterEach functions for a suite or aspect after this function.

This comment has been minimized.

Copy link
@bitpshr

bitpshr Sep 19, 2013

See above comment.

*/
afterEach: function() {
return this.parent && this.parent.afterEach();
var parent = this.parent;
return parent && parent.afterEach && parent.afterEach();
},

/**
* Convenience mechanism for calling pre/post test methods which captures and handles errors that might be
* raised by these methods.
*/
call: function (methodName) {
var result;
try {
result = this[methodName] && this[methodName]();
}
catch (error) {
var dfd = new Deferred();
dfd.reject(error);
result = dfd.promise;
}

return when(result);
},

/**
Expand All @@ -130,23 +152,6 @@ define([
* @returns {dojo/promise/Promise}
*/
run: function () {
/**
* Convenience mechanism for calling pre/post test methods which captures and handles errors that might be
* raised by these methods.
*/
function call(name) {
var result;
try {
result = self[name] && self[name]();
}
catch (error) {
var dfd = new Deferred();
dfd.reject(error);
result = dfd.promise;
}

return when(result);
}

function runNextTest() {
// TODO: Eliminate nextTick once dojo/promise implements Promises/A+
Expand All @@ -171,32 +176,21 @@ define([

var test = tests[i++];
if (test) {
// Don't run beforeEach or afterEach if this test is a suite. The suite's
// run method will do that for its own tests.
if (test instanceof Suite) {
test.run().always(function () {
remoteReset();
test.run().always(function (error) {
if (error && error.fatal) {
handleTestError(error);
} else {
self.remote && self.remote.reset();
runNextTest();
});
} else {
call('beforeEach').then(function () {
test.run().always(function () {
remoteReset();
call('afterEach').then(runNextTest, handleTestError);
});
}, handleTestError);
}
}
});
}
else {
finishRun();
}
});
}

function remoteReset() {
self.remote && self.remote.reset();
}

function handleFatalError(error, fromFinishRun) {
self.error = error;
topic.publish('/suite/error', self);
Expand All @@ -213,7 +207,7 @@ define([
topic.publish('/suite/end', self);
}

call('teardown').always(function (teardownError) {
self.call('teardown').always(function (teardownError) {
if (!error && teardownError instanceof Error) {
handleFatalError(teardownError, true);
error = teardownError;
Expand Down Expand Up @@ -242,7 +236,7 @@ define([
started = true;
}

call('setup').then(function () {
self.call('setup').then(function () {
if (self.publishAfterSetup) {
started = true;
topic.publish('/suite/start', self);
Expand Down
104 changes: 67 additions & 37 deletions lib/Test.js
Expand Up @@ -130,54 +130,84 @@ define([
* @returns {dojo/promise/Promise}
*/
run: function () {
function handleTestError(error) {
self.timeElapsed = Date.now() - startTime;
self.error = error;
topic.publish('/test/fail', self);
finishRun();
dfd.reject(error);
}

function finishRun() {
clearTimeout(timer);
topic.publish('/test/end', self);
}

var self = this,
dfd = new Deferred(),
result,
timer;
function runTest() {
var runTestDfd = new Deferred(),
result,
timer;

topic.publish('/test/start', self);
try {
var startTime = Date.now();
result = self.test();
function handleTestError(error) {
self.timeElapsed = Date.now() - startTime;
self.error = error;
topic.publish('/test/fail', self);
finishRun();
runTestDfd.reject(error);
}

if (self.isAsync && (!result || !result.then)) {
result = self.async().promise;
function finishRun() {
clearTimeout(timer);
topic.publish('/test/end', self);
}

if (result && result.then) {
self.isAsync = true;
timer = setTimeout(function () {
// Cancelling the promise will trigger errback
result.cancel(new CancelError('Timeout reached on ' + self.id));
}, self.timeout);
topic.publish('/test/start', self);
try {
var startTime = Date.now();
result = self.test();

if (self.isAsync && (!result || !result.then)) {
result = self.async().promise;
}

if (result && result.then) {
self.isAsync = true;
timer = setTimeout(function () {
// Cancelling the promise will trigger errback
result.cancel(new CancelError('Timeout reached on ' + self.id));
}, self.timeout);
}

when(result).then(function () {
self.timeElapsed = Date.now() - startTime;
self.hasPassed = true;
topic.publish('/test/pass', self);
finishRun();
runTestDfd.resolve();
}, handleTestError);
}
catch (error) {
handleTestError(error);
}

when(result).then(function () {
self.timeElapsed = Date.now() - startTime;
self.hasPassed = true;
topic.publish('/test/pass', self);
finishRun();
dfd.resolve();
}, handleTestError);
return runTestDfd.promise;
}

function handlePrePostError(error) {
error.fatal = true;
runDfd.reject(error);
}

function callParent(method) {
return when(parent && parent.call && parent.call(method));
}

var self = this,
parent = self.parent,
runDfd = new Deferred();

try {
callParent('beforeEach').then(function () {
runTest().always(function (error) {
callParent('afterEach').then(function () {
error ? runDfd.reject(error) : runDfd.resolve();
}, handlePrePostError);
});
}, handlePrePostError);
}
catch (error) {
handleTestError(error);
handlePrePostError(error);
}

return dfd.promise;
return runDfd.promise;
},

toJSON: function () {
Expand Down

1 comment on commit 1dbc181

@RoystonS
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a comment to issue theintern#67 as this request currently seems to execute the afterEach calls in the reverse order to what I'd expect: it executes them top-to-bottom rather than bottom-to-top.

Please sign in to comment.