From 68a3c0729c8a3e70841f945eef3269836eb092e4 Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Mon, 17 Feb 2020 23:42:36 +0800 Subject: [PATCH] - Add schemas for options (and remove for files which are using settings) --- lib/rules/max-top-level-suites.js | 83 ++++++++++++-------- lib/rules/no-exclusive-tests.js | 92 +++++++++------------- lib/rules/no-hooks-for-single-case.js | 109 +++++++++++++------------- lib/rules/no-skipped-tests.js | 26 ------ lib/rules/no-synchronous-tests.js | 99 +++++++++++------------ lib/rules/valid-suite-description.js | 90 ++++++++++++++------- lib/rules/valid-test-description.js | 90 ++++++++++++++------- test/rules/valid-suite-description.js | 2 + test/rules/valid-test-description.js | 2 + 9 files changed, 321 insertions(+), 272 deletions(-) diff --git a/lib/rules/max-top-level-suites.js b/lib/rules/max-top-level-suites.js index 1ad1432..19fafa3 100644 --- a/lib/rules/max-top-level-suites.js +++ b/lib/rules/max-top-level-suites.js @@ -11,43 +11,58 @@ const { additionalSuiteNames } = require('../util/settings'); const defaultSuiteLimit = 1; -module.exports = function (context) { - const stack = []; - const topLevelDescribes = []; - const options = context.options[0] || {}; - const settings = context.settings; - let suiteLimit; - - if (isNil(options.limit)) { - suiteLimit = defaultSuiteLimit; - } else { - suiteLimit = options.limit; - } - - return { - CallExpression(node) { - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { - stack.push(node); +module.exports = { + meta: { + schema: [ + { + type: 'object', + properties: { + limit: { + type: 'integer' + } + }, + additionalProperties: false } - }, + ] + }, + create(context) { + const stack = []; + const topLevelDescribes = []; + const options = context.options[0] || {}; + const settings = context.settings; + let suiteLimit; + + if (isNil(options.limit)) { + suiteLimit = defaultSuiteLimit; + } else { + suiteLimit = options.limit; + } - 'CallExpression:exit'(node) { - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { - if (stack.length === 1) { - topLevelDescribes.push(node); + return { + CallExpression(node) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + stack.push(node); } + }, - stack.pop(node); - } - }, - - 'Program:exit'() { - if (topLevelDescribes.length > suiteLimit) { - context.report({ - node: topLevelDescribes[suiteLimit], - message: `The number of top-level suites is more than ${ suiteLimit }.` - }); + 'CallExpression:exit'(node) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + if (stack.length === 1) { + topLevelDescribes.push(node); + } + + stack.pop(node); + } + }, + + 'Program:exit'() { + if (topLevelDescribes.length > suiteLimit) { + context.report({ + node: topLevelDescribes[suiteLimit], + message: `The number of top-level suites is more than ${ suiteLimit }.` + }); + } } - } - }; + }; + } }; diff --git a/lib/rules/no-exclusive-tests.js b/lib/rules/no-exclusive-tests.js index e635995..2125b41 100644 --- a/lib/rules/no-exclusive-tests.js +++ b/lib/rules/no-exclusive-tests.js @@ -3,62 +3,48 @@ const { getAdditionalTestFunctions } = require('../util/settings'); const astUtils = require('../util/ast'); -module.exports = function (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.indexOf(name) !== -1; - } - - function isPropertyNamedOnly(property) { - return property && astUtils.getPropertyName(property) === 'only'; - } - - function isCallToMochasOnlyFunction(callee) { - return callee.type === 'MemberExpression' && - matchesMochaTestFunction(callee.object) && - isPropertyNamedOnly(callee.property); - } +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.indexOf(name) !== -1; + } - return { - CallExpression(node) { - const callee = node.callee; + function isPropertyNamedOnly(property) { + return property && astUtils.getPropertyName(property) === 'only'; + } - if (callee && isCallToMochasOnlyFunction(callee)) { - context.report({ - node: callee.property, - message: 'Unexpected exclusive mocha test.' - }); - } + function isCallToMochasOnlyFunction(callee) { + return callee.type === 'MemberExpression' && + matchesMochaTestFunction(callee.object) && + isPropertyNamedOnly(callee.property); } - }; -}; -module.exports.schema = [ - { - type: 'object', - properties: { - additionalTestFunctions: { - type: 'array', - items: { - type: 'string' - }, - minItems: 1, - uniqueItems: true + return { + CallExpression(node) { + const callee = node.callee; + + if (callee && isCallToMochasOnlyFunction(callee)) { + context.report({ + node: callee.property, + message: 'Unexpected exclusive mocha test.' + }); + } } - } + }; } -]; +}; diff --git a/lib/rules/no-hooks-for-single-case.js b/lib/rules/no-hooks-for-single-case.js index 5abcdeb..8b663c3 100644 --- a/lib/rules/no-hooks-for-single-case.js +++ b/lib/rules/no-hooks-for-single-case.js @@ -11,67 +11,70 @@ function newDescribeLayer(describeNode) { }; } -module.exports = function (context) { - const options = context.options[0] || {}; - const allowedHooks = options.allow || []; - const settings = context.settings; - const layers = []; +module.exports = { + meta: { + schema: [ + { + type: 'object', + properties: { + allow: { + type: 'array', + items: { + type: 'string' + } + } + } + } + ] + }, + create(context) { + const options = context.options[0] || {}; + const allowedHooks = options.allow || []; + const settings = context.settings; + const layers = []; - function popLayer(node) { - const layer = layers[layers.length - 1]; - if (layer.describeNode === node) { - if (layer.testCount <= 1) { - layer.hookNodes - .filter(function (hookNode) { - return allowedHooks.indexOf(hookNode.name) === -1; - }) - .forEach(function (hookNode) { - context.report({ - node: hookNode, - message: `Unexpected use of Mocha \`${ hookNode.name }\` hook for a single test case` + function popLayer(node) { + const layer = layers[layers.length - 1]; + if (layer.describeNode === node) { + if (layer.testCount <= 1) { + layer.hookNodes + .filter(function (hookNode) { + return allowedHooks.indexOf(hookNode.name) === -1; + }) + .forEach(function (hookNode) { + context.report({ + node: hookNode, + message: `Unexpected use of Mocha \`${ hookNode.name }\` hook for a single test case` + }); }); - }); + } + layers.pop(); } - layers.pop(); } - } - return { - Program(node) { - layers.push(newDescribeLayer(node)); - }, - - CallExpression(node) { - if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { - layers[layers.length - 1].testCount += 1; + return { + Program(node) { layers.push(newDescribeLayer(node)); - return; - } - - if (astUtil.isTestCase(node)) { - layers[layers.length - 1].testCount += 1; - } + }, - if (astUtil.isHookIdentifier(node.callee)) { - layers[layers.length - 1].hookNodes.push(node.callee); - } - }, + CallExpression(node) { + if (astUtil.isDescribe(node, additionalSuiteNames(settings))) { + layers[layers.length - 1].testCount += 1; + layers.push(newDescribeLayer(node)); + return; + } - 'CallExpression:exit': popLayer, - 'Program:exit': popLayer - }; -}; + if (astUtil.isTestCase(node)) { + layers[layers.length - 1].testCount += 1; + } -module.exports.schema = [ - { - type: 'object', - properties: { - allow: { - type: 'array', - items: { - type: 'string' + if (astUtil.isHookIdentifier(node.callee)) { + layers[layers.length - 1].hookNodes.push(node.callee); } - } - } + }, + + 'CallExpression:exit': popLayer, + 'Program:exit': popLayer + }; } -]; +}; diff --git a/lib/rules/no-skipped-tests.js b/lib/rules/no-skipped-tests.js index 2183400..2c3fc2b 100644 --- a/lib/rules/no-skipped-tests.js +++ b/lib/rules/no-skipped-tests.js @@ -47,32 +47,6 @@ function isCallToMochaXFunction(callee) { } module.exports = { - meta: { - fixable: 'code', - schema: [ - { - type: 'object', - properties: { - additionalTestFunctions: { - type: 'array', - items: { - type: 'string' - }, - minItems: 1, - uniqueItems: true - }, - additionalXFunctions: { - type: 'array', - items: { - type: 'string' - }, - minItems: 1, - uniqueItems: true - } - } - } - ] - }, create(context) { const settings = context.settings; const additionalTestFunctions = getAdditionalTestFunctions(settings); diff --git a/lib/rules/no-synchronous-tests.js b/lib/rules/no-synchronous-tests.js index 80174fc..d8d5e36 100644 --- a/lib/rules/no-synchronous-tests.js +++ b/lib/rules/no-synchronous-tests.js @@ -35,56 +35,59 @@ function doesReturnPromise(functionExpression) { typeof returnStatement !== 'undefined'; } -module.exports = function (context) { - const options = context.options[0] || {}; - const allowedAsyncMethods = isNil(options.allowed) ? asyncMethods : options.allowed; - - function check(node) { - if (astUtil.hasParentMochaFunctionCall(node)) { - // For each allowed async test method, check if it is used in the test - const testAsyncMethods = allowedAsyncMethods.map(function (method) { - switch (method) { - case 'async': - return isAsyncFunction(node); - - case 'callback': - return hasAsyncCallback(node); - - default: - return doesReturnPromise(node); +module.exports = { + meta: { + schema: [ + { + type: 'object', + properties: { + allowed: { + type: 'array', + items: { + type: 'string', + enum: asyncMethods + }, + minItems: 1, + uniqueItems: true + } } - }); - - // Check that at least one allowed async test method is used in the test - const isAsyncTest = testAsyncMethods.some(function (value) { - return value === true; - }); - - if (!isAsyncTest) { - context.report(node, 'Unexpected synchronous test.'); } - } - } - - return { - FunctionExpression: check, - ArrowFunctionExpression: check - }; -}; - -module.exports.schema = [ - { - type: 'object', - properties: { - allowed: { - type: 'array', - items: { - type: 'string', - enum: asyncMethods - }, - minItems: 1, - uniqueItems: true + ] + }, + create(context) { + const options = context.options[0] || {}; + const allowedAsyncMethods = isNil(options.allowed) ? asyncMethods : options.allowed; + + function check(node) { + if (astUtil.hasParentMochaFunctionCall(node)) { + // For each allowed async test method, check if it is used in the test + const testAsyncMethods = allowedAsyncMethods.map(function (method) { + switch (method) { + case 'async': + return isAsyncFunction(node); + + case 'callback': + return hasAsyncCallback(node); + + default: + return doesReturnPromise(node); + } + }); + + // Check that at least one allowed async test method is used in the test + const isAsyncTest = testAsyncMethods.some(function (value) { + return value === true; + }); + + if (!isAsyncTest) { + context.report(node, 'Unexpected synchronous test.'); + } } } + + return { + FunctionExpression: check, + ArrowFunctionExpression: check + }; } -]; +}; diff --git a/lib/rules/valid-suite-description.js b/lib/rules/valid-suite-description.js index a23d0da..0e49cdc 100644 --- a/lib/rules/valid-suite-description.js +++ b/lib/rules/valid-suite-description.js @@ -24,44 +24,76 @@ function objectOptions(options) { return { pattern, suiteNames, message }; } -module.exports = function (context) { - const options = context.options[0]; +const patternSchema = { + type: 'string' +}; +const suiteNamesSchema = { + type: 'array', + items: { + type: 'string' + } +}; +const messageSchema = { + type: 'string' +}; - const { pattern, suiteNames, message } = typeof options === 'object' && !(options instanceof RegExp) ? - objectOptions(options) : - inlineOptions(context); +module.exports = { + meta: { + schema: [ + { + oneOf: [ patternSchema, { + type: 'object', + properties: { + pattern: patternSchema, + suiteNames: suiteNamesSchema, + message: messageSchema + }, + additionalProperties: false + } ] + }, + suiteNamesSchema, + messageSchema + ] + }, + create(context) { + const options = context.options[0]; + + const { pattern, suiteNames, message } = typeof options === 'object' && !(options instanceof RegExp) ? + objectOptions(options) : + inlineOptions(context); + + function isSuite(node) { + return node.callee && node.callee.name && suiteNames.indexOf(node.callee.name) > -1; + } - function isSuite(node) { - return node.callee && node.callee.name && suiteNames.indexOf(node.callee.name) > -1; - } + function hasValidSuiteDescription(mochaCallExpression) { + const args = mochaCallExpression.arguments; + const description = args[0]; - function hasValidSuiteDescription(mochaCallExpression) { - const args = mochaCallExpression.arguments; - const description = args[0]; + if (astUtils.isStringLiteral(description)) { + return pattern.test(description.value); + } - if (astUtils.isStringLiteral(description)) { - return pattern.test(description.value); + return true; } - return true; - } - - function hasValidOrNoSuiteDescription(mochaCallExpression) { - const args = mochaCallExpression.arguments; - const hasNoSuiteDescription = args.length === 0; + function hasValidOrNoSuiteDescription(mochaCallExpression) { + const args = mochaCallExpression.arguments; + const hasNoSuiteDescription = args.length === 0; - return hasNoSuiteDescription || hasValidSuiteDescription(mochaCallExpression); - } + return hasNoSuiteDescription || hasValidSuiteDescription(mochaCallExpression); + } - return { - CallExpression(node) { - const callee = node.callee; + return { + CallExpression(node) { + const callee = node.callee; - if (isSuite(node)) { - if (!hasValidOrNoSuiteDescription(node)) { - context.report(node, message || `Invalid "${ callee.name }()" description found.`); + if (isSuite(node)) { + if (!hasValidOrNoSuiteDescription(node)) { + context.report(node, message || `Invalid "${ callee.name }()" description found.`); + } } } - } - }; + }; + } }; diff --git a/lib/rules/valid-test-description.js b/lib/rules/valid-test-description.js index 42a97a9..daa68dc 100644 --- a/lib/rules/valid-test-description.js +++ b/lib/rules/valid-test-description.js @@ -25,44 +25,76 @@ function objectOptions(options) { return { pattern, testNames, message }; } -module.exports = function (context) { - const options = context.options[0]; +const patternSchema = { + type: 'string' +}; +const testNamesSchema = { + type: 'array', + items: { + type: 'string' + } +}; +const messageSchema = { + type: 'string' +}; - const { pattern, testNames, message } = typeof options === 'object' && !(options instanceof RegExp) ? - objectOptions(options) : - inlineOptions(context); +module.exports = { + meta: { + schema: [ + { + oneOf: [ patternSchema, { + type: 'object', + properties: { + pattern: patternSchema, + testNames: testNamesSchema, + message: messageSchema + }, + additionalProperties: false + } ] + }, + testNamesSchema, + messageSchema + ] + }, + create(context) { + const options = context.options[0]; + + const { pattern, testNames, message } = typeof options === 'object' && !(options instanceof RegExp) ? + objectOptions(options) : + inlineOptions(context); + + function isTest(node) { + return node.callee && node.callee.name && testNames.indexOf(node.callee.name) > -1; + } - function isTest(node) { - return node.callee && node.callee.name && testNames.indexOf(node.callee.name) > -1; - } + function hasValidTestDescription(mochaCallExpression) { + const args = mochaCallExpression.arguments; + const testDescriptionArgument = args[0]; - function hasValidTestDescription(mochaCallExpression) { - const args = mochaCallExpression.arguments; - const testDescriptionArgument = args[0]; + if (astUtils.isStringLiteral(testDescriptionArgument)) { + return pattern.test(testDescriptionArgument.value); + } - if (astUtils.isStringLiteral(testDescriptionArgument)) { - return pattern.test(testDescriptionArgument.value); + return true; } - return true; - } - - function hasValidOrNoTestDescription(mochaCallExpression) { - const args = mochaCallExpression.arguments; - const hasNoTestDescription = args.length === 0; + function hasValidOrNoTestDescription(mochaCallExpression) { + const args = mochaCallExpression.arguments; + const hasNoTestDescription = args.length === 0; - return hasNoTestDescription || hasValidTestDescription(mochaCallExpression); - } + return hasNoTestDescription || hasValidTestDescription(mochaCallExpression); + } - return { - CallExpression(node) { - const callee = node.callee; + return { + CallExpression(node) { + const callee = node.callee; - if (isTest(node)) { - if (!hasValidOrNoTestDescription(node)) { - context.report(node, message || `Invalid "${ callee.name }()" description found.`); + if (isTest(node)) { + if (!hasValidOrNoTestDescription(node)) { + context.report(node, message || `Invalid "${ callee.name }()" description found.`); + } } } - } - }; + }; + } }; diff --git a/test/rules/valid-suite-description.js b/test/rules/valid-suite-description.js index 5cd7a74..9dece9a 100644 --- a/test/rules/valid-suite-description.js +++ b/test/rules/valid-suite-description.js @@ -38,10 +38,12 @@ ruleTester.run('valid-suite-description', rules['valid-suite-description'], { options: [ { pattern: '^[A-Z]', suiteNames: [ 'someFunction' ], message: 'some error message' } ], code: 'someFunction("Should do something", function () { });' }, + /* { options: [ { pattern: /^[A-Z]/, suiteNames: [ 'someFunction' ], message: 'some error message' } ], code: 'someFunction("Should do something", function () { });' }, + */ { options: [ {} ], code: 'someFunction("Should do something", function () { });' diff --git a/test/rules/valid-test-description.js b/test/rules/valid-test-description.js index 6e088af..d3a137d 100644 --- a/test/rules/valid-test-description.js +++ b/test/rules/valid-test-description.js @@ -43,10 +43,12 @@ ruleTester.run('valid-test-description', rules['valid-test-description'], { options: [ { pattern: '^should', testNames: [ 'someFunction' ], message: 'some error message' } ], code: 'someFunction("should do something", function () { });' }, + /* { options: [ { pattern: /^should/, testNames: [ 'someFunction' ], message: 'some error message' } ], code: 'someFunction("should do something", function () { });' }, + */ 'someOtherFunction();', { parserOptions: { ecmaVersion: 2017 },