Skip to content

Commit a710267

Browse files
committed
Change to not use a global variable
Also, changed to also detect a test inside a hook
1 parent b5d8eea commit a710267

File tree

6 files changed

+74
-36
lines changed

6 files changed

+74
-36
lines changed

lib/interfaces/bdd.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,11 @@ module.exports = function bddInterface(suite) {
8888
}
8989

9090
// Check for nested test registration
91-
if (global._mochaExecutionState && global._mochaExecutionState.currentRunnable) {
92-
var currentRunnable = global._mochaExecutionState.currentRunnable;
93-
if (currentRunnable.type === 'test') {
94-
throw createUnsupportedError(
95-
'Nested test "' + title + '" detected inside test "' + currentRunnable.title + '". ' +
96-
'Nested tests are not allowed.'
97-
);
98-
}
91+
var currentRunnable = suite.rootSuite().currentRunnable;
92+
if (currentRunnable) {
93+
throw createUnsupportedError(
94+
'Nested test "' + title + '" detected inside "' + currentRunnable.title + '". '
95+
);
9996
}
10097

10198
var test = new Test(title, fn);

lib/interfaces/tdd.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,11 @@ module.exports = function (suite) {
8888
}
8989

9090
// Check for nested test registration
91-
if (global._mochaExecutionState && global._mochaExecutionState.currentRunnable) {
92-
var currentRunnable = global._mochaExecutionState.currentRunnable;
93-
if (currentRunnable.type === 'test') {
94-
throw createUnsupportedError(
95-
'Nested test "' + title + '" detected inside test "' + currentRunnable.title + '". ' +
96-
'Nested tests are not allowed.'
97-
);
98-
}
91+
var currentRunnable = suite.rootSuite().currentRunnable;
92+
if (currentRunnable) {
93+
throw createUnsupportedError(
94+
'Nested test "' + title + '" detected inside "' + currentRunnable.title + '". '
95+
);
9996
}
10097

10198
var test = new Test(title, fn);

lib/runner.js

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,6 @@ class Runner extends EventEmitter {
191191
this.total = suite.total();
192192
this.failures = 0;
193193

194-
// Initialize global execution state tracking for nested test detection
195-
if (!global._mochaExecutionState) {
196-
global._mochaExecutionState = {
197-
currentRunnable: null
198-
};
199-
}
200194
/**
201195
* @type {Map<EventEmitter,Map<string,Set<EventListener>>>}
202196
*/
@@ -207,11 +201,9 @@ class Runner extends EventEmitter {
207201
test.parent.tests && test.parent.tests.indexOf(test.retriedTest());
208202
if (idx > -1) test.parent.tests[idx] = test;
209203
}
204+
// Clear current runnable for nested test detection when test ends
205+
self.suite.rootSuite().currentRunnable = null;
210206
self.checkGlobals(test);
211-
// Clear execution state when test ends
212-
if (global._mochaExecutionState) {
213-
global._mochaExecutionState.currentRunnable = null;
214-
}
215207
});
216208
this.on(constants.EVENT_HOOK_END, function (hook) {
217209
self.checkGlobals(hook);
@@ -534,7 +526,8 @@ Runner.prototype.hook = function (name, fn) {
534526
return fn();
535527
}
536528
self.currentRunnable = hook;
537-
global._mochaExecutionState.currentRunnable = hook;
529+
// Store current runnable on root suite for nested test detection
530+
self.suite.rootSuite().currentRunnable = hook;
538531

539532
if (name === HOOK_TYPE_BEFORE_ALL) {
540533
hook.ctx.currentTest = hook.parent.tests[0];
@@ -847,7 +840,8 @@ Runner.prototype.runTests = function (suite, fn) {
847840
return hookErr(err, errSuite, false);
848841
}
849842
self.currentRunnable = self.test;
850-
global._mochaExecutionState.currentRunnable = self.test;
843+
// Store current runnable on root suite for nested test detection
844+
self.suite.rootSuite().currentRunnable = self.test;
851845
self.runTest(function (err) {
852846
test = self.test;
853847
// conditional skip within it

lib/suite.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,21 @@ Suite.prototype.titlePath = function () {
400400
return result;
401401
};
402402

403+
/**
404+
* Return the root suite by traversing up the parent chain.
405+
*
406+
* @memberof Suite
407+
* @public
408+
* @return {Suite}
409+
*/
410+
Suite.prototype.rootSuite = function () {
411+
var suite = this;
412+
while (suite.parent) {
413+
suite = suite.parent;
414+
}
415+
return suite;
416+
};
417+
403418
/**
404419
* Return the total number of tests.
405420
*
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
3+
// BDD hook nested test fixture - should fail with nested test error
4+
describe('Hook Nested Test Suite', function() {
5+
before(function() {
6+
// This should fail due to nested test inside hook
7+
it('nested test in before hook', function() {
8+
// This nested test should cause an error
9+
});
10+
});
11+
12+
it('normal test', function() {
13+
// This should pass if no hook error
14+
});
15+
});

test/integration/nested-tests.spec.js

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ var runMocha = helpers.runMocha;
66
var runMochaJSON = helpers.runMochaJSON;
77

88
describe('nested test detection', function () {
9-
var nestedTestErrorMessage = 'Nested tests are not allowed';
9+
var nestedTestErrorMessage = 'Nested test ".*" detected inside';
1010

1111
describe('BDD interface', function () {
1212
it('should fail when nested tests are detected', function (done) {
@@ -20,7 +20,7 @@ describe('nested test detection', function () {
2020
return done(err);
2121
}
2222
expect(res, 'to have failed with output', new RegExp(nestedTestErrorMessage));
23-
expect(res, 'to have failed with output', /inner nested test.*detected inside test.*outer test/);
23+
expect(res, 'to have failed with output', /inner nested test.*detected inside.*outer test/);
2424
done();
2525
},
2626
spawnOpts
@@ -53,7 +53,7 @@ describe('nested test detection', function () {
5353
return done(err);
5454
}
5555
expect(res, 'to have failed with output', new RegExp(nestedTestErrorMessage));
56-
expect(res, 'to have failed with output', /inner nested test.*detected inside test.*outer test/);
56+
expect(res, 'to have failed with output', /inner nested test.*detected inside.*outer test/);
5757
done();
5858
},
5959
spawnOpts
@@ -86,7 +86,7 @@ describe('nested test detection', function () {
8686
return done(err);
8787
}
8888
expect(res, 'to have failed with output', new RegExp(nestedTestErrorMessage));
89-
expect(res, 'to have failed with output', /nested in sync.*detected inside test.*sync nested test/);
89+
expect(res, 'to have failed with output', /nested in sync.*detected inside.*sync nested test/);
9090
done();
9191
},
9292
spawnOpts
@@ -104,7 +104,7 @@ describe('nested test detection', function () {
104104
return done(err);
105105
}
106106
expect(res, 'to have failed with output', new RegExp(nestedTestErrorMessage));
107-
expect(res, 'to have failed with output', /nested in async.*detected inside test.*async\/await nested test/);
107+
expect(res, 'to have failed with output', /nested in async.*detected inside.*async\/await nested test/);
108108
done();
109109
},
110110
spawnOpts
@@ -122,7 +122,7 @@ describe('nested test detection', function () {
122122
return done(err);
123123
}
124124
expect(res, 'to have failed with output', new RegExp(nestedTestErrorMessage));
125-
expect(res, 'to have failed with output', /Uncaught.*nested in callback.*detected inside test.*callback nested test/);
125+
expect(res, 'to have failed with output', /Uncaught.*nested in callback.*detected inside.*callback nested test/);
126126
done();
127127
},
128128
spawnOpts
@@ -140,7 +140,27 @@ describe('nested test detection', function () {
140140
return done(err);
141141
}
142142
expect(res, 'to have failed with output', new RegExp(nestedTestErrorMessage));
143-
expect(res, 'to have failed with output', /Uncaught.*nested in promise.*detected inside test.*promise nested test/);
143+
expect(res, 'to have failed with output', /Uncaught.*nested in promise.*detected inside.*promise nested test/);
144+
done();
145+
},
146+
spawnOpts
147+
);
148+
});
149+
});
150+
151+
describe('hook nested tests', function () {
152+
it('should fail when nested tests are detected inside hooks', function (done) {
153+
var fixture = path.join('nested-tests', 'bdd-hook-nested');
154+
var spawnOpts = {stdio: 'pipe'};
155+
runMocha(
156+
fixture,
157+
['--ui', 'bdd'],
158+
function (err, res) {
159+
if (err) {
160+
return done(err);
161+
}
162+
expect(res, 'to have failed with output', new RegExp(nestedTestErrorMessage));
163+
expect(res, 'to have failed with output', /nested test in before hook.*detected inside.*"before all" hook/);
144164
done();
145165
},
146166
spawnOpts
@@ -160,7 +180,7 @@ describe('nested test detection', function () {
160180
return done(err);
161181
}
162182
expect(res, 'to have failed with output', /Error: Nested test "inner nested test"/);
163-
expect(res, 'to have failed with output', /detected inside test "outer test with nested test"/);
183+
expect(res, 'to have failed with output', /detected inside "outer test with nested test"/);
164184
expect(res, 'to have failed with output', /createUnsupportedError/);
165185
done();
166186
},

0 commit comments

Comments
 (0)