UNPKG

eslint-plugin-mocha

Version:
187 lines (149 loc) 5.22 kB
'use strict'; const { complement, both, isNil, propEq, pathEq, find } = require('rambda'); const { getTestCaseNames, getSuiteNames } = require('./names'); const { getAddtionalNames } = require('./settings'); const isDefined = complement(isNil); const isCallExpression = both(isDefined, propEq('type', 'CallExpression')); const hooks = [ 'before', 'after', 'beforeEach', 'afterEach', 'beforeAll', 'afterAll', 'setup', 'teardown', 'suiteSetup', 'suiteTeardown' ]; const suiteConfig = [ 'timeout', 'slow', 'retries' ]; const findReturnStatement = find(propEq('type', 'ReturnStatement')); function getPropertyName(property) { return property.name || property.value; } function getNodeName(node) { if (node.type === 'ThisExpression') { return 'this'; } if (node.type === 'CallExpression') { return `${getNodeName(node.callee)}()`; } if (node.type === 'MemberExpression') { return `${getNodeName(node.object)}.${getPropertyName(node.property)}`; } return node.name; } function isHookIdentifier(node) { return node && node.type === 'Identifier' && hooks.includes(node.name); } function isHookCall(node) { return isCallExpression(node) && isHookIdentifier(node.callee); } function findReference(scope, node) { const hasSameRangeAsNode = pathEq([ 'identifier', 'range' ], node.range); return find(hasSameRangeAsNode, scope.references); } function isShadowed(scope, identifier) { const reference = findReference(scope, identifier); return ( reference && reference.resolved && reference.resolved.defs.length > 0 ); } function isCallToShadowedReference(node, scope) { const identifier = node.callee.type === 'MemberExpression' ? node.callee.object : node.callee; return isShadowed(scope, identifier); } function isFunctionCallWithName(node, names) { return isCallExpression(node) && names.includes(getNodeName(node.callee)); } // eslint-disable-next-line max-statements function createAstUtils(settings) { const additionalCustomNames = getAddtionalNames(settings); function buildIsDescribeAnswerer(options = {}) { const { modifiers = [ 'skip', 'only' ], modifiersOnly = false } = options; const describeAliases = getSuiteNames({ modifiersOnly, modifiers, additionalCustomNames }); return (node) => isFunctionCallWithName(node, describeAliases); } function isDescribe(node, options = {}) { return buildIsDescribeAnswerer(options)(node); } function buildIsTestCaseAnswerer(options = {}) { const { modifiers = [ 'skip', 'only' ], modifiersOnly = false } = options; const testCaseNames = getTestCaseNames({ modifiersOnly, modifiers, additionalCustomNames }); return (node) => isFunctionCallWithName(node, testCaseNames); } function isTestCase(node, options = {}) { return buildIsTestCaseAnswerer(options)(node); } 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 buildIsMochaFunctionCallAnswerer(_isTestCase, _isDescribe) { function isMochaFunctionCall(node) { return _isTestCase(node) || _isDescribe(node) || isHookCall(node); } return (node, context) => { const { sourceCode = {} } = context; if (isMochaFunctionCall(node)) { const scope = typeof sourceCode.getScope !== 'undefined' ? sourceCode.getScope(node) : context.getScope(); if (!isCallToShadowedReference(node, scope)) { return true; } } return false; }; } function hasParentMochaFunctionCall(functionExpression, options) { return ( isTestCase(functionExpression.parent, options) || isHookCall(functionExpression.parent) ); } function isExplicitUndefined(node) { return node && node.type === 'Identifier' && node.name === 'undefined'; } function isReturnOfUndefined(node) { const argument = node.argument; const isImplicitUndefined = argument === null; return isImplicitUndefined || isExplicitUndefined(argument); } return { isDescribe, isHookIdentifier, isTestCase, getPropertyName, getNodeName, isHookCall, isSuiteConfigCall, hasParentMochaFunctionCall, findReturnStatement, isReturnOfUndefined, buildIsDescribeAnswerer, buildIsTestCaseAnswerer, buildIsMochaFunctionCallAnswerer }; } module.exports = createAstUtils;