Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions lib/interfaces/bdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
var Test = require('../test');
var EVENT_FILE_PRE_REQUIRE =
require('../suite').constants.EVENT_FILE_PRE_REQUIRE;
var errors = require('../errors');
var createUnsupportedError = errors.createUnsupportedError;

/**
* BDD-style interface:
Expand Down Expand Up @@ -84,6 +86,9 @@ module.exports = function bddInterface(suite) {
if (suite.isPending()) {
fn = null;
}

common.checkForNestedTest(suite, title);

var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
Expand Down
16 changes: 16 additions & 0 deletions lib/interfaces/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ module.exports = function (suites, context, mocha) {
};
},

/**
* Check for nested test registration.
*
* @param {Suite} suite The suite to which a test is being added.
* @param {string} title The title of the test being added.
*/
checkForNestedTest: function checkForNestedTests(suite, title) {
// Check for nested test registration
var currentRunnable = suite.rootSuite().currentRunnable;
if (currentRunnable) {
throw createUnsupportedError(
'Nested test "' + title + '" detected inside "' + currentRunnable.title + '".'
);
}
},

/**
* Execute before running tests.
*
Expand Down
5 changes: 5 additions & 0 deletions lib/interfaces/tdd.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
var Test = require('../test');
var EVENT_FILE_PRE_REQUIRE =
require('../suite').constants.EVENT_FILE_PRE_REQUIRE;
var errors = require('../errors');
var createUnsupportedError = errors.createUnsupportedError;

/**
* TDD-style interface:
Expand Down Expand Up @@ -84,6 +86,9 @@ module.exports = function (suite) {
if (suite.isPending()) {
fn = null;
}

common.checkForNestedTest(suite, title);

var test = new Test(title, fn);
test.file = file;
suite.addTest(test);
Expand Down
7 changes: 7 additions & 0 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ class Runner extends EventEmitter {
this.state = constants.STATE_IDLE;
this.total = suite.total();
this.failures = 0;

/**
* @type {Map<EventEmitter,Map<string,Set<EventListener>>>}
*/
Expand All @@ -200,6 +201,8 @@ class Runner extends EventEmitter {
test.parent.tests && test.parent.tests.indexOf(test.retriedTest());
if (idx > -1) test.parent.tests[idx] = test;
}
// Clear current runnable for nested test detection when test ends
self.suite.rootSuite().currentRunnable = null;
self.checkGlobals(test);
});
this.on(constants.EVENT_HOOK_END, function (hook) {
Expand Down Expand Up @@ -523,6 +526,8 @@ Runner.prototype.hook = function (name, fn) {
return fn();
}
self.currentRunnable = hook;
// Store current runnable on root suite for nested test detection
self.suite.rootSuite().currentRunnable = hook;

if (name === HOOK_TYPE_BEFORE_ALL) {
hook.ctx.currentTest = hook.parent.tests[0];
Expand Down Expand Up @@ -835,6 +840,8 @@ Runner.prototype.runTests = function (suite, fn) {
return hookErr(err, errSuite, false);
}
self.currentRunnable = self.test;
// Store current runnable on root suite for nested test detection
self.suite.rootSuite().currentRunnable = self.test;
self.runTest(function (err) {
test = self.test;
// conditional skip within it
Expand Down
15 changes: 15 additions & 0 deletions lib/suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,21 @@ Suite.prototype.titlePath = function () {
return result;
};

/**
* Return the root suite by traversing up the parent chain.
*
* @memberof Suite
* @public
* @return {Suite}
*/
Suite.prototype.rootSuite = function () {
var suite = this;
while (suite.parent) {
suite = suite.parent;
}
return suite;
};

/**
* Return the total number of tests.
*
Expand Down
37 changes: 37 additions & 0 deletions test/integration/fixtures/nested-tests/bdd-async-nested.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';

// BDD async nested test fixtures - should fail with nested test errors
describe('Async Nested Tests', function() {
it('sync nested test', function() {
it('nested in sync', function() {
// Should fail immediately
});
});

it('callback nested test', function(done) {
setTimeout(function() {
it('nested in callback', function() {
// Should fail with uncaught error
});
done();
}, 10);
});

it('promise nested test', function() {
return new Promise(function(resolve) {
setTimeout(function() {
it('nested in promise', function() {
// Should fail with uncaught error
});
resolve();
}, 10);
});
});

it('async/await nested test', async function() {
await new Promise(resolve => setTimeout(resolve, 10));
it('nested in async', function() {
// Should fail
});
});
});
15 changes: 15 additions & 0 deletions test/integration/fixtures/nested-tests/bdd-hook-nested.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

// BDD hook nested test fixture - should fail with nested test error
describe('Hook Nested Test Suite', function() {
before(function() {
// This should fail due to nested test inside hook
it('nested test in before hook', function() {
// This nested test should cause an error
});
});

it('normal test', function() {
// This should pass if no hook error
});
});
19 changes: 19 additions & 0 deletions test/integration/fixtures/nested-tests/bdd-nested.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict';

// BDD nested test fixture - should fail with nested test error
describe('Parent Suite', function() {
it('normal test', function() {
// This should pass
});

it('outer test with nested test', function() {
// This should fail due to nested test
it('inner nested test', function() {
// This nested test should cause an error
});
});

it('another normal test', function() {
// This should not run due to previous failure
});
});
19 changes: 19 additions & 0 deletions test/integration/fixtures/nested-tests/tdd-nested.fixture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict';

// TDD nested test fixture - should fail with nested test error
suite('Parent Suite', function() {
test('normal test', function() {
// This should pass
});

test('outer test with nested test', function() {
// This should fail due to nested test
test('inner nested test', function() {
// This nested test should cause an error
});
});

test('another normal test', function() {
// This should not run due to previous failure
});
});
Loading
Loading