Skip to content

Commit cddbe52

Browse files
a8mboneskull
authored andcommitted
feat(runner): fix '.only()' exclusive feature, #1481
This PR fix #1481, and also extends the .only() behaviour. (i.e: it's not use grep anymore, support suite, test-case or both, add the ability to run multiple .only)
1 parent cbf9bca commit cddbe52

File tree

17 files changed

+523
-44
lines changed

17 files changed

+523
-44
lines changed

Makefile

+13-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ lint:
4040
@printf "==> [Test :: Lint]\n"
4141
@$(ESLINT) $(SRC)
4242

43-
test-node: test-bdd test-tdd test-qunit test-exports test-unit test-integration test-jsapi test-compilers test-glob test-requires test-reporters test-only
43+
test-node: test-bdd test-tdd test-qunit test-exports test-unit test-integration test-jsapi test-compilers test-glob test-requires test-reporters test-only test-global-only
4444

4545
test-browser: test-browser-unit test-browser-bdd test-browser-qunit test-browser-tdd test-browser-exports
4646

@@ -154,10 +154,21 @@ test-only:
154154
--ui qunit \
155155
test/acceptance/misc/only/bdd-require
156156

157+
test-global-only:
158+
@./bin/mocha \
159+
--reporter $(REPORTER) \
160+
--ui tdd \
161+
test/acceptance/misc/only/global/tdd
162+
163+
@./bin/mocha \
164+
--reporter $(REPORTER) \
165+
--ui bdd \
166+
test/acceptance/misc/only/global/bdd
167+
157168
@./bin/mocha \
158169
--reporter $(REPORTER) \
159170
--ui qunit \
160-
test/acceptance/misc/only/qunit
171+
test/acceptance/misc/only/global/qunit
161172

162173
test-mocha:
163174
@printf "==> [Test :: Mocha]\n"

lib/interfaces/bdd.js

+3-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
var Suite = require('../suite');
66
var Test = require('../test');
7-
var escapeRe = require('escape-string-regexp');
87

98
/**
109
* BDD-style interface:
@@ -66,9 +65,7 @@ module.exports = function(suite) {
6665
*/
6766

6867
context.describe.only = function(title, fn) {
69-
var suite = context.describe(title, fn);
70-
mocha.grep(suite.fullTitle());
71-
return suite;
68+
return common.suite.only(mocha, context.describe(title, fn));
7269
};
7370

7471
/**
@@ -77,7 +74,7 @@ module.exports = function(suite) {
7774
* acting as a thunk.
7875
*/
7976

