2020-03-07 11:45:40 +08:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
|
|
value: true
|
|
|
|
});
|
|
|
|
exports.default = void 0;
|
|
|
|
|
|
|
|
var _experimentalUtils = require("@typescript-eslint/experimental-utils");
|
|
|
|
|
|
|
|
var _utils = require("./utils");
|
|
|
|
|
2020-03-31 20:40:00 +08:00
|
|
|
const trimFXprefix = word => ['f', 'x'].includes(word.charAt(0)) ? word.substr(1) : word;
|
2020-03-07 11:45:40 +08:00
|
|
|
|
2020-03-31 20:40:00 +08:00
|
|
|
const doesBinaryExpressionContainStringNode = binaryExp => {
|
|
|
|
if ((0, _utils.isStringNode)(binaryExp.right)) {
|
|
|
|
return true;
|
|
|
|
}
|
2020-03-07 11:45:40 +08:00
|
|
|
|
2020-03-31 20:40:00 +08:00
|
|
|
if (binaryExp.left.type === _experimentalUtils.AST_NODE_TYPES.BinaryExpression) {
|
|
|
|
return doesBinaryExpressionContainStringNode(binaryExp.left);
|
|
|
|
}
|
2020-03-07 11:45:40 +08:00
|
|
|
|
2020-03-31 20:40:00 +08:00
|
|
|
return (0, _utils.isStringNode)(binaryExp.left);
|
|
|
|
};
|
2020-03-07 11:45:40 +08:00
|
|
|
|
2020-03-31 20:40:00 +08:00
|
|
|
const quoteStringValue = node => node.type === _experimentalUtils.AST_NODE_TYPES.TemplateLiteral ? `\`${node.quasis[0].value.raw}\`` : node.raw;
|
2020-03-07 11:45:40 +08:00
|
|
|
|
|
|
|
var _default = (0, _utils.createRule)({
|
|
|
|
name: __filename,
|
|
|
|
meta: {
|
|
|
|
docs: {
|
|
|
|
category: 'Best Practices',
|
|
|
|
description: 'Enforce valid titles',
|
|
|
|
recommended: false
|
|
|
|
},
|
|
|
|
messages: {
|
2020-03-31 20:40:00 +08:00
|
|
|
titleMustBeString: 'Title must be a string',
|
|
|
|
emptyTitle: '{{ jestFunctionName }} should not have an empty title',
|
2020-03-07 11:45:40 +08:00
|
|
|
duplicatePrefix: 'should not have duplicate prefix',
|
2020-03-31 20:40:00 +08:00
|
|
|
accidentalSpace: 'should not have leading or trailing spaces',
|
|
|
|
disallowedWord: '"{{ word }}" is not allowed in test titles.'
|
2020-03-07 11:45:40 +08:00
|
|
|
},
|
|
|
|
type: 'suggestion',
|
2020-03-31 20:40:00 +08:00
|
|
|
schema: [{
|
|
|
|
type: 'object',
|
|
|
|
properties: {
|
|
|
|
ignoreTypeOfDescribeName: {
|
|
|
|
type: 'boolean',
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
disallowedWords: {
|
|
|
|
type: 'array',
|
|
|
|
items: {
|
|
|
|
type: 'string'
|
|
|
|
},
|
|
|
|
default: []
|
|
|
|
}
|
|
|
|
},
|
|
|
|
additionalProperties: false
|
|
|
|
}],
|
2020-03-07 11:45:40 +08:00
|
|
|
fixable: 'code'
|
|
|
|
},
|
2020-03-31 20:40:00 +08:00
|
|
|
defaultOptions: [{
|
|
|
|
ignoreTypeOfDescribeName: false,
|
|
|
|
disallowedWords: []
|
|
|
|
}],
|
|
|
|
|
|
|
|
create(context, [{
|
|
|
|
ignoreTypeOfDescribeName,
|
|
|
|
disallowedWords
|
|
|
|
}]) {
|
|
|
|
const disallowedWordsRegexp = new RegExp(`\\b(${disallowedWords.join('|')})\\b`, 'iu');
|
2020-03-07 11:45:40 +08:00
|
|
|
return {
|
|
|
|
CallExpression(node) {
|
2020-03-31 20:40:00 +08:00
|
|
|
if (!(0, _utils.isDescribe)(node) && !(0, _utils.isTestCase)(node)) {
|
2020-03-07 11:45:40 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-31 20:40:00 +08:00
|
|
|
const [argument] = (0, _utils.getJestFunctionArguments)(node);
|
|
|
|
|
|
|
|
if (!argument) {
|
|
|
|
return;
|
|
|
|
}
|
2020-03-07 11:45:40 +08:00
|
|
|
|
|
|
|
if (!(0, _utils.isStringNode)(argument)) {
|
2020-03-31 20:40:00 +08:00
|
|
|
if (argument.type === _experimentalUtils.AST_NODE_TYPES.BinaryExpression && doesBinaryExpressionContainStringNode(argument)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argument.type !== _experimentalUtils.AST_NODE_TYPES.TemplateLiteral && !(ignoreTypeOfDescribeName && (0, _utils.isDescribe)(node))) {
|
|
|
|
context.report({
|
|
|
|
messageId: 'titleMustBeString',
|
|
|
|
loc: argument.loc
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-03-07 11:45:40 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const title = (0, _utils.getStringValue)(argument);
|
|
|
|
|
|
|
|
if (!title) {
|
2020-03-31 20:40:00 +08:00
|
|
|
context.report({
|
|
|
|
messageId: 'emptyTitle',
|
|
|
|
data: {
|
|
|
|
jestFunctionName: (0, _utils.isDescribe)(node) ? _utils.DescribeAlias.describe : _utils.TestCaseName.test
|
|
|
|
},
|
|
|
|
node
|
|
|
|
});
|
2020-03-07 11:45:40 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-31 20:40:00 +08:00
|
|
|
if (disallowedWords.length > 0) {
|
|
|
|
const disallowedMatch = disallowedWordsRegexp.exec(title);
|
|
|
|
|
|
|
|
if (disallowedMatch) {
|
|
|
|
context.report({
|
|
|
|
data: {
|
|
|
|
word: disallowedMatch[1]
|
|
|
|
},
|
|
|
|
messageId: 'disallowedWord',
|
|
|
|
node: argument
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-07 11:45:40 +08:00
|
|
|
if (title.trim().length !== title.length) {
|
|
|
|
context.report({
|
|
|
|
messageId: 'accidentalSpace',
|
|
|
|
node: argument,
|
2020-03-31 20:40:00 +08:00
|
|
|
fix: fixer => [fixer.replaceTextRange(argument.range, quoteStringValue(argument).replace(/^([`'"]) +?/u, '$1').replace(/ +?([`'"])$/u, '$1'))]
|
2020-03-07 11:45:40 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
const nodeName = trimFXprefix((0, _utils.getNodeName)(node.callee));
|
2020-03-31 20:40:00 +08:00
|
|
|
const [firstWord] = title.split(' ');
|
2020-03-07 11:45:40 +08:00
|
|
|
|
|
|
|
if (firstWord.toLowerCase() === nodeName) {
|
|
|
|
context.report({
|
|
|
|
messageId: 'duplicatePrefix',
|
|
|
|
node: argument,
|
2020-03-31 20:40:00 +08:00
|
|
|
fix: fixer => [fixer.replaceTextRange(argument.range, quoteStringValue(argument).replace(/^([`'"]).+? /u, '$1'))]
|
2020-03-07 11:45:40 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
exports.default = _default;
|