Skip to content

Commit

Permalink
feat(runner): fix '.only()' exclusive feature, #1481
Browse files Browse the repository at this point in the history
  • Loading branch information
a8m committed Mar 22, 2015
1 parent 2c2ed43 commit 1ae9d44
Show file tree
Hide file tree
Showing 12 changed files with 400 additions and 33 deletions.
18 changes: 17 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ 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-failing test-regression
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-global-only test-only test-failing test-regression

test-jsapi:
@node test/jsapi
Expand Down Expand Up @@ -164,6 +164,22 @@ test-only:
--ui qunit \
test/acceptance/misc/only/qunit

test-global-only:
@./bin/mocha \
--reporter $(REPORTER) \
--ui tdd \
test/acceptance/misc/global-only/tdd

@./bin/mocha \
--reporter $(REPORTER) \
--ui bdd \
test/acceptance/misc/global-only/bdd

@./bin/mocha \
--reporter $(REPORTER) \
--ui qunit \
test/acceptance/misc/global-only/qunit

test-sort:
@./bin/mocha \
--reporter $(REPORTER) \
Expand Down
13 changes: 8 additions & 5 deletions lib/interfaces/bdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ module.exports = function(suite){
* Exclusive suite.
*/

context.describe.only = function(title, fn){
context.describe.only = function(title, fn) {
var suite = context.describe(title, fn);
mocha.grep(suite.fullTitle());
mocha.options.hasOnly = true;
suite.isOnly = true;
return suite;
};

Expand All @@ -95,9 +96,11 @@ module.exports = function(suite){
*/

context.it.only = function(title, fn){
var test = context.it(title, fn);
var reString = '^' + escapeRe(test.fullTitle()) + '$';
mocha.grep(new RegExp(reString));
var test = context.it(title, fn)
, suite = test.parent;
mocha.options.hasOnly = true;
suite.isOnly = true;
suite.onlyTests = (suite.onlyTests || []).concat(test);
return test;
};

Expand Down
13 changes: 9 additions & 4 deletions lib/interfaces/qunit.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ module.exports = function(suite){

context.suite.only = function(title, fn){
var suite = context.suite(title, fn);
mocha.grep(suite.fullTitle());
mocha.options.hasOnly = true;
suite.isOnly = true;
return suite;
};

/**
Expand All @@ -83,9 +85,12 @@ module.exports = function(suite){
*/

context.test.only = function(title, fn){
var test = context.test(title, fn);
var reString = '^' + escapeRe(test.fullTitle()) + '$';
mocha.grep(new RegExp(reString));
var test = context.test(title, fn)
, suite = test.parent;
mocha.options.hasOnly = true;
suite.isOnly = true;
suite.onlyTests = (suite.onlyTests || []).concat(test);
return test;
};

context.test.skip = common.test.skip;
Expand Down
13 changes: 9 additions & 4 deletions lib/interfaces/tdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ module.exports = function(suite){

context.suite.only = function(title, fn){
var suite = context.suite(title, fn);
mocha.grep(suite.fullTitle());
mocha.options.hasOnly = true;
suite.isOnly = true;
return suite;
};

/**
Expand All @@ -99,9 +101,12 @@ module.exports = function(suite){
*/

context.test.only = function(title, fn){
var test = context.test(title, fn);
var reString = '^' + escapeRe(test.fullTitle()) + '$';
mocha.grep(new RegExp(reString));
var test = context.test(title, fn)
, suite = test.parent;
mocha.options.hasOnly = true;
suite.isOnly = true;
suite.onlyTests = (suite.onlyTests || []).concat(test);
return test;
};

context.test.skip = common.test.skip;
Expand Down
2 changes: 1 addition & 1 deletion lib/mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ Mocha.prototype.run = function(fn){
var reporter = new this._reporter(runner, options);
runner.ignoreLeaks = false !== options.ignoreLeaks;
runner.fullStackTrace = options.fullStackTrace;
runner.hasOnly = options.hasOnly;
runner.asyncOnly = options.asyncOnly;
if (options.grep) runner.grep(options.grep, options.invert);
if (options.globals) runner.globals(options.globals);
Expand All @@ -441,6 +442,5 @@ Mocha.prototype.run = function(fn){
reporter.done(failures, fn);
} else fn && fn(failures);
}

return runner.run(done);
};
22 changes: 22 additions & 0 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ Runner.prototype.runSuite = function(suite, fn){
, self = this
, i = 0;


debug('run suite %s', suite.fullTitle());

if (!total) return fn();
Expand Down Expand Up @@ -606,6 +607,9 @@ Runner.prototype.run = function(fn){
var self = this,
rootSuite = this.suite;

// If there is an `only` filter
if (this.hasOnly) filterOnly(rootSuite);

fn = fn || function(){};

function uncaught(err){
Expand Down Expand Up @@ -656,6 +660,24 @@ Runner.prototype.abort = function(){
this._abort = true;
};

/**
* Filter suites based on `isOnly` logic.
*
* @param {Array} suite
* @returns {Boolean}
* @api private
*/
function filterOnly(suite) {
// If it has `only` tests, run only those
if (suite.onlyTests) suite.tests = suite.onlyTests;
// Filter the nested suites
suite.suites = filter(suite.suites, filterOnly);
// Don't run tests from suites that are not marked as `only`
suite.tests = suite.isOnly ? suite.tests : [];
// Keep the suite only if there is something to run
return suite.suites.length || suite.tests.length;
}

/**
* Filter leaks with the given globals flagged as `ok`.
*
Expand Down
12 changes: 12 additions & 0 deletions test/acceptance/misc/global-only/bdd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Root-only test cases
it.only('#Root-Suite, should run this bdd test-case #1', function() {
(true).should.equal(true);
});

it('#Root-Suite, should not run this bdd test-case #2', function() {
(false).should.equal(true);
});

it('#Root-Suite, should not run this bdd test-case #3', function() {
(false).should.equal(true);
});
12 changes: 12 additions & 0 deletions test/acceptance/misc/global-only/qunit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Root-only test cases
test.only('#Root-Suite, should run this qunit test-case #1', function() {
(true).should.equal(true);
});

test('#Root-Suite, should not run this qunit test-case #2', function() {
(false).should.equal(true);
});

test('#Root-Suite, should not run this qunit test-case #3', function() {
(false).should.equal(true);
});
12 changes: 12 additions & 0 deletions test/acceptance/misc/global-only/tdd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Root-only test cases
test.only('#Root-Suite, should run this tdd test-case #1', function() {
(true).should.equal(true);
});

test('#Root-Suite, should not run this tdd test-case #2', function() {
(false).should.equal(true);
});

test('#Root-Suite, should not run this tdd test-case #3', function() {
(false).should.equal(true);
});
123 changes: 117 additions & 6 deletions test/acceptance/misc/only/bdd.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,125 @@
describe('should only run .only test in this bdd suite', function() {
it('should not run this test', function() {
var zero = 0;
zero.should.equal(1, 'this test should have been skipped');
(0).should.equal(1, 'this test should have been skipped');
});
it.only('should run this test', function() {
var zero = 0;
zero.should.equal(0, 'this .only test should run');
(0).should.equal(0, 'this .only test should run');
});
it('should run this test, not (includes the title of the .only test)', function() {
var zero = 0;
zero.should.equal(1, 'this test should have been skipped');
(0).should.equal(1, 'this test should have been skipped');
});
});

describe('should not run this suite', function() {
it('should not run this test', function() {
(true).should.equal(false);
});

it('should not run this test', function() {
(true).should.equal(false);
});

it('should not run this test', function() {
(true).should.equal(false);
});
});

describe.only('should run all tests in this bdd suite', function() {
it('should run this test #1', function() {
(true).should.equal(true);
});

it('should run this test #2', function() {
(1).should.equal(1);
});

it('should run this test #3', function() {
('foo').should.equal('foo');
});
});

describe('should run only suites that marked as `only`', function() {
describe.only('should run all this tdd suite', function() {
it('should run this test #1', function() {
(true).should.equal(true);
});

it('should run this test #2', function() {
(true).should.equal(true);
});
});

describe('should not run this suite', function() {
it('should run this test', function() {
(true).should.equal(false);
});
});
});

// Nested situation
describe('should not run parent tests', function() {
it('should not run this test', function() {
(true).should.equal(false);
});
describe('and not the child tests too', function() {
it('should not run this test', function() {
(true).should.equal(false);
});
describe.only('but run all the tests in this suite', function() {
it('should run this test #1', function() {
(true).should.equal(true);
});
it('should run this test #2', function() {
(true).should.equal(true);
});
});
});
});

// mark test as `only` override the suite behavior
describe.only('should run only tests that marked as `only`', function() {
it('should not run this test #1', function() {
(false).should.equal(true);
});

it.only('should run this test #2', function() {
(true).should.equal(true);
});

it('should not run this test #3', function() {
(false).should.equal(true);
});

it.only('should run this test #4', function() {
(true).should.equal(true);
});
});

describe.only('Should run only test cases that mark as only', function() {
it.only('should runt his test', function() {
(true).should.equal(true);
});

it('should not run this test', function() {
(false).should.equal(true);
});

describe('should not run this suite', function() {
it('should not run this test', function() {
(false).should.equal(true);
});
});
});

// Root Suite
it.only('#Root-Suite, should run this test-case #1', function() {
(true).should.equal(true);
});

it.only('#Root-Suite, should run this test-case #2', function() {
(true).should.equal(true);
});

it('#Root-Suite, should not run this test', function() {
(false).should.equal(true);
});
Loading

0 comments on commit 1ae9d44

Please sign in to comment.