80-
var it = context.it = context.specify = function(title, fn) {
77+
context.it = context.specify = function(title, fn) {
8178
var suite = suites[0];
8279
if (suite.isPending()) {
8380
fn = null;
@@ -93,10 +90,7 @@ module.exports = function(suite) {
9390
*/
9491

9592
context.it.only = function(title, fn) {
96-
var test = it(title, fn);
97-
var reString = '^' + escapeRe(test.fullTitle()) + '$';
98-
mocha.grep(new RegExp(reString));
99-
return test;
93+
return common.test.only(mocha, context.it(title, fn));
10094
};
10195

10296
/**

lib/interfaces/common.js

+31
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,38 @@ module.exports = function(suites, context) {
6262
suites[0].afterEach(name, fn);
6363
},
6464

65+
suite: {
66+
/**
67+
* Exclusive suite.
68+
*
69+
* @param {Object} mocha
70+
* @param {Function} suite
71+
*/
72+
73+
only: function(mocha, suite) {
74+
suite.isOnly = true;
75+
mocha.options.hasOnly = true;
76+
return suite;
77+
}
78+
},
79+
6580
test: {
81+
82+
/**
83+
* Exclusive test-case.
84+
*
85+
* @param {Object} mocha
86+
* @param {Function} test
87+
* @returns {*}
88+
*/
89+
only: function(mocha, test) {
90+
var suite = test.parent;
91+
suite.isOnly = true;
92+
suite.onlyTests = (suite.onlyTests || []).concat(test);
93+
mocha.options.hasOnly = true;
94+
return test;
95+
},
96+
6697
/**
6798
* Pending test case.
6899
*

lib/interfaces/qunit.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
var Suite = require('../suite');
66
var Test = require('../test');
7-
var escapeRe = require('escape-string-regexp');
87

98
/**
109
* QUnit-style interface:
@@ -61,8 +60,7 @@ module.exports = function(suite) {
6160
*/
6261

6362
context.suite.only = function(title, fn) {
64-
var suite = context.suite(title, fn);
65-
mocha.grep(suite.fullTitle());
63+
return common.suite.only(mocha, context.suite(title, fn));
6664
};
6765

6866
/**
@@ -83,9 +81,7 @@ module.exports = function(suite) {
8381
*/
8482

8583
context.test.only = function(title, fn) {
86-
var test = context.test(title, fn);
87-
var reString = '^' + escapeRe(test.fullTitle()) + '$';
88-
mocha.grep(new RegExp(reString));
84+
return common.test.only(mocha, context.test(title, fn));
8985
};
9086

9187
context.test.skip = common.test.skip;

lib/interfaces/tdd.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
var Suite = require('../suite');
66
var Test = require('../test');
7-
var escapeRe = require('escape-string-regexp');
87

98
/**
109
* TDD-style interface:
@@ -71,8 +70,7 @@ module.exports = function(suite) {
7170
* Exclusive test-case.
7271
*/
7372
context.suite.only = function(title, fn) {
74-
var suite = context.suite(title, fn);
75-
mocha.grep(suite.fullTitle());
73+
return common.suite.only(mocha, context.suite(title, fn));
7674
};
7775

7876
/**
@@ -95,9 +93,7 @@ module.exports = function(suite) {
9593
*/
9694

9795
context.test.only = function(title, fn) {
98-
var test = context.test(title, fn);
99-
var reString = '^' + escapeRe(test.fullTitle()) + '$';
100-
mocha.grep(new RegExp(reString));
96+
return common.test.only(mocha, context.test(title, fn));
10197
};
10298

10399
context.test.skip = common.test.skip;

lib/mocha.js

+1
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ Mocha.prototype.run = function(fn) {
491491
var reporter = new this._reporter(runner, options);
492492
runner.ignoreLeaks = options.ignoreLeaks !== false;
493493
runner.fullStackTrace = options.fullStackTrace;
494+
runner.hasOnly = options.hasOnly;
494495
runner.asyncOnly = options.asyncOnly;
495496
runner.allowUncaught = options.allowUncaught;
496497
if (options.grep) {

lib/runner.js

+25
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,11 @@ Runner.prototype.run = function(fn) {
778778
var self = this;
779779
var rootSuite = this.suite;
780780

781+
// If there is an `only` filter
782+
if (this.hasOnly) {
783+
filterOnly(rootSuite);
784+
}
785+
781786
fn = fn || function() {};
782787

783788
function uncaught(err) {
@@ -833,6 +838,26 @@ Runner.prototype.abort = function() {
833838
return this;
834839
};
835840

841+
/**
842+
* Filter suites based on `isOnly` logic.
843+
*
844+
* @param {Array} suite
845+
* @returns {Boolean}
846+
* @api private
847+
*/
848+
function filterOnly(suite) {
849+
// If it has `only` tests, run only those
850+
if (suite.onlyTests) {
851+
suite.tests = suite.onlyTests;
852+
}
853+
// Filter the nested suites
854+
suite.suites = filter(suite.suites, filterOnly);
855+
// Don't run tests from suites that are not marked as `only`
856+
suite.tests = suite.isOnly ? suite.tests : [];
857+
// Keep the suite only if there is something to run
858+
return suite.suites.length || suite.tests.length;
859+
}
860+
836861
/**
837862
* Filter leaks with the given globals flagged as `ok`.
838863
*

test/acceptance/misc/only/bdd.js

+118-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,125 @@
11
describe('should only run .only test in this bdd suite', function() {
22
it('should not run this test', function() {
3-
var zero = 0;
4-
expect(zero).to.equal(1, 'this test should have been skipped');
3+
(0).should.equal(1, 'this test should have been skipped');
54
});
6-
it.only('should run this test', function() {
7-
var zero = 0;
8-
expect(zero).to.equal(0, 'this .only test should run');
5+
it.only('should run this test', function() {
6+
(0).should.equal(0, 'this .only test should run');
97
});
108
it('should run this test, not (includes the title of the .only test)', function() {
11-
var zero = 0;
12-
expect(zero).to.equal(1, 'this test should have been skipped');
9+
(0).should.equal(1, 'this test should have been skipped');
1310
});
1411
});
12+
13+
describe('should not run this suite', function() {
14+
it('should not run this test', function() {
15+
(true).should.equal(false);
16+
});
17+
18+
it('should not run this test', function() {
19+
(true).should.equal(false);
20+
});
21+
22+
it('should not run this test', function() {
23+
(true).should.equal(false);
24+
});
25+
});
26+
27+
describe.only('should run all tests in this bdd suite', function() {
28+
it('should run this test #1', function() {
29+
(true).should.equal(true);
30+
});
31+
32+
it('should run this test #2', function() {
33+
(1).should.equal(1);
34+
});
35+
36+
it('should run this test #3', function() {
37+
('foo').should.equal('foo');
38+
});
39+
});
40+
41+
describe('should run only suites that marked as `only`', function() {
42+
describe.only('should run all this tdd suite', function() {
43+
it('should run this test #1', function() {
44+
(true).should.equal(true);
45+
});
46+
47+
it('should run this test #2', function() {
48+
(true).should.equal(true);
49+
});
50+
});
51+
52+
describe('should not run this suite', function() {
53+
it('should run this test', function() {
54+
(true).should.equal(false);
55+
});
56+
});
57+
});
58+
59+
// Nested situation
60+
describe('should not run parent tests', function() {
61+
it('should not run this test', function() {
62+
(true).should.equal(false);
63+
});
64+
describe('and not the child tests too', function() {
65+
it('should not run this test', function() {
66+
(true).should.equal(false);
67+
});
68+
describe.only('but run all the tests in this suite', function() {
69+
it('should run this test #1', function() {
70+
(true).should.equal(true);
71+
});
72+
it('should run this test #2', function() {
73+
(true).should.equal(true);
74+
});
75+
});
76+
});
77+
});
78+
79+
// mark test as `only` override the suite behavior
80+
describe.only('should run only tests that marked as `only`', function() {
81+
it('should not run this test #1', function() {
82+
(false).should.equal(true);
83+
});
84+
85+
it.only('should run this test #2', function() {
86+
(true).should.equal(true);
87+
});
88+
89+
it('should not run this test #3', function() {
90+
(false).should.equal(true);
91+
});
92+
93+
it.only('should run this test #4', function() {
94+
(true).should.equal(true);
95+
});
96+
});
97+
98+
describe.only('Should run only test cases that mark as only', function() {
99+
it.only('should runt his test', function() {
100+
(true).should.equal(true);
101+
});
102+
103+
it('should not run this test', function() {
104+
(false).should.equal(true);
105+
});
106+
107+
describe('should not run this suite', function() {
108+
it('should not run this test', function() {
109+
(false).should.equal(true);
110+
});
111+
});
112+
});
113+
114+
// Root Suite
115+
it.only('#Root-Suite, should run this test-case #1', function() {
116+
(true).should.equal(true);
117+
});
118+
119+
it.only('#Root-Suite, should run this test-case #2', function() {
120+
(true).should.equal(true);
121+
});
122+
123+
it('#Root-Suite, should not run this test', function() {
124+
(false).should.equal(true);
125+
});
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Root-only test cases
2+
it.only('#Root-Suite, should run this bdd test-case #1', function() {
3+
(true).should.equal(true);
4+
});
5+
6+
it('#Root-Suite, should not run this bdd test-case #2', function() {
7+
(false).should.equal(true);
8+
});
9+
10+
it('#Root-Suite, should not run this bdd test-case #3', function() {
11+
(false).should.equal(true);
12+
});
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Root-only test cases
2+
test.only('#Root-Suite, should run this qunit test-case #1', function() {
3+
(true).should.equal(true);
4+
});
5+
6+
test('#Root-Suite, should not run this qunit test-case #2', function() {
7+
(false).should.equal(true);
8+
});
9+
10+
test('#Root-Suite, should not run this qunit test-case #3', function() {
11+
(false).should.equal(true);
12+
});
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Root-only test cases
2+
test.only('#Root-Suite, should run this tdd test-case #1', function() {
3+
(true).should.equal(true);
4+
});
5+
6+
test('#Root-Suite, should not run this tdd test-case #2', function() {
7+
(false).should.equal(true);
8+
});
9+
10+
test('#Root-Suite, should not run this tdd test-case #3', function() {
11+
(false).should.equal(true);
12+
});

0 commit comments

Comments
 (0)