You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

139 lines
4.1 KiB

'use strict';
const complement = require('ramda/src/complement');
const both = require('ramda/src/both');
const isNil = require('ramda/src/isNil');
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'));
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 === '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));
}
function createAstUtils(settings) {
const additionalCustomNames = getAddtionalNames(settings);
function isDescribe(node, options = {}) {
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' ], modifiersOnly = false } = options;
const testCaseNames = getTestCaseNames({ modifiersOnly, modifiers, additionalCustomNames });
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;
}
function isSuiteConfigCall(node) {
return isCallExpression(node) && isSuiteConfigExpression(node.callee);
}
function isMochaFunctionCall(node, scope) {
if (isCallToShadowedReference(node, scope)) {
return false;
}
return isTestCase(node) || isDescribe(node) || isHookCall(node);
}
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,
isMochaFunctionCall,
isHookCall,
isSuiteConfigCall,
hasParentMochaFunctionCall,
findReturnStatement,
isReturnOfUndefined
};
}
module.exports = createAstUtils;