Skip to content

Commit

Permalink
Merge pull request #109 from lo1tuma/no-nested-tests
Browse files Browse the repository at this point in the history
Add no-nested-tests rule
  • Loading branch information
lo1tuma committed Oct 12, 2016
2 parents f3d9f83 + 4e61e9b commit 7d0d872
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/rules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
* [no-top-level-hooks](no-top-level-hooks.md) - disallow top-level hooks
* [no-identical-title](no-identical-title.md) - disallow identical titles
* [max-top-level-suites](max-top-level-suites.md) - limit the number of top-level suites in a single file
* [no-nested-tests](no-nested-tests.md) - disallow tests to be nested within other tests
47 changes: 47 additions & 0 deletions docs/rules/no-nested-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Disallow tests to be nested within other tests (no-nested-tests)

Test cases in mocha can be either global or within a suite but they can’t be nested within other tests. Unfortunately there is nothing stopping you from creating a test case within another test case but mocha will simply ignore those tests.

```js
it('something', function () {
it('should work', function () {
assert(fasle);
});
});
```
Something like this could be easily happen by accident where the outer test case was actually meant to be a suite instead of a test.
This rule reports such nested test cases in order to prevent problems where those nested tests are skipped silently.

## Rule Details

This rule looks for all test cases (`it`, `specify` and `test`) or suites (`describe`, `context` and `suite`) which are nested within another test case.

The following patterns are considered problems:

```js
it('something', function () {
it('should work', function () {});
});

test('something', function () {
specify('should work', function () {});
});

it('something', function () {
describe('other thing', function () {
//
});
});

```

These patterns would not be considered problems:

```js
it('should work', function () {});
it('should work too', function () {});

describe('something', function () {
it('should work', function () {});
});
```
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = {
'no-sibling-hooks': require('./lib/rules/no-sibling-hooks'),
'no-top-level-hooks': require('./lib/rules/no-top-level-hooks'),
'no-identical-title': require('./lib/rules/no-identical-title'),
'max-top-level-suites': require('./lib/rules/max-top-level-suites')
'max-top-level-suites': require('./lib/rules/max-top-level-suites'),
'no-nested-tests': require('./lib/rules/no-nested-tests')
},
configs: {
recommended: {
Expand Down
38 changes: 38 additions & 0 deletions lib/rules/no-nested-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

var astUtils = require('../util/ast');

module.exports = function noNestedTests(context) {
var testNestingLevel = 0;

function report(callExpression, isTestCase) {
var message = isTestCase ? 'Unexpected test nested within another test.' :
'Unexpected suite nested within a test.';

context.report({
message: message,
node: callExpression.callee
});
}

return {
CallExpression: function (node) {
var isTestCase = astUtils.isTestCase(node),
isDescribe = astUtils.isDescribe(node);

if (testNestingLevel > 0 && (isTestCase || isDescribe)) {
report(node, isTestCase);
}

if (isTestCase) {
testNestingLevel += 1;
}
},

'CallExpression:exit': function (node) {
if (astUtils.isTestCase(node)) {
testNestingLevel -= 1;
}
}
};
};
4 changes: 3 additions & 1 deletion lib/util/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ var describeAliases = [ 'describe', 'xdescribe', 'describe.only', 'describe.skip
'context', 'xcontext', 'context.only', 'context.skip',
'suite', 'xsuite', 'suite.only', 'suite.skip' ],
hooks = [ 'before', 'after', 'beforeEach', 'afterEach' ],
testCaseNames = [ 'it', 'it.only', 'test', 'test.only', 'specify', 'specify.only' ];
testCaseNames = [ 'it', 'it.only', 'it.skip',
'test', 'test.only', 'test.skip',
'specify', 'specify.only', 'specify.skip' ];

function getNodeName(node) {
if (node.type === 'MemberExpression') {
Expand Down
109 changes: 109 additions & 0 deletions test/rules/no-nested-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
'use strict';

var RuleTester = require('eslint').RuleTester,
rule = require('../../lib/rules/no-nested-tests'),
ruleTester = new RuleTester();

ruleTester.run('no-nested-tests', rule, {
valid: [
'it()',
'it(); it(); it()',
'describe("", function () { it(); })',
'describe("", function () { describe("", function () { it(); }); it(); })'
],

invalid: [
{
code: 'it("", function () { it() });',
errors: [ {
message: 'Unexpected test nested within another test.',
line: 1,
column: 22
} ]
},
{
code: 'it.only("", function () { it() });',
errors: [ {
message: 'Unexpected test nested within another test.',
line: 1,
column: 27
} ]
},
{
code: 'it.skip("", function () { it() });',
errors: [ {
message: 'Unexpected test nested within another test.',
line: 1,
column: 27
} ]
},
{
code: 'test("", function () { it() });',
errors: [ {
message: 'Unexpected test nested within another test.',
line: 1,
column: 24
} ]
},
{
code: 'specify("", function () { it() });',
errors: [ {
message: 'Unexpected test nested within another test.',
line: 1,
column: 27
} ]
},
{
code: 'it("", function () { describe() });',
errors: [ {
message: 'Unexpected suite nested within a test.',
line: 1,
column: 22
} ]
},
{
code: 'it("", function () { context() });',
errors: [ {
message: 'Unexpected suite nested within a test.',
line: 1,
column: 22
} ]
},
{
code: 'it("", function () { suite() });',
errors: [ {
message: 'Unexpected suite nested within a test.',
line: 1,
column: 22
} ]
},
{
code: 'it("", function () { describe.skip() });',
errors: [ {
message: 'Unexpected suite nested within a test.',
line: 1,
column: 22
} ]
},
{
code: 'it("", function () { describe("", function () { it(); it(); }); });',
errors: [
{
message: 'Unexpected suite nested within a test.',
line: 1,
column: 22
},
{
message: 'Unexpected test nested within another test.',
line: 1,
column: 49
},
{
message: 'Unexpected test nested within another test.',
line: 1,
column: 55
}
]
}
]
});

0 comments on commit 7d0d872

Please sign in to comment.