Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue #973 - mark suite with failing hook(s) as pending #975

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,14 @@ lib-cov:

test: test-unit

test-all: test-bdd test-tdd test-qunit test-exports test-unit test-grep test-jsapi test-compilers test-sort test-glob test-requires test-reporters test-only
test-all: test-integration test-bdd test-tdd test-qunit test-exports test-unit test-grep test-jsapi test-compilers test-sort test-glob test-requires test-reporters test-only

test-jsapi:
@node test/jsapi

test-integration:
test/integration/hook_fail_before_each.js

test-unit:
@./bin/mocha \
--reporter $(REPORTER) \
Expand Down Expand Up @@ -165,4 +168,4 @@ non-tty:
tm:
@open editors/$(TM_BUNDLE)

.PHONY: test-cov test-jsapi test-compilers watch test test-all test-bdd test-tdd test-qunit test-exports test-unit non-tty test-grep tm clean
.PHONY: test-cov test-jsapi test-compilers watch test test-all test-bdd test-tdd test-qunit test-exports test-unit non-tty test-grep tm clean test-integration
14 changes: 14 additions & 0 deletions lib/runnable.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,20 @@ Runnable.prototype.resetTimeout = function(){
}, ms);
};

/**
* Mark the runnable pending.
*
* @api private
*/
Runnable.prototype.markPending = function(){
// don't alter the tests state after the fact
if (this.state) return;

this.pending = true;
this.async = false;
this.sync = true;
}

/**
* Run the test and invoke `fn(err)`.
*
Expand Down
20 changes: 14 additions & 6 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ Runner.prototype.fail = function(test, err){

Runner.prototype.failHook = function(hook, err){
this.fail(hook, err);
this.emit('end');
hook.parent && hook.parent.markPending();
};

/**
Expand Down Expand Up @@ -250,7 +250,7 @@ Runner.prototype.hook = function(name, fn){
hook.removeAllListeners('error');
var testError = hook.error();
if (testError) self.fail(self.test, testError);
if (err) return self.failHook(hook, err);
if (err) self.failHook(hook, err);
self.emit('hook end', hook);
delete hook.ctx.currentTest;
next(++i);
Expand Down Expand Up @@ -391,15 +391,23 @@ Runner.prototype.runTests = function(suite, fn){
if (!match) return next();

// pending
if (test.pending) {
self.emit('pending', test);
self.emit('test end', test);
return next();
function checkPending() {
if (test && test.pending) {
self.emit('pending', test);
self.emit('test end', test);
next();
return true;
}
}

// go to the next test
if (checkPending()) return;

// execute test and hook(s)
self.emit('test', self.test = test);
self.hookDown('beforeEach', function(){
if (checkPending()) return;

self.currentRunnable = self.test;
self.runTest(function(err){
test = self.test;
Expand Down
22 changes: 22 additions & 0 deletions lib/suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,28 @@ Suite.prototype.total = function(){
}, 0) + this.tests.length;
};

/**
* Marks suite (and all children suites/tests) pending.
*
* @api private
* @return {Suite}
*/
Suite.prototype.markPending = function() {
this.pending = true;

// mark all suites pending
utils.forEach(this.suites, function(suite) {
suite.markPending();
});

// mark all tests pending
this.eachTest(function(test) {
test.markPending();
});

return this;
};

