eslint-plugin-jest
Advanced tools
Comparing version 27.1.2 to 27.1.3
"use strict"; | ||
var _fs = require("fs"); | ||
var _path = require("path"); | ||
var _globals = _interopRequireDefault(require("./globals.json")); | ||
var snapshotProcessor = _interopRequireWildcard(require("./processors/snapshot-processor")); | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
// copied from https://github.com/babel/babel/blob/d8da63c929f2d28c401571e2a43166678c555bc4/packages/babel-helpers/src/helpers.js#L602-L606 | ||
/* istanbul ignore next */ | ||
@@ -23,18 +15,19 @@ const interopRequireDefault = obj => obj && obj.__esModule ? obj : { | ||
}; | ||
const importDefault = moduleName => // eslint-disable-next-line @typescript-eslint/no-require-imports | ||
const importDefault = moduleName => | ||
// eslint-disable-next-line @typescript-eslint/no-require-imports | ||
interopRequireDefault(require(moduleName)).default; | ||
const rulesDir = (0, _path.join)(__dirname, 'rules'); | ||
const excludedFiles = ['__tests__', 'detectJestVersion', 'utils']; | ||
const rules = (0, _fs.readdirSync)(rulesDir).map(rule => (0, _path.parse)(rule).name).filter(rule => !excludedFiles.includes(rule)).reduce((acc, curr) => ({ ...acc, | ||
const rules = (0, _fs.readdirSync)(rulesDir).map(rule => (0, _path.parse)(rule).name).filter(rule => !excludedFiles.includes(rule)).reduce((acc, curr) => ({ | ||
...acc, | ||
[curr]: importDefault((0, _path.join)(rulesDir, curr)) | ||
}), {}); | ||
const recommendedRules = Object.entries(rules).filter(([, rule]) => rule.meta.docs.recommended).reduce((acc, [name, rule]) => ({ ...acc, | ||
const recommendedRules = Object.entries(rules).filter(([, rule]) => rule.meta.docs.recommended).reduce((acc, [name, rule]) => ({ | ||
...acc, | ||
[`jest/${name}`]: rule.meta.docs.recommended | ||
}), {}); | ||
const allRules = Object.entries(rules).filter(([, rule]) => !rule.meta.deprecated).reduce((acc, [name]) => ({ ...acc, | ||
const allRules = Object.entries(rules).filter(([, rule]) => !rule.meta.deprecated).reduce((acc, [name]) => ({ | ||
...acc, | ||
[`jest/${name}`]: 'error' | ||
}), {}); | ||
const createConfig = rules => ({ | ||
@@ -47,3 +40,2 @@ plugins: ['jest'], | ||
}); | ||
module.exports = { | ||
@@ -50,0 +42,0 @@ configs: { |
@@ -7,12 +7,10 @@ "use strict"; | ||
exports.preprocess = exports.postprocess = void 0; | ||
// https://eslint.org/docs/developer-guide/working-with-plugins#processors-in-plugins | ||
// https://github.com/typescript-eslint/typescript-eslint/issues/808 | ||
const preprocess = source => [source]; | ||
exports.preprocess = preprocess; | ||
const postprocess = messages => // snapshot files should only be linted with snapshot specific rules | ||
const postprocess = messages => | ||
// snapshot files should only be linted with snapshot specific rules | ||
messages[0].filter(message => message.ruleId === 'jest/no-large-snapshots'); | ||
exports.postprocess = postprocess; |
@@ -7,9 +7,5 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const buildFixer = (callee, nodeName, preferredTestKeyword) => fixer => [fixer.replaceText(callee.type === _utils.AST_NODE_TYPES.MemberExpression ? callee.object : callee, getPreferredNodeName(nodeName, preferredTestKeyword))]; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -46,3 +42,2 @@ name: __filename, | ||
}], | ||
create(context) { | ||
@@ -56,7 +51,5 @@ const configObj = context.options[0] || {}; | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if (!jestFnCall) { | ||
return; | ||
} | ||
if (jestFnCall.type === 'describe') { | ||
@@ -66,5 +59,3 @@ describeNestingLevel++; | ||
} | ||
const funcNode = node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression ? node.callee.tag : node.callee.type === _utils.AST_NODE_TYPES.CallExpression ? node.callee.callee : node.callee; | ||
if (jestFnCall.type === 'test' && describeNestingLevel === 0 && !jestFnCall.name.endsWith(testKeyword)) { | ||
@@ -82,3 +73,2 @@ const oppositeTestKeyword = getOppositeTestKeyword(testKeyword); | ||
} | ||
if (jestFnCall.type === 'test' && describeNestingLevel > 0 && !jestFnCall.name.endsWith(testKeywordWithinDescribe)) { | ||
@@ -97,3 +87,2 @@ const oppositeTestKeyword = getOppositeTestKeyword(testKeywordWithinDescribe); | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -104,10 +93,6 @@ if ((0, _utils2.isTypeOfJestFnCall)(node, context, ['describe'])) { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; | ||
function getPreferredNodeName(nodeName, preferredTestKeyword) { | ||
@@ -117,6 +102,4 @@ if (nodeName === _utils2.TestCaseName.fit) { | ||
} | ||
return nodeName.startsWith('f') || nodeName.startsWith('x') ? nodeName.charAt(0) + preferredTestKeyword : preferredTestKeyword; | ||
} | ||
function getOppositeTestKeyword(test) { | ||
@@ -126,4 +109,3 @@ if (test === _utils2.TestCaseName.test) { | ||
} | ||
return _utils2.TestCaseName.test; | ||
} |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
/* | ||
@@ -31,3 +28,2 @@ * This implementation is adapted from eslint-plugin-jasmine. | ||
} | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -68,3 +64,2 @@ name: __filename, | ||
}], | ||
create(context, [{ | ||
@@ -75,7 +70,5 @@ assertFunctionNames = ['expect'], | ||
const unchecked = []; | ||
function checkCallExpressionUsed(nodes) { | ||
for (const node of nodes) { | ||
const index = node.type === _utils.AST_NODE_TYPES.CallExpression ? unchecked.indexOf(node) : -1; | ||
if (node.type === _utils.AST_NODE_TYPES.FunctionDeclaration) { | ||
@@ -86,3 +79,2 @@ const declaredVariables = context.getDeclaredVariables(node); | ||
} | ||
if (index !== -1) { | ||
@@ -94,7 +86,5 @@ unchecked.splice(index, 1); | ||
} | ||
return { | ||
CallExpression(node) { | ||
const name = (0, _utils2.getNodeName)(node.callee) ?? ''; | ||
if ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test']) || additionalTestBlockFunctions.includes(name)) { | ||
@@ -104,3 +94,2 @@ if (node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property, 'todo')) { | ||
} | ||
unchecked.push(node); | ||
@@ -112,3 +101,2 @@ } else if (matchesAssertFunctionName(name, assertFunctionNames)) { | ||
}, | ||
'Program:exit'() { | ||
@@ -120,8 +108,5 @@ unchecked.forEach(node => context.report({ | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -39,3 +36,2 @@ name: __filename, | ||
}], | ||
create(context, [{ | ||
@@ -45,8 +41,5 @@ max | ||
let count = 0; | ||
const maybeResetCount = node => { | ||
var _node$parent; | ||
const isTestFn = ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) !== _utils.AST_NODE_TYPES.CallExpression || (0, _utils2.isTypeOfJestFnCall)(node.parent, context, ['test']); | ||
if (isTestFn) { | ||
@@ -56,3 +49,2 @@ count = 0; | ||
}; | ||
return { | ||
@@ -63,14 +55,9 @@ FunctionExpression: maybeResetCount, | ||
'ArrowFunctionExpression:exit': maybeResetCount, | ||
CallExpression(node) { | ||
var _jestFnCall$head$node; | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || ((_jestFnCall$head$node = jestFnCall.head.node.parent) === null || _jestFnCall$head$node === void 0 ? void 0 : _jestFnCall$head$node.type) === _utils.AST_NODE_TYPES.MemberExpression) { | ||
return; | ||
} | ||
count += 1; | ||
if (count > max) { | ||
@@ -87,8 +74,5 @@ context.report({ | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -39,3 +36,2 @@ name: __filename, | ||
}], | ||
create(context, [{ | ||
@@ -45,3 +41,2 @@ max | ||
const describeCallbackStack = []; | ||
function pushDescribeCallback(node) { | ||
@@ -51,9 +46,6 @@ const { | ||
} = node; | ||
if ((parent === null || parent === void 0 ? void 0 : parent.type) !== _utils.AST_NODE_TYPES.CallExpression || !(0, _utils2.isTypeOfJestFnCall)(parent, context, ['describe'])) { | ||
return; | ||
} | ||
describeCallbackStack.push(0); | ||
if (describeCallbackStack.length > max) { | ||
@@ -70,3 +62,2 @@ context.report({ | ||
} | ||
function popDescribeCallback(node) { | ||
@@ -76,3 +67,2 @@ const { | ||
} = node; | ||
if ((parent === null || parent === void 0 ? void 0 : parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTypeOfJestFnCall)(parent, context, ['describe'])) { | ||
@@ -82,3 +72,2 @@ describeCallbackStack.pop(); | ||
} | ||
return { | ||
@@ -91,5 +80,3 @@ FunctionExpression: pushDescribeCallback, | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -27,3 +25,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -47,7 +44,5 @@ // map of jest matcher aliases & their canonical names | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
const { | ||
@@ -57,3 +52,2 @@ matcher | ||
const alias = (0, _utils.getAccessorValue)(matcher); | ||
if (alias in methodNames) { | ||
@@ -72,8 +66,5 @@ const canonical = methodNames[alias]; | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,9 +7,6 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
function hasTests(node) { | ||
return /^\s*[xf]?(test|it|describe)(\.\w+|\[['"]\w+['"]\])?\s*\(/mu.test(node.value); | ||
} | ||
var _default = (0, _utils.createRule)({ | ||
@@ -30,6 +27,4 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
const sourceCode = context.getSourceCode(); | ||
function checkNode(node) { | ||
@@ -39,3 +34,2 @@ if (!hasTests(node)) { | ||
} | ||
context.report({ | ||
@@ -46,3 +40,2 @@ messageId: 'commentedTests', | ||
} | ||
return { | ||
@@ -53,8 +46,5 @@ Program() { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,9 +7,5 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const isCatchCall = node => node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property, 'catch'); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -30,3 +26,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -36,7 +31,4 @@ let conditionalDepth = 0; | ||
let inPromiseCatch = false; | ||
const increaseConditionalDepth = () => inTestCase && conditionalDepth++; | ||
const decreaseConditionalDepth = () => inTestCase && conditionalDepth--; | ||
return { | ||
@@ -46,3 +38,2 @@ FunctionDeclaration(node) { | ||
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context); | ||
if (testCallExpressions.length > 0) { | ||
@@ -52,3 +43,2 @@ inTestCase = true; | ||
}, | ||
CallExpression(node) { | ||
@@ -58,11 +48,8 @@ const { | ||
} = (0, _utils2.parseJestFnCall)(node, context) ?? {}; | ||
if (jestFnCallType === 'test') { | ||
inTestCase = true; | ||
} | ||
if (isCatchCall(node)) { | ||
inPromiseCatch = true; | ||
} | ||
if (inTestCase && jestFnCallType === 'expect' && conditionalDepth > 0) { | ||
@@ -74,3 +61,2 @@ context.report({ | ||
} | ||
if (inPromiseCatch && jestFnCallType === 'expect') { | ||
@@ -83,3 +69,2 @@ context.report({ | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -89,3 +74,2 @@ if ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) { | ||
} | ||
if (isCatchCall(node)) { | ||
@@ -95,3 +79,2 @@ inPromiseCatch = false; | ||
}, | ||
CatchClause: increaseConditionalDepth, | ||
@@ -109,5 +92,3 @@ 'CatchClause:exit': decreaseConditionalDepth, | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -26,6 +24,4 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
let inTestCase = false; | ||
const maybeReportConditional = node => { | ||
@@ -39,3 +35,2 @@ if (inTestCase) { | ||
}; | ||
return { | ||
@@ -47,3 +42,2 @@ CallExpression(node) { | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -54,3 +48,2 @@ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['test'])) { | ||
}, | ||
IfStatement: maybeReportConditional, | ||
@@ -62,5 +55,3 @@ SwitchStatement: maybeReportConditional, | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const parseJestVersion = rawVersion => { | ||
@@ -17,7 +14,5 @@ if (typeof rawVersion === 'number') { | ||
} | ||
const [majorVersion] = rawVersion.split('.'); | ||
return parseInt(majorVersion, 10); | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -39,8 +34,7 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
var _context$settings, _context$settings$jes; | ||
const jestVersion = parseJestVersion(((_context$settings = context.settings) === null || _context$settings === void 0 ? void 0 : (_context$settings$jes = _context$settings.jest) === null || _context$settings$jes === void 0 ? void 0 : _context$settings$jes.version) || (0, _utils2.detectJestVersion)()); | ||
const deprecations = { ...(jestVersion >= 15 && { | ||
const deprecations = { | ||
...(jestVersion >= 15 && { | ||
'jest.resetModuleRegistry': 'jest.resetModules' | ||
@@ -67,9 +61,6 @@ }), | ||
} | ||
const deprecation = (0, _utils2.getNodeName)(node); | ||
if (!deprecation || !(deprecation in deprecations)) { | ||
return; | ||
} | ||
const replacement = deprecations[deprecation]; | ||
@@ -86,21 +77,14 @@ const { | ||
node, | ||
fix(fixer) { | ||
let [name, func] = replacement.split('.'); | ||
if (callee.property.type === _utils.AST_NODE_TYPES.Literal) { | ||
func = `'${func}'`; | ||
} | ||
return [fixer.replaceText(callee.object, name), fixer.replaceText(callee.property, func)]; | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -31,3 +29,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -39,14 +36,10 @@ let suiteDepth = 0; | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if (!jestFnCall) { | ||
return; | ||
} | ||
if (jestFnCall.type === 'describe') { | ||
suiteDepth++; | ||
} | ||
if (jestFnCall.type === 'test') { | ||
testDepth++; | ||
if (node.arguments.length < 2 && jestFnCall.members.every(s => (0, _utils.getAccessorValue)(s) !== 'todo')) { | ||
@@ -59,4 +52,4 @@ context.report({ | ||
} | ||
if ( // the only jest functions that are with "x" are "xdescribe", "xtest", and "xit" | ||
if ( | ||
// the only jest functions that are with "x" are "xdescribe", "xtest", and "xit" | ||
jestFnCall.name.startsWith('x') || jestFnCall.members.some(s => (0, _utils.getAccessorValue)(s) === 'skip')) { | ||
@@ -69,14 +62,10 @@ context.report({ | ||
}, | ||
'CallExpression:exit'(node) { | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if (!jestFnCall) { | ||
return; | ||
} | ||
if (jestFnCall.type === 'describe') { | ||
suiteDepth--; | ||
} | ||
if (jestFnCall.type === 'test') { | ||
@@ -86,3 +75,2 @@ testDepth--; | ||
}, | ||
'CallExpression[callee.name="pending"]'(node) { | ||
@@ -92,3 +80,2 @@ if ((0, _utils.scopeHasLocalReference)(context.getScope(), 'pending')) { | ||
} | ||
if (testDepth > 0) { | ||
@@ -111,8 +98,5 @@ context.report({ | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const findCallbackArg = (node, isJestEach, context) => { | ||
@@ -17,16 +14,11 @@ if (isJestEach) { | ||
} | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'hook' && node.arguments.length >= 1) { | ||
return node.arguments[0]; | ||
} | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test' && node.arguments.length >= 2) { | ||
return node.arguments[1]; | ||
} | ||
return null; | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -50,3 +42,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -56,6 +47,4 @@ return { | ||
var _getNodeName; | ||
// done is the second argument for it.each, not the first | ||
const isJestEach = ((_getNodeName = (0, _utils2.getNodeName)(node.callee)) === null || _getNodeName === void 0 ? void 0 : _getNodeName.endsWith('.each')) ?? false; | ||
if (isJestEach && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) { | ||
@@ -67,12 +56,8 @@ // isJestEach but not a TaggedTemplateExpression, so this must be | ||
} | ||
const callback = findCallbackArg(node, isJestEach, context); | ||
const callbackArgIndex = Number(isJestEach); | ||
if (!callback || !(0, _utils2.isFunction)(callback) || callback.params.length !== 1 + callbackArgIndex) { | ||
return; | ||
} | ||
const argument = callback.params[callbackArgIndex]; | ||
if (argument.type !== _utils.AST_NODE_TYPES.Identifier) { | ||
@@ -85,3 +70,2 @@ context.report({ | ||
} | ||
if (callback.async) { | ||
@@ -94,3 +78,2 @@ context.report({ | ||
} | ||
context.report({ | ||
@@ -104,3 +87,2 @@ node: argument, | ||
}, | ||
fix(fixer) { | ||
@@ -115,25 +97,19 @@ const { | ||
const tokenAfterArgument = sourceCode.getTokenAfter(argument); | ||
/* istanbul ignore if */ | ||
if (!firstBodyToken || !lastBodyToken || !tokenBeforeArgument || !tokenAfterArgument) { | ||
throw new Error(`Unexpected null when attempting to fix ${context.getFilename()} - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`); | ||
} | ||
const argumentInParens = tokenBeforeArgument.value === '(' && tokenAfterArgument.value === ')'; | ||
let argumentFix = fixer.replaceText(argument, '()'); | ||
if (argumentInParens) { | ||
argumentFix = fixer.remove(argument); | ||
} | ||
let newCallback = argument.name; | ||
if (argumentInParens) { | ||
newCallback = `(${newCallback})`; | ||
} | ||
let beforeReplacement = `new Promise(${newCallback} => `; | ||
let afterReplacement = ')'; | ||
let replaceBefore = true; | ||
if (body.type === _utils.AST_NODE_TYPES.BlockStatement) { | ||
@@ -145,15 +121,10 @@ const keyword = 'return'; | ||
} | ||
return [argumentFix, replaceBefore ? fixer.insertTextBefore(firstBodyToken, beforeReplacement) : fixer.insertTextAfter(firstBodyToken, beforeReplacement), fixer.insertTextAfter(lastBodyToken, afterReplacement)]; | ||
} | ||
}] | ||
}); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -26,3 +24,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -33,17 +30,12 @@ const hookContexts = [{}]; | ||
var _jestFnCall$name; | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'describe') { | ||
hookContexts.push({}); | ||
} | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'hook') { | ||
return; | ||
} | ||
const currentLayer = hookContexts[hookContexts.length - 1]; | ||
currentLayer[_jestFnCall$name = jestFnCall.name] || (currentLayer[_jestFnCall$name] = 0); | ||
currentLayer[jestFnCall.name] += 1; | ||
if (currentLayer[jestFnCall.name] > 1) { | ||
@@ -59,3 +51,2 @@ context.report({ | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -66,8 +57,5 @@ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -28,3 +25,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -44,3 +40,2 @@ const exportNodes = []; | ||
}, | ||
CallExpression(node) { | ||
@@ -51,7 +46,5 @@ if ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) { | ||
}, | ||
'ExportNamedDeclaration, ExportDefaultDeclaration'(node) { | ||
exportNodes.push(node); | ||
}, | ||
'AssignmentExpression > MemberExpression'(node) { | ||
@@ -62,3 +55,2 @@ let { | ||
} = node; | ||
if (object.type === _utils.AST_NODE_TYPES.MemberExpression) { | ||
@@ -70,3 +62,2 @@ ({ | ||
} | ||
if ('name' in object && object.name === 'module' && property.type === _utils.AST_NODE_TYPES.Identifier && /^exports?$/u.test(property.name)) { | ||
@@ -76,8 +67,5 @@ exportNodes.push(node); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -30,3 +27,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -36,7 +32,5 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test' && (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe') { | ||
return; | ||
} | ||
if (jestFnCall.name.startsWith('f')) { | ||
@@ -48,3 +42,2 @@ context.report({ | ||
messageId: 'suggestRemoveFocus', | ||
fix(fixer) { | ||
@@ -55,6 +48,4 @@ // don't apply the fixer if we're an aliased import | ||
} | ||
return fixer.removeRange([node.range[0], node.range[0] + 1]); | ||
} | ||
}] | ||
@@ -64,9 +55,6 @@ }); | ||
} | ||
const onlyNode = jestFnCall.members.find(s => (0, _utils2.getAccessorValue)(s) === 'only'); | ||
if (!onlyNode) { | ||
return; | ||
} | ||
context.report({ | ||
@@ -81,8 +69,5 @@ messageId: 'focusedTest', | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -37,3 +35,2 @@ name: __filename, | ||
}], | ||
create(context, [{ | ||
@@ -45,3 +42,2 @@ allow = [] | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'hook' && !allow.includes(jestFnCall.name)) { | ||
@@ -57,8 +53,5 @@ context.report({ | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
const newDescribeContext = () => ({ | ||
@@ -15,3 +13,2 @@ describeTitles: [], | ||
}); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -33,3 +30,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -41,23 +37,16 @@ const contexts = [newDescribeContext()]; | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if (!jestFnCall) { | ||
return; | ||
} | ||
if (jestFnCall.type === 'describe') { | ||
contexts.push(newDescribeContext()); | ||
} | ||
if (jestFnCall.members.find(s => (0, _utils.isSupportedAccessor)(s, 'each'))) { | ||
return; | ||
} | ||
const [argument] = node.arguments; | ||
if (!argument || !(0, _utils.isStringNode)(argument)) { | ||
return; | ||
} | ||
const title = (0, _utils.getStringValue)(argument); | ||
if (jestFnCall.type === 'test') { | ||
@@ -70,10 +59,7 @@ if (currentLayer.testTitles.includes(title)) { | ||
} | ||
currentLayer.testTitles.push(title); | ||
} | ||
if (jestFnCall.type !== 'describe') { | ||
return; | ||
} | ||
if (currentLayer.describeTitles.includes(title)) { | ||
@@ -85,6 +71,4 @@ context.report({ | ||
} | ||
currentLayer.describeTitles.push(title); | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -95,8 +79,5 @@ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,11 +7,6 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const testCaseNames = new Set([...Object.keys(_utils2.TestCaseName), 'it.only', 'it.only', 'it.skip', 'it.skip', 'test.only', 'test.only', 'test.skip', 'test.skip', 'fit.concurrent']); | ||
const isTestFunctionExpression = node => node.parent !== undefined && node.parent.type === _utils.AST_NODE_TYPES.CallExpression && testCaseNames.has((0, _utils2.getNodeName)(node.parent.callee)); | ||
const conditionName = { | ||
@@ -22,3 +17,2 @@ [_utils.AST_NODE_TYPES.ConditionalExpression]: 'conditional', | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -41,13 +35,9 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
const stack = []; | ||
function validate(node) { | ||
const lastElementInStack = stack[stack.length - 1]; | ||
if (stack.length === 0 || !lastElementInStack) { | ||
return; | ||
} | ||
context.report({ | ||
@@ -61,10 +51,7 @@ data: { | ||
} | ||
return { | ||
CallExpression(node) { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') { | ||
stack.push(true); | ||
if (jestFnCall.members.some(s => (0, _utils2.getAccessorValue)(s) === 'each')) { | ||
@@ -75,7 +62,5 @@ stack.push(true); | ||
}, | ||
FunctionExpression(node) { | ||
stack.push(isTestFunctionExpression(node)); | ||
}, | ||
FunctionDeclaration(node) { | ||
@@ -86,32 +71,23 @@ const declaredVariables = context.getDeclaredVariables(node); | ||
}, | ||
ArrowFunctionExpression(node) { | ||
stack.push(isTestFunctionExpression(node)); | ||
}, | ||
IfStatement: validate, | ||
SwitchStatement: validate, | ||
ConditionalExpression: validate, | ||
'CallExpression:exit'() { | ||
stack.pop(); | ||
}, | ||
'FunctionExpression:exit'() { | ||
stack.pop(); | ||
}, | ||
'FunctionDeclaration:exit'() { | ||
stack.pop(); | ||
}, | ||
'ArrowFunctionExpression:exit'() { | ||
stack.pop(); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -28,3 +25,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -34,7 +30,5 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
if (['toMatchInlineSnapshot', 'toThrowErrorMatchingInlineSnapshot'].includes((0, _utils2.getAccessorValue)(jestFnCall.matcher))) { | ||
@@ -52,8 +46,5 @@ // Check all since the optional 'propertyMatchers' argument might be present | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -33,3 +30,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -42,7 +38,5 @@ return { | ||
const calleeName = (0, _utils2.getNodeName)(callee); | ||
if (!calleeName) { | ||
return; | ||
} | ||
if (calleeName === 'spyOn' || calleeName === 'spyOnProperty' || calleeName === 'fail' || calleeName === 'pending') { | ||
@@ -53,3 +47,2 @@ if ((0, _utils2.scopeHasLocalReference)(context.getScope(), calleeName)) { | ||
} | ||
switch (calleeName) { | ||
@@ -67,3 +60,2 @@ case 'spyOn': | ||
break; | ||
case 'fail': | ||
@@ -75,3 +67,2 @@ context.report({ | ||
break; | ||
case 'pending': | ||
@@ -84,9 +75,6 @@ context.report({ | ||
} | ||
return; | ||
} | ||
if (callee.type === _utils.AST_NODE_TYPES.MemberExpression && calleeName.startsWith('jasmine.')) { | ||
const functionName = calleeName.replace('jasmine.', ''); | ||
if (functionName === 'any' || functionName === 'anything' || functionName === 'arrayContaining' || functionName === 'objectContaining' || functionName === 'stringMatching') { | ||
@@ -104,3 +92,2 @@ context.report({ | ||
} | ||
if (functionName === 'addMatchers') { | ||
@@ -117,3 +104,2 @@ context.report({ | ||
} | ||
if (functionName === 'createSpy') { | ||
@@ -130,3 +116,2 @@ context.report({ | ||
} | ||
context.report({ | ||
@@ -138,3 +123,2 @@ node, | ||
}, | ||
MemberExpression(node) { | ||
@@ -146,3 +130,2 @@ if ((0, _utils2.isSupportedAccessor)(node.object, 'jasmine')) { | ||
} = node; | ||
if (parent && parent.type === _utils.AST_NODE_TYPES.AssignmentExpression) { | ||
@@ -153,3 +136,2 @@ if ((0, _utils2.isSupportedAccessor)(property, 'DEFAULT_TIMEOUT_INTERVAL')) { | ||
} = parent; | ||
if (right.type === _utils.AST_NODE_TYPES.Literal) { | ||
@@ -164,3 +146,2 @@ context.report({ | ||
} | ||
context.report({ | ||
@@ -173,8 +154,5 @@ node, | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,9 +7,5 @@ "use strict"; | ||
exports.default = void 0; | ||
var _path = require("path"); | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const reportOnViolation = (context, node, { | ||
@@ -23,13 +19,9 @@ maxSize: lineLimit = 50, | ||
const allPathsAreAbsolute = Object.keys(allowedSnapshots).every(_path.isAbsolute); | ||
if (!allPathsAreAbsolute) { | ||
throw new Error('All paths for allowedSnapshots must be absolute. You can use JS config and `path.resolve`'); | ||
} | ||
let isAllowed = false; | ||
if (node.type === _utils.AST_NODE_TYPES.ExpressionStatement && 'left' in node.expression && node.expression.left.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.expression.left.property)) { | ||
const fileName = context.getFilename(); | ||
const allowedSnapshotsInFile = allowedSnapshots[fileName]; | ||
if (allowedSnapshotsInFile) { | ||
@@ -41,3 +33,2 @@ const snapshotName = (0, _utils2.getAccessorValue)(node.expression.left.property); | ||
} | ||
return snapshotName === name; | ||
@@ -47,3 +38,2 @@ }); | ||
} | ||
if (!isAllowed && lineCount > lineLimit) { | ||
@@ -60,3 +50,2 @@ context.report({ | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -95,3 +84,2 @@ name: __filename, | ||
defaultOptions: [{}], | ||
create(context, [options]) { | ||
@@ -103,16 +91,13 @@ if (context.getFilename().endsWith('.snap')) { | ||
} | ||
}; | ||
} | ||
return { | ||
CallExpression(node) { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
if (['toMatchInlineSnapshot', 'toThrowErrorMatchingInlineSnapshot'].includes((0, _utils2.getAccessorValue)(jestFnCall.matcher)) && jestFnCall.args.length) { | ||
reportOnViolation(context, jestFnCall.args[0], { ...options, | ||
reportOnViolation(context, jestFnCall.args[0], { | ||
...options, | ||
maxSize: options.inlineMaxSize ?? options.maxSize | ||
@@ -122,8 +107,5 @@ }); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,13 +7,7 @@ "use strict"; | ||
exports.default = void 0; | ||
var _path = require("path"); | ||
var _utils = require("./utils"); | ||
const mocksDirName = '__mocks__'; | ||
const isMockPath = path => path.split(_path.posix.sep).includes(mocksDirName); | ||
const isMockImportLiteral = expression => (0, _utils.isStringNode)(expression) && isMockPath((0, _utils.getStringValue)(expression)); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -34,3 +28,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -46,6 +39,4 @@ return { | ||
}, | ||
'CallExpression[callee.name="require"]'(node) { | ||
const [arg] = node.arguments; | ||
if (arg && isMockImportLiteral(arg)) { | ||
@@ -58,8 +49,5 @@ context.report({ | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
const messages = { | ||
@@ -15,3 +13,2 @@ restrictedJestMethod: 'Use of `{{ restriction }}` is disallowed', | ||
}; | ||
var _default = (0, _utils.createRule)({ | ||
@@ -35,3 +32,2 @@ name: __filename, | ||
defaultOptions: [{}], | ||
create(context, [restrictedMethods]) { | ||
@@ -41,9 +37,6 @@ return { | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'jest') { | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'jest' || jestFnCall.members.length === 0) { | ||
return; | ||
} | ||
const method = (0, _utils.getAccessorValue)(jestFnCall.members[0]); | ||
if (method in restrictedMethods) { | ||
@@ -64,8 +57,5 @@ const message = restrictedMethods[method]; | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
const isChainRestricted = (chain, restriction) => { | ||
@@ -15,6 +13,4 @@ if (_utils.ModifierName.hasOwnProperty(restriction) || restriction.endsWith('.not')) { | ||
} | ||
return chain === restriction; | ||
}; | ||
var _default = (0, _utils.createRule)({ | ||
@@ -41,3 +37,2 @@ name: __filename, | ||
defaultOptions: [{}], | ||
create(context, [restrictedChains]) { | ||
@@ -47,9 +42,6 @@ return { | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
const chain = jestFnCall.members.map(nod => (0, _utils.getAccessorValue)(nod)).join('.'); | ||
for (const [restriction, message] of Object.entries(restrictedChains)) { | ||
@@ -72,8 +64,5 @@ if (isChainRestricted(chain, restriction)) { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,28 +7,25 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const getBlockType = (statement, context) => { | ||
const func = statement.parent; | ||
/* istanbul ignore if */ | ||
if (!func) { | ||
throw new Error(`Unexpected BlockStatement. No parent defined. - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`); | ||
} // functionDeclaration: function func() {} | ||
} | ||
// functionDeclaration: function func() {} | ||
if (func.type === _utils.AST_NODE_TYPES.FunctionDeclaration) { | ||
return 'function'; | ||
} | ||
if ((0, _utils2.isFunction)(func) && func.parent) { | ||
const expr = func.parent; // arrow function or function expr | ||
const expr = func.parent; | ||
// arrow function or function expr | ||
if (expr.type === _utils.AST_NODE_TYPES.VariableDeclarator) { | ||
return 'function'; | ||
} // if it's not a variable, it will be callExpr, we only care about describe | ||
} | ||
// if it's not a variable, it will be callExpr, we only care about describe | ||
if (expr.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTypeOfJestFnCall)(expr, context, ['describe'])) { | ||
@@ -38,6 +35,4 @@ return 'describe'; | ||
} | ||
return null; | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -70,3 +65,2 @@ name: __filename, | ||
}], | ||
create(context, [{ | ||
@@ -76,18 +70,12 @@ additionalTestBlockFunctions = [] | ||
const callStack = []; | ||
const isCustomTestBlockFunction = node => additionalTestBlockFunctions.includes((0, _utils2.getNodeName)(node) || ''); | ||
return { | ||
CallExpression(node) { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'expect') { | ||
var _jestFnCall$head$node; | ||
if (((_jestFnCall$head$node = jestFnCall.head.node.parent) === null || _jestFnCall$head$node === void 0 ? void 0 : _jestFnCall$head$node.type) === _utils.AST_NODE_TYPES.MemberExpression && jestFnCall.members.length === 1 && !['assertions', 'hasAssertions'].includes((0, _utils2.getAccessorValue)(jestFnCall.members[0]))) { | ||
return; | ||
} | ||
const parent = callStack[callStack.length - 1]; | ||
if (!parent || parent === _utils2.DescribeAlias.describe) { | ||
@@ -99,10 +87,7 @@ context.report({ | ||
} | ||
return; | ||
} | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test' || isCustomTestBlockFunction(node)) { | ||
callStack.push('test'); | ||
} | ||
if (node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression) { | ||
@@ -112,6 +97,4 @@ callStack.push('template'); | ||
}, | ||
'CallExpression:exit'(node) { | ||
const top = callStack[callStack.length - 1]; | ||
if (top === 'test' && ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test']) || isCustomTestBlockFunction(node)) && node.callee.type !== _utils.AST_NODE_TYPES.MemberExpression || top === 'template' && node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression) { | ||
@@ -121,6 +104,4 @@ callStack.pop(); | ||
}, | ||
BlockStatement(statement) { | ||
const blockType = getBlockType(statement, context); | ||
if (blockType) { | ||
@@ -130,3 +111,2 @@ callStack.push(blockType); | ||
}, | ||
'BlockStatement:exit'(statement) { | ||
@@ -137,6 +117,4 @@ if (callStack[callStack.length - 1] === getBlockType(statement, context)) { | ||
}, | ||
ArrowFunctionExpression(node) { | ||
var _node$parent; | ||
if (((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) !== _utils.AST_NODE_TYPES.CallExpression) { | ||
@@ -146,3 +124,2 @@ callStack.push('arrow'); | ||
}, | ||
'ArrowFunctionExpression:exit'() { | ||
@@ -153,8 +130,5 @@ if (callStack[callStack.length - 1] === 'arrow') { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -29,3 +26,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -35,11 +31,8 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe' && (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test') { | ||
return; | ||
} | ||
if (jestFnCall.name[0] !== 'f' && jestFnCall.name[0] !== 'x') { | ||
return; | ||
} | ||
const preferredNodeName = [jestFnCall.name.slice(1), jestFnCall.name[0] === 'f' ? 'only' : 'skip', ...jestFnCall.members.map(s => (0, _utils2.getAccessorValue)(s))].join('.'); | ||
@@ -53,15 +46,10 @@ const funcNode = node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression ? node.callee.tag : node.callee.type === _utils.AST_NODE_TYPES.CallExpression ? node.callee.callee : node.callee; | ||
}, | ||
fix(fixer) { | ||
return [fixer.replaceText(funcNode, preferredNodeName)]; | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,17 +7,11 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const getBody = args => { | ||
const [, secondArg] = args; | ||
if (secondArg && (0, _utils2.isFunction)(secondArg) && secondArg.body.type === _utils.AST_NODE_TYPES.BlockStatement) { | ||
return secondArg.body.body; | ||
} | ||
return []; | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -38,3 +32,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -46,3 +39,2 @@ return { | ||
} | ||
const body = getBody(node.arguments); | ||
@@ -56,3 +48,2 @@ const returnStmt = body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement); | ||
}, | ||
FunctionDeclaration(node) { | ||
@@ -69,8 +60,5 @@ const declaredVariables = context.getDeclaredVariables(node); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -26,3 +24,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -32,11 +29,8 @@ return { | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
if (jestFnCall.modifiers.some(nod => (0, _utils.getAccessorValue)(nod) === 'not')) { | ||
return; | ||
} | ||
const { | ||
@@ -46,3 +40,2 @@ matcher | ||
const matcherName = (0, _utils.getAccessorValue)(matcher); | ||
if (['toBeCalled', 'toHaveBeenCalled'].includes(matcherName)) { | ||
@@ -58,8 +51,5 @@ context.report({ | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,15 +7,10 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const isString = node => { | ||
return (0, _utils2.isStringNode)(node) || node.type === _utils.AST_NODE_TYPES.TemplateLiteral; | ||
}; | ||
const isComparingToString = expression => { | ||
return isString(expression.left) || isString(expression.right); | ||
}; | ||
const invertOperator = operator => { | ||
@@ -25,36 +20,25 @@ switch (operator) { | ||
return '<='; | ||
case '<': | ||
return '>='; | ||
case '>=': | ||
return '<'; | ||
case '<=': | ||
return '>'; | ||
} | ||
return null; | ||
}; | ||
const determineMatcher = (operator, negated) => { | ||
const op = negated ? invertOperator(operator) : operator; | ||
switch (op) { | ||
case '>': | ||
return 'toBeGreaterThan'; | ||
case '<': | ||
return 'toBeLessThan'; | ||
case '>=': | ||
return 'toBeGreaterThanOrEqual'; | ||
case '<=': | ||
return 'toBeLessThanOrEqual'; | ||
} | ||
return null; | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -76,3 +60,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -82,15 +65,11 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) { | ||
return; | ||
} | ||
const { | ||
parent: expect | ||
} = jestFnCall.head.node; | ||
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) { | ||
return; | ||
} | ||
const { | ||
@@ -104,26 +83,25 @@ arguments: [comparison], | ||
const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall); | ||
if ((comparison === null || comparison === void 0 ? void 0 : comparison.type) !== _utils.AST_NODE_TYPES.BinaryExpression || isComparingToString(comparison) || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg)) { | ||
return; | ||
} | ||
const [modifier] = jestFnCall.modifiers; | ||
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not'); | ||
const preferredMatcher = determineMatcher(comparison.operator, matcherArg.value === hasNot); | ||
if (!preferredMatcher) { | ||
return; | ||
} | ||
context.report({ | ||
fix(fixer) { | ||
const sourceCode = context.getSourceCode(); // preserve the existing modifier if it's not a negation | ||
const sourceCode = context.getSourceCode(); | ||
// preserve the existing modifier if it's not a negation | ||
const modifierText = modifier && (0, _utils2.getAccessorValue)(modifier) !== 'not' ? `.${(0, _utils2.getAccessorValue)(modifier)}` : ''; | ||
return [// replace the comparison argument with the left-hand side of the comparison | ||
fixer.replaceText(comparison, sourceCode.getText(comparison.left)), // replace the current matcher & modifier with the preferred matcher | ||
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${preferredMatcher}`), // replace the matcher argument with the right-hand side of the comparison | ||
return [ | ||
// replace the comparison argument with the left-hand side of the comparison | ||
fixer.replaceText(comparison, sourceCode.getText(comparison.left)), | ||
// replace the current matcher & modifier with the preferred matcher | ||
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${preferredMatcher}`), | ||
// replace the matcher argument with the right-hand side of the comparison | ||
fixer.replaceText(matcherArg, sourceCode.getText(comparison.right))]; | ||
}, | ||
messageId: 'useToBeComparison', | ||
@@ -136,8 +114,5 @@ data: { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -26,7 +24,5 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
const jestFnCalls = []; | ||
let inTestCaseCall = false; | ||
const recommendFn = () => { | ||
@@ -36,6 +32,4 @@ if (jestFnCalls.length === 1 && jestFnCalls[0] === 'test') { | ||
} | ||
return 'describe'; | ||
}; | ||
const enterForLoop = () => { | ||
@@ -45,6 +39,4 @@ if (jestFnCalls.length === 0 || inTestCaseCall) { | ||
} | ||
jestFnCalls.length = 0; | ||
}; | ||
const exitForLoop = node => { | ||
@@ -54,3 +46,2 @@ if (jestFnCalls.length === 0 || inTestCaseCall) { | ||
} | ||
context.report({ | ||
@@ -65,3 +56,2 @@ node, | ||
}; | ||
return { | ||
@@ -74,3 +64,2 @@ ForStatement: enterForLoop, | ||
'ForOfStatement:exit': exitForLoop, | ||
CallExpression(node) { | ||
@@ -80,7 +69,5 @@ const { | ||
} = (0, _utils.parseJestFnCall)(node, context) ?? {}; | ||
if (jestFnCallType === 'hook' || jestFnCallType === 'describe' || jestFnCallType === 'test') { | ||
jestFnCalls.push(jestFnCallType); | ||
} | ||
if (jestFnCallType === 'test') { | ||
@@ -90,3 +77,2 @@ inTestCaseCall = true; | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -96,3 +82,2 @@ const { | ||
} = (0, _utils.parseJestFnCall)(node, context) ?? {}; | ||
if (jestFnCallType === 'test') { | ||
@@ -102,8 +87,5 @@ inTestCaseCall = false; | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -30,3 +27,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -36,15 +32,11 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) { | ||
return; | ||
} | ||
const { | ||
parent: expect | ||
} = jestFnCall.head.node; | ||
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) { | ||
return; | ||
} | ||
const { | ||
@@ -58,29 +50,28 @@ arguments: [comparison], | ||
const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall); | ||
if ((comparison === null || comparison === void 0 ? void 0 : comparison.type) !== _utils.AST_NODE_TYPES.BinaryExpression || comparison.operator !== '===' && comparison.operator !== '!==' || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg)) { | ||
return; | ||
} | ||
const matcherValue = matcherArg.value; | ||
const [modifier] = jestFnCall.modifiers; | ||
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not'); // we need to negate the expectation if the current expected | ||
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not'); | ||
// we need to negate the expectation if the current expected | ||
// value is itself negated by the "not" modifier | ||
const addNotModifier = (comparison.operator === '!==' ? !matcherValue : matcherValue) === hasNot; | ||
const buildFixer = equalityMatcher => fixer => { | ||
const sourceCode = context.getSourceCode(); // preserve the existing modifier if it's not a negation | ||
const sourceCode = context.getSourceCode(); | ||
// preserve the existing modifier if it's not a negation | ||
let modifierText = modifier && (0, _utils2.getAccessorValue)(modifier) !== 'not' ? `.${(0, _utils2.getAccessorValue)(modifier)}` : ''; | ||
if (addNotModifier) { | ||
modifierText += `.${_utils2.ModifierName.not}`; | ||
} | ||
return [// replace the comparison argument with the left-hand side of the comparison | ||
fixer.replaceText(comparison, sourceCode.getText(comparison.left)), // replace the current matcher & modifier with the preferred matcher | ||
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${equalityMatcher}`), // replace the matcher argument with the right-hand side of the comparison | ||
return [ | ||
// replace the comparison argument with the left-hand side of the comparison | ||
fixer.replaceText(comparison, sourceCode.getText(comparison.left)), | ||
// replace the current matcher & modifier with the preferred matcher | ||
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${equalityMatcher}`), | ||
// replace the matcher argument with the right-hand side of the comparison | ||
fixer.replaceText(matcherArg, sourceCode.getText(comparison.right))]; | ||
}; | ||
context.report({ | ||
@@ -98,8 +89,5 @@ messageId: 'useEqualityMatcher', | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,31 +7,23 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const isFirstStatement = node => { | ||
let parent = node; | ||
while (parent) { | ||
var _parent$parent, _parent$parent2; | ||
if (((_parent$parent = parent.parent) === null || _parent$parent === void 0 ? void 0 : _parent$parent.type) === _utils.AST_NODE_TYPES.BlockStatement) { | ||
return parent.parent.body[0] === parent; | ||
} // if we've hit an arrow function, then it must have a single expression | ||
} | ||
// if we've hit an arrow function, then it must have a single expression | ||
// as its body, as otherwise we would have hit the block statement already | ||
if (((_parent$parent2 = parent.parent) === null || _parent$parent2 === void 0 ? void 0 : _parent$parent2.type) === _utils.AST_NODE_TYPES.ArrowFunctionExpression) { | ||
return true; | ||
} | ||
parent = parent.parent; | ||
} | ||
/* istanbul ignore next */ | ||
throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`); | ||
}; | ||
const suggestRemovingExtraArguments = (args, extraArgsStartAt) => ({ | ||
@@ -41,3 +33,2 @@ messageId: 'suggestRemovingExtraArguments', | ||
}); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -83,3 +74,2 @@ name: __filename, | ||
}], | ||
create(context, [options]) { | ||
@@ -92,3 +82,2 @@ let expressionDepth = 0; | ||
let inForLoop = false; | ||
const shouldCheckFunction = testFunction => { | ||
@@ -98,3 +87,2 @@ if (!options.onlyFunctionsWithAsyncKeyword && !options.onlyFunctionsWithExpectInLoop && !options.onlyFunctionsWithExpectInCallback) { | ||
} | ||
if (options.onlyFunctionsWithAsyncKeyword) { | ||
@@ -105,3 +93,2 @@ if (testFunction.async) { | ||
} | ||
if (options.onlyFunctionsWithExpectInLoop) { | ||
@@ -112,3 +99,2 @@ if (hasExpectInLoop) { | ||
} | ||
if (options.onlyFunctionsWithExpectInCallback) { | ||
@@ -119,6 +105,4 @@ if (hasExpectInCallback) { | ||
} | ||
return false; | ||
}; | ||
const checkExpectHasAssertions = expectFnCall => { | ||
@@ -133,6 +117,4 @@ if ((0, _utils2.getAccessorValue)(expectFnCall.members[0]) === 'hasAssertions') { | ||
} | ||
return; | ||
} | ||
if (expectFnCall.args.length !== 1) { | ||
@@ -143,3 +125,2 @@ let { | ||
const suggest = []; | ||
if (expectFnCall.args.length) { | ||
@@ -149,3 +130,2 @@ loc = expectFnCall.args[1].loc; | ||
} | ||
context.report({ | ||
@@ -158,9 +138,6 @@ messageId: 'assertionsRequiresOneArgument', | ||
} | ||
const [arg] = expectFnCall.args; | ||
if (arg.type === _utils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) { | ||
return; | ||
} | ||
context.report({ | ||
@@ -171,11 +148,6 @@ messageId: 'assertionsRequiresNumberArgument', | ||
}; | ||
const enterExpression = () => inTestCaseCall && expressionDepth++; | ||
const exitExpression = () => inTestCaseCall && expressionDepth--; | ||
const enterForLoop = () => inForLoop = true; | ||
const exitForLoop = () => inForLoop = false; | ||
return { | ||
@@ -192,6 +164,4 @@ FunctionExpression: enterExpression, | ||
'ForOfStatement:exit': exitForLoop, | ||
CallExpression(node) { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') { | ||
@@ -201,6 +171,4 @@ inTestCaseCall = true; | ||
} | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'expect' && inTestCaseCall) { | ||
var _jestFnCall$head$node; | ||
if (expressionDepth === 1 && isFirstStatement(node) && ((_jestFnCall$head$node = jestFnCall.head.node.parent) === null || _jestFnCall$head$node === void 0 ? void 0 : _jestFnCall$head$node.type) === _utils.AST_NODE_TYPES.MemberExpression && jestFnCall.members.length === 1 && ['assertions', 'hasAssertions'].includes((0, _utils2.getAccessorValue)(jestFnCall.members[0]))) { | ||
@@ -210,7 +178,5 @@ checkExpectHasAssertions(jestFnCall); | ||
} | ||
if (inForLoop) { | ||
hasExpectInLoop = true; | ||
} | ||
if (expressionDepth > 1) { | ||
@@ -221,3 +187,2 @@ hasExpectInCallback = true; | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -227,18 +192,12 @@ if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) { | ||
} | ||
inTestCaseCall = false; | ||
if (node.arguments.length < 2) { | ||
return; | ||
} | ||
const [, testFn] = node.arguments; | ||
if (!(0, _utils2.isFunction)(testFn) || !shouldCheckFunction(testFn)) { | ||
return; | ||
} | ||
hasExpectInLoop = false; | ||
hasExpectInCallback = false; | ||
if (hasExpectAssertionsAsFirstStatement) { | ||
@@ -248,9 +207,6 @@ hasExpectAssertionsAsFirstStatement = false; | ||
} | ||
const suggestions = []; | ||
if (testFn.body.type === _utils.AST_NODE_TYPES.BlockStatement) { | ||
suggestions.push(['suggestAddingHasAssertions', 'expect.hasAssertions();'], ['suggestAddingAssertions', 'expect.assertions();']); | ||
} | ||
context.report({ | ||
@@ -265,8 +221,5 @@ messageId: 'haveExpectAssertions', | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -32,17 +29,12 @@ name: __filename, | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
const { | ||
parent | ||
} = jestFnCall.head.node; | ||
if ((parent === null || parent === void 0 ? void 0 : parent.type) !== _utils.AST_NODE_TYPES.CallExpression) { | ||
return; | ||
} | ||
const [awaitNode] = parent.arguments; | ||
if ((awaitNode === null || awaitNode === void 0 ? void 0 : awaitNode.type) === _utils.AST_NODE_TYPES.AwaitExpression) { | ||
@@ -52,14 +44,10 @@ context.report({ | ||
messageId: 'expectResolves', | ||
fix(fixer) { | ||
return [fixer.insertTextBefore(parent, 'await '), fixer.removeRange([awaitNode.range[0], awaitNode.argument.range[0]]), fixer.insertTextAfter(parent, '.resolves')]; | ||
} | ||
}); | ||
} | ||
} | ||
}) | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
const HooksOrder = ['beforeAll', 'beforeEach', 'afterEach', 'afterAll']; | ||
var _default = (0, _utils.createRule)({ | ||
@@ -28,3 +25,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -39,5 +35,3 @@ let previousHookIndex = -1; | ||
} | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'hook') { | ||
@@ -48,7 +42,5 @@ // Reset the previousHookIndex when encountering something different from a hook | ||
} | ||
inHook = true; | ||
const currentHook = jestFnCall.name; | ||
const currentHookIndex = HooksOrder.indexOf(currentHook); | ||
if (currentHookIndex < previousHookIndex) { | ||
@@ -65,6 +57,4 @@ context.report({ | ||
} | ||
previousHookIndex = currentHookIndex; | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -75,16 +65,12 @@ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['hook'])) { | ||
} | ||
if (inHook) { | ||
return; | ||
} // Reset the previousHookIndex when encountering something different from a hook | ||
} | ||
// Reset the previousHookIndex when encountering something different from a hook | ||
previousHookIndex = -1; | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -26,3 +24,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -35,3 +32,2 @@ const hooksContext = [false]; | ||
} | ||
if (hooksContext[hooksContext.length - 1] && (0, _utils.isTypeOfJestFnCall)(node, context, ['hook'])) { | ||
@@ -43,15 +39,10 @@ context.report({ | ||
} | ||
hooksContext.push(false); | ||
}, | ||
'CallExpression:exit'() { | ||
hooksContext.pop(); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,25 +7,17 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
const hasStringAsFirstArgument = node => node.arguments[0] && (0, _utils.isStringNode)(node.arguments[0]); | ||
const populateIgnores = ignore => { | ||
const ignores = []; | ||
if (ignore.includes(_utils.DescribeAlias.describe)) { | ||
ignores.push(...Object.keys(_utils.DescribeAlias)); | ||
} | ||
if (ignore.includes(_utils.TestCaseName.test)) { | ||
ignores.push(...Object.keys(_utils.TestCaseName).filter(k => k.endsWith(_utils.TestCaseName.test))); | ||
} | ||
if (ignore.includes(_utils.TestCaseName.it)) { | ||
ignores.push(...Object.keys(_utils.TestCaseName).filter(k => k.endsWith(_utils.TestCaseName.it))); | ||
} | ||
return ignores; | ||
}; | ||
var _default = (0, _utils.createRule)({ | ||
@@ -74,3 +66,2 @@ name: __filename, | ||
}], | ||
create(context, [{ | ||
@@ -86,10 +77,7 @@ ignore = [], | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if (!jestFnCall || !hasStringAsFirstArgument(node)) { | ||
return; | ||
} | ||
if (jestFnCall.type === 'describe') { | ||
numberOfDescribeBlocks++; | ||
if (ignoreTopLevelDescribe && numberOfDescribeBlocks === 1) { | ||
@@ -101,16 +89,11 @@ return; | ||
} | ||
const [firstArg] = node.arguments; | ||
const description = (0, _utils.getStringValue)(firstArg); | ||
if (allowedPrefixes.some(name => description.startsWith(name))) { | ||
return; | ||
} | ||
const firstCharacter = description.charAt(0); | ||
if (!firstCharacter || firstCharacter === firstCharacter.toLowerCase() || ignores.includes(jestFnCall.name)) { | ||
return; | ||
} | ||
context.report({ | ||
@@ -122,3 +105,2 @@ messageId: 'unexpectedLowercase', | ||
}, | ||
fix(fixer) { | ||
@@ -130,6 +112,4 @@ const description = (0, _utils.getStringValue)(firstArg); | ||
} | ||
}); | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -140,8 +120,5 @@ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,25 +7,17 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const withOnce = (name, addOnce) => { | ||
return `${name}${addOnce ? 'Once' : ''}`; | ||
}; | ||
const findSingleReturnArgumentNode = fnNode => { | ||
var _fnNode$body$body$; | ||
if (fnNode.body.type !== _utils.AST_NODE_TYPES.BlockStatement) { | ||
return fnNode.body; | ||
} | ||
if (((_fnNode$body$body$ = fnNode.body.body[0]) === null || _fnNode$body$body$ === void 0 ? void 0 : _fnNode$body$body$.type) === _utils.AST_NODE_TYPES.ReturnStatement) { | ||
return fnNode.body.body[0].argument; | ||
} | ||
return null; | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -47,3 +39,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -54,9 +45,6 @@ const report = (property, isOnce, outerArgNode, innerArgNode = outerArgNode) => { | ||
} | ||
const argName = (0, _utils2.getNodeName)(innerArgNode); | ||
if (argName !== 'Promise.resolve' && argName !== 'Promise.reject') { | ||
return; | ||
} | ||
const replacement = withOnce(argName.endsWith('reject') ? 'mockRejectedValue' : 'mockResolvedValue', isOnce); | ||
@@ -69,12 +57,12 @@ context.report({ | ||
}, | ||
fix(fixer) { | ||
const sourceCode = context.getSourceCode(); | ||
fix(fixer) { | ||
const sourceCode = context.getSourceCode(); // there shouldn't be more than one argument, but if there is don't try | ||
// there shouldn't be more than one argument, but if there is don't try | ||
// fixing since we have no idea what to do with the extra arguments | ||
if (innerArgNode.arguments.length > 1) { | ||
return null; | ||
} | ||
return [fixer.replaceText(property, replacement), fixer.replaceText(outerArgNode, // the value argument for both Promise methods is optional, | ||
return [fixer.replaceText(property, replacement), fixer.replaceText(outerArgNode, | ||
// the value argument for both Promise methods is optional, | ||
// whereas for Jest they're required so use an explicit undefined | ||
@@ -84,6 +72,4 @@ // if no argument is being passed to the call we're replacing | ||
} | ||
}); | ||
}; | ||
return { | ||
@@ -94,6 +80,4 @@ CallExpression(node) { | ||
} | ||
const mockFnName = (0, _utils2.getAccessorValue)(node.callee.property); | ||
const isOnce = mockFnName.endsWith('Once'); | ||
if (mockFnName === withOnce('mockReturnValue', isOnce)) { | ||
@@ -103,16 +87,11 @@ report(node.callee.property, isOnce, node.arguments[0]); | ||
const [arg] = node.arguments; | ||
if (!(0, _utils2.isFunction)(arg) || arg.params.length !== 0) { | ||
return; | ||
} | ||
report(node.callee.property, isOnce, arg, findSingleReturnArgumentNode(arg)); | ||
} | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,35 +7,30 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
const snapshotMatchers = ['toMatchSnapshot', 'toThrowErrorMatchingSnapshot']; | ||
const snapshotMatcherNames = snapshotMatchers; | ||
const isSnapshotMatcherWithoutHint = expectFnCall => { | ||
if (expectFnCall.args.length === 0) { | ||
return true; | ||
} // this matcher only supports one argument which is the hint | ||
} | ||
// this matcher only supports one argument which is the hint | ||
if (!(0, _utils.isSupportedAccessor)(expectFnCall.matcher, 'toMatchSnapshot')) { | ||
return expectFnCall.args.length !== 1; | ||
} // if we're being passed two arguments, | ||
} | ||
// if we're being passed two arguments, | ||
// the second one should be the hint | ||
if (expectFnCall.args.length === 2) { | ||
return false; | ||
} | ||
const [arg] = expectFnCall.args; | ||
const [arg] = expectFnCall.args; // the first argument to `toMatchSnapshot` can be _either_ a snapshot hint or | ||
// the first argument to `toMatchSnapshot` can be _either_ a snapshot hint or | ||
// an object with asymmetric matchers, so we can't just assume that the first | ||
// argument is a hint when it's by itself. | ||
return !(0, _utils.isStringNode)(arg); | ||
}; | ||
const messages = { | ||
missingHint: 'You should provide a hint for this snapshot' | ||
}; | ||
var _default = (0, _utils.createRule)({ | ||
@@ -57,3 +52,2 @@ name: __filename, | ||
defaultOptions: ['multi'], | ||
create(context, [mode]) { | ||
@@ -63,3 +57,2 @@ const snapshotMatchers = []; | ||
let expressionDepth = 0; | ||
const reportSnapshotMatchersWithoutHints = () => { | ||
@@ -75,10 +68,7 @@ for (const snapshotMatcher of snapshotMatchers) { | ||
}; | ||
const enterExpression = () => { | ||
expressionDepth++; | ||
}; | ||
const exitExpression = () => { | ||
expressionDepth--; | ||
if (mode === 'always') { | ||
@@ -88,3 +78,2 @@ reportSnapshotMatchersWithoutHints(); | ||
} | ||
if (mode === 'multi' && expressionDepth === 0) { | ||
@@ -94,7 +83,5 @@ if (snapshotMatchers.length > 1) { | ||
} | ||
snapshotMatchers.length = 0; | ||
} | ||
}; | ||
return { | ||
@@ -105,3 +92,2 @@ 'Program:exit'() { | ||
}, | ||
FunctionExpression: enterExpression, | ||
@@ -111,3 +97,2 @@ 'FunctionExpression:exit': exitExpression, | ||
'ArrowFunctionExpression:exit': exitExpression, | ||
'CallExpression:exit'(node) { | ||
@@ -119,6 +104,4 @@ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe', 'test'])) { | ||
}, | ||
CallExpression(node) { | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
@@ -129,20 +112,13 @@ if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'describe' || (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') { | ||
} | ||
return; | ||
} | ||
const matcherName = (0, _utils.getAccessorValue)(jestFnCall.matcher); | ||
if (!snapshotMatcherNames.includes(matcherName)) { | ||
return; | ||
} | ||
snapshotMatchers.push(jestFnCall); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const findNodeObject = node => { | ||
@@ -17,10 +14,7 @@ if ('object' in node) { | ||
} | ||
if (node.callee.type === _utils.AST_NODE_TYPES.MemberExpression) { | ||
return node.callee.object; | ||
} | ||
return null; | ||
}; | ||
const getJestFnCall = node => { | ||
@@ -30,16 +24,11 @@ if (node.type !== _utils.AST_NODE_TYPES.CallExpression && node.type !== _utils.AST_NODE_TYPES.MemberExpression) { | ||
} | ||
const obj = findNodeObject(node); | ||
if (!obj) { | ||
return null; | ||
} | ||
if (obj.type === _utils.AST_NODE_TYPES.Identifier) { | ||
return node.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.getNodeName)(node.callee) === 'jest.fn' ? node : null; | ||
} | ||
return getJestFnCall(obj); | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -61,3 +50,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -76,3 +64,2 @@ return { | ||
messageId: 'useJestSpyOn', | ||
fix(fixer) { | ||
@@ -85,11 +72,7 @@ const leftPropQuote = left.property.type === _utils.AST_NODE_TYPES.Identifier ? "'" : ''; | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -28,3 +26,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -34,11 +31,8 @@ return { | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
const { | ||
matcher | ||
} = jestFnCall; | ||
if ((0, _utils.isSupportedAccessor)(matcher, 'toEqual')) { | ||
@@ -55,8 +49,5 @@ context.report({ | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,8 +7,6 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const isNullLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && node.value === null; | ||
const isNullLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && node.value === null; | ||
/** | ||
@@ -18,15 +16,9 @@ * Checks if the given `ParsedEqualityMatcherCall` is a call to one of the equality matchers, | ||
*/ | ||
const isNullEqualityMatcher = expectFnCall => isNullLiteral((0, _utils2.getFirstMatcherArg)(expectFnCall)); | ||
const isFirstArgumentIdentifier = (expectFnCall, name) => (0, _utils2.isIdentifier)((0, _utils2.getFirstMatcherArg)(expectFnCall), name); | ||
const shouldUseToBe = expectFnCall => { | ||
let firstArg = (0, _utils2.getFirstMatcherArg)(expectFnCall); | ||
if (firstArg.type === _utils.AST_NODE_TYPES.UnaryExpression && firstArg.operator === '-') { | ||
firstArg = firstArg.argument; | ||
} | ||
if (firstArg.type === _utils.AST_NODE_TYPES.Literal) { | ||
@@ -37,30 +29,21 @@ // regex literals are classed as literals, but they're actually objects | ||
} | ||
return firstArg.type === _utils.AST_NODE_TYPES.TemplateLiteral; | ||
}; | ||
const reportPreferToBe = (context, whatToBe, expectFnCall, modifierNode) => { | ||
context.report({ | ||
messageId: `useToBe${whatToBe}`, | ||
fix(fixer) { | ||
var _expectFnCall$args; | ||
const fixes = [(0, _utils2.replaceAccessorFixer)(fixer, expectFnCall.matcher, `toBe${whatToBe}`)]; | ||
if ((_expectFnCall$args = expectFnCall.args) !== null && _expectFnCall$args !== void 0 && _expectFnCall$args.length && whatToBe !== '') { | ||
fixes.push(fixer.remove(expectFnCall.args[0])); | ||
} | ||
if (modifierNode) { | ||
fixes.push(fixer.removeRange([modifierNode.range[0] - 1, modifierNode.range[1]])); | ||
} | ||
return fixes; | ||
}, | ||
node: expectFnCall.matcher | ||
}); | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -86,3 +69,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -92,10 +74,7 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
const matcherName = (0, _utils2.getAccessorValue)(jestFnCall.matcher); | ||
const notModifier = jestFnCall.modifiers.find(nod => (0, _utils2.getAccessorValue)(nod) === 'not'); | ||
if (notModifier && ['toBeUndefined', 'toBeDefined'].includes(matcherName)) { | ||
@@ -105,7 +84,5 @@ reportPreferToBe(context, matcherName === 'toBeDefined' ? 'Undefined' : 'Defined', jestFnCall, notModifier); | ||
} | ||
if (!_utils2.EqualityMatcher.hasOwnProperty(matcherName) || jestFnCall.args.length === 0) { | ||
return; | ||
} | ||
if (isNullEqualityMatcher(jestFnCall)) { | ||
@@ -115,3 +92,2 @@ reportPreferToBe(context, 'Null', jestFnCall); | ||
} | ||
if (isFirstArgumentIdentifier(jestFnCall, 'undefined')) { | ||
@@ -122,3 +98,2 @@ const name = notModifier ? 'Defined' : 'Undefined'; | ||
} | ||
if (isFirstArgumentIdentifier(jestFnCall, 'NaN')) { | ||
@@ -128,3 +103,2 @@ reportPreferToBe(context, 'NaN', jestFnCall); | ||
} | ||
if (shouldUseToBe(jestFnCall) && matcherName !== _utils2.EqualityMatcher.toBe) { | ||
@@ -134,8 +108,5 @@ reportPreferToBe(context, '', jestFnCall); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
/** | ||
@@ -21,5 +18,5 @@ * Checks if the given `node` is a `CallExpression` representing the calling | ||
*/ | ||
const isFixableIncludesCallExpression = node => node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property, 'includes') && (0, _utils2.hasOnlyOneArgument)(node) && node.arguments[0].type !== _utils.AST_NODE_TYPES.SpreadElement; // expect(array.includes(<value>)[not.]{toBe,toEqual}(<boolean>) | ||
const isFixableIncludesCallExpression = node => node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property, 'includes') && (0, _utils2.hasOnlyOneArgument)(node) && node.arguments[0].type !== _utils.AST_NODE_TYPES.SpreadElement; | ||
// expect(array.includes(<value>)[not.]{toBe,toEqual}(<boolean>) | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -41,3 +38,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -47,15 +43,11 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) { | ||
return; | ||
} | ||
const { | ||
parent: expect | ||
} = jestFnCall.head.node; | ||
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) { | ||
return; | ||
} | ||
const { | ||
@@ -69,20 +61,21 @@ arguments: [includesCall], | ||
const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall); | ||
if (!includesCall || matcherArg.type === _utils.AST_NODE_TYPES.SpreadElement || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg) || !isFixableIncludesCallExpression(includesCall)) { | ||
return; | ||
} | ||
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not'); | ||
context.report({ | ||
fix(fixer) { | ||
const sourceCode = context.getSourceCode(); // we need to negate the expectation if the current expected | ||
const sourceCode = context.getSourceCode(); | ||
// we need to negate the expectation if the current expected | ||
// value is itself negated by the "not" modifier | ||
const addNotModifier = matcherArg.value === hasNot; | ||
return [// remove the "includes" call entirely | ||
fixer.removeRange([includesCall.callee.property.range[0] - 1, includesCall.range[1]]), // replace the current matcher with "toContain", adding "not" if needed | ||
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], addNotModifier ? `.${_utils2.ModifierName.not}.toContain` : '.toContain'), // replace the matcher argument with the value from the "includes" | ||
return [ | ||
// remove the "includes" call entirely | ||
fixer.removeRange([includesCall.callee.property.range[0] - 1, includesCall.range[1]]), | ||
// replace the current matcher with "toContain", adding "not" if needed | ||
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], addNotModifier ? `.${_utils2.ModifierName.not}.toContain` : '.toContain'), | ||
// replace the matcher argument with the value from the "includes" | ||
fixer.replaceText(jestFnCall.args[0], sourceCode.getText(includesCall.arguments[0]))]; | ||
}, | ||
messageId: 'useToContain', | ||
@@ -92,8 +85,5 @@ node: matcher | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -29,3 +26,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -35,15 +31,11 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
const { | ||
parent: expect | ||
} = jestFnCall.head.node; | ||
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) { | ||
return; | ||
} | ||
const [argument] = expect.arguments; | ||
@@ -53,14 +45,13 @@ const { | ||
} = jestFnCall; | ||
if (!_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || (argument === null || argument === void 0 ? void 0 : argument.type) !== _utils.AST_NODE_TYPES.MemberExpression || !(0, _utils2.isSupportedAccessor)(argument.property, 'length')) { | ||
return; | ||
} | ||
context.report({ | ||
fix(fixer) { | ||
return [// remove the "length" property accessor | ||
fixer.removeRange([argument.property.range[0] - 1, argument.range[1]]), // replace the current matcher with "toHaveLength" | ||
return [ | ||
// remove the "length" property accessor | ||
fixer.removeRange([argument.property.range[0] - 1, argument.range[1]]), | ||
// replace the current matcher with "toHaveLength" | ||
fixer.replaceTextRange([matcher.parent.object.range[1], matcher.parent.range[1]], '.toHaveLength')]; | ||
}, | ||
messageId: 'useToHaveLength', | ||
@@ -70,8 +61,5 @@ node: matcher | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
function isEmptyFunction(node) { | ||
@@ -17,6 +14,4 @@ if (!(0, _utils2.isFunction)(node)) { | ||
} | ||
return node.body.type === _utils.AST_NODE_TYPES.BlockStatement && !node.body.body.length; | ||
} | ||
function createTodoFixer(jestFnCall, fixer) { | ||
@@ -26,19 +21,15 @@ if (jestFnCall.members.length) { | ||
} | ||
return fixer.replaceText(jestFnCall.head.node, `${jestFnCall.head.local}.todo`); | ||
} | ||
const isTargetedTestCase = jestFnCall => { | ||
if (jestFnCall.members.some(s => (0, _utils2.getAccessorValue)(s) !== 'skip')) { | ||
return false; | ||
} // todo: we should support this too (needs custom fixer) | ||
} | ||
// todo: we should support this too (needs custom fixer) | ||
if (jestFnCall.name.startsWith('x')) { | ||
return false; | ||
} | ||
return !jestFnCall.name.startsWith('f'); | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -61,3 +52,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -68,7 +58,5 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if (!title || (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test' || !isTargetedTestCase(jestFnCall) || !(0, _utils2.isStringNode)(title)) { | ||
return; | ||
} | ||
if (callback && isEmptyFunction(callback)) { | ||
@@ -81,3 +69,2 @@ context.report({ | ||
} | ||
if ((0, _utils2.hasOnlyOneArgument)(node)) { | ||
@@ -91,8 +78,5 @@ context.report({ | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,21 +7,14 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const isJestFnCall = (node, context) => { | ||
var _getNodeName; | ||
if ((0, _utils2.parseJestFnCall)(node, context)) { | ||
return true; | ||
} | ||
return !!((_getNodeName = (0, _utils2.getNodeName)(node)) !== null && _getNodeName !== void 0 && _getNodeName.startsWith('jest.')); | ||
}; | ||
const isNullOrUndefined = node => { | ||
return node.type === _utils.AST_NODE_TYPES.Literal && node.value === null || (0, _utils2.isIdentifier)(node, 'undefined'); | ||
}; | ||
const shouldBeInHook = (node, context, allowedFunctionCalls = []) => { | ||
@@ -31,6 +24,4 @@ switch (node.type) { | ||
return shouldBeInHook(node.expression, context, allowedFunctionCalls); | ||
case _utils.AST_NODE_TYPES.CallExpression: | ||
return !(isJestFnCall(node, context) || allowedFunctionCalls.includes((0, _utils2.getNodeName)(node))); | ||
case _utils.AST_NODE_TYPES.VariableDeclaration: | ||
@@ -41,3 +32,2 @@ { | ||
} | ||
return node.declarations.some(({ | ||
@@ -47,3 +37,2 @@ init | ||
} | ||
default: | ||
@@ -53,3 +42,2 @@ return false; | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -83,3 +71,2 @@ name: __filename, | ||
}], | ||
create(context) { | ||
@@ -89,3 +76,2 @@ const { | ||
} = context.options[0] ?? {}; | ||
const checkBlockBody = body => { | ||
@@ -101,3 +87,2 @@ for (const statement of body) { | ||
}; | ||
return { | ||
@@ -107,3 +92,2 @@ Program(program) { | ||
}, | ||
CallExpression(node) { | ||
@@ -113,17 +97,11 @@ if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['describe']) || node.arguments.length < 2) { | ||
} | ||
const [, testFn] = node.arguments; | ||
if (!(0, _utils2.isFunction)(testFn) || testFn.body.type !== _utils.AST_NODE_TYPES.BlockStatement) { | ||
return; | ||
} | ||
checkBlockBody(testFn.body.body); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
var _default = (0, _utils.createRule)({ | ||
@@ -26,3 +24,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -32,7 +29,5 @@ return { | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
return; | ||
} | ||
const { | ||
@@ -42,3 +37,2 @@ matcher | ||
const matcherName = (0, _utils.getAccessorValue)(matcher); | ||
if (jestFnCall.args.length === 0 && ['toThrow', 'toThrowError'].includes(matcherName) && !jestFnCall.modifiers.some(nod => (0, _utils.getAccessorValue)(nod) === 'not')) { | ||
@@ -55,8 +49,5 @@ // Look for `toThrow` calls with no arguments. | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("./utils"); | ||
const messages = { | ||
@@ -16,3 +14,2 @@ tooManyDescribes: 'There should not be more than {{ max }} describe{{ s }} at the top level', | ||
}; | ||
var _default = (0, _utils.createRule)({ | ||
@@ -40,3 +37,2 @@ name: __filename, | ||
defaultOptions: [{}], | ||
create(context) { | ||
@@ -51,13 +47,9 @@ const { | ||
const jestFnCall = (0, _utils.parseJestFnCall)(node, context); | ||
if (!jestFnCall) { | ||
return; | ||
} | ||
if (jestFnCall.type === 'describe') { | ||
numberOfDescribeBlocks++; | ||
if (numberOfDescribeBlocks === 1) { | ||
numberOfTopLevelDescribeBlocks++; | ||
if (numberOfTopLevelDescribeBlocks > maxNumberOfTopLevelDescribes) { | ||
@@ -74,6 +66,4 @@ context.report({ | ||
} | ||
return; | ||
} | ||
if (numberOfDescribeBlocks === 0) { | ||
@@ -87,3 +77,2 @@ if (jestFnCall.type === 'test') { | ||
} | ||
if (jestFnCall.type === 'hook') { | ||
@@ -98,3 +87,2 @@ context.report({ | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -105,8 +93,5 @@ if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,9 +7,5 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const toThrowMatchers = ['toThrow', 'toThrowError', 'toThrowErrorMatchingSnapshot', 'toThrowErrorMatchingInlineSnapshot']; | ||
const baseRule = (() => { | ||
@@ -19,17 +15,12 @@ try { | ||
const TSESLintPlugin = require('@typescript-eslint/eslint-plugin'); | ||
return TSESLintPlugin.rules['unbound-method']; | ||
} catch (e) { | ||
const error = e; | ||
if (error.code === 'MODULE_NOT_FOUND') { | ||
return null; | ||
} | ||
throw error; | ||
} | ||
})(); | ||
const DEFAULT_MESSAGE = 'This rule requires `@typescript-eslint/eslint-plugin`'; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -57,18 +48,13 @@ defaultOptions: [{ | ||
}, | ||
create(context) { | ||
const baseSelectors = baseRule === null || baseRule === void 0 ? void 0 : baseRule.create(context); | ||
if (!baseSelectors) { | ||
return {}; | ||
} | ||
return { ...baseSelectors, | ||
return { | ||
...baseSelectors, | ||
MemberExpression(node) { | ||
var _node$parent, _baseSelectors$Member; | ||
if (((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) === _utils.AST_NODE_TYPES.CallExpression) { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)((0, _utils2.findTopMostCallExpression)(node.parent), context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'expect') { | ||
@@ -78,3 +64,2 @@ const { | ||
} = jestFnCall; | ||
if (!toThrowMatchers.includes((0, _utils2.getAccessorValue)(matcher))) { | ||
@@ -85,11 +70,7 @@ return; | ||
} | ||
(_baseSelectors$Member = baseSelectors.MemberExpression) === null || _baseSelectors$Member === void 0 ? void 0 : _baseSelectors$Member.call(baseSelectors, node); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,5 +7,3 @@ "use strict"; | ||
exports.isSupportedAccessor = exports.isStringNode = exports.isIdentifier = exports.getStringValue = exports.getAccessorValue = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
/** | ||
@@ -25,3 +23,2 @@ * Checks if the given `node` is a `StringLiteral`. | ||
const isStringLiteral = (node, value) => node.type === _utils.AST_NODE_TYPES.Literal && typeof node.value === 'string' && (value === undefined || node.value === value); | ||
/** | ||
@@ -42,5 +39,5 @@ * Checks if the given `node` is a `TemplateLiteral`. | ||
*/ | ||
const isTemplateLiteral = (node, value) => node.type === _utils.AST_NODE_TYPES.TemplateLiteral && node.quasis.length === 1 && ( // bail out if not simple | ||
const isTemplateLiteral = (node, value) => node.type === _utils.AST_NODE_TYPES.TemplateLiteral && node.quasis.length === 1 && ( | ||
// bail out if not simple | ||
value === undefined || node.quasis[0].value.raw === value); | ||
/** | ||
@@ -57,2 +54,3 @@ * Checks if the given `node` is a {@link StringNode}. | ||
const isStringNode = (node, specifics) => isStringLiteral(node, specifics) || isTemplateLiteral(node, specifics); | ||
/** | ||
@@ -70,14 +68,9 @@ * Gets the value of the given `StringNode`. | ||
*/ | ||
exports.isStringNode = isStringNode; | ||
const getStringValue = node => isTemplateLiteral(node) ? node.quasis[0].value.raw : node.value; | ||
const getStringValue = node => isTemplateLiteral(node) ? node.quasis[0].value.raw : node.value; | ||
/** | ||
* An `Identifier` with a known `name` value - i.e `expect`. | ||
*/ | ||
exports.getStringValue = getStringValue; | ||
/** | ||
@@ -97,2 +90,3 @@ * Checks if the given `node` is an `Identifier`. | ||
const isIdentifier = (node, name) => node.type === _utils.AST_NODE_TYPES.Identifier && (name === undefined || node.name === name); | ||
/** | ||
@@ -120,7 +114,5 @@ * Checks if the given `node` is a "supported accessor". | ||
*/ | ||
exports.isIdentifier = isIdentifier; | ||
const isSupportedAccessor = (node, value) => isIdentifier(node, value) || isStringNode(node, value); | ||
const isSupportedAccessor = (node, value) => isIdentifier(node, value) || isStringNode(node, value); | ||
/** | ||
@@ -136,8 +128,4 @@ * Gets the value of the given `AccessorNode`, | ||
*/ | ||
exports.isSupportedAccessor = isSupportedAccessor; | ||
const getAccessorValue = accessor => accessor.type === _utils.AST_NODE_TYPES.Identifier ? accessor.name : getStringValue(accessor); | ||
exports.getAccessorValue = getAccessorValue; |
@@ -8,3 +8,2 @@ "use strict"; | ||
let cachedJestVersion = null; | ||
const detectJestVersion = () => { | ||
@@ -14,9 +13,7 @@ if (cachedJestVersion) { | ||
} | ||
try { | ||
const jestPath = require.resolve('jest/package.json'); | ||
const jestPackageJson = // eslint-disable-next-line @typescript-eslint/no-require-imports | ||
const jestPackageJson = | ||
// eslint-disable-next-line @typescript-eslint/no-require-imports | ||
require(jestPath); | ||
if (jestPackageJson.version) { | ||
@@ -27,6 +24,4 @@ const [majorVersion] = jestPackageJson.version.split('.'); | ||
} catch {} | ||
throw new Error('Unable to detect Jest version - please ensure jest package is installed, or otherwise set version explicitly'); | ||
}; | ||
exports.detectJestVersion = detectJestVersion; |
@@ -7,9 +7,5 @@ "use strict"; | ||
exports.followTypeAssertionChain = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
const isTypeCastExpression = node => node.type === _utils.AST_NODE_TYPES.TSAsExpression || node.type === _utils.AST_NODE_TYPES.TSTypeAssertion; | ||
const followTypeAssertionChain = expression => isTypeCastExpression(expression) ? followTypeAssertionChain(expression.expression) : expression; | ||
exports.followTypeAssertionChain = followTypeAssertionChain; |
@@ -6,5 +6,3 @@ "use strict"; | ||
}); | ||
var _accessors = require("./accessors"); | ||
Object.keys(_accessors).forEach(function (key) { | ||
@@ -20,5 +18,3 @@ if (key === "default" || key === "__esModule") return; | ||
}); | ||
var _detectJestVersion = require("./detectJestVersion"); | ||
Object.keys(_detectJestVersion).forEach(function (key) { | ||
@@ -34,5 +30,3 @@ if (key === "default" || key === "__esModule") return; | ||
}); | ||
var _followTypeAssertionChain = require("./followTypeAssertionChain"); | ||
Object.keys(_followTypeAssertionChain).forEach(function (key) { | ||
@@ -48,5 +42,3 @@ if (key === "default" || key === "__esModule") return; | ||
}); | ||
var _misc = require("./misc"); | ||
Object.keys(_misc).forEach(function (key) { | ||
@@ -62,5 +54,3 @@ if (key === "default" || key === "__esModule") return; | ||
}); | ||
var _parseJestFnCall = require("./parseJestFnCall"); | ||
Object.keys(_parseJestFnCall).forEach(function (key) { | ||
@@ -67,0 +57,0 @@ if (key === "default" || key === "__esModule") return; |
@@ -9,17 +9,9 @@ "use strict"; | ||
exports.replaceAccessorFixer = exports.isFunction = exports.isBooleanLiteral = exports.hasOnlyOneArgument = exports.getTestCallExpressionsFromDeclaredVariables = void 0; | ||
var _path = require("path"); | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _package = require("../../../package.json"); | ||
var _accessors = require("./accessors"); | ||
var _followTypeAssertionChain = require("./followTypeAssertionChain"); | ||
var _parseJestFnCall = require("./parseJestFnCall"); | ||
const REPO_URL = 'https://github.com/jest-community/eslint-plugin-jest'; | ||
const createRule = _utils.ESLintUtils.RuleCreator(name => { | ||
@@ -29,9 +21,7 @@ const ruleName = (0, _path.parse)(name).name; | ||
}); | ||
/** | ||
* Represents a `MemberExpression` with a "known" `property`. | ||
*/ | ||
exports.createRule = createRule; | ||
/** | ||
@@ -45,7 +35,5 @@ * Guards that the given `call` has only one `argument`. | ||
const hasOnlyOneArgument = call => call.arguments.length === 1; | ||
exports.hasOnlyOneArgument = hasOnlyOneArgument; | ||
let DescribeAlias; | ||
exports.DescribeAlias = DescribeAlias; | ||
(function (DescribeAlias) { | ||
@@ -56,6 +44,4 @@ DescribeAlias["describe"] = "describe"; | ||
})(DescribeAlias || (exports.DescribeAlias = DescribeAlias = {})); | ||
let TestCaseName; | ||
exports.TestCaseName = TestCaseName; | ||
(function (TestCaseName) { | ||
@@ -68,6 +54,4 @@ TestCaseName["fit"] = "fit"; | ||
})(TestCaseName || (exports.TestCaseName = TestCaseName = {})); | ||
let HookName; | ||
exports.HookName = HookName; | ||
(function (HookName) { | ||
@@ -79,6 +63,4 @@ HookName["beforeAll"] = "beforeAll"; | ||
})(HookName || (exports.HookName = HookName = {})); | ||
let ModifierName; | ||
exports.ModifierName = ModifierName; | ||
(function (ModifierName) { | ||
@@ -89,6 +71,4 @@ ModifierName["not"] = "not"; | ||
})(ModifierName || (exports.ModifierName = ModifierName = {})); | ||
let EqualityMatcher; | ||
exports.EqualityMatcher = EqualityMatcher; | ||
(function (EqualityMatcher) { | ||
@@ -99,5 +79,3 @@ EqualityMatcher["toBe"] = "toBe"; | ||
})(EqualityMatcher || (exports.EqualityMatcher = EqualityMatcher = {})); | ||
const joinNames = (a, b) => a && b ? `${a}.${b}` : null; | ||
function getNodeName(node) { | ||
@@ -107,10 +85,7 @@ if ((0, _accessors.isSupportedAccessor)(node)) { | ||
} | ||
switch (node.type) { | ||
case _utils.AST_NODE_TYPES.TaggedTemplateExpression: | ||
return getNodeName(node.tag); | ||
case _utils.AST_NODE_TYPES.MemberExpression: | ||
return joinNames(getNodeName(node.object), getNodeName(node.property)); | ||
case _utils.AST_NODE_TYPES.NewExpression: | ||
@@ -120,10 +95,6 @@ case _utils.AST_NODE_TYPES.CallExpression: | ||
} | ||
return null; | ||
} | ||
const isFunction = node => node.type === _utils.AST_NODE_TYPES.FunctionExpression || node.type === _utils.AST_NODE_TYPES.ArrowFunctionExpression; | ||
exports.isFunction = isFunction; | ||
const getTestCallExpressionsFromDeclaredVariables = (declaredVariables, context) => { | ||
@@ -136,2 +107,3 @@ return declaredVariables.reduce((acc, { | ||
}; | ||
/** | ||
@@ -143,12 +115,7 @@ * Replaces an accessor node with the given `text`, surrounding it in quotes if required. | ||
*/ | ||
exports.getTestCallExpressionsFromDeclaredVariables = getTestCallExpressionsFromDeclaredVariables; | ||
const replaceAccessorFixer = (fixer, node, text) => { | ||
return fixer.replaceText(node, node.type === _utils.AST_NODE_TYPES.Identifier ? text : `'${text}'`); | ||
}; | ||
exports.replaceAccessorFixer = replaceAccessorFixer; | ||
const findTopMostCallExpression = node => { | ||
@@ -159,3 +126,2 @@ let topMostCallExpression = node; | ||
} = node; | ||
while (parent) { | ||
@@ -167,29 +133,19 @@ if (parent.type === _utils.AST_NODE_TYPES.CallExpression) { | ||
} | ||
if (parent.type !== _utils.AST_NODE_TYPES.MemberExpression) { | ||
break; | ||
} | ||
parent = parent.parent; | ||
} | ||
return topMostCallExpression; | ||
}; | ||
exports.findTopMostCallExpression = findTopMostCallExpression; | ||
const isBooleanLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && typeof node.value === 'boolean'; | ||
exports.isBooleanLiteral = isBooleanLiteral; | ||
const getFirstMatcherArg = expectFnCall => { | ||
const [firstArg] = expectFnCall.args; | ||
if (firstArg.type === _utils.AST_NODE_TYPES.SpreadElement) { | ||
return firstArg; | ||
} | ||
return (0, _followTypeAssertionChain.followTypeAssertionChain)(firstArg); | ||
}; | ||
exports.getFirstMatcherArg = getFirstMatcherArg; |
@@ -8,7 +8,4 @@ "use strict"; | ||
exports.scopeHasLocalReference = exports.parseJestFnCallWithReason = exports.parseJestFnCall = exports.isTypeOfJestFnCall = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("../utils"); | ||
const isTypeOfJestFnCall = (node, context, types) => { | ||
@@ -18,7 +15,4 @@ const jestFnCall = parseJestFnCall(node, context); | ||
}; | ||
exports.isTypeOfJestFnCall = isTypeOfJestFnCall; | ||
const joinChains = (a, b) => a && b ? [...a, ...b] : null; | ||
function getNodeChain(node) { | ||
@@ -28,17 +22,12 @@ if ((0, _utils2.isSupportedAccessor)(node)) { | ||
} | ||
switch (node.type) { | ||
case _utils.AST_NODE_TYPES.TaggedTemplateExpression: | ||
return getNodeChain(node.tag); | ||
case _utils.AST_NODE_TYPES.MemberExpression: | ||
return joinChains(getNodeChain(node.object), getNodeChain(node.property)); | ||
case _utils.AST_NODE_TYPES.CallExpression: | ||
return getNodeChain(node.callee); | ||
} | ||
return null; | ||
} | ||
const determineJestFnType = name => { | ||
@@ -48,62 +37,44 @@ if (name === 'expect') { | ||
} | ||
if (name === 'jest') { | ||
return 'jest'; | ||
} | ||
if (_utils2.DescribeAlias.hasOwnProperty(name)) { | ||
return 'describe'; | ||
} | ||
if (_utils2.TestCaseName.hasOwnProperty(name)) { | ||
return 'test'; | ||
} | ||
/* istanbul ignore else */ | ||
if (_utils2.HookName.hasOwnProperty(name)) { | ||
return 'hook'; | ||
} | ||
/* istanbul ignore next */ | ||
return 'unknown'; | ||
}; | ||
const ValidJestFnCallChains = ['afterAll', 'afterEach', 'beforeAll', 'beforeEach', 'describe', 'describe.each', 'describe.only', 'describe.only.each', 'describe.skip', 'describe.skip.each', 'fdescribe', 'fdescribe.each', 'xdescribe', 'xdescribe.each', 'it', 'it.concurrent', 'it.concurrent.each', 'it.concurrent.only.each', 'it.concurrent.skip.each', 'it.each', 'it.failing', 'it.only', 'it.only.each', 'it.only.failing', 'it.skip', 'it.skip.each', 'it.skip.failing', 'it.todo', 'fit', 'fit.each', 'fit.failing', 'xit', 'xit.each', 'xit.failing', 'test', 'test.concurrent', 'test.concurrent.each', 'test.concurrent.only.each', 'test.concurrent.skip.each', 'test.each', 'test.failing', 'test.only', 'test.only.each', 'test.only.failing', 'test.skip', 'test.skip.each', 'test.skip.failing', 'test.todo', 'xtest', 'xtest.each', 'xtest.failing']; | ||
const resolvePossibleAliasedGlobal = (global, context) => { | ||
var _context$settings$jes; | ||
const globalAliases = ((_context$settings$jes = context.settings.jest) === null || _context$settings$jes === void 0 ? void 0 : _context$settings$jes.globalAliases) ?? {}; | ||
const alias = Object.entries(globalAliases).find(([, aliases]) => aliases.includes(global)); | ||
if (alias) { | ||
return alias[0]; | ||
} | ||
return null; | ||
}; | ||
const parseJestFnCallCache = new WeakMap(); | ||
const parseJestFnCall = (node, context) => { | ||
const jestFnCall = parseJestFnCallWithReason(node, context); | ||
if (typeof jestFnCall === 'string') { | ||
return null; | ||
} | ||
return jestFnCall; | ||
}; | ||
exports.parseJestFnCall = parseJestFnCall; | ||
const parseJestFnCallWithReason = (node, context) => { | ||
let parsedJestFnCall = parseJestFnCallCache.get(node); | ||
if (parsedJestFnCall) { | ||
return parsedJestFnCall; | ||
} | ||
parsedJestFnCall = parseJestFnCallWithReasonInner(node, context); | ||
@@ -113,17 +84,13 @@ parseJestFnCallCache.set(node, parsedJestFnCall); | ||
}; | ||
exports.parseJestFnCallWithReason = parseJestFnCallWithReason; | ||
const parseJestFnCallWithReasonInner = (node, context) => { | ||
var _node$parent2, _node$parent3; | ||
const chain = getNodeChain(node); | ||
if (!(chain !== null && chain !== void 0 && chain.length)) { | ||
return null; | ||
} | ||
const [first, ...rest] = chain; | ||
const lastLink = (0, _utils2.getAccessorValue)(chain[chain.length - 1]); // if we're an `each()`, ensure we're the outer CallExpression (i.e `.each()()`) | ||
const lastLink = (0, _utils2.getAccessorValue)(chain[chain.length - 1]); | ||
// if we're an `each()`, ensure we're the outer CallExpression (i.e `.each()()`) | ||
if (lastLink === 'each') { | ||
@@ -134,23 +101,20 @@ if (node.callee.type !== _utils.AST_NODE_TYPES.CallExpression && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) { | ||
} | ||
if (node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression && lastLink !== 'each') { | ||
return null; | ||
} | ||
const resolved = resolveToJestFn(context, (0, _utils2.getAccessorValue)(first)); | ||
const resolved = resolveToJestFn(context, (0, _utils2.getAccessorValue)(first)); // we're not a jest function | ||
// we're not a jest function | ||
if (!resolved) { | ||
return null; | ||
} | ||
const name = resolved.original ?? resolved.local; | ||
const links = [name, ...rest.map(link => (0, _utils2.getAccessorValue)(link))]; | ||
if (name !== 'jest' && name !== 'expect' && !ValidJestFnCallChains.includes(links.join('.'))) { | ||
return null; | ||
} | ||
const parsedJestFnCall = { | ||
name, | ||
head: { ...resolved, | ||
head: { | ||
...resolved, | ||
node: first | ||
@@ -163,14 +127,12 @@ }, | ||
const type = determineJestFnType(name); | ||
if (type === 'expect') { | ||
const result = parseJestExpectCall(parsedJestFnCall); | ||
if (type === 'expect') { | ||
const result = parseJestExpectCall(parsedJestFnCall); // if the `expect` call chain is not valid, only report on the topmost node | ||
// if the `expect` call chain is not valid, only report on the topmost node | ||
// since all members in the chain are likely to get flagged for some reason | ||
if (typeof result === 'string' && (0, _utils2.findTopMostCallExpression)(node) !== node) { | ||
return null; | ||
} | ||
if (result === 'matcher-not-found') { | ||
var _node$parent; | ||
if (((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) === _utils.AST_NODE_TYPES.MemberExpression) { | ||
@@ -180,33 +142,28 @@ return 'matcher-not-called'; | ||
} | ||
return result; | ||
} // check that every link in the chain except the last is a member expression | ||
} | ||
// check that every link in the chain except the last is a member expression | ||
if (chain.slice(0, chain.length - 1).some(nod => { | ||
var _nod$parent; | ||
return ((_nod$parent = nod.parent) === null || _nod$parent === void 0 ? void 0 : _nod$parent.type) !== _utils.AST_NODE_TYPES.MemberExpression; | ||
})) { | ||
return null; | ||
} // ensure that we're at the "top" of the function call chain otherwise when | ||
} | ||
// ensure that we're at the "top" of the function call chain otherwise when | ||
// parsing e.g. x().y.z(), we'll incorrectly find & parse "x()" even though | ||
// the full chain is not a valid jest function call chain | ||
if (((_node$parent2 = node.parent) === null || _node$parent2 === void 0 ? void 0 : _node$parent2.type) === _utils.AST_NODE_TYPES.CallExpression || ((_node$parent3 = node.parent) === null || _node$parent3 === void 0 ? void 0 : _node$parent3.type) === _utils.AST_NODE_TYPES.MemberExpression) { | ||
return null; | ||
} | ||
return { ...parsedJestFnCall, | ||
return { | ||
...parsedJestFnCall, | ||
type | ||
}; | ||
}; | ||
const findModifiersAndMatcher = members => { | ||
const modifiers = []; | ||
for (const member of members) { | ||
var _member$parent, _member$parent$parent; | ||
// check if the member is being called, which means it is the matcher | ||
@@ -220,7 +177,6 @@ // (and also the end of the entire "expect" call chain) | ||
}; | ||
} // otherwise, it should be a modifier | ||
} | ||
// otherwise, it should be a modifier | ||
const name = (0, _utils2.getAccessorValue)(member); | ||
if (modifiers.length === 0) { | ||
@@ -236,5 +192,5 @@ // the first modifier can be any of the three modifiers | ||
} | ||
const firstModifier = (0, _utils2.getAccessorValue)(modifiers[0]); | ||
const firstModifier = (0, _utils2.getAccessorValue)(modifiers[0]); // and the first modifier has to be either "resolves" or "rejects" | ||
// and the first modifier has to be either "resolves" or "rejects" | ||
if (firstModifier !== _utils2.ModifierName.resolves && firstModifier !== _utils2.ModifierName.rejects) { | ||
@@ -246,18 +202,15 @@ return 'modifier-unknown'; | ||
} | ||
modifiers.push(member); | ||
} // this will only really happen if there are no members | ||
} | ||
// this will only really happen if there are no members | ||
return 'matcher-not-found'; | ||
}; | ||
const parseJestExpectCall = typelessParsedJestFnCall => { | ||
const modifiersAndMatcher = findModifiersAndMatcher(typelessParsedJestFnCall.members); | ||
if (typeof modifiersAndMatcher === 'string') { | ||
return modifiersAndMatcher; | ||
} | ||
return { ...typelessParsedJestFnCall, | ||
return { | ||
...typelessParsedJestFnCall, | ||
type: 'expect', | ||
@@ -267,3 +220,2 @@ ...modifiersAndMatcher | ||
}; | ||
const describeImportDefAsImport = def => { | ||
@@ -273,12 +225,10 @@ if (def.parent.type === _utils.AST_NODE_TYPES.TSImportEqualsDeclaration) { | ||
} | ||
if (def.node.type !== _utils.AST_NODE_TYPES.ImportSpecifier) { | ||
return null; | ||
} // we only care about value imports | ||
} | ||
// we only care about value imports | ||
if (def.parent.importKind === 'type') { | ||
return null; | ||
} | ||
return { | ||
@@ -290,2 +240,3 @@ source: def.parent.source.value, | ||
}; | ||
/** | ||
@@ -298,4 +249,2 @@ * Attempts to find the node that represents the import source for the | ||
*/ | ||
const findImportSourceNode = node => { | ||
@@ -306,16 +255,11 @@ if (node.type === _utils.AST_NODE_TYPES.AwaitExpression) { | ||
} | ||
return null; | ||
} | ||
if (node.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isIdentifier)(node.callee, 'require')) { | ||
return node.arguments[0] ?? null; | ||
} | ||
return null; | ||
}; | ||
const describeVariableDefAsImport = def => { | ||
var _def$name$parent; | ||
// make sure that we've actually being assigned a value | ||
@@ -325,17 +269,12 @@ if (!def.node.init) { | ||
} | ||
const sourceNode = findImportSourceNode(def.node.init); | ||
if (!sourceNode || !(0, _utils2.isStringNode)(sourceNode)) { | ||
return null; | ||
} | ||
if (((_def$name$parent = def.name.parent) === null || _def$name$parent === void 0 ? void 0 : _def$name$parent.type) !== _utils.AST_NODE_TYPES.Property) { | ||
return null; | ||
} | ||
if (!(0, _utils2.isSupportedAccessor)(def.name.parent.key)) { | ||
return null; | ||
} | ||
return { | ||
@@ -347,2 +286,3 @@ source: (0, _utils2.getStringValue)(sourceNode), | ||
}; | ||
/** | ||
@@ -358,4 +298,2 @@ * Attempts to describe a definition as an import if possible. | ||
*/ | ||
const describePossibleImportDef = def => { | ||
@@ -365,10 +303,7 @@ if (def.type === 'Variable') { | ||
} | ||
if (def.type === 'ImportBinding') { | ||
return describeImportDefAsImport(def); | ||
} | ||
return null; | ||
}; | ||
const collectReferences = scope => { | ||
@@ -379,3 +314,2 @@ const locals = new Set(); | ||
let currentScope = scope; | ||
while (currentScope !== null) { | ||
@@ -386,6 +320,4 @@ for (const ref of currentScope.variables) { | ||
} | ||
const def = ref.defs[ref.defs.length - 1]; | ||
const importDetails = describePossibleImportDef(def); | ||
if (importDetails) { | ||
@@ -395,13 +327,9 @@ imports.set(importDetails.local, importDetails); | ||
} | ||
locals.add(ref.name); | ||
} | ||
for (const ref of currentScope.through) { | ||
unresolved.add(ref.identifier.name); | ||
} | ||
currentScope = currentScope.upper; | ||
} | ||
return { | ||
@@ -413,7 +341,5 @@ locals, | ||
}; | ||
const resolveToJestFn = (context, identifier) => { | ||
const references = collectReferences(context.getScope()); | ||
const maybeImport = references.imports.get(identifier); | ||
if (maybeImport) { | ||
@@ -429,12 +355,10 @@ // the identifier is imported from @jest/globals, | ||
} | ||
return null; | ||
} | ||
return null; | ||
} // the identifier was found as a local variable or function declaration | ||
// the identifier was found as a local variable or function declaration | ||
// meaning it's not a function from jest | ||
if (references.locals.has(identifier)) { | ||
return null; | ||
} | ||
return { | ||
@@ -446,8 +370,10 @@ original: resolvePossibleAliasedGlobal(identifier, context), | ||
}; | ||
const scopeHasLocalReference = (scope, referenceName) => { | ||
const references = collectReferences(scope); | ||
return (// referenceName was found as a local variable or function declaration. | ||
references.locals.has(referenceName) || // referenceName was found as an imported identifier | ||
references.imports.has(referenceName) || // referenceName was not found as an unresolved reference, | ||
return ( | ||
// referenceName was found as a local variable or function declaration. | ||
references.locals.has(referenceName) || | ||
// referenceName was found as an imported identifier | ||
references.imports.has(referenceName) || | ||
// referenceName was not found as an unresolved reference, | ||
// meaning it is likely not an implicit global reference. | ||
@@ -457,3 +383,2 @@ !references.unresolved.has(referenceName) | ||
}; | ||
exports.scopeHasLocalReference = scopeHasLocalReference; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const paramsLocation = params => { | ||
@@ -21,3 +18,2 @@ const [first] = params; | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -42,3 +38,2 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
@@ -48,7 +43,5 @@ return { | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe') { | ||
return; | ||
} | ||
if (node.arguments.length < 1) { | ||
@@ -60,5 +53,3 @@ return context.report({ | ||
} | ||
const [, callback] = node.arguments; | ||
if (!callback) { | ||
@@ -71,3 +62,2 @@ context.report({ | ||
} | ||
if (!(0, _utils2.isFunction)(callback)) { | ||
@@ -80,3 +70,2 @@ context.report({ | ||
} | ||
if (callback.async) { | ||
@@ -88,3 +77,2 @@ context.report({ | ||
} | ||
if (jestFnCall.members.every(s => (0, _utils2.getAccessorValue)(s) !== 'each') && callback.params.length) { | ||
@@ -96,3 +84,2 @@ context.report({ | ||
} | ||
if (callback.body.type === _utils.AST_NODE_TYPES.CallExpression) { | ||
@@ -104,3 +91,2 @@ context.report({ | ||
} | ||
if (callback.body.type === _utils.AST_NODE_TYPES.BlockStatement) { | ||
@@ -117,8 +103,5 @@ callback.body.body.forEach(node => { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const isPromiseChainCall = node => { | ||
@@ -19,7 +16,5 @@ if (node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property)) { | ||
} | ||
switch ((0, _utils2.getAccessorValue)(node.callee.property)) { | ||
case 'then': | ||
return node.arguments.length < 3; | ||
case 'catch': | ||
@@ -30,15 +25,10 @@ case 'finally': | ||
} | ||
return false; | ||
}; | ||
const isTestCaseCallWithCallbackArg = (node, context) => { | ||
const jestCallFn = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestCallFn === null || jestCallFn === void 0 ? void 0 : jestCallFn.type) !== 'test') { | ||
return false; | ||
} | ||
const isJestEach = jestCallFn.members.some(s => (0, _utils2.getAccessorValue)(s) === 'each'); | ||
if (isJestEach && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) { | ||
@@ -51,3 +41,2 @@ // isJestEach but not a TaggedTemplateExpression, so this must be | ||
} | ||
const [, callback] = node.arguments; | ||
@@ -57,3 +46,2 @@ const callbackArgIndex = Number(isJestEach); | ||
}; | ||
const isPromiseMethodThatUsesValue = (node, identifier) => { | ||
@@ -63,13 +51,9 @@ const { | ||
} = identifier; | ||
if (node.argument === null) { | ||
return false; | ||
} | ||
if (node.argument.type === _utils.AST_NODE_TYPES.CallExpression && node.argument.arguments.length > 0) { | ||
const nodeName = (0, _utils2.getNodeName)(node.argument); | ||
if (['Promise.all', 'Promise.allSettled'].includes(nodeName)) { | ||
const [firstArg] = node.argument.arguments; | ||
if (firstArg.type === _utils.AST_NODE_TYPES.ArrayExpression && firstArg.elements.some(nod => (0, _utils2.isIdentifier)(nod, name))) { | ||
@@ -79,3 +63,2 @@ return true; | ||
} | ||
if (['Promise.resolve', 'Promise.reject'].includes(nodeName) && node.argument.arguments.length === 1) { | ||
@@ -85,5 +68,5 @@ return (0, _utils2.isIdentifier)(node.argument.arguments[0], name); | ||
} | ||
return (0, _utils2.isIdentifier)(node.argument, name); | ||
}; | ||
/** | ||
@@ -93,4 +76,2 @@ * Attempts to determine if the runtime value represented by the given `identifier` | ||
*/ | ||
const isValueAwaitedInElements = (name, elements) => { | ||
@@ -101,3 +82,2 @@ for (const element of elements) { | ||
} | ||
if (element.type === _utils.AST_NODE_TYPES.ArrayExpression && isValueAwaitedInElements(name, element.elements)) { | ||
@@ -107,5 +87,5 @@ return true; | ||
} | ||
return false; | ||
}; | ||
/** | ||
@@ -115,7 +95,4 @@ * Attempts to determine if the runtime value represented by the given `identifier` | ||
*/ | ||
const isValueAwaitedInArguments = (name, call) => { | ||
let node = call; | ||
while (node) { | ||
@@ -126,20 +103,14 @@ if (node.type === _utils.AST_NODE_TYPES.CallExpression) { | ||
} | ||
node = node.callee; | ||
} | ||
if (node.type !== _utils.AST_NODE_TYPES.MemberExpression) { | ||
break; | ||
} | ||
node = node.object; | ||
} | ||
return false; | ||
}; | ||
const getLeftMostCallExpression = call => { | ||
let leftMostCallExpression = call; | ||
let node = call; | ||
while (node) { | ||
@@ -150,12 +121,10 @@ if (node.type === _utils.AST_NODE_TYPES.CallExpression) { | ||
} | ||
if (node.type !== _utils.AST_NODE_TYPES.MemberExpression) { | ||
break; | ||
} | ||
node = node.object; | ||
} | ||
return leftMostCallExpression; | ||
}; | ||
/** | ||
@@ -165,4 +134,2 @@ * Attempts to determine if the runtime value represented by the given `identifier` | ||
*/ | ||
const isValueAwaitedOrReturned = (identifier, body, context) => { | ||
@@ -172,3 +139,2 @@ const { | ||
} = identifier; | ||
for (const node of body) { | ||
@@ -180,7 +146,5 @@ // skip all nodes that are before this identifier, because they'd probably | ||
} | ||
if (node.type === _utils.AST_NODE_TYPES.ReturnStatement) { | ||
return isPromiseMethodThatUsesValue(node, identifier); | ||
} | ||
if (node.type === _utils.AST_NODE_TYPES.ExpressionStatement) { | ||
@@ -192,6 +156,4 @@ // it's possible that we're awaiting the value as an argument | ||
} | ||
const leftMostCall = getLeftMostCallExpression(node.expression); | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node.expression, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'expect' && leftMostCall.arguments.length > 0 && (0, _utils2.isIdentifier)(leftMostCall.arguments[0], name)) { | ||
@@ -206,12 +168,10 @@ if (jestFnCall.members.some(m => { | ||
} | ||
if (node.expression.type === _utils.AST_NODE_TYPES.AwaitExpression && isPromiseMethodThatUsesValue(node.expression, identifier)) { | ||
return true; | ||
} // (re)assignment changes the runtime value, so if we've not found an | ||
} | ||
// (re)assignment changes the runtime value, so if we've not found an | ||
// await or return already we act as if we've reached the end of the body | ||
if (node.expression.type === _utils.AST_NODE_TYPES.AssignmentExpression) { | ||
var _getNodeName; | ||
// unless we're assigning to the same identifier, in which case | ||
@@ -222,7 +182,5 @@ // we might be chaining off the existing promise value | ||
} | ||
break; | ||
} | ||
} | ||
if (node.type === _utils.AST_NODE_TYPES.BlockStatement && isValueAwaitedOrReturned(identifier, node.body, context)) { | ||
@@ -232,9 +190,6 @@ return true; | ||
} | ||
return false; | ||
}; | ||
const findFirstBlockBodyUp = node => { | ||
let parent = node; | ||
while (parent) { | ||
@@ -244,39 +199,30 @@ if (parent.type === _utils.AST_NODE_TYPES.BlockStatement) { | ||
} | ||
parent = parent.parent; | ||
} | ||
/* istanbul ignore next */ | ||
throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`); | ||
}; | ||
const isDirectlyWithinTestCaseCall = (node, context) => { | ||
let parent = node; | ||
while (parent) { | ||
if ((0, _utils2.isFunction)(parent)) { | ||
var _parent; | ||
parent = parent.parent; | ||
return ((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTypeOfJestFnCall)(parent, context, ['test']); | ||
} | ||
parent = parent.parent; | ||
} | ||
return false; | ||
}; | ||
const isVariableAwaitedOrReturned = (variable, context) => { | ||
const body = findFirstBlockBodyUp(variable); | ||
const isVariableAwaitedOrReturned = (variable, context) => { | ||
const body = findFirstBlockBodyUp(variable); // it's pretty much impossible for us to track destructuring assignments, | ||
// it's pretty much impossible for us to track destructuring assignments, | ||
// so we return true to bailout gracefully | ||
if (!(0, _utils2.isIdentifier)(variable.id)) { | ||
return true; | ||
} | ||
return isValueAwaitedOrReturned(variable.id, body, context); | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -297,5 +243,5 @@ name: __filename, | ||
defaultOptions: [], | ||
create(context) { | ||
let inTestCaseWithDoneCallback = false; // an array of booleans representing each promise chain we enter, with the | ||
let inTestCaseWithDoneCallback = false; | ||
// an array of booleans representing each promise chain we enter, with the | ||
// boolean value representing if we think a given chain contains an expect | ||
@@ -307,3 +253,2 @@ // in it's body. | ||
// slightly less code to assign to by not needing to know the length | ||
const chains = []; | ||
@@ -317,13 +262,13 @@ return { | ||
return; | ||
} // if this call expression is a promise chain, add it to the stack with | ||
} | ||
// if this call expression is a promise chain, add it to the stack with | ||
// value of "false", as we assume there are no expect calls initially | ||
if (isPromiseChainCall(node)) { | ||
chains.unshift(false); | ||
return; | ||
} // if we're within a promise chain, and this call expression looks like | ||
} | ||
// if we're within a promise chain, and this call expression looks like | ||
// an expect call, mark the deepest chain as having an expect call | ||
if (chains.length > 0 && (0, _utils2.isTypeOfJestFnCall)(node, context, ['expect'])) { | ||
@@ -333,3 +278,2 @@ chains[0] = true; | ||
}, | ||
'CallExpression:exit'(node) { | ||
@@ -343,30 +287,28 @@ // there are too many ways that the "done" argument could be used to | ||
} | ||
return; | ||
} | ||
if (!isPromiseChainCall(node)) { | ||
return; | ||
} // since we're exiting this call expression (which is a promise chain) | ||
} | ||
// since we're exiting this call expression (which is a promise chain) | ||
// we remove it from the stack of chains, since we're unwinding | ||
const hasExpectCall = chains.shift(); | ||
const hasExpectCall = chains.shift(); // if the promise chain we're exiting doesn't contain an expect, | ||
// if the promise chain we're exiting doesn't contain an expect, | ||
// then we don't need to check it for anything | ||
if (!hasExpectCall) { | ||
return; | ||
} | ||
const { | ||
parent | ||
} = (0, _utils2.findTopMostCallExpression)(node); // if we don't have a parent (which is technically impossible at runtime) | ||
} = (0, _utils2.findTopMostCallExpression)(node); | ||
// if we don't have a parent (which is technically impossible at runtime) | ||
// or our parent is not directly within the test case, we stop checking | ||
// because we're most likely in the body of a function being defined | ||
// within the test, which we can't track | ||
if (!parent || !isDirectlyWithinTestCaseCall(parent, context)) { | ||
return; | ||
} | ||
switch (parent.type) { | ||
@@ -378,6 +320,4 @@ case _utils.AST_NODE_TYPES.VariableDeclarator: | ||
} | ||
break; | ||
} | ||
case _utils.AST_NODE_TYPES.AssignmentExpression: | ||
@@ -388,9 +328,6 @@ { | ||
} | ||
break; | ||
} | ||
case _utils.AST_NODE_TYPES.ExpressionStatement: | ||
break; | ||
case _utils.AST_NODE_TYPES.ReturnStatement: | ||
@@ -401,3 +338,2 @@ case _utils.AST_NODE_TYPES.AwaitExpression: | ||
} | ||
context.report({ | ||
@@ -408,8 +344,5 @@ messageId: 'expectInFloatingPromise', | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,7 +7,4 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
/* | ||
@@ -29,21 +26,14 @@ * This implementation is ported from from eslint-plugin-jasmine. | ||
} | ||
if (node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.object, 'Promise') && node.parent) { | ||
return node; | ||
} | ||
return null; | ||
}; | ||
const findPromiseCallExpressionNode = node => { | ||
var _node$parent; | ||
return (_node$parent = node.parent) !== null && _node$parent !== void 0 && _node$parent.parent && [_utils.AST_NODE_TYPES.CallExpression, _utils.AST_NODE_TYPES.ArrayExpression].includes(node.parent.type) ? getPromiseCallExpressionNode(node.parent) : null; | ||
}; | ||
const getParentIfThenified = node => { | ||
var _node$parent2; | ||
const grandParentNode = (_node$parent2 = node.parent) === null || _node$parent2 === void 0 ? void 0 : _node$parent2.parent; | ||
if (grandParentNode && grandParentNode.type === _utils.AST_NODE_TYPES.CallExpression && grandParentNode.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(grandParentNode.callee.property) && ['then', 'catch'].includes((0, _utils2.getAccessorValue)(grandParentNode.callee.property)) && grandParentNode.parent) { | ||
@@ -53,6 +43,4 @@ // Just in case `then`s are chained look one above. | ||
} | ||
return node; | ||
}; | ||
const isAcceptableReturnNode = (node, allowReturn) => { | ||
@@ -62,10 +50,7 @@ if (allowReturn && node.type === _utils.AST_NODE_TYPES.ReturnStatement) { | ||
} | ||
if (node.type === _utils.AST_NODE_TYPES.ConditionalExpression && node.parent) { | ||
return isAcceptableReturnNode(node.parent, allowReturn); | ||
} | ||
return [_utils.AST_NODE_TYPES.ArrowFunctionExpression, _utils.AST_NODE_TYPES.AwaitExpression].includes(node.type); | ||
}; | ||
const promiseArrayExceptionKey = ({ | ||
@@ -75,5 +60,3 @@ start, | ||
}) => `${start.line}:${start.column}-${end.line}:${end.column}`; | ||
const defaultAsyncMatchers = ['toReject', 'toResolve']; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -128,3 +111,2 @@ name: __filename, | ||
}], | ||
create(context, [{ | ||
@@ -138,4 +120,4 @@ alwaysAwait, | ||
const arrayExceptions = new Set(); | ||
const pushPromiseArrayException = loc => arrayExceptions.add(promiseArrayExceptionKey(loc)); | ||
const pushPromiseArrayException = loc => arrayExceptions.add(promiseArrayExceptionKey(loc)); | ||
/** | ||
@@ -148,6 +130,3 @@ * Promise method that accepts an array of promises, | ||
*/ | ||
const promiseArrayExceptionExists = loc => arrayExceptions.has(promiseArrayExceptionKey(loc)); | ||
const findTopMostMemberExpression = node => { | ||
@@ -158,3 +137,2 @@ let topMostMemberExpression = node; | ||
} = node; | ||
while (parent) { | ||
@@ -164,19 +142,13 @@ if (parent.type !== _utils.AST_NODE_TYPES.MemberExpression) { | ||
} | ||
topMostMemberExpression = parent; | ||
parent = parent.parent; | ||
} | ||
return topMostMemberExpression; | ||
}; | ||
return { | ||
CallExpression(node) { | ||
const jestFnCall = (0, _utils2.parseJestFnCallWithReason)(node, context); | ||
if (typeof jestFnCall === 'string') { | ||
var _node$parent3; | ||
const reportingNode = ((_node$parent3 = node.parent) === null || _node$parent3 === void 0 ? void 0 : _node$parent3.type) === _utils.AST_NODE_TYPES.MemberExpression ? findTopMostMemberExpression(node.parent).property : node; | ||
if (jestFnCall === 'matcher-not-found') { | ||
@@ -189,3 +161,2 @@ context.report({ | ||
} | ||
if (jestFnCall === 'matcher-not-called') { | ||
@@ -197,3 +168,2 @@ context.report({ | ||
} | ||
if (jestFnCall === 'modifier-unknown') { | ||
@@ -206,3 +176,2 @@ context.report({ | ||
} | ||
return; | ||
@@ -212,11 +181,8 @@ } else if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') { | ||
} | ||
const { | ||
parent: expect | ||
} = jestFnCall.head.node; | ||
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) { | ||
return; | ||
} | ||
if (expect.arguments.length < minArgs) { | ||
@@ -244,3 +210,2 @@ const expectLength = (0, _utils2.getAccessorValue)(jestFnCall.head.node).length; | ||
} | ||
if (expect.arguments.length > maxArgs) { | ||
@@ -270,3 +235,2 @@ const { | ||
} | ||
const { | ||
@@ -277,3 +241,2 @@ matcher | ||
const shouldBeAwaited = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) !== 'not') || asyncMatchers.includes((0, _utils2.getAccessorValue)(matcher)); | ||
if (!(parentNode !== null && parentNode !== void 0 && parentNode.parent) || !shouldBeAwaited) { | ||
@@ -286,4 +249,2 @@ return; | ||
*/ | ||
const isParentArrayExpression = parentNode.parent.type === _utils.AST_NODE_TYPES.ArrayExpression; | ||
@@ -296,8 +257,8 @@ const orReturned = alwaysAwait ? '' : ' or returned'; | ||
*/ | ||
const targetNode = getParentIfThenified(parentNode); | ||
const finalNode = findPromiseCallExpressionNode(targetNode) || targetNode; | ||
if (finalNode.parent && // If node is not awaited or returned | ||
!isAcceptableReturnNode(finalNode.parent, !alwaysAwait) && // if we didn't warn user already | ||
if (finalNode.parent && | ||
// If node is not awaited or returned | ||
!isAcceptableReturnNode(finalNode.parent, !alwaysAwait) && | ||
// if we didn't warn user already | ||
!promiseArrayExceptionExists(finalNode.loc)) { | ||
@@ -312,3 +273,2 @@ context.report({ | ||
}); | ||
if (isParentArrayExpression) { | ||
@@ -319,8 +279,5 @@ pushPromiseArrayException(finalNode.loc); | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
@@ -7,9 +7,5 @@ "use strict"; | ||
exports.default = void 0; | ||
var _utils = require("@typescript-eslint/utils"); | ||
var _utils2 = require("./utils"); | ||
const trimFXprefix = word => ['f', 'x'].includes(word.charAt(0)) ? word.substr(1) : word; | ||
const doesBinaryExpressionContainStringNode = binaryExp => { | ||
@@ -19,12 +15,8 @@ if ((0, _utils2.isStringNode)(binaryExp.right)) { | ||
} | ||
if (binaryExp.left.type === _utils.AST_NODE_TYPES.BinaryExpression) { | ||
return doesBinaryExpressionContainStringNode(binaryExp.left); | ||
} | ||
return (0, _utils2.isStringNode)(binaryExp.left); | ||
}; | ||
const quoteStringValue = node => node.type === _utils.AST_NODE_TYPES.TemplateLiteral ? `\`${node.quasis[0].value.raw}\`` : node.raw; | ||
const compileMatcherPattern = matcherMaybeWithMessage => { | ||
@@ -34,3 +26,2 @@ const [matcher, message] = Array.isArray(matcherMaybeWithMessage) ? matcherMaybeWithMessage : [matcherMaybeWithMessage]; | ||
}; | ||
const compileMatcherPatterns = matchers => { | ||
@@ -45,3 +36,2 @@ if (typeof matchers === 'string' || Array.isArray(matchers)) { | ||
} | ||
return { | ||
@@ -53,3 +43,2 @@ describe: matchers.describe ? compileMatcherPattern(matchers.describe) : null, | ||
}; | ||
const MatcherAndMessageSchema = { | ||
@@ -64,3 +53,2 @@ type: 'array', | ||
}; | ||
var _default = (0, _utils2.createRule)({ | ||
@@ -125,3 +113,2 @@ name: __filename, | ||
}], | ||
create(context, [{ | ||
@@ -139,13 +126,9 @@ ignoreTypeOfDescribeName, | ||
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context); | ||
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe' && (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test') { | ||
return; | ||
} | ||
const [argument] = node.arguments; | ||
if (!argument) { | ||
return; | ||
} | ||
if (!(0, _utils2.isStringNode)(argument)) { | ||
@@ -155,3 +138,2 @@ if (argument.type === _utils.AST_NODE_TYPES.BinaryExpression && doesBinaryExpressionContainStringNode(argument)) { | ||
} | ||
if (argument.type !== _utils.AST_NODE_TYPES.TemplateLiteral && !(ignoreTypeOfDescribeName && jestFnCall.type === 'describe')) { | ||
@@ -163,8 +145,5 @@ context.report({ | ||
} | ||
return; | ||
} | ||
const title = (0, _utils2.getStringValue)(argument); | ||
if (!title) { | ||
@@ -180,6 +159,4 @@ context.report({ | ||
} | ||
if (disallowedWords.length > 0) { | ||
const disallowedMatch = disallowedWordsRegexp.exec(title); | ||
if (disallowedMatch) { | ||
@@ -196,3 +173,2 @@ context.report({ | ||
} | ||
if (title.trim().length !== title.length) { | ||
@@ -205,6 +181,4 @@ context.report({ | ||
} | ||
const unprefixedName = trimFXprefix(jestFnCall.name); | ||
const [firstWord] = title.split(' '); | ||
if (firstWord.toLowerCase() === unprefixedName) { | ||
@@ -217,6 +191,4 @@ context.report({ | ||
} | ||
const jestFunctionName = unprefixedName; | ||
const [mustNotMatchPattern, mustNotMatchMessage] = mustNotMatchPatterns[jestFunctionName] ?? []; | ||
if (mustNotMatchPattern) { | ||
@@ -236,5 +208,3 @@ if (mustNotMatchPattern.test(title)) { | ||
} | ||
const [mustMatchPattern, mustMatchMessage] = mustMatchPatterns[jestFunctionName] ?? []; | ||
if (mustMatchPattern) { | ||
@@ -255,8 +225,5 @@ if (!mustMatchPattern.test(title)) { | ||
} | ||
}; | ||
} | ||
}); | ||
exports.default = _default; |
{ | ||
"name": "eslint-plugin-jest", | ||
"version": "27.1.2", | ||
"version": "27.1.3", | ||
"description": "ESLint rules for Jest", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
5285
314987