Permalink
Browse files

Combine all suite finishing events into one event with a 'status' arg…

…ument

This simplifies the API to:

onTestStart
onTestDone
onSuiteDone
  • Loading branch information...
1 parent 9b6378f commit ea7baf9cb9d19f70baae536103c32bcc77250589 Benjamin Thomas committed Oct 30, 2010
Showing with 117 additions and 112 deletions.
  1. +59 −41 docs/running-tests.html
  2. +2 −8 lib/child.js
  3. +24 −24 lib/console-runner.js
  4. +8 −11 lib/testing.js
  5. +12 −17 lib/web-runner.js
  6. +7 −7 lib/web-runner/public/main.js
  7. +5 −4 todo.txt
View
@@ -50,7 +50,7 @@
<div class="highlight"><pre>require<span class="o">(</span><span class="s1">&#39;async_testing&#39;</span><span class="o">)</span>.run<span class="o">(</span><span class="s1">&#39;test-suite.js&#39;</span><span class="o">)</span>;</pre></div>
<p>
- The <code>run</code> method can take a file name or a directory name (it
+ The <code>run</code> function can take a file name or a directory name (it
recursively searches directories for javascript files that start with <code>test-</code>)
or an array of any combination of those two options.
</p>
@@ -75,14 +75,14 @@
<p>
To make a file easy to execute with the <code>node</code> command, we need
- how to make our file run the suite when it is the script being ran. Some where
+ to make our file run the suite when it is the script being ran. Some where
in the file we put this code (I like to put it at the very top):
</p>
<div class="highlight"><pre>
<span class="c1">// if this module is the script being run, then run the tests:</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">module</span> <span class="o">===</span> <span class="nx">require</span><span class="p">.</span><span class="nx">main</span><span class="p">)</span> <span class="p">{</span>
- <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;async_testing&#39;</span><span class="p">).</span><span class="nx">run</span><span class="p">(</span><span class="nx">__filename</span><span class="p">);</span>
+ <span class="k">return</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;async_testing&#39;</span><span class="p">).</span><span class="nx">run</span><span class="p">(</span><span class="nx">__filename</span><span class="p">);</span>
<span class="p">}</span></pre></div>
<p>
@@ -93,7 +93,7 @@
<div class="highlight"><pre>node <span class="nb">test</span>-suite.js</pre></div>
<p>
- The <code>run</code> method can also be passed the <code>process.ARGV</code>
+ The <code>run</code> function can also be passed the <code>process.ARGV</code>
array of command line arguments, so <b>node-async-testing</b> settings can
be altered at run time:
</p>
@@ -162,12 +162,10 @@
<p>
To use the web runner you also need to install
- <a href="http://github.com/LearnBoost/Socket.IO-node">Socket.IO</a>
- and
- <a href="http://github.com/pgriess/node-webworker">node-webworker</a>:
+ <a href="http://github.com/LearnBoost/Socket.IO-node">Socket.IO</a>.
</p>
- <div class="highlight"><pre>npm install socket.io webworker</pre></div>
+ <div class="highlight"><pre>npm install socket.io</pre></div>
<p>
[The server is known to work in the lastest versions of Safari, Chrome and
@@ -184,7 +182,7 @@
</p>
<p>
- <b>node-async-testing</b> comes with the following methods for running suites
+ <b>node-async-testing</b> comes with the following functions for running suites
and test runners:
</p>
@@ -309,7 +307,7 @@
<dt id="run"><code>run()</code></dt>
<dd>
<p>
- The <code>run</code> method is talked about at length in the
+ The <code>run</code> functions is talked about at length in the
<a href="#suite-files">Running Suite Files</a> section. It handles
outputing the results of suites for you, so you don't have to worry about it.
<b>node-async-testing</b> comes with two built-in runners, one for consoles and one
@@ -392,7 +390,7 @@
<section id="running-events">
<h1>Description of event callbacks</h1>
<p>
- The <code>runSuite</code> method can be given event callbacks for outputing
+ The <code>runSuite</code> and <code>runFile</code> functions can be given event callbacks for outputing
the results of the tests. Using these callbacks it is possible to write your
own test runners and format the output however you'd like. These callbacks
are not for manipulating tests, but purely for reporting.
@@ -411,49 +409,69 @@
below.
</dd>
- <dt><code>onSuiteCompleted(suiteResult)</code></dt>
+ <dt><code>onSuiteDone(status, suiteResult)</code></dt>
<dd>
Called when a suite finishes. See <a href="#suite-result">Suite result</a>
- below.
+ below. <code>status</code> is one of the following: complete, error,
+ loadError and exit.
</dd>
+ </dl>
- <dt><code>onSuiteError(err, testNames)</code></dt>
+ <h2 id="suite-result">Suite Result</h2>
+ <p>
+ A suite result is an object that looks like one of the following, depending
+ on what the finish status of the suite was:
+ </p>
+
+ <dl>
+ <dt>complete</dt>
<dd>
- Called when an uncaught error is thrown from a test. This stops running
- the suite. The first argument is the error, the second argument is an
- array of the names of the tests that could have thrown it.
+ <p>
+ occures when all tests finished running, and <b>node-async-testing</b>
+ was able to accurately determine how each one finished.
+ </p>
+ <div class="highlight"><pre>
+{ tests: an Array of <a href="#test-results">test results</a> for each test that completed
+, numFailures: the number of tests that failed
+, numSuccesses: the number of tests that passed
+}</pre></div>
</dd>
- <dt><code>onSuiteExit(testNames)</code></dt>
+ <dt>error</dt>
<dd>
- Called when the process exits and there are still tests that haven't
- finished. This occurs when people forget to finish their tests or their
- tests don't work like they expected. This gets one argument: an array of
- the names of the tests that haven't finished.
+ <p>
+ occures when an uncaught error is thrown from a test and <b>node-async-testing</b>
+ can't determine which test caused it. When this happens, <b>node-async-testing</b>
+ stops running the suite and exits the process.
+ </p>
+ <div class="highlight"><pre>
+{ error: the error object that was thrown
+, tests: an Array of the names of each test that could have caused the error
+}</pre></div>
</dd>
- <dt><code>onSuiteLoadError(err)</code></dt>
+ <dt>exit</dt>
<dd>
- Only called from <code>runFile</code>, and called when the child process
- can't load the suite. This gets one argument, the contents of what
- was written to <code>stderr</code> when the child process exited.
+ <p>
+ occures when the process running the suite exits and there are still tests that
+ haven't finished. This occurs when people forget to finish their tests or their
+ tests don't work like they expected.
+ </p>
+ <div class="highlight"><pre>
+{ tests: an Array of the names of each test that didn't finish
+}</pre></div>
</dd>
- </dl>
-
- <h2 id="suite-result">Suite Result</h2>
- <p>A suite result is an object that has the following properties:</p>
-
- <dl>
- <dt><code>name</code></dt>
- <dd>suite name (if applicable)</dd>
- <dt><code>results</code></dt>
- <dd>an Array of <a href="#test-results">test results</a> for each test that completed</dd>
- <dt><code>numFailures</code></dt>
- <dd>the number of tests that failed</dd>
- <dt><code>numSuccesses</code></dt>
- <dd>the number of tests that passed</dd>
- </dl>
+ <dt>loadError</dt>
+ <dd>
+ <p>
+ this type of result is only produced from <code>runFile</code>, and
+ occures when the child process can't load the suite.
+ </p>
+ <div class="highlight"><pre>
+{ stderr: what was written to &lt;stderr&gt; before the child process exited
+}</pre></div>
+ </dd>
<h2 id="test-result">Test Result</h2>
<p> A test result is an object that looks like one of the following:</p>
View
@@ -13,14 +13,8 @@ var opts =
postMessage('onTestDone', result);
}
- , onSuiteCompleted: function suiteDone(results) {
- postMessage('onSuiteCompleted', results);
- }
- , onSuiteError: function error(err, tests) {
- postMessage('onSuiteError', makeErrorJsonable(err), tests);
- }
- , onSuiteExit: function exit(tests) {
- postMessage('onSuiteExit', tests);
+ , onSuiteDone: function suiteDone(status, results) {
+ postMessage('onSuiteDone', status, results);
}
};
View
@@ -108,17 +108,8 @@ exports.run = function(list, options, callback) {
, onTestDone: function(result) {
testFinished(suite, result);
}
- , onSuiteLoadError: function() {
- suiteFinished(suite, 'suiteLoadError', Array.prototype.slice.call(arguments));
- }
- , onSuiteCompleted: function(results) {
- suiteFinished(suite, 'suiteCompleted', Array.prototype.slice.call(arguments));
- }
- , onSuiteError: function(error, tests) {
- suiteFinished(suite, 'suiteErrored', Array.prototype.slice.call(arguments));
- }
- , onSuiteExit: function(tests) {
- suiteFinished(suite, 'suiteExited', Array.prototype.slice.call(arguments));
+ , onSuiteDone: function(status, results) {
+ suiteFinished(suite, status, results);
}
}
@@ -130,6 +121,9 @@ exports.run = function(list, options, callback) {
}
}
+ // we want to output the suite results in the order they were given to us,
+ // so as suties finish we buffer them, and then output them in the right
+ // order when we can
function suiteFinished(suite, status, results) {
suite.finished = true;
suite.status = status;
@@ -143,7 +137,7 @@ exports.run = function(list, options, callback) {
while(suites[i].queuedTestResults.length) {
output.testDone(suites[i], suites[i].queuedTestResults.shift());
}
- output[suites[i].status](suites[i]);
+ output.suiteDone(suites[i]);
}
else {
break;
@@ -186,8 +180,11 @@ exports.run = function(list, options, callback) {
console.log('' + result.name);
}
}
+ , suiteDone: function(suite) {
+ output['suite'+suite.status.substr(0,1).toUpperCase()+suite.status.substr(1)](suite);
+ }
, suiteLoadError: function(suite) {
- var err = suite.results[0];
+ var err = suite.results.stderr;
if (!suite.printedName) {
console.log(bold(suite.name));
@@ -208,8 +205,8 @@ exports.run = function(list, options, callback) {
console.log('');
}
- , suiteCompleted: function(suite) {
- var suiteResults = suite.results[0];
+ , suiteComplete: function(suite) {
+ var suiteResults = suite.results;
var tests = suiteResults.tests;
if (tests.length == 0) {
@@ -275,14 +272,14 @@ exports.run = function(list, options, callback) {
console.log('');
}
}
- else if(suiteResults.numFailures > 0 && suites.length > 1) {
+ else if(last.length && suites.length > 1) {
console.log(last + ' ' + (suite.duration/1000) + ' seconds.');
console.log('');
}
}
- , suiteErrored: function(suite) {
- var err = suite.results[0];
- var tests = suite.results[1];
+ , suiteError: function(suite) {
+ var err = suite.results.error;
+ var tests = suite.results.tests;
if (!suite.printedName && suite.name) {
console.log(bold(suite.name));
@@ -326,7 +323,10 @@ exports.run = function(list, options, callback) {
console.log('');
}
- , suiteExited: function(tests) {
+ , suiteExit: function(suite) {
+ // TODO: test me
+ var tests = suite.results.tests;
+
console.log('');
console.log('Process exited. The following test'+(tests.length == 1 ? '' : 's')+' never finished:');
@@ -347,13 +347,13 @@ exports.run = function(list, options, callback) {
for(var i = 0; i < suites.length; i++) {
totalSuites++;
- if (suites[i].status == 'suiteCompleted' && suites[i].results[0].numFailures == 0) {
+ if (suites[i].status == 'suiteCompleted' && suites[i].results.numFailures == 0) {
passingSuites++;
}
- if (typeof suites[i].results[0] == 'object' && 'numSuccesses' in suites[i].results[0]) {
- totalTests += suites[i].results[0].numSuccesses + suites[i].results[0].numFailures;
- passingTests += suites[i].results[0].numSuccesses;
+ if ('numSuccesses' in suites[i].results) {
+ totalTests += suites[i].results.numSuccesses + suites[i].results.numFailures;
+ passingTests += suites[i].results.numSuccesses;
}
else {
totalTests += NaN;
View
@@ -20,9 +20,6 @@ var assert = require('assert')
*
* + onTestStart
* + onTestDone
- * + onSuiteCompleted
- * + onSuiteError
- * + onSuiteExit
*/
exports.runSuite = function(obj, options) {
// make sure options exists
@@ -257,12 +254,12 @@ exports.runSuite = function(obj, options) {
process.removeListener('uncaughtException', errorHandler);
process.removeListener('exit', exitHandler);
- if (options.onSuiteError) {
+ if (options.onSuiteDone) {
var tests = test ? [test] : suite.started;
if (tests.length < 1) {
tests = suite.results;
}
- options.onSuiteError(err, tests.map(function(t) { return t.name; }));
+ options.onSuiteDone('error', { error: err, tests: tests.map(function(t) { return t.name; })});
process.exit(1);
}
else {
@@ -272,8 +269,8 @@ exports.runSuite = function(obj, options) {
function exitHandler() {
if (suite.started.length > 0) {
- if (options.onSuiteExit) {
- options.onSuiteExit(suite.started.map(function(t) { return t.name; }));
+ if (options.onSuiteDone) {
+ options.onSuiteDone('exit', {tests: suite.started.map(function(t) { return t.name; })});
}
}
}
@@ -287,7 +284,7 @@ exports.runSuite = function(obj, options) {
process.removeListener('uncaughtException', errorHandler);
process.removeListener('exit', exitHandler);
- if (options.onSuiteCompleted) {
+ if (options.onSuiteDone) {
var result =
{ tests: suite.results
, numFailures: 0
@@ -299,7 +296,7 @@ exports.runSuite = function(obj, options) {
result[r.failure ? 'numFailures' : 'numSuccesses']++;
});
- options.onSuiteCompleted(result);
+ options.onSuiteDone('complete', result);
}
}
}
@@ -343,8 +340,8 @@ exports.runFile = function(modulepath, options) {
});
child.stderr.on('close', function() {
- if (errorBuffer && options.onSuiteLoadError) {
- options.onSuiteLoadError(errorBuffer.trim());
+ if (errorBuffer && options.onSuiteDone) {
+ options.onSuiteDone('loadError', {stderr: errorBuffer.trim()});
}
});
Oops, something went wrong.

0 comments on commit ea7baf9

Please sign in to comment.