From eae858622fb09783c9c22e41fcd2c3792aaed8f9 Mon Sep 17 00:00:00 2001 From: Mathias Schreck Date: Fri, 31 Jul 2020 20:30:46 +0200 Subject: [PATCH 1/2] Consistently use shared settings in all rules --- README.md | 52 ++++++++-- docs/rules/no-exclusive-tests.md | 19 ---- docs/rules/no-skipped-tests.md | 22 ---- lib/rules/handle-done-callback.js | 6 +- lib/rules/max-top-level-suites.js | 7 +- lib/rules/no-async-describe.js | 6 +- lib/rules/no-exclusive-tests.js | 38 ++----- lib/rules/no-global-tests.js | 4 +- lib/rules/no-hooks-for-single-case.js | 11 +- lib/rules/no-hooks.js | 5 +- lib/rules/no-identical-title.js | 65 ++++++------ lib/rules/no-mocha-arrows.js | 3 +- lib/rules/no-nested-tests.js | 7 +- lib/rules/no-pending-tests.js | 4 +- lib/rules/no-return-and-callback.js | 46 +++++---- lib/rules/no-return-from-async.js | 47 +++++---- lib/rules/no-setup-in-describe.js | 7 +- lib/rules/no-sibling-hooks.js | 11 +- lib/rules/no-skipped-tests.js | 60 ++--------- lib/rules/no-synchronous-tests.js | 5 +- lib/rules/no-top-level-hooks.js | 9 +- lib/rules/prefer-arrow-callback.js | 123 +++++++++++----------- lib/util/ast.js | 136 ++++++++++++++----------- lib/util/names.js | 32 +++--- lib/util/settings.js | 39 +++++-- test/rules/max-top-level-suites.js | 8 +- test/rules/no-async-describe.js | 2 +- test/rules/no-exclusive-tests.js | 22 ++-- test/rules/no-hooks-for-single-case.js | 8 +- test/rules/no-identical-title.js | 8 +- test/rules/no-nested-tests.js | 8 +- test/rules/no-setup-in-describe.js | 26 +++-- test/rules/no-sibling-hooks.js | 8 +- test/rules/no-skipped-tests.js | 12 +-- test/rules/no-top-level-hooks.js | 4 +- test/util/namesSpec.js | 80 +++++++++++++++ 36 files changed, 507 insertions(+), 443 deletions(-) diff --git a/README.md b/README.md index 9f2d919..ba9cc36 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,49 @@ Then add a reference to this plugin and selected rules in your eslint config: ```json { - "plugins": [ - "mocha" - ], + "plugins": [ + "mocha" + ] +} +``` + +### Plugin Settings + +This plugin supports the following settings, which are used by multiple rules: + +* `additionalCustomNames`: This allows rules to check additional function names when looking for suites or test cases. This might be used with a custom Mocha extension, such as [`ember-mocha`](https://github.com/switchfly/ember-mocha) +**Example:** + +```json +{ + "rules": { + "mocha/no-skipped-tests": "error", + "mocha/no-exclusive-tests": "error" + }, + "settings": { + "mocha/additionalCustomNames": { + "suites": [ + "describeModule" + ], + "suitesWithSkipModifier": [ + "describeModule.skip", + "xdescribeModule" + ], + "exclusiveSuites": [ + "describeModule.only" + ], + "testCases": [ + "testModule" + ], + "testCasesWithSkipModifier": [ + "testModule.customSkip", + "xtestModules" + ], + "exclusiveTestCases": [ + "testModule.only" + ] + } + } } ``` @@ -34,9 +74,9 @@ Enable it with the extends option: ```json { - "extends": [ - "plugin:mocha/recommended" - ], + "extends": [ + "plugin:mocha/recommended" + ] } ``` diff --git a/docs/rules/no-exclusive-tests.md b/docs/rules/no-exclusive-tests.md index 3d1bb31..cb586b9 100644 --- a/docs/rules/no-exclusive-tests.md +++ b/docs/rules/no-exclusive-tests.md @@ -49,25 +49,6 @@ suite.skip("bar", function () {}); test.skip("bar", function () {}); ``` -## Settings - -This rule supports the following shared configuration setting: - -* `additionalTestFunctions`: An array of extra test functions to protect. This might be used with a custom Mocha extension, such as [`ember-mocha`](https://github.com/switchfly/ember-mocha) - -```json -{ - "rules": { - "mocha/no-exclusive-tests": "error" - }, - "settings": { - "mocha/additionalTestFunctions": [ - "describeModule" - ] - } -} -``` - ## When Not To Use It * If you really want to execute only one test-suite or test-case because all other tests should not be executed, turn this rule off. diff --git a/docs/rules/no-skipped-tests.md b/docs/rules/no-skipped-tests.md index a78501a..cd63084 100644 --- a/docs/rules/no-skipped-tests.md +++ b/docs/rules/no-skipped-tests.md @@ -42,28 +42,6 @@ suite.only("bar", function () {}); test.only("bar", function () {}); ``` -## Settings - -This rule supports the following shared configuration settings: - -* `additionalTestFunctions`: An array of extra test functions to protect. This might be used with a custom Mocha extension, such as [`ember-mocha`](https://github.com/switchfly/ember-mocha) -* `additionalXFunctions`: An array of extra x-function to protect - -```json -{ - "rules": { - "mocha/no-skipped-tests": "error" - }, - "settings": { - "mocha/additionalTestFunctions": [ - "describeModule" - ], - "mocha/additionalXFunctions": [ - "xdescribeModule" - ] - } -} -``` ## When Not To Use It * If you really want to commit skipped tests to your repo, turn this rule off. diff --git a/lib/rules/handle-done-callback.js b/lib/rules/handle-done-callback.js index 49b6d3e..f5e5ea1 100644 --- a/lib/rules/handle-done-callback.js +++ b/lib/rules/handle-done-callback.js @@ -1,7 +1,7 @@ 'use strict'; const find = require('ramda/src/find'); -const astUtils = require('../util/ast'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -23,8 +23,8 @@ module.exports = { ] }, create(context) { - const [ config = {} ] = context.options; - const { ignoreSkipped = false } = config; + const astUtils = createAstUtils(context.settings); + const [ { ignoreSkipped = false } = {} ] = context.options; const modifiersToCheck = ignoreSkipped ? [ 'only' ] : [ 'only', 'skip' ]; function isAsyncFunction(functionExpression) { diff --git a/lib/rules/max-top-level-suites.js b/lib/rules/max-top-level-suites.js index 88b1848..80511a7 100644 --- a/lib/rules/max-top-level-suites.js +++ b/lib/rules/max-top-level-suites.js @@ -6,8 +6,7 @@ */ const isNil = require('ramda/src/isNil'); -const astUtil = require('../util/ast'); -const { additionalSuiteNames } = require('../util/settings'); +const createAstUtils = require('../util/ast'); const defaultSuiteLimit = 1; @@ -34,9 +33,9 @@ module.exports = { ] }, create(context) { + const astUtils = createAstUtils(context.settings); const topLevelDescribes = []; const options = context.options[0] || {}; - const settings = context.settings; let suiteLimit; if (isNil(options.limit)) { @@ -47,7 +46,7 @@ module.exports = { return { CallExpression(node) { - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + if (astUtils.isDescribe(node)) { const scope = context.getScope(); if (isTopLevelScope(scope)) { diff --git a/lib/rules/no-async-describe.js b/lib/rules/no-async-describe.js index 9f9b9d5..e52bd1d 100644 --- a/lib/rules/no-async-describe.js +++ b/lib/rules/no-async-describe.js @@ -6,8 +6,7 @@ * @fileoverview Disallow async functions as arguments to describe */ -const astUtils = require('../util/ast'); -const { additionalSuiteNames } = require('../util/settings'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -18,6 +17,7 @@ module.exports = { fixable: 'code' }, create(context) { + const astUtils = createAstUtils(context.settings); const sourceCode = context.getSourceCode(); function isFunction(node) { @@ -62,7 +62,7 @@ module.exports = { CallExpression(node) { const name = astUtils.getNodeName(node.callee); - if (astUtils.isDescribe(node, additionalSuiteNames(context.settings))) { + if (astUtils.isDescribe(node)) { const fnArg = node.arguments.slice(-1)[0]; if (isAsyncFunction(fnArg)) { context.report({ diff --git a/lib/rules/no-exclusive-tests.js b/lib/rules/no-exclusive-tests.js index 739be8c..a0bc3e4 100644 --- a/lib/rules/no-exclusive-tests.js +++ b/lib/rules/no-exclusive-tests.js @@ -1,7 +1,6 @@ 'use strict'; -const { getAdditionalTestFunctions } = require('../util/settings'); -const astUtils = require('../util/ast'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -11,40 +10,15 @@ module.exports = { } }, create(context) { - let mochaTestFunctions = [ - 'it', - 'describe', - 'suite', - 'test', - 'context', - 'specify' - ]; - const settings = context.settings; - const additionalTestFunctions = getAdditionalTestFunctions(settings); - - mochaTestFunctions = mochaTestFunctions.concat(additionalTestFunctions); - - function matchesMochaTestFunction(object) { - const name = astUtils.getNodeName(object); - - return mochaTestFunctions.includes(name); - } - - function isPropertyNamedOnly(property) { - return property && astUtils.getPropertyName(property) === 'only'; - } - - function isCallToMochasOnlyFunction(callee) { - return callee.type === 'MemberExpression' && - matchesMochaTestFunction(callee.object) && - isPropertyNamedOnly(callee.property); - } + const astUtils = createAstUtils(context.settings); return { CallExpression(node) { - const callee = node.callee; + const options = { modifiers: [ 'only' ], baseNames: false }; + + if (astUtils.isDescribe(node, options) || astUtils.isTestCase(node, options)) { + const callee = node.callee; - if (callee && isCallToMochasOnlyFunction(callee)) { context.report({ node: callee.property, message: 'Unexpected exclusive mocha test.' diff --git a/lib/rules/no-global-tests.js b/lib/rules/no-global-tests.js index 441f006..fc15674 100644 --- a/lib/rules/no-global-tests.js +++ b/lib/rules/no-global-tests.js @@ -1,6 +1,6 @@ 'use strict'; -const astUtils = require('../util/ast'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -10,6 +10,8 @@ module.exports = { } }, create(context) { + const astUtils = createAstUtils(context.settings); + function isGlobalScope(scope) { return scope.type === 'global' || scope.type === 'module'; } diff --git a/lib/rules/no-hooks-for-single-case.js b/lib/rules/no-hooks-for-single-case.js index 2645814..0dd6e12 100644 --- a/lib/rules/no-hooks-for-single-case.js +++ b/lib/rules/no-hooks-for-single-case.js @@ -1,7 +1,6 @@ 'use strict'; -const astUtil = require('../util/ast'); -const { additionalSuiteNames } = require('../util/settings'); +const createAstUtils = require('../util/ast'); function newDescribeLayer(describeNode) { return { @@ -32,9 +31,9 @@ module.exports = { ] }, create(context) { + const astUtils = createAstUtils(context.settings); const options = context.options[0] || {}; const allowedHooks = options.allow || []; - const settings = context.settings; let layers = []; function increaseTestCount() { @@ -72,17 +71,17 @@ module.exports = { }, CallExpression(node) { - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + if (astUtils.isDescribe(node)) { increaseTestCount(); layers.push(newDescribeLayer(node)); return; } - if (astUtil.isTestCase(node)) { + if (astUtils.isTestCase(node)) { increaseTestCount(); } - if (astUtil.isHookIdentifier(node.callee)) { + if (astUtils.isHookIdentifier(node.callee)) { layers[layers.length - 1].hookNodes.push(node.callee); } }, diff --git a/lib/rules/no-hooks.js b/lib/rules/no-hooks.js index 02eff9c..86fdf63 100644 --- a/lib/rules/no-hooks.js +++ b/lib/rules/no-hooks.js @@ -1,6 +1,6 @@ 'use strict'; -const astUtil = require('../util/ast'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -25,6 +25,7 @@ module.exports = { }, create(context) { + const astUtils = createAstUtils(context.settings); const [ config = {} ] = context.options; const { allow = [] } = config; @@ -32,7 +33,7 @@ module.exports = { CallExpression(node) { const isHookAllowed = allow.includes(node.callee.name); - if (astUtil.isHookIdentifier(node.callee) && !isHookAllowed) { + if (astUtils.isHookIdentifier(node.callee) && !isHookAllowed) { context.report({ node: node.callee, message: `Unexpected use of Mocha \`${ node.callee.name }\` hook` diff --git a/lib/rules/no-identical-title.js b/lib/rules/no-identical-title.js index 82e98dd..678dbd9 100644 --- a/lib/rules/no-identical-title.js +++ b/lib/rules/no-identical-title.js @@ -1,7 +1,6 @@ 'use strict'; -const astUtil = require('../util/ast'); -const { additionalSuiteNames } = require('../util/settings'); +const createAstUtils = require('../util/ast'); function newLayer() { return { @@ -10,33 +9,6 @@ function newLayer() { }; } -function handlTestCaseTitles(context, titles, node, title) { - if (astUtil.isTestCase(node)) { - if (titles.includes(title)) { - context.report({ - node, - message: 'Test title is used multiple times in the same test suite.' - }); - } - titles.push(title); - } -} - -function handlTestSuiteTitles(context, titles, node, title) { - const settings = context.settings; - - if (!astUtil.isDescribe(node, additionalSuiteNames(settings))) { - return; - } - if (titles.includes(title)) { - context.report({ - node, - message: 'Test suite title is used multiple times.' - }); - } - titles.push(title); -} - function isFirstArgLiteral(node) { return node.arguments && node.arguments[0] && node.arguments[0].type === 'Literal'; } @@ -49,14 +21,39 @@ module.exports = { } }, create(context) { + const astUtils = createAstUtils(context.settings); const titleLayers = [ newLayer() ]; - const settings = context.settings; + + function handlTestCaseTitles(titles, node, title) { + if (astUtils.isTestCase(node)) { + if (titles.includes(title)) { + context.report({ + node, + message: 'Test title is used multiple times in the same test suite.' + }); + } + titles.push(title); + } + } + + function handlTestSuiteTitles(titles, node, title) { + if (!astUtils.isDescribe(node)) { + return; + } + if (titles.includes(title)) { + context.report({ + node, + message: 'Test suite title is used multiple times.' + }); + } + titles.push(title); + } return { CallExpression(node) { const currentLayer = titleLayers[titleLayers.length - 1]; - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + if (astUtils.isDescribe(node)) { titleLayers.push(newLayer()); } if (!isFirstArgLiteral(node)) { @@ -64,11 +61,11 @@ module.exports = { } const title = node.arguments[0].value; - handlTestCaseTitles(context, currentLayer.testTitles, node, title); - handlTestSuiteTitles(context, currentLayer.describeTitles, node, title); + handlTestCaseTitles(currentLayer.testTitles, node, title); + handlTestSuiteTitles(currentLayer.describeTitles, node, title); }, 'CallExpression:exit'(node) { - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + if (astUtils.isDescribe(node)) { titleLayers.pop(); } } diff --git a/lib/rules/no-mocha-arrows.js b/lib/rules/no-mocha-arrows.js index e6559fc..aa84eaf 100644 --- a/lib/rules/no-mocha-arrows.js +++ b/lib/rules/no-mocha-arrows.js @@ -5,7 +5,7 @@ * @author Paul Melnikow */ -const astUtils = require('../util/ast'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -16,6 +16,7 @@ module.exports = { fixable: 'code' }, create(context) { + const astUtils = createAstUtils(context.settings); const sourceCode = context.getSourceCode(); function extractSourceTextByRange(start, end) { diff --git a/lib/rules/no-nested-tests.js b/lib/rules/no-nested-tests.js index 439e2f8..089bfdf 100644 --- a/lib/rules/no-nested-tests.js +++ b/lib/rules/no-nested-tests.js @@ -2,8 +2,7 @@ /* eslint "complexity": [ "error", 5 ] */ -const astUtils = require('../util/ast'); -const { additionalSuiteNames } = require('../util/settings'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -13,7 +12,7 @@ module.exports = { } }, create(context) { - const settings = context.settings; + const astUtils = createAstUtils(context.settings); let testNestingLevel = 0; let hookCallNestingLevel = 0; @@ -49,7 +48,7 @@ module.exports = { CallExpression(node) { const isTestCase = astUtils.isTestCase(node); const isHookCall = astUtils.isHookCall(node); - const isDescribe = astUtils.isDescribe(node, additionalSuiteNames(settings)); + const isDescribe = astUtils.isDescribe(node); checkForAndReportErrors(node, isTestCase, isDescribe, isHookCall); diff --git a/lib/rules/no-pending-tests.js b/lib/rules/no-pending-tests.js index 54b3248..e9c182e 100644 --- a/lib/rules/no-pending-tests.js +++ b/lib/rules/no-pending-tests.js @@ -1,6 +1,6 @@ 'use strict'; -const astUtils = require('../util/ast'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -10,6 +10,8 @@ module.exports = { } }, create(context) { + const astUtils = createAstUtils(context.settings); + function isPendingMochaTest(node) { return astUtils.isTestCase(node) && node.arguments.length === 1 && diff --git a/lib/rules/no-return-and-callback.js b/lib/rules/no-return-and-callback.js index 453d7cf..54b0ad4 100644 --- a/lib/rules/no-return-and-callback.js +++ b/lib/rules/no-return-and-callback.js @@ -1,6 +1,6 @@ 'use strict'; -const astUtils = require('../util/ast'); +const createAstUtils = require('../util/ast'); function reportIfShortArrowFunction(context, node) { if (node.body.type !== 'BlockStatement') { @@ -19,26 +19,6 @@ function isFunctionCallWithName(node, name) { node.callee.name === name; } -function isAllowedReturnStatement(node, doneName) { - const argument = node.argument; - - if (astUtils.isReturnOfUndefined(node) || argument.type === 'Literal') { - return true; - } - - return isFunctionCallWithName(argument, doneName); -} - -function reportIfFunctionWithBlock(context, node, doneName) { - const returnStatement = astUtils.findReturnStatement(node.body.body); - if (returnStatement && !isAllowedReturnStatement(returnStatement, doneName)) { - context.report({ - node: returnStatement, - message: 'Unexpected use of `return` in a test with callback' - }); - } -} - module.exports = { meta: { type: 'problem', @@ -47,13 +27,35 @@ module.exports = { } }, create(context) { + const astUtils = createAstUtils(context.settings); + + function isAllowedReturnStatement(node, doneName) { + const argument = node.argument; + + if (astUtils.isReturnOfUndefined(node) || argument.type === 'Literal') { + return true; + } + + return isFunctionCallWithName(argument, doneName); + } + + function reportIfFunctionWithBlock(node, doneName) { + const returnStatement = astUtils.findReturnStatement(node.body.body); + if (returnStatement && !isAllowedReturnStatement(returnStatement, doneName)) { + context.report({ + node: returnStatement, + message: 'Unexpected use of `return` in a test with callback' + }); + } + } + function check(node) { if (node.params.length === 0 || !astUtils.hasParentMochaFunctionCall(node)) { return; } if (!reportIfShortArrowFunction(context, node)) { - reportIfFunctionWithBlock(context, node, node.params[0].name); + reportIfFunctionWithBlock(node, node.params[0].name); } } diff --git a/lib/rules/no-return-from-async.js b/lib/rules/no-return-from-async.js index 3185a61..590c99e 100644 --- a/lib/rules/no-return-from-async.js +++ b/lib/rules/no-return-from-async.js @@ -1,6 +1,6 @@ 'use strict'; -const astUtils = require('../util/ast'); +const createAstUtils = require('../util/ast'); function reportIfShortArrowFunction(context, node) { if (node.body.type !== 'BlockStatement') { @@ -13,26 +13,6 @@ function reportIfShortArrowFunction(context, node) { return false; } -function isAllowedReturnStatement(node) { - const argument = node.argument; - - if (astUtils.isReturnOfUndefined(node) || argument.type === 'Literal') { - return true; - } - - return false; -} - -function reportIfFunctionWithBlock(context, node) { - const returnStatement = astUtils.findReturnStatement(node.body.body); - if (returnStatement && !isAllowedReturnStatement(returnStatement)) { - context.report({ - node: returnStatement, - message: 'Unexpected use of `return` in a test with an async function' - }); - } -} - module.exports = { meta: { type: 'suggestion', @@ -41,13 +21,36 @@ module.exports = { } }, create(context) { + const astUtils = createAstUtils(context.settings); + + function isAllowedReturnStatement(node) { + const argument = node.argument; + + if (astUtils.isReturnOfUndefined(node) || argument.type === 'Literal') { + return true; + } + + return false; + } + + function reportIfFunctionWithBlock(node) { + const returnStatement = astUtils.findReturnStatement(node.body.body); + + if (returnStatement && !isAllowedReturnStatement(returnStatement)) { + context.report({ + node: returnStatement, + message: 'Unexpected use of `return` in a test with an async function' + }); + } + } + function check(node) { if (!node.async || !astUtils.hasParentMochaFunctionCall(node)) { return; } if (!reportIfShortArrowFunction(context, node)) { - reportIfFunctionWithBlock(context, node); + reportIfFunctionWithBlock(node); } } diff --git a/lib/rules/no-setup-in-describe.js b/lib/rules/no-setup-in-describe.js index 90cd322..d34714a 100644 --- a/lib/rules/no-setup-in-describe.js +++ b/lib/rules/no-setup-in-describe.js @@ -1,7 +1,6 @@ 'use strict'; -const astUtils = require('../util/ast'); -const { additionalSuiteNames } = require('../util/settings'); +const createAstUtils = require('../util/ast'); const FUNCTION = 1; const DESCRIBE = 2; @@ -17,7 +16,7 @@ module.exports = { }, create(context) { const nesting = []; - const settings = context.settings; + const astUtils = createAstUtils(context.settings); function isPureNode(node) { return astUtils.isHookCall(node) || @@ -59,7 +58,7 @@ module.exports = { } function isDescribe(node) { - return astUtils.isDescribe(node, additionalSuiteNames(settings)); + return astUtils.isDescribe(node); } function isParentDescribe(node) { diff --git a/lib/rules/no-sibling-hooks.js b/lib/rules/no-sibling-hooks.js index 08f433f..deae1ff 100644 --- a/lib/rules/no-sibling-hooks.js +++ b/lib/rules/no-sibling-hooks.js @@ -1,7 +1,6 @@ 'use strict'; -const astUtil = require('../util/ast'); -const { additionalSuiteNames } = require('../util/settings'); +const createAstUtils = require('../util/ast'); function newDescribeLayer(describeNode) { return { @@ -22,7 +21,7 @@ module.exports = { }, create(context) { const isUsed = []; - const settings = context.settings; + const astUtils = createAstUtils(context.settings); return { Program(node) { @@ -30,14 +29,14 @@ module.exports = { }, CallExpression(node) { - const name = astUtil.getNodeName(node.callee); + const name = astUtils.getNodeName(node.callee); - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + if (astUtils.isDescribe(node)) { isUsed.push(newDescribeLayer(node)); return; } - if (!astUtil.isHookIdentifier(node.callee)) { + if (!astUtils.isHookIdentifier(node.callee)) { return; } diff --git a/lib/rules/no-skipped-tests.js b/lib/rules/no-skipped-tests.js index 4ca8847..2e340fa 100644 --- a/lib/rules/no-skipped-tests.js +++ b/lib/rules/no-skipped-tests.js @@ -1,31 +1,6 @@ 'use strict'; -const { getAdditionalTestFunctions, getAdditionalXFunctions } = require('../util/settings'); - -let mochaTestFunctions; -let mochaXFunctions; - -function matchesMochaTestFunction(object) { - return object && mochaTestFunctions.includes(object.name); -} - -function isPropertyNamedSkip(property) { - return property && (property.name === 'skip' || property.value === 'skip'); -} - -function isCallToMochasSkipFunction(callee) { - return callee.type === 'MemberExpression' && - matchesMochaTestFunction(callee.object) && - isPropertyNamedSkip(callee.property); -} - -function isMochaXFunction(name) { - return mochaXFunctions.includes(name); -} - -function isCallToMochaXFunction(callee) { - return callee.type === 'Identifier' && isMochaXFunction(callee.name); -} +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -35,37 +10,18 @@ module.exports = { type: 'problem' }, create(context) { - const settings = context.settings; - const additionalTestFunctions = getAdditionalTestFunctions(settings); - const additionalXFunctions = getAdditionalXFunctions(settings); - - mochaTestFunctions = [ - 'it', - 'describe', - 'suite', - 'test', - 'context', - 'specify' - ].concat(additionalTestFunctions); - mochaXFunctions = [ - 'xit', - 'xdescribe', - 'xcontext', - 'xspecify' - ].concat(additionalXFunctions); + const astUtils = createAstUtils(context.settings); return { CallExpression(node) { - const callee = node.callee; + const options = { modifiers: [ 'skip' ], baseNames: false }; + + if (astUtils.isDescribe(node, options) || astUtils.isTestCase(node, options)) { + const callee = node.callee; + const nodeToReport = callee.type === 'MemberExpression' ? callee.property : callee; - if (isCallToMochasSkipFunction(callee)) { - context.report({ - node: callee.property, - message: 'Unexpected skipped mocha test.' - }); - } else if (isCallToMochaXFunction(callee)) { context.report({ - node: callee, + node: nodeToReport, message: 'Unexpected skipped mocha test.' }); } diff --git a/lib/rules/no-synchronous-tests.js b/lib/rules/no-synchronous-tests.js index 3f0bac9..9bd0559 100644 --- a/lib/rules/no-synchronous-tests.js +++ b/lib/rules/no-synchronous-tests.js @@ -2,7 +2,7 @@ const isNil = require('ramda/src/isNil'); const find = require('ramda/src/find'); -const astUtil = require('../util/ast'); +const createAstUtils = require('../util/ast'); const asyncMethods = [ 'async', 'callback', 'promise' ]; @@ -59,11 +59,12 @@ module.exports = { ] }, create(context) { + const astUtils = createAstUtils(context.settings); const options = context.options[0] || {}; const allowedAsyncMethods = isNil(options.allowed) ? asyncMethods : options.allowed; function check(node) { - if (astUtil.hasParentMochaFunctionCall(node)) { + if (astUtils.hasParentMochaFunctionCall(node)) { // For each allowed async test method, check if it is used in the test const testAsyncMethods = allowedAsyncMethods.map(function (method) { switch (method) { diff --git a/lib/rules/no-top-level-hooks.js b/lib/rules/no-top-level-hooks.js index 3128b4e..5ae09a0 100644 --- a/lib/rules/no-top-level-hooks.js +++ b/lib/rules/no-top-level-hooks.js @@ -1,7 +1,6 @@ 'use strict'; -const astUtil = require('../util/ast'); -const { additionalSuiteNames } = require('../util/settings'); +const createAstUtils = require('../util/ast'); module.exports = { meta: { @@ -11,17 +10,17 @@ module.exports = { } }, create(context) { - const settings = context.settings; + const astUtils = createAstUtils(context.settings); const testSuiteStack = []; return { CallExpression(node) { - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + if (astUtils.isDescribe(node)) { testSuiteStack.push(node); return; } - if (!astUtil.isHookIdentifier(node.callee)) { + if (!astUtils.isHookIdentifier(node.callee)) { return; } diff --git a/lib/rules/prefer-arrow-callback.js b/lib/rules/prefer-arrow-callback.js index 1a341b8..2493018 100644 --- a/lib/rules/prefer-arrow-callback.js +++ b/lib/rules/prefer-arrow-callback.js @@ -12,7 +12,7 @@ * @author Toru Nagashima (core eslint rule) * @author Michael Fields (mocha-aware rule modifications) */ -const astUtils = require('../util/ast'); +const createAstUtils = require('../util/ast'); // ------------------------------------------------------------------------------ // Helpers @@ -75,66 +75,6 @@ function isBindThis(node, currentNode) { node.parent.callee === node; } -/** - * Checkes whether or not a given node is a callback. - * @param {ASTNode} node - A node to check. - * @param {object} context - The eslint context. - * @returns {Object} - * {boolean} retv.isCallback - `true` if the node is a callback. - * {boolean} retv.isMochaCallback - `true` if the node is an argument to a mocha function. - * {boolean} retv.isLexicalThis - `true` if the node is with `.bind(this)`. - */ -function getCallbackInfo(node, context) { - const retv = { isCallback: false, isLexicalThis: false }; - let searchComplete = false; - let currentNode = node; - let parent = node.parent; - - while (currentNode && !searchComplete) { - switch (parent.type) { - // Checks parents recursively. - - case 'LogicalExpression': - case 'ConditionalExpression': - break; - - // Checks whether the parent node is `.bind(this)` call. - case 'MemberExpression': - if (isBindThis(parent, currentNode)) { - retv.isLexicalThis = - parent.parent.arguments.length === 1 && - parent.parent.arguments[0].type === 'ThisExpression'; - parent = parent.parent; - } else { - searchComplete = true; - } - break; - - // Checks whether the node is a callback. - case 'CallExpression': - case 'NewExpression': - if (parent.callee !== currentNode) { - retv.isCallback = true; - } - // Checks whether the node is a mocha function callback. - if (retv.isCallback && astUtils.isMochaFunctionCall(parent, context.getScope())) { - retv.isMochaCallback = true; - } - searchComplete = true; - break; - - default: - searchComplete = true; - } - - if (!searchComplete) { - currentNode = parent; - parent = parent.parent; - } - } - return retv; -} - /** * Checks whether a simple list of parameters contains any duplicates. This does not handle complex * parameter lists (e.g. with destructuring), since complex parameter lists are a SyntaxError with duplicate @@ -181,6 +121,7 @@ module.exports = { }, create(context) { + const astUtils = createAstUtils(context.settings); const options = context.options[0] || {}; // allowUnboundThis defaults to true @@ -188,6 +129,66 @@ module.exports = { const allowNamedFunctions = options.allowNamedFunctions; const sourceCode = context.getSourceCode(); + /** + * Checkes whether or not a given node is a callback. + * @param {ASTNode} node - A node to check. + * @param {object} context - The eslint context. + * @returns {Object} + * {boolean} retv.isCallback - `true` if the node is a callback. + * {boolean} retv.isMochaCallback - `true` if the node is an argument to a mocha function. + * {boolean} retv.isLexicalThis - `true` if the node is with `.bind(this)`. + */ + function getCallbackInfo(node) { + const retv = { isCallback: false, isLexicalThis: false }; + let searchComplete = false; + let currentNode = node; + let parent = node.parent; + + while (currentNode && !searchComplete) { + switch (parent.type) { + // Checks parents recursively. + + case 'LogicalExpression': + case 'ConditionalExpression': + break; + + // Checks whether the parent node is `.bind(this)` call. + case 'MemberExpression': + if (isBindThis(parent, currentNode)) { + retv.isLexicalThis = + parent.parent.arguments.length === 1 && + parent.parent.arguments[0].type === 'ThisExpression'; + parent = parent.parent; + } else { + searchComplete = true; + } + break; + + // Checks whether the node is a callback. + case 'CallExpression': + case 'NewExpression': + if (parent.callee !== currentNode) { + retv.isCallback = true; + } + // Checks whether the node is a mocha function callback. + if (retv.isCallback && astUtils.isMochaFunctionCall(parent, context.getScope())) { + retv.isMochaCallback = true; + } + searchComplete = true; + break; + + default: + searchComplete = true; + } + + if (!searchComplete) { + currentNode = parent; + parent = parent.parent; + } + } + return retv; + } + /* * {Array<{this: boolean, meta: boolean}>} * - this - A flag which shows there are one or more ThisExpression. diff --git a/lib/util/ast.js b/lib/util/ast.js index 4fa15f2..b3d73a4 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -7,6 +7,7 @@ const propEq = require('ramda/src/propEq'); const pathEq = require('ramda/src/pathEq'); const find = require('ramda/src/find'); const { getTestCaseNames, getSuiteNames } = require('./names'); +const { getAddtionalNames } = require('./settings'); const isDefined = complement(isNil); const isCallExpression = both(isDefined, propEq('type', 'CallExpression')); @@ -17,6 +18,8 @@ const hooks = [ ]; const suiteConfig = [ 'timeout', 'slow', 'retries' ]; +const findReturnStatement = find(propEq('type', 'ReturnStatement')); + function getPropertyName(property) { return property.name || property.value; } @@ -28,12 +31,6 @@ function getNodeName(node) { return node.name; } -function isDescribe(node, additionalSuiteNames = []) { - const describeAliases = getSuiteNames({ modifiers: [ 'skip', 'only' ], additionalSuiteNames }); - - return isCallExpression(node) && describeAliases.includes(getNodeName(node.callee)); -} - function isHookIdentifier(node) { return node && node.type === 'Identifier' && @@ -44,31 +41,6 @@ function isHookCall(node) { return isCallExpression(node) && isHookIdentifier(node.callee); } -function isTestCase(node, options = {}) { - const { modifiers = [ 'skip', 'only' ] } = options; - - const testCaseNames = getTestCaseNames({ modifiers }); - return isCallExpression(node) && testCaseNames.includes(getNodeName(node.callee)); -} - -function isSuiteConfigExpression(node) { - if (node.type !== 'MemberExpression') { - return false; - } - - const usingThis = node.object.type === 'ThisExpression'; - - if (usingThis || isTestCase(node.object)) { - return suiteConfig.includes(getPropertyName(node.property)); - } - - return false; -} - -function isSuiteConfigCall(node) { - return isCallExpression(node) && isSuiteConfigExpression(node.callee); -} - function findReference(scope, node) { const hasSameRangeAsNode = pathEq([ 'identifier', 'range' ], node.range); @@ -87,41 +59,85 @@ function isCallToShadowedReference(node, scope) { return isShadowed(scope, identifier); } -function isMochaFunctionCall(node, scope) { - if (isCallToShadowedReference(node, scope)) { +function isFunctionCallWithName(node, names) { + return isCallExpression(node) && names.includes(getNodeName(node.callee)); +} + +function createAstUtils(settings) { + const additionalNames = getAddtionalNames(settings); + + function isDescribe(node, options = {}) { + const { modifiers = [ 'skip', 'only' ], baseNames = true } = options; + const { additionalSuiteNames, additionalSuiteModifiers } = additionalNames; + const describeAliases = getSuiteNames({ baseNames, modifiers, additionalSuiteNames, additionalSuiteModifiers }); + + return isFunctionCallWithName(node, describeAliases); + } + + function isTestCase(node, options = {}) { + const { modifiers = [ 'skip', 'only' ], baseNames = true } = options; + const { additionalTestCaseNames, additionalTestCaseModifiers } = additionalNames; + const testCaseNames = getTestCaseNames({ + baseNames, modifiers, additionalTestCaseNames, additionalTestCaseModifiers + }); + + return isFunctionCallWithName(node, testCaseNames); + } + + function isSuiteConfigExpression(node) { + if (node.type !== 'MemberExpression') { + return false; + } + + const usingThis = node.object.type === 'ThisExpression'; + + if (usingThis || isTestCase(node.object)) { + return suiteConfig.includes(getPropertyName(node.property)); + } + return false; } - return isTestCase(node) || isDescribe(node) || isHookCall(node); -} + function isSuiteConfigCall(node) { + return isCallExpression(node) && isSuiteConfigExpression(node.callee); + } -function hasParentMochaFunctionCall(functionExpression, options) { - return isTestCase(functionExpression.parent, options) || isHookCall(functionExpression.parent); -} + function isMochaFunctionCall(node, scope) { + if (isCallToShadowedReference(node, scope)) { + return false; + } -function isExplicitUndefined(node) { - return node && node.type === 'Identifier' && node.name === 'undefined'; -} + return isTestCase(node) || isDescribe(node) || isHookCall(node); + } -function isReturnOfUndefined(node) { - const argument = node.argument; - const isImplicitUndefined = argument === null; + function hasParentMochaFunctionCall(functionExpression, options) { + return isTestCase(functionExpression.parent, options) || isHookCall(functionExpression.parent); + } - return isImplicitUndefined || isExplicitUndefined(argument); -} + function isExplicitUndefined(node) { + return node && node.type === 'Identifier' && node.name === 'undefined'; + } -const findReturnStatement = find(propEq('type', 'ReturnStatement')); + function isReturnOfUndefined(node) { + const argument = node.argument; + const isImplicitUndefined = argument === null; + + return isImplicitUndefined || isExplicitUndefined(argument); + } + + return { + isDescribe, + isHookIdentifier, + isTestCase, + getPropertyName, + getNodeName, + isMochaFunctionCall, + isHookCall, + isSuiteConfigCall, + hasParentMochaFunctionCall, + findReturnStatement, + isReturnOfUndefined + }; +} -module.exports = { - isDescribe, - isHookIdentifier, - isTestCase, - getPropertyName, - getNodeName, - isMochaFunctionCall, - isHookCall, - isSuiteConfigCall, - hasParentMochaFunctionCall, - findReturnStatement, - isReturnOfUndefined -}; +module.exports = createAstUtils; diff --git a/lib/util/names.js b/lib/util/names.js index 1b41f27..d857061 100644 --- a/lib/util/names.js +++ b/lib/util/names.js @@ -24,6 +24,13 @@ const suiteModifiers = { ] }; +function getSuiteModifiers(modifierName, additionalSuiteModifiers = {}) { + const names = suiteModifiers[modifierName] || []; + const additionalNames = additionalSuiteModifiers[modifierName] || []; + + return [ ...names, ...additionalNames ]; +} + const testCaseNames = [ 'it', 'test', @@ -45,29 +52,28 @@ const testCaseModifiers = { ] }; +function getTestCaseModifiers(modifierName, additionalTestCaseModifiers = {}) { + const names = testCaseModifiers[modifierName] || []; + const additionalNames = additionalTestCaseModifiers[modifierName] || []; + + return [ ...names, ...additionalNames ]; +} + function getTestCaseNames(options = {}) { - const { modifiers = [], baseNames = true } = options; - const names = baseNames ? testCaseNames : []; + const { modifiers = [], baseNames = true, additionalTestCaseNames = [], additionalTestCaseModifiers } = options; + const names = baseNames ? testCaseNames.concat(additionalTestCaseNames) : []; return names.concat(chain((modifierName) => { - if (testCaseModifiers[modifierName]) { - return testCaseModifiers[modifierName]; - } - - return []; + return getTestCaseModifiers(modifierName, additionalTestCaseModifiers); }, modifiers)); } function getSuiteNames(options = {}) { - const { modifiers = [], baseNames = true, additionalSuiteNames = [] } = options; + const { modifiers = [], baseNames = true, additionalSuiteNames = [], additionalSuiteModifiers } = options; const names = baseNames ? suiteNames.concat(additionalSuiteNames) : []; return names.concat(chain((modifierName) => { - if (suiteModifiers[modifierName]) { - return suiteModifiers[modifierName]; - } - - return []; + return getSuiteModifiers(modifierName, additionalSuiteModifiers); }, modifiers)); } diff --git a/lib/util/settings.js b/lib/util/settings.js index f1f03f7..2a44ac5 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -1,18 +1,35 @@ -/* eslint-env node*/ - 'use strict'; -function settingFor(propertyName) { - return function (settings) { - const value = settings[`mocha/${ propertyName}`]; - const mochaSettings = settings.mocha || {}; +function settingFor(settings, propertyName, fallback) { + const value = settings[`mocha/${propertyName}`]; + const mochaSettings = settings.mocha || {}; - return value || mochaSettings[propertyName] || []; - }; + return value || mochaSettings[propertyName] || fallback; } module.exports = { - getAdditionalTestFunctions: settingFor('additionalTestFunctions'), - additionalSuiteNames: settingFor('additionalSuiteNames'), - getAdditionalXFunctions: settingFor('additionalXFunctions') + getAddtionalNames(settings) { + const additionalCustomNamesSettings = settingFor(settings, 'additionalCustomNames', {}); + const { + suites = [], + testCases = [], + suitesWithSkipModifier = [], + testCasesWithSkipModifier = [], + exclusiveTestCases = [], + exclusiveSuites = [] + } = additionalCustomNamesSettings; + + return { + additionalSuiteNames: suites, + additionalTestCaseNames: testCases, + additionalTestCaseModifiers: { + skip: testCasesWithSkipModifier, + only: exclusiveTestCases + }, + additionalSuiteModifiers: { + skip: suitesWithSkipModifier, + only: exclusiveSuites + } + }; + } }; diff --git a/test/rules/max-top-level-suites.js b/test/rules/max-top-level-suites.js index 6ce54df..498a95e 100644 --- a/test/rules/max-top-level-suites.js +++ b/test/rules/max-top-level-suites.js @@ -43,13 +43,13 @@ ruleTester.run('max-top-level-suites', rules['max-top-level-suites'], { { code: 'foo("This is a test", function () { });', settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } } }, { code: 'foo("This is a test", function () { });', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } } }, @@ -195,7 +195,7 @@ ruleTester.run('max-top-level-suites', rules['max-top-level-suites'], { code: 'foo("this is a test", function () { });' + 'foo("this is a different test", function () { });', settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } }, errors: [ { message: 'The number of top-level suites is more than 1.' } @@ -205,7 +205,7 @@ ruleTester.run('max-top-level-suites', rules['max-top-level-suites'], { 'foo("this is a different test", function () { });', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } }, errors: [ diff --git a/test/rules/no-async-describe.js b/test/rules/no-async-describe.js index d8ef7ab..f643c97 100644 --- a/test/rules/no-async-describe.js +++ b/test/rules/no-async-describe.js @@ -32,7 +32,7 @@ ruleTester.run('no-async-describe', rule, { output: 'foo("hello", function () {})', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } }, parserOptions: { ecmaVersion: 8 }, errors: [ { diff --git a/test/rules/no-exclusive-tests.js b/test/rules/no-exclusive-tests.js index 4efacf7..6acd50d 100644 --- a/test/rules/no-exclusive-tests.js +++ b/test/rules/no-exclusive-tests.js @@ -27,7 +27,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'a.b.c.skip()', settings: { mocha: { - additionalTestFunctions: [ 'a.b.c' ] + additionalCustomNames: { exclusiveTestCases: [ 'a.b.c.only' ] } } } }, @@ -35,7 +35,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'a[b].c.skip()', settings: { mocha: { - additionalTestFunctions: [ 'a.b.c' ] + additionalCustomNames: { exclusiveTestCases: [ 'a.b.c.only' ] } } } } @@ -93,14 +93,14 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { { code: 'custom.only()', settings: { - 'mocha/additionalTestFunctions': [ 'custom' ] + 'mocha/additionalCustomNames': { exclusiveTestCases: [ 'custom.only' ] } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] }, { code: 'custom["only"]()', settings: { - 'mocha/additionalTestFunctions': [ 'custom' ] + 'mocha/additionalCustomNames': { exclusiveTestCases: [ 'custom.only' ] } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] }, @@ -108,7 +108,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'custom.only()', settings: { mocha: { - additionalTestFunctions: [ 'custom' ] + additionalCustomNames: { exclusiveTestCases: [ 'custom.only' ] } } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] @@ -117,7 +117,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'custom["only"]()', settings: { mocha: { - additionalTestFunctions: [ 'custom' ] + additionalCustomNames: { exclusiveTestCases: [ 'custom.only' ] } } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] @@ -126,7 +126,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'foo.bar.only()', settings: { mocha: { - additionalTestFunctions: [ 'foo.bar' ] + additionalCustomNames: { exclusiveTestCases: [ 'foo.bar.only' ] } } }, errors: [ { message: expectedErrorMessage, column: 9, line: 1 } ] @@ -135,7 +135,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'foo.bar["only"]()', settings: { mocha: { - additionalTestFunctions: [ 'foo.bar' ] + additionalCustomNames: { exclusiveTestCases: [ 'foo.bar.only' ] } } }, errors: [ { message: expectedErrorMessage, column: 9, line: 1 } ] @@ -144,7 +144,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'foo["bar"].only()', settings: { mocha: { - additionalTestFunctions: [ 'foo.bar' ] + additionalCustomNames: { exclusiveTestCases: [ 'foo.bar.only' ] } } }, errors: [ { message: expectedErrorMessage, column: 12, line: 1 } ] @@ -153,7 +153,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'foo["bar"]["only"]()', settings: { mocha: { - additionalTestFunctions: [ 'foo.bar' ] + additionalCustomNames: { exclusiveTestCases: [ 'foo.bar.only' ] } } }, errors: [ { message: expectedErrorMessage, column: 12, line: 1 } ] @@ -162,7 +162,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'a.b.c.only()', settings: { mocha: { - additionalTestFunctions: [ 'a.b.c' ] + additionalCustomNames: { exclusiveTestCases: [ 'a.b.c.only' ] } } }, errors: [ { message: expectedErrorMessage, column: 7, line: 1 } ] diff --git a/test/rules/no-hooks-for-single-case.js b/test/rules/no-hooks-for-single-case.js index 6eeb677..97d11bc 100644 --- a/test/rules/no-hooks-for-single-case.js +++ b/test/rules/no-hooks-for-single-case.js @@ -153,7 +153,7 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { ].join('\n'), settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } } }, @@ -166,7 +166,7 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { '});' ].join('\n'), settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } } } ], @@ -294,7 +294,7 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { ].join('\n'), settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } }, errors: [ { message: 'Unexpected use of Mocha `before` hook for a single test case', column: 5, line: 2 } ] @@ -306,7 +306,7 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { '});' ].join('\n'), settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ '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 43e0fde..b97664c 100644 --- a/test/rules/no-identical-title.js +++ b/test/rules/no-identical-title.js @@ -98,7 +98,7 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { 'foo("describe2", function() {});' ].join('\n'), settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } } }, { code: [ @@ -107,7 +107,7 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { ].join('\n'), settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } } } @@ -180,7 +180,7 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { 'foo("describe1", function() {});' ].join('\n'), settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } }, errors: [ { message: 'Test suite title is used multiple times.', column: 1, line: 2 } ] }, { @@ -190,7 +190,7 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { ].join('\n'), settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ '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 98f7b41..4dc8353 100644 --- a/test/rules/no-nested-tests.js +++ b/test/rules/no-nested-tests.js @@ -13,13 +13,13 @@ ruleTester.run('no-nested-tests', rule, { { code: 'foo("", function () { it(); })', settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } } }, { code: 'foo("", function () { it(); })', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } } } @@ -121,7 +121,7 @@ ruleTester.run('no-nested-tests', rule, { { code: 'it("", function () { foo() });', settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } }, errors: [ { message: 'Unexpected suite nested within a test.', @@ -133,7 +133,7 @@ ruleTester.run('no-nested-tests', rule, { code: 'it("", function () { foo() });', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } }, errors: [ { diff --git a/test/rules/no-setup-in-describe.js b/test/rules/no-setup-in-describe.js index 63139e5..41b4424 100644 --- a/test/rules/no-setup-in-describe.js +++ b/test/rules/no-setup-in-describe.js @@ -56,20 +56,24 @@ ruleTester.run('no-setup-in-describe', rule, { { code: 'foo("", function () { it(); })', settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } } }, { code: 'foo("", function () { it(); })', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { + suites: [ 'foo' ] + } } } }, { code: 'foo("", function () { it("", function () { b(); }); })', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { + suites: [ 'foo' ] + } } } }, @@ -112,7 +116,9 @@ ruleTester.run('no-setup-in-describe', rule, { code: 'foo("", function () { a(); });', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { + suites: [ 'foo' ] + } } }, errors: [ { @@ -124,7 +130,9 @@ ruleTester.run('no-setup-in-describe', rule, { code: 'foo("", function () { a[b]; });', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { + suites: [ 'foo' ] + } } }, errors: [ { @@ -136,7 +144,9 @@ ruleTester.run('no-setup-in-describe', rule, { code: 'foo("", function () { a["b"]; });', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { + suites: [ 'foo' ] + } } }, errors: [ { @@ -167,7 +177,9 @@ ruleTester.run('no-setup-in-describe', rule, { code: 'foo("", function () { a.b; });', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { + suites: [ 'foo' ] + } } }, errors: [ { diff --git a/test/rules/no-sibling-hooks.js b/test/rules/no-sibling-hooks.js index 198d253..b94ef42 100644 --- a/test/rules/no-sibling-hooks.js +++ b/test/rules/no-sibling-hooks.js @@ -82,7 +82,7 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { '});' ].join('\n'), settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } } }, { code: [ @@ -95,7 +95,7 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { ].join('\n'), settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } } } @@ -153,7 +153,7 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { '});' ].join('\n'), settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } }, errors: [ { message: 'Unexpected use of duplicate Mocha `before` hook', column: 5, line: 6 } ] }, { @@ -168,7 +168,7 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { ].join('\n'), settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } }, errors: [ { message: 'Unexpected use of duplicate Mocha `before` hook', column: 5, line: 6 } ] diff --git a/test/rules/no-skipped-tests.js b/test/rules/no-skipped-tests.js index 91bf89c..57d41d2 100644 --- a/test/rules/no-skipped-tests.js +++ b/test/rules/no-skipped-tests.js @@ -87,21 +87,21 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { { code: 'custom.skip()', settings: { - 'mocha/additionalTestFunctions': [ 'custom' ] + 'mocha/additionalCustomNames': { testCasesWithSkipModifier: [ 'custom.skip' ] } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] }, { code: 'custom["skip"]()', settings: { - 'mocha/additionalTestFunctions': [ 'custom' ] + 'mocha/additionalCustomNames': { testCasesWithSkipModifier: [ 'custom.skip' ] } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] }, { code: 'xcustom()', settings: { - 'mocha/additionalXFunctions': [ 'xcustom' ] + 'mocha/additionalCustomNames': { testCasesWithSkipModifier: [ 'xcustom' ] } }, errors: [ { message: expectedErrorMessage, column: 1, line: 1 } ] }, @@ -109,7 +109,7 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { code: 'custom.skip()', settings: { mocha: { - additionalTestFunctions: [ 'custom' ] + additionalCustomNames: { testCasesWithSkipModifier: [ 'custom.skip' ] } } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] @@ -118,7 +118,7 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { code: 'custom["skip"]()', settings: { mocha: { - additionalTestFunctions: [ 'custom' ] + additionalCustomNames: { testCasesWithSkipModifier: [ 'custom.skip' ] } } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] @@ -127,7 +127,7 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { code: 'xcustom()', settings: { mocha: { - additionalXFunctions: [ 'xcustom' ] + additionalCustomNames: { testCasesWithSkipModifier: [ 'xcustom' ] } } }, errors: [ { message: expectedErrorMessage, column: 1, line: 1 } ] diff --git a/test/rules/no-top-level-hooks.js b/test/rules/no-top-level-hooks.js index a7c4a07..d577b99 100644 --- a/test/rules/no-top-level-hooks.js +++ b/test/rules/no-top-level-hooks.js @@ -25,13 +25,13 @@ ruleTester.run('no-top-level-hooks', rules['no-top-level-hooks'], { { code: 'foo(function() { before(function() {}); });', settings: { - 'mocha/additionalSuiteNames': [ 'foo' ] + 'mocha/additionalCustomNames': { suites: [ 'foo' ] } } }, { code: 'foo(function() { before(function() {}); });', settings: { mocha: { - additionalSuiteNames: [ 'foo' ] + additionalCustomNames: { suites: [ 'foo' ] } } } } diff --git a/test/util/namesSpec.js b/test/util/namesSpec.js index 545c01c..ad2f183 100644 --- a/test/util/namesSpec.js +++ b/test/util/namesSpec.js @@ -117,6 +117,54 @@ describe('mocha names', () => { 'specify.only' ]); }); + + it('returns the additional test case names', () => { + const testCaseNames = getTestCaseNames({ additionalTestCaseNames: [ 'myCustomIt' ] }); + + expect(testCaseNames).to.deep.equal([ + 'it', + 'test', + 'specify', + 'myCustomIt' + ]); + }); + + it('doesn’t return the additional suite names when base names shouldn’t be included', () => { + const testCaseNames = getTestCaseNames({ additionalSuiteNames: [ 'myCustomIt' ], baseNames: false }); + + expect(testCaseNames).to.deep.equal([]); + }); + + it('returns the additional skip modifiers', () => { + const testCaseNames = getTestCaseNames({ + additionalTestCaseModifiers: { skip: [ 'myCustomIt.skip' ] }, + modifiers: [ 'skip' ], + baseNames: false + }); + + expect(testCaseNames).to.deep.equal([ + 'it.skip', + 'test.skip', + 'specify.skip', + 'xit', + 'xspecify', + 'myCustomIt.skip' + ]); + }); + + it('doesn’t return additional skip modifiers when skip modifiers shouldn’t be included', () => { + const testCaseNames = getTestCaseNames({ + additionalTestCaseModifiers: { skip: [ 'myCustomIt.skip' ] }, + modifiers: [ 'only' ], + baseNames: false + }); + + expect(testCaseNames).to.deep.equal([ + 'it.only', + 'test.only', + 'specify.only' + ]); + }); }); describe('suite names', () => { @@ -253,5 +301,37 @@ describe('mocha names', () => { expect(suiteNames).to.deep.equal([]); }); + + it('returns the additional skip modifiers', () => { + const suiteNames = getSuiteNames({ + additionalSuiteModifiers: { skip: [ 'myCustomDescribe.skip' ] }, + modifiers: [ 'skip' ], + baseNames: false + }); + + expect(suiteNames).to.deep.equal([ + 'describe.skip', + 'context.skip', + 'suite.skip', + 'xdescribe', + 'xcontext', + 'xsuite', + 'myCustomDescribe.skip' + ]); + }); + + it('doesn’t return additional skip modifiers when skip modifiers shouldn’t be included', () => { + const suiteNames = getSuiteNames({ + additionalSuiteModifiers: { skip: [ 'myCustomDescribe.skip' ] }, + modifiers: [ 'only' ], + baseNames: false + }); + + expect(suiteNames).to.deep.equal([ + 'describe.only', + 'context.only', + 'suite.only' + ]); + }); }); }); From 6fe21e6e96f479d63055cda50d341b1142f7b8ec Mon Sep 17 00:00:00 2001 From: Mathias Schreck Date: Mon, 3 Aug 2020 13:38:11 +0200 Subject: [PATCH 2/2] Improve data structure of custom names --- README.md | 24 +--- lib/rules/no-exclusive-tests.js | 2 +- lib/rules/no-skipped-tests.js | 2 +- lib/util/ast.js | 14 +-- lib/util/names.js | 164 ++++++++++++++++--------- lib/util/settings.js | 24 +--- test/rules/max-top-level-suites.js | 8 +- test/rules/no-async-describe.js | 2 +- test/rules/no-exclusive-tests.js | 22 ++-- test/rules/no-hooks-for-single-case.js | 8 +- test/rules/no-identical-title.js | 8 +- test/rules/no-nested-tests.js | 8 +- test/rules/no-setup-in-describe.js | 26 ++-- test/rules/no-sibling-hooks.js | 8 +- test/rules/no-skipped-tests.js | 23 ++-- test/rules/no-top-level-hooks.js | 4 +- test/rules/prefer-arrow-callback.js | 1 - test/util/namesSpec.js | 151 +++++++++++------------ 18 files changed, 244 insertions(+), 255 deletions(-) diff --git a/README.md b/README.md index ba9cc36..0f6f586 100644 --- a/README.md +++ b/README.md @@ -40,27 +40,9 @@ This plugin supports the following settings, which are used by multiple rules: "mocha/no-exclusive-tests": "error" }, "settings": { - "mocha/additionalCustomNames": { - "suites": [ - "describeModule" - ], - "suitesWithSkipModifier": [ - "describeModule.skip", - "xdescribeModule" - ], - "exclusiveSuites": [ - "describeModule.only" - ], - "testCases": [ - "testModule" - ], - "testCasesWithSkipModifier": [ - "testModule.customSkip", - "xtestModules" - ], - "exclusiveTestCases": [ - "testModule.only" - ] + "mocha/additionalCustomNames": [ + { "name": "describeModule", "type": "suite", "interfaces": [ "BDD" ] }, + { "name": "testModule", "type": "testCase", "interfaces": [ "TDD" ] } } } } diff --git a/lib/rules/no-exclusive-tests.js b/lib/rules/no-exclusive-tests.js index a0bc3e4..862bb05 100644 --- a/lib/rules/no-exclusive-tests.js +++ b/lib/rules/no-exclusive-tests.js @@ -14,7 +14,7 @@ module.exports = { return { CallExpression(node) { - const options = { modifiers: [ 'only' ], baseNames: false }; + const options = { modifiers: [ 'only' ], modifiersOnly: true }; if (astUtils.isDescribe(node, options) || astUtils.isTestCase(node, options)) { const callee = node.callee; diff --git a/lib/rules/no-skipped-tests.js b/lib/rules/no-skipped-tests.js index 2e340fa..34edd70 100644 --- a/lib/rules/no-skipped-tests.js +++ b/lib/rules/no-skipped-tests.js @@ -14,7 +14,7 @@ module.exports = { return { CallExpression(node) { - const options = { modifiers: [ 'skip' ], baseNames: false }; + const options = { modifiers: [ 'skip' ], modifiersOnly: true }; if (astUtils.isDescribe(node, options) || astUtils.isTestCase(node, options)) { const callee = node.callee; diff --git a/lib/util/ast.js b/lib/util/ast.js index b3d73a4..d2e2bba 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -64,22 +64,18 @@ function isFunctionCallWithName(node, names) { } function createAstUtils(settings) { - const additionalNames = getAddtionalNames(settings); + const additionalCustomNames = getAddtionalNames(settings); function isDescribe(node, options = {}) { - const { modifiers = [ 'skip', 'only' ], baseNames = true } = options; - const { additionalSuiteNames, additionalSuiteModifiers } = additionalNames; - const describeAliases = getSuiteNames({ baseNames, modifiers, additionalSuiteNames, additionalSuiteModifiers }); + const { modifiers = [ 'skip', 'only' ], modifiersOnly = false } = options; + const describeAliases = getSuiteNames({ modifiersOnly, modifiers, additionalCustomNames }); return isFunctionCallWithName(node, describeAliases); } function isTestCase(node, options = {}) { - const { modifiers = [ 'skip', 'only' ], baseNames = true } = options; - const { additionalTestCaseNames, additionalTestCaseModifiers } = additionalNames; - const testCaseNames = getTestCaseNames({ - baseNames, modifiers, additionalTestCaseNames, additionalTestCaseModifiers - }); + const { modifiers = [ 'skip', 'only' ], modifiersOnly = false } = options; + const testCaseNames = getTestCaseNames({ modifiersOnly, modifiers, additionalCustomNames }); return isFunctionCallWithName(node, testCaseNames); } diff --git a/lib/util/names.js b/lib/util/names.js index d857061..f96fc57 100644 --- a/lib/util/names.js +++ b/lib/util/names.js @@ -1,80 +1,126 @@ 'use strict'; -const chain = require('ramda/src/chain'); +const where = require('ramda/src/where'); +const includes = require('ramda/src/includes'); +const intersection = require('ramda/src/intersection'); +const pipe = require('ramda/src/pipe'); +const isEmpty = require('ramda/src/isEmpty'); +const complement = require('ramda/src/complement'); +const flip = require('ramda/src/flip'); +const filter = require('ramda/src/filter'); +const over = require('ramda/src/over'); +const lensProp = require('ramda/src/lensProp'); +const map = require('ramda/src/map'); +const view = require('ramda/src/view'); +const assoc = require('ramda/src/assoc'); +const allPass = require('ramda/src/allPass'); -const suiteNames = [ - 'describe', - 'context', - 'suite' -]; +const INTERFACES = { + BDD: 'BDD', + TDD: 'TDD', + QUnit: 'QUnit' +}; + +const TYPES = { + suite: 'suite', + testCase: 'testCase', + hook: 'hook' +}; -const suiteModifiers = { - skip: [ - 'describe.skip', - 'context.skip', - 'suite.skip', - 'xdescribe', - 'xcontext', - 'xsuite' - ], - only: [ - 'describe.only', - 'context.only', - 'suite.only' - ] +const MODIFIERS = { + skip: 'skip', + only: 'only' }; -function getSuiteModifiers(modifierName, additionalSuiteModifiers = {}) { - const names = suiteModifiers[modifierName] || []; - const additionalNames = additionalSuiteModifiers[modifierName] || []; +const baseNames = [ + { name: 'describe', interfaces: [ INTERFACES.BDD ], type: TYPES.suite }, + { name: 'context', interfaces: [ INTERFACES.BDD ], type: TYPES.suite }, + { name: 'suite', interfaces: [ INTERFACES.TDD, INTERFACES.QUnit ], type: TYPES.suite }, + { name: 'it', interfaces: [ INTERFACES.BDD ], type: TYPES.testCase }, + { name: 'specify', interfaces: [ INTERFACES.BDD ], type: TYPES.testCase }, + { name: 'test', interfaces: [ INTERFACES.TDD, INTERFACES.QUnit ], type: TYPES.testCase }, + { name: 'before', interfaces: [ INTERFACES.BDD, INTERFACES.QUnit ], type: TYPES.hook }, + { name: 'after', interfaces: [ INTERFACES.BDD, INTERFACES.QUnit ], type: TYPES.hook }, + { name: 'beforeEach', interfaces: [ INTERFACES.BDD, INTERFACES.QUnit ], type: TYPES.hook }, + { name: 'afterEach', interfaces: [ INTERFACES.BDD, INTERFACES.QUnit ], type: TYPES.hook }, + { name: 'suiteSetup', interfaces: [ INTERFACES.TDD ], type: TYPES.hook }, + { name: 'suiteTeardown', interfaces: [ INTERFACES.TDD ], type: TYPES.hook }, + { name: 'setup', interfaces: [ INTERFACES.TDD ], type: TYPES.hook }, + { name: 'teardown', interfaces: [ INTERFACES.TDD ], type: TYPES.hook } +]; + +const includesSublist = (sublist) => pipe(intersection(sublist), complement(isEmpty)); +const isIncludedIn = flip(includes); +const hasMatchingType = (typesToMatch) => where({ type: isIncludedIn(typesToMatch) }); +const hasMatchingInterfaces = (interfacesToMatch) => where({ interfaces: includesSublist(interfacesToMatch) }); +const hasMatchingModifier = (modifierToMatch) => where({ modifier: isIncludedIn(modifierToMatch) }); +const filterTestCasesAndSuites = filter(hasMatchingType([ TYPES.suite, TYPES.testCase ])); - return [ ...names, ...additionalNames ]; +const nameLens = lensProp('name'); +const mapNames = (fn) => map(over(nameLens, fn)); +const extractNames = map(view(nameLens)); +const addModifier = (modifier) => map(assoc('modifier', modifier)); + +function formatXVariant(name) { + return `x${name}`; } -const testCaseNames = [ - 'it', - 'test', - 'specify' -]; +function formatSkipVariant(name) { + return `${name}.${MODIFIERS.skip}`; +} -const testCaseModifiers = { - skip: [ - 'it.skip', - 'test.skip', - 'specify.skip', - 'xit', - 'xspecify' - ], - only: [ - 'it.only', - 'test.only', - 'specify.only' - ] -}; +function formatExclusiveVariant(name) { + return `${name}.${MODIFIERS.only}`; +} + +const buildXVariants = pipe( + filterTestCasesAndSuites, + filter(hasMatchingInterfaces([ INTERFACES.BDD ])), + mapNames(formatXVariant), + addModifier(MODIFIERS.skip) +); -function getTestCaseModifiers(modifierName, additionalTestCaseModifiers = {}) { - const names = testCaseModifiers[modifierName] || []; - const additionalNames = additionalTestCaseModifiers[modifierName] || []; +const buildSkipVariants = pipe( + filterTestCasesAndSuites, + mapNames(formatSkipVariant), + addModifier(MODIFIERS.skip) +); - return [ ...names, ...additionalNames ]; +const buildExclusiveVariants = pipe( + filterTestCasesAndSuites, + mapNames(formatExclusiveVariant), + addModifier(MODIFIERS.only) +); + +function buildAllNames(additionalNames) { + const names = addModifier(null)([ ...baseNames, ...additionalNames ]); + + return [ + ...names, + ...buildSkipVariants(names), + ...buildXVariants(names), + ...buildExclusiveVariants(names) + ]; } -function getTestCaseNames(options = {}) { - const { modifiers = [], baseNames = true, additionalTestCaseNames = [], additionalTestCaseModifiers } = options; - const names = baseNames ? testCaseNames.concat(additionalTestCaseNames) : []; +function getNamesByType(type, filterOptions = {}) { + const { modifiers = [], modifiersOnly = false, additionalCustomNames = [] } = filterOptions; + const allNames = buildAllNames(additionalCustomNames); + const predicates = [ + hasMatchingType([ type ]), + hasMatchingModifier([ ...modifiers, ...modifiersOnly ? [] : [ null ] ]) + ]; + const filteredNames = filter(allPass(predicates), allNames); - return names.concat(chain((modifierName) => { - return getTestCaseModifiers(modifierName, additionalTestCaseModifiers); - }, modifiers)); + return extractNames(filteredNames); } -function getSuiteNames(options = {}) { - const { modifiers = [], baseNames = true, additionalSuiteNames = [], additionalSuiteModifiers } = options; - const names = baseNames ? suiteNames.concat(additionalSuiteNames) : []; +function getTestCaseNames(options) { + return getNamesByType(TYPES.testCase, options); +} - return names.concat(chain((modifierName) => { - return getSuiteModifiers(modifierName, additionalSuiteModifiers); - }, modifiers)); +function getSuiteNames(options) { + return getNamesByType(TYPES.suite, options); } module.exports = { diff --git a/lib/util/settings.js b/lib/util/settings.js index 2a44ac5..52245eb 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -9,27 +9,7 @@ function settingFor(settings, propertyName, fallback) { module.exports = { getAddtionalNames(settings) { - const additionalCustomNamesSettings = settingFor(settings, 'additionalCustomNames', {}); - const { - suites = [], - testCases = [], - suitesWithSkipModifier = [], - testCasesWithSkipModifier = [], - exclusiveTestCases = [], - exclusiveSuites = [] - } = additionalCustomNamesSettings; - - return { - additionalSuiteNames: suites, - additionalTestCaseNames: testCases, - additionalTestCaseModifiers: { - skip: testCasesWithSkipModifier, - only: exclusiveTestCases - }, - additionalSuiteModifiers: { - skip: suitesWithSkipModifier, - only: exclusiveSuites - } - }; + const additionalCustomNames = settingFor(settings, 'additionalCustomNames', []); + return additionalCustomNames; } }; diff --git a/test/rules/max-top-level-suites.js b/test/rules/max-top-level-suites.js index 498a95e..fe41c39 100644 --- a/test/rules/max-top-level-suites.js +++ b/test/rules/max-top-level-suites.js @@ -43,13 +43,13 @@ ruleTester.run('max-top-level-suites', rules['max-top-level-suites'], { { code: 'foo("This is a test", function () { });', settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, { code: 'foo("This is a test", function () { });', settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } }, @@ -195,7 +195,7 @@ ruleTester.run('max-top-level-suites', rules['max-top-level-suites'], { code: 'foo("this is a test", function () { });' + 'foo("this is a different test", function () { });', settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] }, errors: [ { message: 'The number of top-level suites is more than 1.' } @@ -205,7 +205,7 @@ ruleTester.run('max-top-level-suites', rules['max-top-level-suites'], { 'foo("this is a different test", function () { });', settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, errors: [ diff --git a/test/rules/no-async-describe.js b/test/rules/no-async-describe.js index f643c97..bcb16c2 100644 --- a/test/rules/no-async-describe.js +++ b/test/rules/no-async-describe.js @@ -32,7 +32,7 @@ ruleTester.run('no-async-describe', rule, { output: 'foo("hello", function () {})', settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, parserOptions: { ecmaVersion: 8 }, errors: [ { diff --git a/test/rules/no-exclusive-tests.js b/test/rules/no-exclusive-tests.js index 6acd50d..eee1ab1 100644 --- a/test/rules/no-exclusive-tests.js +++ b/test/rules/no-exclusive-tests.js @@ -27,7 +27,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'a.b.c.skip()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'a.b.c.only' ] } + additionalCustomNames: [ { name: 'a.b.c', type: 'testCase', interfaces: [ 'BDD' ] } ] } } }, @@ -35,7 +35,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'a[b].c.skip()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'a.b.c.only' ] } + additionalCustomNames: [ { name: 'a.b.c', type: 'testCase', interfaces: [ 'BDD' ] } ] } } } @@ -93,14 +93,14 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { { code: 'custom.only()', settings: { - 'mocha/additionalCustomNames': { exclusiveTestCases: [ 'custom.only' ] } + 'mocha/additionalCustomNames': [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] }, { code: 'custom["only"]()', settings: { - 'mocha/additionalCustomNames': { exclusiveTestCases: [ 'custom.only' ] } + 'mocha/additionalCustomNames': [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] }, @@ -108,7 +108,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'custom.only()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'custom.only' ] } + additionalCustomNames: [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] @@ -117,7 +117,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'custom["only"]()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'custom.only' ] } + additionalCustomNames: [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] @@ -126,7 +126,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'foo.bar.only()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'foo.bar.only' ] } + additionalCustomNames: [ { name: 'foo.bar', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 9, line: 1 } ] @@ -135,7 +135,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'foo.bar["only"]()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'foo.bar.only' ] } + additionalCustomNames: [ { name: 'foo.bar', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 9, line: 1 } ] @@ -144,7 +144,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'foo["bar"].only()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'foo.bar.only' ] } + additionalCustomNames: [ { name: 'foo.bar', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 12, line: 1 } ] @@ -153,7 +153,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'foo["bar"]["only"]()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'foo.bar.only' ] } + additionalCustomNames: [ { name: 'foo.bar', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 12, line: 1 } ] @@ -162,7 +162,7 @@ ruleTester.run('no-exclusive-tests', rules['no-exclusive-tests'], { code: 'a.b.c.only()', settings: { mocha: { - additionalCustomNames: { exclusiveTestCases: [ 'a.b.c.only' ] } + additionalCustomNames: [ { name: 'a.b.c', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 7, line: 1 } ] diff --git a/test/rules/no-hooks-for-single-case.js b/test/rules/no-hooks-for-single-case.js index 97d11bc..48abafa 100644 --- a/test/rules/no-hooks-for-single-case.js +++ b/test/rules/no-hooks-for-single-case.js @@ -153,7 +153,7 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { ].join('\n'), settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } }, @@ -166,7 +166,7 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { '});' ].join('\n'), settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } ], @@ -294,7 +294,7 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { ].join('\n'), settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: 'Unexpected use of Mocha `before` hook for a single test case', column: 5, line: 2 } ] @@ -306,7 +306,7 @@ ruleTester.run('no-hooks-for-single-case', rules['no-hooks-for-single-case'], { '});' ].join('\n'), settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] }, 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 b97664c..4a8f2dd 100644 --- a/test/rules/no-identical-title.js +++ b/test/rules/no-identical-title.js @@ -98,7 +98,7 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { 'foo("describe2", function() {});' ].join('\n'), settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, { code: [ @@ -107,7 +107,7 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { ].join('\n'), settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } } @@ -180,7 +180,7 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { 'foo("describe1", function() {});' ].join('\n'), settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] }, errors: [ { message: 'Test suite title is used multiple times.', column: 1, line: 2 } ] }, { @@ -190,7 +190,7 @@ ruleTester.run('no-identical-title', rules['no-identical-title'], { ].join('\n'), settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, 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 4dc8353..6a912da 100644 --- a/test/rules/no-nested-tests.js +++ b/test/rules/no-nested-tests.js @@ -13,13 +13,13 @@ ruleTester.run('no-nested-tests', rule, { { code: 'foo("", function () { it(); })', settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', interfaces: [ 'BDD' ] } ] } }, { code: 'foo("", function () { it(); })', settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } } @@ -121,7 +121,7 @@ ruleTester.run('no-nested-tests', rule, { { code: 'it("", function () { foo() });', settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] }, errors: [ { message: 'Unexpected suite nested within a test.', @@ -133,7 +133,7 @@ ruleTester.run('no-nested-tests', rule, { code: 'it("", function () { foo() });', settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, errors: [ { diff --git a/test/rules/no-setup-in-describe.js b/test/rules/no-setup-in-describe.js index 41b4424..cd13e47 100644 --- a/test/rules/no-setup-in-describe.js +++ b/test/rules/no-setup-in-describe.js @@ -56,24 +56,20 @@ ruleTester.run('no-setup-in-describe', rule, { { code: 'foo("", function () { it(); })', settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, { code: 'foo("", function () { it(); })', settings: { mocha: { - additionalCustomNames: { - suites: [ 'foo' ] - } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } }, { code: 'foo("", function () { it("", function () { b(); }); })', settings: { mocha: { - additionalCustomNames: { - suites: [ 'foo' ] - } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } }, @@ -116,9 +112,7 @@ ruleTester.run('no-setup-in-describe', rule, { code: 'foo("", function () { a(); });', settings: { mocha: { - additionalCustomNames: { - suites: [ 'foo' ] - } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, errors: [ { @@ -130,9 +124,7 @@ ruleTester.run('no-setup-in-describe', rule, { code: 'foo("", function () { a[b]; });', settings: { mocha: { - additionalCustomNames: { - suites: [ 'foo' ] - } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, errors: [ { @@ -144,9 +136,7 @@ ruleTester.run('no-setup-in-describe', rule, { code: 'foo("", function () { a["b"]; });', settings: { mocha: { - additionalCustomNames: { - suites: [ 'foo' ] - } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, errors: [ { @@ -177,9 +167,7 @@ ruleTester.run('no-setup-in-describe', rule, { code: 'foo("", function () { a.b; });', settings: { mocha: { - additionalCustomNames: { - suites: [ 'foo' ] - } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, errors: [ { diff --git a/test/rules/no-sibling-hooks.js b/test/rules/no-sibling-hooks.js index b94ef42..3c62fa0 100644 --- a/test/rules/no-sibling-hooks.js +++ b/test/rules/no-sibling-hooks.js @@ -82,7 +82,7 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { '});' ].join('\n'), settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, { code: [ @@ -95,7 +95,7 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { ].join('\n'), settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } } @@ -153,7 +153,7 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { '});' ].join('\n'), settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] }, errors: [ { message: 'Unexpected use of duplicate Mocha `before` hook', column: 5, line: 6 } ] }, { @@ -168,7 +168,7 @@ ruleTester.run('no-sibling-hooks', rules['no-sibling-hooks'], { ].join('\n'), settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: 'Unexpected use of duplicate Mocha `before` hook', column: 5, line: 6 } ] diff --git a/test/rules/no-skipped-tests.js b/test/rules/no-skipped-tests.js index 57d41d2..7655c5e 100644 --- a/test/rules/no-skipped-tests.js +++ b/test/rules/no-skipped-tests.js @@ -20,7 +20,15 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { 'context.only()', 'var appliedOnly = describe.skip; appliedOnly.apply(describe)', 'var calledOnly = it.skip; calledOnly.call(it)', - 'var dynamicOnly = "skip"; suite[dynamicOnly]()' + 'var dynamicOnly = "skip"; suite[dynamicOnly]()', + { + code: 'xcustom()', + settings: { + mocha: { + additionalCustomNames: [ { name: 'custom', type: 'testCase', interfaces: [ 'TDD' ] } ] + } + } + } ], invalid: [ @@ -87,21 +95,21 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { { code: 'custom.skip()', settings: { - 'mocha/additionalCustomNames': { testCasesWithSkipModifier: [ 'custom.skip' ] } + 'mocha/additionalCustomNames': [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] }, { code: 'custom["skip"]()', settings: { - 'mocha/additionalCustomNames': { testCasesWithSkipModifier: [ 'custom.skip' ] } + 'mocha/additionalCustomNames': [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] }, { code: 'xcustom()', settings: { - 'mocha/additionalCustomNames': { testCasesWithSkipModifier: [ 'xcustom' ] } + 'mocha/additionalCustomNames': [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] }, errors: [ { message: expectedErrorMessage, column: 1, line: 1 } ] }, @@ -109,7 +117,7 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { code: 'custom.skip()', settings: { mocha: { - additionalCustomNames: { testCasesWithSkipModifier: [ 'custom.skip' ] } + additionalCustomNames: [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] @@ -118,7 +126,7 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { code: 'custom["skip"]()', settings: { mocha: { - additionalCustomNames: { testCasesWithSkipModifier: [ 'custom.skip' ] } + additionalCustomNames: [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 8, line: 1 } ] @@ -127,12 +135,11 @@ ruleTester.run('no-skipped-tests', rules['no-skipped-tests'], { code: 'xcustom()', settings: { mocha: { - additionalCustomNames: { testCasesWithSkipModifier: [ 'xcustom' ] } + additionalCustomNames: [ { name: 'custom', type: 'testCase', interfaces: [ 'BDD' ] } ] } }, errors: [ { message: expectedErrorMessage, column: 1, line: 1 } ] } - ] }); diff --git a/test/rules/no-top-level-hooks.js b/test/rules/no-top-level-hooks.js index d577b99..b1d76f2 100644 --- a/test/rules/no-top-level-hooks.js +++ b/test/rules/no-top-level-hooks.js @@ -25,13 +25,13 @@ ruleTester.run('no-top-level-hooks', rules['no-top-level-hooks'], { { code: 'foo(function() { before(function() {}); });', settings: { - 'mocha/additionalCustomNames': { suites: [ 'foo' ] } + 'mocha/additionalCustomNames': [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } }, { code: 'foo(function() { before(function() {}); });', settings: { mocha: { - additionalCustomNames: { suites: [ 'foo' ] } + additionalCustomNames: [ { name: 'foo', type: 'suite', interfaces: [ 'BDD' ] } ] } } } diff --git a/test/rules/prefer-arrow-callback.js b/test/rules/prefer-arrow-callback.js index 4264d91..f18ffba 100644 --- a/test/rules/prefer-arrow-callback.js +++ b/test/rules/prefer-arrow-callback.js @@ -57,7 +57,6 @@ ruleTester.run('prefer-arrow-callback', rules['prefer-arrow-callback'], { 'context.only("name", function bar() {});', 'context.skip("name", function bar() {});', 'suite("name", function bar() {});', - 'xsuite("name", function bar() {});', 'suite.only("name", function bar() {});', 'suite.skip("name", function bar() {});', 'it("name", function bar() {});', diff --git a/test/util/namesSpec.js b/test/util/namesSpec.js index ad2f183..5275ff5 100644 --- a/test/util/namesSpec.js +++ b/test/util/namesSpec.js @@ -10,27 +10,27 @@ describe('mocha names', () => { expect(testCaseNames).to.deep.equal([ 'it', - 'test', - 'specify' + 'specify', + 'test' ]); }); it('returns an empty list when no modifiers and no base names are wanted', () => { - const testCaseNames = getTestCaseNames({ baseNames: false }); + const testCaseNames = getTestCaseNames({ modifiersOnly: true, modifiers: [] }); expect(testCaseNames).to.deep.equal([]); }); it('always returns a new array', () => { - const testCaseNames1 = getTestCaseNames({ baseNames: false }); - const testCaseNames2 = getTestCaseNames({ baseNames: false }); + const testCaseNames1 = getTestCaseNames({ modifiersOnly: true }); + const testCaseNames2 = getTestCaseNames({ modifiersOnly: true }); expect(testCaseNames1).to.deep.equal(testCaseNames2); expect(testCaseNames1).to.not.equal(testCaseNames2); }); it('ignores invalid modifiers', () => { - const testCaseNames = getTestCaseNames({ modifiers: [ 'foo' ], baseNames: false }); + const testCaseNames = getTestCaseNames({ modifiers: [ 'foo' ], modifiersOnly: true }); expect(testCaseNames).to.deep.equal([]); }); @@ -40,23 +40,23 @@ describe('mocha names', () => { expect(testCaseNames).to.deep.equal([ 'it', - 'test', 'specify', + 'test', 'it.skip', - 'test.skip', 'specify.skip', + 'test.skip', 'xit', 'xspecify' ]); }); it('returns the list of test case names only with "skip" modifiers applied', () => { - const testCaseNames = getTestCaseNames({ modifiers: [ 'skip' ], baseNames: false }); + const testCaseNames = getTestCaseNames({ modifiers: [ 'skip' ], modifiersOnly: true }); expect(testCaseNames).to.deep.equal([ 'it.skip', - 'test.skip', 'specify.skip', + 'test.skip', 'xit', 'xspecify' ]); @@ -67,21 +67,21 @@ describe('mocha names', () => { expect(testCaseNames).to.deep.equal([ 'it', - 'test', 'specify', + 'test', 'it.only', - 'test.only', - 'specify.only' + 'specify.only', + 'test.only' ]); }); it('returns the list of test case names only with "only" modifiers applied', () => { - const testCaseNames = getTestCaseNames({ modifiers: [ 'only' ], baseNames: false }); + const testCaseNames = getTestCaseNames({ modifiers: [ 'only' ], modifiersOnly: true }); expect(testCaseNames).to.deep.equal([ 'it.only', - 'test.only', - 'specify.only' + 'specify.only', + 'test.only' ]); }); @@ -90,79 +90,80 @@ describe('mocha names', () => { expect(testCaseNames).to.deep.equal([ 'it', - 'test', 'specify', + 'test', 'it.skip', - 'test.skip', 'specify.skip', + 'test.skip', 'xit', 'xspecify', 'it.only', - 'test.only', - 'specify.only' + 'specify.only', + 'test.only' ]); }); it('returns the list of test case names only with modifiers applied', () => { - const testCaseNames = getTestCaseNames({ modifiers: [ 'skip', 'only' ], baseNames: false }); + const testCaseNames = getTestCaseNames({ modifiers: [ 'skip', 'only' ], modifiersOnly: true }); expect(testCaseNames).to.deep.equal([ 'it.skip', - 'test.skip', 'specify.skip', + 'test.skip', 'xit', 'xspecify', 'it.only', - 'test.only', - 'specify.only' + 'specify.only', + 'test.only' ]); }); it('returns the additional test case names', () => { - const testCaseNames = getTestCaseNames({ additionalTestCaseNames: [ 'myCustomIt' ] }); + const testCaseNames = getTestCaseNames({ + additionalCustomNames: [ + { name: 'myCustomIt', type: 'testCase', interfaces: [ 'BDD' ] } + ] + }); expect(testCaseNames).to.deep.equal([ 'it', - 'test', 'specify', + 'test', 'myCustomIt' ]); }); it('doesn’t return the additional suite names when base names shouldn’t be included', () => { - const testCaseNames = getTestCaseNames({ additionalSuiteNames: [ 'myCustomIt' ], baseNames: false }); + const testCaseNames = getTestCaseNames({ + additionalCustomNames: [ + { name: 'myCustomIt', type: 'testCase', interfaces: [ 'BDD' ] } + ], + modifiersOnly: true + }); expect(testCaseNames).to.deep.equal([]); }); it('returns the additional skip modifiers', () => { const testCaseNames = getTestCaseNames({ - additionalTestCaseModifiers: { skip: [ 'myCustomIt.skip' ] }, - modifiers: [ 'skip' ], - baseNames: false + additionalCustomNames: [ + { name: 'myCustomIt', type: 'testCase', interfaces: [ 'BDD' ] }, + { name: 'myCustomTest', type: 'testCase', interfaces: [ 'TDD' ] } + + ], + modifiersOnly: true, + modifiers: [ 'skip' ] }); expect(testCaseNames).to.deep.equal([ 'it.skip', - 'test.skip', 'specify.skip', + 'test.skip', + 'myCustomIt.skip', + 'myCustomTest.skip', 'xit', 'xspecify', - 'myCustomIt.skip' - ]); - }); - - it('doesn’t return additional skip modifiers when skip modifiers shouldn’t be included', () => { - const testCaseNames = getTestCaseNames({ - additionalTestCaseModifiers: { skip: [ 'myCustomIt.skip' ] }, - modifiers: [ 'only' ], - baseNames: false - }); - - expect(testCaseNames).to.deep.equal([ - 'it.only', - 'test.only', - 'specify.only' + 'xmyCustomIt' ]); }); }); @@ -179,21 +180,21 @@ describe('mocha names', () => { }); it('returns an empty list when no modifiers and no base names are wanted', () => { - const suiteNames = getSuiteNames({ baseNames: false }); + const suiteNames = getSuiteNames({ modifiersOnly: true }); expect(suiteNames).to.deep.equal([]); }); it('always returns a new array', () => { - const suiteNames1 = getSuiteNames({ baseNames: false }); - const suiteNames2 = getSuiteNames({ baseNames: false }); + const suiteNames1 = getSuiteNames({ modifiersOnly: true }); + const suiteNames2 = getSuiteNames({ modifiersOnly: true }); expect(suiteNames1).to.deep.equal(suiteNames2); expect(suiteNames1).to.not.equal(suiteNames2); }); it('ignores invalid modifiers', () => { - const suiteNames = getSuiteNames({ modifiers: [ 'foo' ], baseNames: false }); + const suiteNames = getSuiteNames({ modifiers: [ 'foo' ], modifiersOnly: true }); expect(suiteNames).to.deep.equal([]); }); @@ -209,21 +210,19 @@ describe('mocha names', () => { 'context.skip', 'suite.skip', 'xdescribe', - 'xcontext', - 'xsuite' + 'xcontext' ]); }); it('returns the list of suite names only with "skip" modifiers applied', () => { - const suiteNames = getSuiteNames({ modifiers: [ 'skip' ], baseNames: false }); + const suiteNames = getSuiteNames({ modifiers: [ 'skip' ], modifiersOnly: true }); expect(suiteNames).to.deep.equal([ 'describe.skip', 'context.skip', 'suite.skip', 'xdescribe', - 'xcontext', - 'xsuite' + 'xcontext' ]); }); @@ -241,7 +240,7 @@ describe('mocha names', () => { }); it('returns the list of suite names only with "only" modifiers applied', () => { - const suiteNames = getSuiteNames({ modifiers: [ 'only' ], baseNames: false }); + const suiteNames = getSuiteNames({ modifiers: [ 'only' ], modifiersOnly: true }); expect(suiteNames).to.deep.equal([ 'describe.only', @@ -262,15 +261,14 @@ describe('mocha names', () => { 'suite.skip', 'xdescribe', 'xcontext', - 'xsuite', 'describe.only', 'context.only', 'suite.only' ]); }); - it('returns the list of suite names names only with modifiers applied', () => { - const suiteNames = getSuiteNames({ modifiers: [ 'skip', 'only' ], baseNames: false }); + it('returns the list of suite names only with modifiers applied', () => { + const suiteNames = getSuiteNames({ modifiers: [ 'skip', 'only' ], modifiersOnly: true }); expect(suiteNames).to.deep.equal([ 'describe.skip', @@ -278,7 +276,6 @@ describe('mocha names', () => { 'suite.skip', 'xdescribe', 'xcontext', - 'xsuite', 'describe.only', 'context.only', 'suite.only' @@ -286,7 +283,11 @@ describe('mocha names', () => { }); it('returns the additional suite names', () => { - const suiteNames = getSuiteNames({ additionalSuiteNames: [ 'myCustomDescribe' ] }); + const suiteNames = getSuiteNames({ + additionalCustomNames: [ + { name: 'myCustomDescribe', type: 'suite', interfaces: [ 'BDD' ] } + ] + }); expect(suiteNames).to.deep.equal([ 'describe', @@ -297,40 +298,30 @@ describe('mocha names', () => { }); it('doesn’t return the additional suite names when base names shouldn’t be included', () => { - const suiteNames = getSuiteNames({ additionalSuiteNames: [ 'myCustomDescribe' ], baseNames: false }); + const suiteNames = getSuiteNames({ additionalSuiteNames: [ 'myCustomDescribe' ], modifiersOnly: true }); expect(suiteNames).to.deep.equal([]); }); it('returns the additional skip modifiers', () => { const suiteNames = getSuiteNames({ - additionalSuiteModifiers: { skip: [ 'myCustomDescribe.skip' ] }, + additionalCustomNames: [ + { name: 'myCustomDescribe', type: 'suite', interfaces: [ 'BDD' ] }, + { name: 'myCustomSuite', type: 'suite', interfaces: [ 'TDD' ] } + ], modifiers: [ 'skip' ], - baseNames: false + modifiersOnly: true }); expect(suiteNames).to.deep.equal([ 'describe.skip', 'context.skip', 'suite.skip', + 'myCustomDescribe.skip', + 'myCustomSuite.skip', 'xdescribe', 'xcontext', - 'xsuite', - 'myCustomDescribe.skip' - ]); - }); - - it('doesn’t return additional skip modifiers when skip modifiers shouldn’t be included', () => { - const suiteNames = getSuiteNames({ - additionalSuiteModifiers: { skip: [ 'myCustomDescribe.skip' ] }, - modifiers: [ 'only' ], - baseNames: false - }); - - expect(suiteNames).to.deep.equal([ - 'describe.only', - 'context.only', - 'suite.only' + 'xmyCustomDescribe' ]); }); });