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

let child suites run if parent is exclusive; closes #2378 #2387

Merged
merged 1 commit into from
Jul 26, 2016
Merged
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
30 changes: 16 additions & 14 deletions lib/interfaces/bdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Module dependencies.
*/

var Suite = require('../suite');
var Test = require('../test');

/**
Expand All @@ -26,7 +25,7 @@ module.exports = function(suite) {
var suites = [suite];

suite.on('pre-require', function(context, file, mocha) {
var common = require('./common')(suites, context);
var common = require('./common')(suites, context, mocha);

context.before = common.before;
context.after = common.after;
Expand All @@ -40,32 +39,35 @@ module.exports = function(suite) {
*/

context.describe = context.context = function(title, fn) {
var suite = Suite.create(suites[0], title);
suite.file = file;
suites.unshift(suite);
fn.call(suite);
suites.shift();
return suite;
return common.suite.create({
title: title,
file: file,
fn: fn
});
};

/**
* Pending describe.
*/

context.xdescribe = context.xcontext = context.describe.skip = function(title, fn) {
var suite = Suite.create(suites[0], title);
suite.pending = true;
suites.unshift(suite);
fn.call(suite);
suites.shift();
return common.suite.skip({
title: title,
file: file,
fn: fn
});
};

/**
* Exclusive suite.
*/

context.describe.only = function(title, fn) {
return common.suite.only(mocha, context.describe(title, fn));
return common.suite.only({
title: title,
file: file,
fn: fn
});
};