/**
* Iterates through each suite recursively to find
* all tests. Applies a function in the format
Expand Down
2 changes: 1 addition & 1 deletion test/acceptance/pending.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

describe('pending', function(){
it('should be allowed')
})
})
17 changes: 17 additions & 0 deletions test/integration/hook_fail_before_each.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#! /usr/bin/env node

var run = require('./runner');
var expected = require('./tests/hook_fail_before_each.json');
var assert = require('assert');

run([
'hook_fail_before_each/one.js',
'hook_fail_before_each/two.js',
'hook_fail_before_each/three.js'
], function(err, report) {
if (!err) {
console.error('mocha should fail');
process.exit(1);
}
assert.deepEqual(report.tests, expected.tests);
});
26 changes: 26 additions & 0 deletions test/integration/runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
var fsPath = require('path'),
exec = require('child_process').exec,
debug = require('debug')('integration test');

var TESTS = __dirname + '/tests/';
var BIN = __dirname + '/../../bin/mocha';

function run(tests, callback) {
var paths = [];

var tests = tests.map(function(test) {
return fsPath.join(TESTS, test);
});

var cmd = [BIN, '--reporter', 'json'].concat(tests);
debug('run', cmd);

exec(
cmd.join(' '),
function(err, stdout, stderr) {
callback(err, JSON.parse(stdout));
}
);
}

module.exports = run;
67 changes: 67 additions & 0 deletions test/integration/tests/hook_fail_before_each.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"stats": {
"suites": 3,
"tests": 5,
"passes": 4,
"pending": 1,
"failures": 1,
"start": "2013-09-13T12:41:15.471Z",
"end": "2013-09-13T12:41:15.474Z",
"duration": 3
},
"tests": [
{
"title": "should work",
"fullTitle": "one should work",
"duration": 0
},
{
"title": "should fail",
"fullTitle": "one should fail"
},
{
"title": "should work",
"fullTitle": "two should work",
"duration": 0
},
{
"title": "should work 1",
"fullTitle": "three should work 1",
"duration": 0
},
{
"title": "should work 2",
"fullTitle": "three should work 2",
"duration": 0
}
],
"failures": [
{
"title": "\"before each\" hook",
"fullTitle": "one \"before each\" hook",
"duration": 0
}
],
"passes": [
{
"title": "should work",
"fullTitle": "one should work",
"duration": 0
},
{
"title": "should work",
"fullTitle": "two should work",
"duration": 0
},
{
"title": "should work 1",
"fullTitle": "three should work 1",
"duration": 0
},
{
"title": "should work 2",
"fullTitle": "three should work 2",
"duration": 0
}
]
}
15 changes: 15 additions & 0 deletions test/integration/tests/hook_fail_before_each/one.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
describe('one', function() {
var increment = 0;

beforeEach(function() {
if (++increment === 2) {
throw new Error('ouch');
}
});

it('should work', function() {
});

it('should fail', function() {
});
});
6 changes: 6 additions & 0 deletions test/integration/tests/hook_fail_before_each/three.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
describe('three', function() {
it('should work 1', function() {
});
it('should work 2', function() {
});
});
4 changes: 4 additions & 0 deletions test/integration/tests/hook_fail_before_each/two.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
describe('two', function() {
it('should work', function() {
});
});
31 changes: 31 additions & 0 deletions test/runnable.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,37 @@ describe('Runnable(title, fn)', function(){
})
})

describe('.markPending', function() {
describe('when passing', function() {
it('should still be passing', function() {
var run = new Runnable('foo', function() {});
// should needs a not-undefined value
run.pending = '';
run.state = 'passed';
run.markPending();
run.pending.should.not.be.true;
})
});

describe('when sync', function() {
it('should be sync and pending', function() {
var run = new Runnable('foo', function() {});
run.markPending();
run.sync.should.be.true;
run.pending.should.be.true;
})
})

describe('when async', function() {
it('should be sync and pending', function() {
var run = new Runnable('foo', function(done) {});
run.markPending();
run.sync.should.be.true;
run.pending.should.be.true;
});
});
});

describe('.run(fn)', function(){
describe('when .pending', function(){
it('should not invoke the callback', function(done){
Expand Down
6 changes: 0 additions & 6 deletions test/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,5 @@ describe('Runner', function(){
});
runner.failHook(hook, err);
})

it('should emit "end"', function(done){
var hook = {}, err = {};
runner.on('end', done);
runner.failHook(hook, err);
})
})
})
34 changes: 34 additions & 0 deletions test/suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,40 @@ describe('Suite', function(){
// this.suite.tests[0].should.equal(this.test);
// });
// });
describe('.markPending', function() {
var result;
beforeEach(function() {
this.suite = new Suite('Parent');
this.suite.addTest(new Test('test 1', function() {}));

// add a child suite
var child = new Suite('Child');
this.suite.addSuite(child);

// test in child
child.addTest(new Test('test 2', function() {}));

result = this.suite.markPending();
});

it('should be chainable', function() {
result.should.equal(this.suite);
});

it('should mark suite pending', function() {
this.suite.pending.should.be.true;
});

it('should mark tests pending', function() {
this.suite.eachTest(function(test) {
test.pending.should.be.true;
});
});

it('should mark child suite pending', function() {
this.suite.suites[0].pending.should.be.true;
});
});

describe('.fullTitle()', function(){
beforeEach(function(){
Expand Down