diff --git a/lib/rules/max-top-level-suites.js b/lib/rules/max-top-level-suites.js index 94cc53c..b05407b 100644 --- a/lib/rules/max-top-level-suites.js +++ b/lib/rules/max-top-level-suites.js @@ -7,12 +7,14 @@ var R = require('ramda'), astUtil = require('../util/ast'), + additionalSuiteNames = require('../util/settings').additionalSuiteNames, defaultSuiteLimit = 1; module.exports = function (context) { var stack = [], topLevelDescribes = [], options = context.options[0] || {}, + settings = context.settings, suiteLimit; if (R.isNil(options.limit)) { @@ -23,13 +25,13 @@ module.exports = function (context) { return { CallExpression: function (node) { - if (astUtil.isDescribe(node)) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { stack.push(node); } }, 'CallExpression:exit': function (node) { - if (astUtil.isDescribe(node)) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { if (stack.length === 1) { topLevelDescribes.push(node); } diff --git a/lib/rules/no-hooks-for-single-case.js b/lib/rules/no-hooks-for-single-case.js index 7b78c28..5a008ef 100644 --- a/lib/rules/no-hooks-for-single-case.js +++ b/lib/rules/no-hooks-for-single-case.js @@ -1,6 +1,7 @@ 'use strict'; -var astUtil = require('../util/ast'); +var astUtil = require('../util/ast'), + additionalSuiteNames = require('../util/settings').additionalSuiteNames; function newDescribeLayer(describeNode) { return { @@ -13,6 +14,7 @@ function newDescribeLayer(describeNode) { module.exports = function (context) { var options = context.options[0] || {}, allowedHooks = options.allow || [], + settings = context.settings, layers = []; function popLayer(node) { @@ -40,7 +42,7 @@ module.exports = function (context) { }, CallExpression: function (node) { - if (astUtil.isDescribe(node)) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { layers[layers.length - 1].testCount += 1; layers.push(newDescribeLayer(node)); return; diff --git a/lib/rules/no-identical-title.js b/lib/rules/no-identical-title.js index 10137ab..137ceab 100644 --- a/lib/rules/no-identical-title.js +++ b/lib/rules/no-identical-title.js @@ -1,6 +1,7 @@ 'use strict'; -var astUtil = require('../util/ast'); +var astUtil = require('../util/ast'), + additionalSuiteNames = require('../util/settings').additionalSuiteNames; function newLayer() { return { @@ -22,7 +23,9 @@ function handlTestCaseTitles(context, titles, node, title) { } function handlTestSuiteTitles(context, titles, node, title) { - if (!astUtil.isDescribe(node)) { + var settings = context.settings; + + if (!astUtil.isDescribe(node, additionalSuiteNames(settings))) { return; } if (titles.indexOf(title) !== -1) { @@ -41,12 +44,14 @@ function isFirstArgLiteral(node) { module.exports = function (context) { var titleLayers = [ newLayer() - ]; + ], + settings = context.settings; + return { CallExpression: function (node) { var currentLayer = titleLayers[titleLayers.length - 1], title; - if (astUtil.isDescribe(node)) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { titleLayers.push(newLayer()); } if (!isFirstArgLiteral(node)) { @@ -58,7 +63,7 @@ module.exports = function (context) { handlTestSuiteTitles(context, currentLayer.describeTitles, node, title); }, 'CallExpression:exit': function (node) { - if (astUtil.isDescribe(node)) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { titleLayers.pop(); } } diff --git a/lib/rules/no-nested-tests.js b/lib/rules/no-nested-tests.js index 84fddef..d7fe8b7 100644 --- a/lib/rules/no-nested-tests.js +++ b/lib/rules/no-nested-tests.js @@ -1,9 +1,11 @@ 'use strict'; -var astUtils = require('../util/ast'); +var astUtils = require('../util/ast'), + additionalSuiteNames = require('../util/settings').additionalSuiteNames; module.exports = function noNestedTests(context) { - var testNestingLevel = 0; + var testNestingLevel = 0, + settings = context.settings; function report(callExpression, isTestCase) { var message = isTestCase ? 'Unexpected test nested within another test.' : @@ -18,7 +20,7 @@ module.exports = function noNestedTests(context) { return { CallExpression: function (node) { var isTestCase = astUtils.isTestCase(node), - isDescribe = astUtils.isDescribe(node); + isDescribe = astUtils.isDescribe(node, additionalSuiteNames(settings)); if (testNestingLevel > 0 && (isTestCase || isDescribe)) { report(node, isTestCase); diff --git a/lib/rules/no-sibling-hooks.js b/lib/rules/no-sibling-hooks.js index 4270a63..700d82f 100644 --- a/lib/rules/no-sibling-hooks.js +++ b/lib/rules/no-sibling-hooks.js @@ -1,6 +1,7 @@ 'use strict'; -var astUtil = require('../util/ast'); +var astUtil = require('../util/ast'), + additionalSuiteNames = require('../util/settings').additionalSuiteNames; function newDescribeLayer(describeNode) { return { @@ -13,7 +14,8 @@ function newDescribeLayer(describeNode) { } module.exports = function (context) { - var isUsed = []; + var isUsed = [], + settings = context.settings; return { Program: function (node) { @@ -22,7 +24,7 @@ module.exports = function (context) { CallExpression: function (node) { var name = node.callee && node.callee.name; - if (astUtil.isDescribe(node)) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { isUsed.push(newDescribeLayer(node)); return; } diff --git a/lib/rules/no-top-level-hooks.js b/lib/rules/no-top-level-hooks.js index 83f36f4..bc8ac2b 100644 --- a/lib/rules/no-top-level-hooks.js +++ b/lib/rules/no-top-level-hooks.js @@ -1,13 +1,15 @@ 'use strict'; -var astUtil = require('../util/ast'); +var astUtil = require('../util/ast'), + additionalSuiteNames = require('../util/settings').additionalSuiteNames; module.exports = function (context) { - var testSuiteStack = []; + var settings = context.settings, + testSuiteStack = []; return { CallExpression: function (node) { - if (astUtil.isDescribe(node)) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { testSuiteStack.push(node); return; } diff --git a/lib/util/ast.js b/lib/util/ast.js index 471673c..176adf3 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -21,10 +21,10 @@ function getNodeName(node) { return node.name; } -function isDescribe(node) { +function isDescribe(node, additionalSuiteNames) { return node && node.type === 'CallExpression' - && describeAliases.indexOf(getNodeName(node.callee)) > -1; + && describeAliases.concat(additionalSuiteNames).indexOf(getNodeName(node.callee)) > -1; } function isHookIdentifier(node) { diff --git a/lib/util/settings.js b/lib/util/settings.js index 749d287..af239cc 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -13,5 +13,6 @@ function settingFor(propertyName) { module.exports = { getAdditionalTestFunctions: settingFor('additionalTestFunctions'), + additionalSuiteNames: settingFor('additionalSuiteNames'), getAdditionalXFunctions: settingFor('additionalXFunctions') }; diff --git a/test/rules/max-top-level-suites.js b/test/rules/max-top-level-suites.js index d4a0efc..bd558c9 100644 --- a/test/rules/max-top-level-suites.js +++ b/test/rules/max-top-level-suites.js @@ -40,6 +40,19 @@ ruleTester.run('max-top-level-suites', rules['max-top-level-suites'], { options: [ { } ], code: 'someOtherFunction();' }, + { + code: 'foo("This is a test", function () { });', + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + } + }, { + code: 'foo("This is a test", function () { });', + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + } + }, 'someOtherFunction();' ], @@ -151,6 +164,27 @@ ruleTester.run('max-top-level-suites', rules['max-top-level-suites'], { errors: [ { message: 'The number of top-level suites is more than 1.' } ] + }, + { + code: 'foo("this is a test", function () { });' + + 'foo("this is a different test", function () { });', + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + }, + errors: [ + { message: 'The number of top-level suites is more than 1.' } + ] + }, { + code: 'foo("this is a test", function () { });' + + 'foo("this is a different test", function () { });', + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + }, + errors: [ + { message: 'The number of top-level suites is more than 1.' } + ] } ] }); diff --git a/test/rules/no-hooks-for-single-case.js b/test/rules/no-hooks-for-single-case.js index 6ba8943..07dbe36 100644 --- a/test/rules/no-hooks-for-single-case.js +++ b/test/rules/no-hooks-for-single-case.js @@ -128,6 +128,32 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { '});' ].join('\n'), options: [ { allow: [ 'after', 'afterEach' ] } ] + }, + { + code: [ + 'foo(function() {', + ' before(function() {});', + ' it(function() {});', + ' it(function() {});', + '});' + ].join('\n'), + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + } + }, + { + code: [ + 'foo(function() {', + ' before(function() {});', + ' it(function() {});', + ' it(function() {});', + '});' + ].join('\n'), + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + } } ], @@ -258,6 +284,30 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { ].join('\n'), options: [ { allow: [ 'before' ] } ], errors: [ { message: 'Unexpected use of Mocha `after` hook for a single test case', column: 5, line: 2 } ] + }, + { + code: [ + 'foo(function() {', + ' before(function() {});', + '});' + ].join('\n'), + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + }, + errors: [ { message: 'Unexpected use of Mocha `before` hook for a single test case', column: 5, line: 2 } ] + }, + { + code: [ + 'foo(function() {', + ' before(function() {});', + '});' + ].join('\n'), + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + }, + errors: [ { message: 'Unexpected use of Mocha `before` hook for a single test case', column: 5, line: 2 } ] } ] diff --git a/test/rules/no-identical-title.js b/test/rules/no-identical-title.js index 9b956b9..835fc4f 100644 --- a/test/rules/no-identical-title.js +++ b/test/rules/no-identical-title.js @@ -91,7 +91,26 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { ' describe("describe2", function() {});', ' });', '});' - ].join('\n') + ].join('\n'), + { + code: [ + 'foo("describe1", function() {});', + 'foo("describe2", function() {});' + ].join('\n'), + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + } + }, { + code: [ + 'foo("describe1", function() {});', + 'foo("describe2", function() {});' + ].join('\n'), + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + } + } ], invalid: [ @@ -154,7 +173,28 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { 'describe("describe1", function() {});' ].join('\n'), errors: [ { message: 'Test suite title is used multiple times.', column: 1, line: 4 } ] - } + }, + { + code: [ + 'foo("describe1", function() {});', + 'foo("describe1", function() {});' + ].join('\n'), + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + }, + errors: [ { message: 'Test suite title is used multiple times.', column: 1, line: 2 } ] + }, { + code: [ + 'foo("describe1", function() {});', + 'foo("describe1", function() {});' + ].join('\n'), + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + }, + errors: [ { message: 'Test suite title is used multiple times.', column: 1, line: 2 } ] + } ] }); diff --git a/test/rules/no-nested-tests.js b/test/rules/no-nested-tests.js index a3c126c..32e04b0 100644 --- a/test/rules/no-nested-tests.js +++ b/test/rules/no-nested-tests.js @@ -9,7 +9,20 @@ ruleTester.run('no-nested-tests', rule, { 'it()', 'it(); it(); it()', 'describe("", function () { it(); })', - 'describe("", function () { describe("", function () { it(); }); it(); })' + 'describe("", function () { describe("", function () { it(); }); it(); })', + { + code: 'foo("", function () { it(); })', + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + } + }, { + code: 'foo("", function () { it(); })', + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + } + } ], invalid: [ @@ -104,6 +117,30 @@ ruleTester.run('no-nested-tests', rule, { column: 55 } ] + }, + { + code: 'it("", function () { foo() });', + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + }, + errors: [ { + message: 'Unexpected suite nested within a test.', + line: 1, + column: 22 + } ] + }, + { + code: 'it("", function () { foo() });', + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + }, + errors: [ { + message: 'Unexpected suite nested within a test.', + line: 1, + column: 22 + } ] } ] }); diff --git a/test/rules/no-sibling-hooks.js b/test/rules/no-sibling-hooks.js index 1616458..ec88959 100644 --- a/test/rules/no-sibling-hooks.js +++ b/test/rules/no-sibling-hooks.js @@ -71,7 +71,34 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { ' });', ' before(function() {});', '});' - ].join('\n') + ].join('\n'), + { + code: [ + 'foo(function() {', + ' foo(function() {', + ' before(function() {});', + ' });', + ' before(function() {});', + '});' + ].join('\n'), + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + } + }, { + code: [ + 'foo(function() {', + ' foo(function() {', + ' before(function() {});', + ' });', + ' before(function() {});', + '});' + ].join('\n'), + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + } + } ], invalid: [ @@ -114,7 +141,38 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { '});' ].join('\n'), errors: [ { message: 'Unexpected use of duplicate Mocha `before` hook', column: 5, line: 6 } ] - } + }, + { + code: [ + 'foo(function() {', + ' before(function() {});', + ' foo(function() {', + ' before(function() {});', + ' });', + ' before(function() {});', + '});' + ].join('\n'), + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + }, + errors: [ { message: 'Unexpected use of duplicate Mocha `before` hook', column: 5, line: 6 } ] + }, { + code: [ + 'foo(function() {', + ' before(function() {});', + ' foo(function() {', + ' before(function() {});', + ' });', + ' before(function() {});', + '});' + ].join('\n'), + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + }, + errors: [ { message: 'Unexpected use of duplicate Mocha `before` hook', column: 5, line: 6 } ] + } ] }); diff --git a/test/rules/no-top-level-hooks.js b/test/rules/no-top-level-hooks.js index 59710b1..ec52ef7 100644 --- a/test/rules/no-top-level-hooks.js +++ b/test/rules/no-top-level-hooks.js @@ -21,9 +21,21 @@ ruleTester.run('no-top-level-hooks', rules['no-top-level-hooks'], { 'after.foo()', 'beforeEach.foo()', 'afterEach.foo()', - 'var before = 2; before + 3;' + 'var before = 2; before + 3;', + { + code: 'foo(function() { before(function() {}); });', + settings: { + 'mocha/additionalSuiteNames': [ 'foo' ] + } + }, { + code: 'foo(function() { before(function() {}); });', + settings: { + mocha: { + additionalSuiteNames: [ 'foo' ] + } + } + } ], - invalid: [ { code: 'before(function() {});', @@ -72,6 +84,14 @@ ruleTester.run('no-top-level-hooks', rules['no-top-level-hooks'], { column: 1, line: 1 } ] + }, + { + code: 'foo(function() {}); before(function() {});', + errors: [ { + message: 'Unexpected use of Mocha `before` hook outside of a test suite', + column: 21, + line: 1 + } ] } ]