/**
Expand Down
69 changes: 60 additions & 9 deletions lib/interfaces/common.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
'use strict';

var Suite = require('../suite');

/**
* Functions common to more than one interface.
*
* @param {Suite[]} suites
* @param {Context} context
* @param {Mocha} mocha
* @return {Object} An object containing common functions.
*/
module.exports = function(suites, context) {
module.exports = function(suites, context, mocha) {
return {
/**
* This is only present if flag --delay is passed into Mocha. It triggers
Expand Down Expand Up @@ -64,15 +67,60 @@ module.exports = function(suites, context) {

suite: {
/**
* Exclusive suite.
* Create an exclusive Suite; convenience function
* See docstring for create() below.
*
* @param {Object} mocha
* @param {Function} suite
* @param {Object} opts
* @returns {Suite}
*/

only: function(mocha, suite) {
suite.isOnly = true;
only: function only(opts) {
mocha.options.hasOnly = true;
opts.isOnly = true;
return this.create(opts);
},

/**
* Create a Suite, but skip it; convenience function
* See docstring for create() below.
*
* @param {Object} opts
* @returns {Suite}
*/
skip: function skip(opts) {
opts.pending = true;
return this.create(opts);
},

/**
* Creates a suite.
* @param {Object} opts Options
* @param {string} opts.title Title of Suite
* @param {Function} [opts.fn] Suite Function (not always applicable)
* @param {boolean} [opts.pending] Is Suite pending?
* @param {string} [opts.file] Filepath where this Suite resides
* @param {boolean} [opts.isOnly] Is Suite exclusive?
* @returns {Suite}
*/
create: function create(opts) {
var suite = Suite.create(suites[0], opts.title);
suite.pending = Boolean(opts.pending);
suite.file = opts.file;
suites.unshift(suite);
// I should be pilloried for the following.
Copy link
Contributor Author

@boneskull boneskull Jul 21, 2016

Choose a reason for hiding this comment

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

The general idea is that we don't flip a bit on a Suite if something like describe.only() is used; instead we just reference its tests prop to onlyTests, so any tests in it (and within child Suites!) will be in the bucket.

If a Test would override this behavior, we destroy the reference. The behavior below depends on whether or not the parent still has the reference intact, which is confusing and bad.

If anyone wants to "adjust" this, feel free; it's in the issue/2387 branch.

if (opts.isOnly) {
if (suite.parent && suite.parent.onlyTests) {
suite.onlyTests = suite.parent.onlyTests === suite.parent.tests ? suite.tests : [];
} else {
suite.onlyTests = suite.tests;
}
} else {
suite.onlyTests = suite.parent && suite.parent.onlyTests === suite.parent.tests ? suite.tests : [];
}
if (typeof opts.fn === 'function') {
opts.fn.call(suite);
suites.shift();
}

return suite;
}
},
Expand All @@ -88,8 +136,11 @@ module.exports = function(suites, context) {
*/
only: function(mocha, test) {
var suite = test.parent;
suite.isOnly = true;
suite.onlyTests = (suite.onlyTests || []).concat(test);
if (suite.onlyTests === suite.tests) {
suite.onlyTests = [test];
} else {
suite.onlyTests = (suite.onlyTests || []).concat(test);
}
mocha.options.hasOnly = true;
return test;
},
Expand Down
23 changes: 14 additions & 9 deletions lib/interfaces/qunit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Module dependencies.
*/

var Suite = require('../suite');
var Test = require('../test');

/**
Expand Down Expand Up @@ -34,7 +33,7 @@ module.exports = function(suite) {
var suites = [suite];

suite.on('pre-require', function(context, file, mocha) {
var common = require('./common')(suites, context);
var common = require('./common')(suites, context, mocha);

context.before = common.before;
context.after = common.after;
Expand All @@ -49,18 +48,24 @@ module.exports = function(suite) {
if (suites.length > 1) {
suites.shift();
}
var suite = Suite.create(suites[0], title);
suite.file = file;
suites.unshift(suite);
return suite;
return common.suite.create({
title: title,
file: file
});
};

/**
* Exclusive test-case.
* Exclusive Suite.
*/

context.suite.only = function(title, fn) {
return common.suite.only(mocha, context.suite(title, fn));
context.suite.only = function(title) {
if (suites.length > 1) {
suites.shift();
}
return common.suite.only({
title: title,
file: file
});
};

/**
Expand Down
30 changes: 16 additions & 14 deletions lib/interfaces/tdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* Module dependencies.
*/

var Suite = require('../suite');
var Test = require('../test');

/**
Expand Down Expand Up @@ -34,7 +33,7 @@ module.exports = function(suite) {
var suites = [suite];

suite.on('pre-require', function(context, file, mocha) {
var common = require('./common')(suites, context);
var common = require('./common')(suites, context, mocha);

context.setup = common.beforeEach;
context.teardown = common.afterEach;
Expand All @@ -47,30 +46,33 @@ module.exports = function(suite) {
* nested suites and/or tests.
*/
context.suite = function(title, fn) {
var suite = Suite.create(suites[0], title);
suite.file = file;
suites.unshift(suite);
fn.call(suite);
suites.shift();
return suite;
return common.suite.create({
title: title,
file: file,
fn: fn
});
};

/**
* Pending suite.
*/
context.suite.skip = function(title, fn) {
var suite = Suite.create(suites[0], title);
suite.pending = true;
suites.unshift(suite);
fn.call(suite);
suites.shift();
return common.suite.skip({
title: title,
file: file,
fn: fn
});
};

/**
* Exclusive test-case.
*/
context.suite.only = function(title, fn) {
return common.suite.only(mocha, context.suite(title, fn));
return common.suite.only({
title: title,
file: file,
fn: fn
});
};

/**
Expand Down
6 changes: 1 addition & 5 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -847,13 +847,9 @@ Runner.prototype.abort = function() {
*/
function filterOnly(suite) {
// If it has `only` tests, run only those
if (suite.onlyTests) {
suite.tests = suite.onlyTests;
}
suite.tests = suite.onlyTests ? 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;
}
Expand Down
52 changes: 51 additions & 1 deletion test/integration/fixtures/options/only/bdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,54 @@ describe('should not run this suite', function() {
it('should not run this test', function() {
(true).should.equal(false);
});
});
});

describe.only('should run this suite too', function() {
describe('should run this nested suite', function () {
it('should run this test', function() {});

it('should run this test', function() {});

it('should run this test', function() {});
});
});

describe.only('should run this suite, even', function() {
describe('should run this nested suite, even', function () {
describe('should run this doubly-nested suite!', function () {
it('should run this test', function() {});

it('should run this test', function() {});

it('should run this test', function() {});
});
});
});


describe('should run this suite with an exclusive test', function() {
it.only('should run this test', function () {});

describe('should not run this nested suite', function () {
describe.only('should not run this doubly-nested suite', function () {
it('should not run this test', function() {});

it('should not run this test', function() {});

it('should not run this test', function() {});
});
});
});

describe('should run this suite with an exclusive test (reverse order)', function() {
describe('should not run this nested suite', function () {
describe.only('should not run this doubly-nested suite', function () {
it('should not run this test', function() {});

it('should not run this test', function() {});

it('should not run this test', function() {});
});
});
it.only('should run this test', function () {});
});
14 changes: 13 additions & 1 deletion test/integration/fixtures/options/only/tdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,16 @@ suite('should not run this suite', function() {
test('should not run this test', function() {
(true).should.equal(false);
});
});
});

suite.only('should run this suite too', function() {
suite('should run this nested suite', function () {
test('should run this test', function() {});

test('should run this test', function() {});

test('should run this test', function() {});

test('should run this test', function() {});
});
});
4 changes: 2 additions & 2 deletions test/integration/only.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('.only()', function() {
run('options/only/bdd.js', ['--ui', 'bdd'], function(err, res) {
assert(!err);
assert.equal(res.stats.pending, 0);
assert.equal(res.stats.passes, 3);
assert.equal(res.stats.passes, 11);
assert.equal(res.stats.failures, 0);
assert.equal(res.code, 0);
done();
Expand All @@ -17,7 +17,7 @@ describe('.only()', function() {
run('options/only/tdd.js', ['--ui', 'tdd'], function(err, res) {
assert(!err);
assert.equal(res.stats.pending, 0);
assert.equal(res.stats.passes, 4);
assert.equal(res.stats.passes, 8);
assert.equal(res.stats.failures, 0);
assert.equal(res.code, 0);
done();
Expand Down