@@ -887,15 +887,9 @@ module.exports = function(suites, context, mocha) {
887887 suite . pending = Boolean ( opts . pending ) ;
888888 suite . file = opts . file ;
889889 suites . unshift ( suite ) ;
890- // I should be pilloried for the following.
891890 if ( opts . isOnly ) {
892- if ( suite . parent && suite . parent . onlyTests ) {
893- suite . onlyTests = suite . parent . onlyTests === suite . parent . tests ? suite . tests : [ ] ;
894- } else {
895- suite . onlyTests = suite . tests ;
896- }
897- } else {
898- suite . onlyTests = suite . parent && suite . parent . onlyTests === suite . parent . tests ? suite . tests : [ ] ;
891+ suite . parent . _onlySuites = suite . parent . _onlySuites . concat ( suite ) ;
892+ mocha . options . hasOnly = true ;
899893 }
900894 if ( typeof opts . fn === 'function' ) {
901895 opts . fn . call ( suite ) ;
@@ -916,12 +910,7 @@ module.exports = function(suites, context, mocha) {
916910 * @returns {* }
917911 */
918912 only : function ( mocha , test ) {
919- var suite = test . parent ;
920- if ( suite . onlyTests === suite . tests ) {
921- suite . onlyTests = [ test ] ;
922- } else {
923- suite . onlyTests = ( suite . onlyTests || [ ] ) . concat ( test ) ;
924- }
913+ test . parent . _onlyTests = test . parent . _onlyTests . concat ( test ) ;
925914 mocha . options . hasOnly = true ;
926915 return test ;
927916 } ,
@@ -4417,6 +4406,7 @@ var debug = require('debug')('mocha:runner');
44174406var Runnable = require ( './runnable' ) ;
44184407var filter = utils . filter ;
44194408var indexOf = utils . indexOf ;
4409+ var some = utils . some ;
44204410var keys = utils . keys ;
44214411var stackFilter = utils . stackTraceFilter ( ) ;
44224412var stringify = utils . stringify ;
@@ -5253,12 +5243,38 @@ Runner.prototype.abort = function() {
52535243 * @api private
52545244 */
52555245function filterOnly ( suite ) {
5256- // If it has `only` tests, run only those
5257- suite . tests = suite . onlyTests ? suite . onlyTests : [ ] ;
5258- // Filter the nested suites
5259- suite . suites = filter ( suite . suites , filterOnly ) ;
5246+ if ( suite . _onlyTests . length ) {
5247+ // If the suite contains `only` tests, run those and ignore any nested suites.
5248+ suite . tests = suite . _onlyTests ;
5249+ suite . suites = [ ] ;
5250+ } else {
5251+ // Otherwise, do not run any of the tests in this suite.
5252+ suite . tests = [ ] ;
5253+ suite . _onlySuites . forEach ( function ( onlySuite ) {
5254+ // If there are other `only` tests/suites nested in the current `only` suite, then filter the current suite.
5255+ // Otherwise, all of the tests on this `only` suite should be run, so don't filter it.
5256+ if ( hasOnly ( onlySuite ) ) {
5257+ filterOnly ( suite ) ;
5258+ }
5259+ } ) ;
5260+ // Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants.
5261+ suite . suites = filter ( suite . suites , function ( childSuite ) {
5262+ return indexOf ( suite . _onlySuites , childSuite ) !== - 1 || filterOnly ( childSuite ) ;
5263+ } ) ;
5264+ }
52605265 // Keep the suite only if there is something to run
5261- return suite . suites . length || suite . tests . length ;
5266+ return suite . tests . length || suite . suites . length ;
5267+ }
5268+
5269+ /**
5270+ * Determines whether a suite has an `only` test or suite as a descendant.
5271+ *
5272+ * @param {Array } suite
5273+ * @returns {Boolean }
5274+ * @api private
5275+ */
5276+ function hasOnly ( suite ) {
5277+ return suite . _onlyTests . length || suite . _onlySuites . length || some ( suite . suites , hasOnly ) ;
52625278}
52635279
52645280/**
@@ -5392,6 +5408,8 @@ function Suite(title, parentContext) {
53925408 this . _slow = 75 ;
53935409 this . _bail = false ;
53945410 this . _retries = - 1 ;
5411+ this . _onlyTests = [ ] ;
5412+ this . _onlySuites = [ ] ;
53955413 this . delayed = false ;
53965414}
53975415
@@ -5961,6 +5979,23 @@ exports.filter = function(arr, fn) {
59615979 return ret ;
59625980} ;
59635981
5982+ /**
5983+ * Array#some (<=IE8)
5984+ *
5985+ * @api private
5986+ * @param {Array } arr
5987+ * @param {Function } fn
5988+ * @return {Array }
5989+ */
5990+ exports . some = function ( arr , fn ) {
5991+ for ( var i = 0 , l = arr . length ; i < l ; i ++ ) {
5992+ if ( fn ( arr [ i ] ) ) {
5993+ return true ;
5994+ }
5995+ }
5996+ return false ;
5997+ } ;
5998+
59645999/**
59656000 * Object.keys (<=IE8)
59666001 *
0 commit comments