eslint-plugin-jest
Advanced tools
Comparing version 23.13.2 to 23.14.0
@@ -0,1 +1,15 @@ | ||
# [23.14.0](https://github.com/jest-community/eslint-plugin-jest/compare/v23.13.2...v23.14.0) (2020-06-20) | ||
### Bug Fixes | ||
* **no-test-callback:** check argument is an identifier ([f70612d](https://github.com/jest-community/eslint-plugin-jest/commit/f70612d8b414575725a5831ed9dfad1eaf1e6548)) | ||
* **no-test-callback:** provide suggestion instead of autofix ([782d8fa](https://github.com/jest-community/eslint-plugin-jest/commit/782d8fa00149143f453e7cb066f90c017e2d3f61)) | ||
* **prefer-strict-equal:** provide suggestion instead of autofix ([2eaed2b](https://github.com/jest-community/eslint-plugin-jest/commit/2eaed2bf30c72b03ee205910887f8aab304047a5)) | ||
### Features | ||
* **prefer-expect-assertions:** provide suggestions ([bad88a0](https://github.com/jest-community/eslint-plugin-jest/commit/bad88a006135258e8da18902a84bdb52a9bb9fa7)) | ||
## [23.13.2](https://github.com/jest-community/eslint-plugin-jest/compare/v23.13.1...v23.13.2) (2020-05-26) | ||
@@ -2,0 +16,0 @@ |
@@ -15,3 +15,3 @@ "use strict"; | ||
const isConcurrentExpression = expression => expression.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(expression.property, _utils.TestCaseProperty.concurrent) && !!expression.parent && expression.parent.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression; | ||
const isConcurrentExpression = expression => (0, _utils.isSupportedAccessor)(expression.property, _utils.TestCaseProperty.concurrent) && !!expression.parent && expression.parent.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression; | ||
@@ -18,0 +18,0 @@ const matchesTestFunction = object => 'name' in object && (object.name in _utils.TestCaseName || object.name in _utils.DescribeAlias); |
@@ -35,3 +35,3 @@ "use strict"; | ||
if (whitelistedSnapshots && node.type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement && 'left' in node.expression && (0, _utils.isExpectMember)(node.expression.left)) { | ||
if (node.type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement && 'left' in node.expression && (0, _utils.isExpectMember)(node.expression.left)) { | ||
const fileName = context.getFilename(); | ||
@@ -38,0 +38,0 @@ const whitelistedSnapshotsInFile = whitelistedSnapshots[fileName]; |
@@ -37,3 +37,3 @@ "use strict"; | ||
ImportDeclaration(node) { | ||
if (node.source && isMockImportLiteral(node.source)) { | ||
if (isMockImportLiteral(node.source)) { | ||
context.report({ | ||
@@ -40,0 +40,0 @@ node, |
@@ -18,9 +18,10 @@ "use strict"; | ||
description: 'Avoid using a callback in asynchronous tests', | ||
recommended: false | ||
recommended: false, | ||
suggestion: true | ||
}, | ||
messages: { | ||
illegalTestCallback: 'Illegal usage of test callback', | ||
suggestWrappingInPromise: 'Wrap in `new Promise({{ callback }} => ...`', | ||
useAwaitInsteadOfCallback: 'Use await instead of callback in async functions' | ||
}, | ||
fixable: 'code', | ||
schema: [], | ||
@@ -46,2 +47,10 @@ type: 'suggestion' | ||
if (argument.type !== _experimentalUtils.AST_NODE_TYPES.Identifier) { | ||
context.report({ | ||
node: argument, | ||
messageId: 'illegalTestCallback' | ||
}); | ||
return; | ||
} | ||
if (callback.async) { | ||
@@ -58,51 +67,57 @@ context.report({ | ||
messageId: 'illegalTestCallback', | ||
suggest: [{ | ||
messageId: 'suggestWrappingInPromise', | ||
data: { | ||
callback: argument.name | ||
}, | ||
fix(fixer) { | ||
const { | ||
body | ||
} = callback; | ||
/* istanbul ignore if https://github.com/typescript-eslint/typescript-eslint/issues/734 */ | ||
fix(fixer) { | ||
const { | ||
body | ||
} = callback; | ||
/* istanbul ignore if https://github.com/typescript-eslint/typescript-eslint/issues/734 */ | ||
if (!body) { | ||
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`); | ||
} | ||
if (!body) { | ||
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 sourceCode = context.getSourceCode(); | ||
const firstBodyToken = sourceCode.getFirstToken(body); | ||
const lastBodyToken = sourceCode.getLastToken(body); | ||
const tokenBeforeArgument = sourceCode.getTokenBefore(argument); | ||
const tokenAfterArgument = sourceCode.getTokenAfter(argument); | ||
/* istanbul ignore if */ | ||
const sourceCode = context.getSourceCode(); | ||
const firstBodyToken = sourceCode.getFirstToken(body); | ||
const lastBodyToken = sourceCode.getLastToken(body); | ||
const tokenBeforeArgument = sourceCode.getTokenBefore(argument); | ||
const tokenAfterArgument = sourceCode.getTokenAfter(argument); | ||
/* istanbul ignore if */ | ||
if (!('name' in argument) || !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`); | ||
} | ||
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, '()'); | ||
const argumentInParens = tokenBeforeArgument.value === '(' && tokenAfterArgument.value === ')'; | ||
let argumentFix = fixer.replaceText(argument, '()'); | ||
if (argumentInParens) { | ||
argumentFix = fixer.remove(argument); | ||
} | ||
if (argumentInParens) { | ||
argumentFix = fixer.remove(argument); | ||
} | ||
let newCallback = argument.name; | ||
let newCallback = argument.name; | ||
if (argumentInParens) { | ||
newCallback = `(${newCallback})`; | ||
} | ||
if (argumentInParens) { | ||
newCallback = `(${newCallback})`; | ||
} | ||
let beforeReplacement = `new Promise(${newCallback} => `; | ||
let afterReplacement = ')'; | ||
let replaceBefore = true; | ||
let beforeReplacement = `new Promise(${newCallback} => `; | ||
let afterReplacement = ')'; | ||
let replaceBefore = true; | ||
if (body.type === _experimentalUtils.AST_NODE_TYPES.BlockStatement) { | ||
const keyword = 'return'; | ||
beforeReplacement = `${keyword} ${beforeReplacement}{`; | ||
afterReplacement += '}'; | ||
replaceBefore = false; | ||
if (body.type === _experimentalUtils.AST_NODE_TYPES.BlockStatement) { | ||
const keyword = 'return'; | ||
beforeReplacement = `${keyword} ${beforeReplacement}{`; | ||
afterReplacement += '}'; | ||
replaceBefore = false; | ||
} | ||
return [argumentFix, replaceBefore ? fixer.insertTextBefore(firstBodyToken, beforeReplacement) : fixer.insertTextAfter(firstBodyToken, beforeReplacement), fixer.insertTextAfter(lastBodyToken, afterReplacement)]; | ||
} | ||
return [argumentFix, replaceBefore ? fixer.insertTextBefore(firstBodyToken, beforeReplacement) : fixer.insertTextAfter(firstBodyToken, beforeReplacement), fixer.insertTextAfter(lastBodyToken, afterReplacement)]; | ||
} | ||
}] | ||
}); | ||
@@ -109,0 +124,0 @@ } |
@@ -12,21 +12,13 @@ "use strict"; | ||
const isExpectAssertionsOrHasAssertionsCall = expression => { | ||
if (expression.type !== _experimentalUtils.AST_NODE_TYPES.CallExpression || expression.callee.type !== _experimentalUtils.AST_NODE_TYPES.MemberExpression || !(0, _utils.isSupportedAccessor)(expression.callee.object, 'expect') || !(0, _utils.isSupportedAccessor)(expression.callee.property)) { | ||
return false; | ||
} | ||
const isExpectAssertionsOrHasAssertionsCall = expression => expression.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && expression.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(expression.callee.object, 'expect') && (0, _utils.isSupportedAccessor)(expression.callee.property) && ['assertions', 'hasAssertions'].includes((0, _utils.getAccessorValue)(expression.callee.property)); | ||
const expectAssertionName = (0, _utils.getAccessorValue)(expression.callee.property); | ||
const isFirstLineExprStmt = functionBody => functionBody[0] && functionBody[0].type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement; | ||
if (expectAssertionName !== 'assertions') { | ||
return expectAssertionName === 'hasAssertions'; | ||
} | ||
const suggestRemovingExtraArguments = (args, extraArgsStartAt) => ({ | ||
messageId: 'suggestRemovingExtraArguments', | ||
fix: fixer => fixer.removeRange([args[extraArgsStartAt].range[0] - Math.sign(extraArgsStartAt), args[args.length - 1].range[1]]) | ||
}); | ||
const [arg] = expression.arguments; | ||
return (0, _utils.hasOnlyOneArgument)(expression) && arg.type === _experimentalUtils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value); | ||
}; | ||
const suggestions = [['suggestAddingHasAssertions', 'expect.hasAssertions();'], ['suggestAddingAssertions', 'expect.assertions();']]; | ||
const getFunctionFirstLine = functionBody => functionBody[0] && functionBody[0].expression; | ||
const isFirstLineExprStmt = functionBody => functionBody[0] && functionBody[0].type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement; | ||
var _default = (0, _utils.createRule)({ | ||
@@ -38,6 +30,13 @@ name: __filename, | ||
description: 'Suggest using `expect.assertions()` OR `expect.hasAssertions()`', | ||
recommended: false | ||
recommended: false, | ||
suggestion: true | ||
}, | ||
messages: { | ||
haveExpectAssertions: 'Every test should have either `expect.assertions(<number of assertions>)` or `expect.hasAssertions()` as its first expression' | ||
hasAssertionsTakesNoArguments: '`expect.hasAssertions` expects no arguments', | ||
assertionsRequiresOneArgument: '`expect.assertions` excepts a single argument of type number', | ||
assertionsRequiresNumberArgument: 'This argument should be a number', | ||
haveExpectAssertions: 'Every test should have either `expect.assertions(<number of assertions>)` or `expect.hasAssertions()` as its first expression', | ||
suggestAddingHasAssertions: 'Add `expect.hasAssertions()`', | ||
suggestAddingAssertions: 'Add `expect.assertions(<number of assertions>)`', | ||
suggestRemovingExtraArguments: 'Remove extra arguments' | ||
}, | ||
@@ -57,3 +56,7 @@ type: 'suggestion', | ||
messageId: 'haveExpectAssertions', | ||
node | ||
node, | ||
suggest: suggestions.map(([messageId, text]) => ({ | ||
messageId, | ||
fix: fixer => fixer.insertTextBeforeRange([node.arguments[1].body.range[0] + 1, node.arguments[1].body.range[1]], text) | ||
})) | ||
}); | ||
@@ -63,3 +66,3 @@ return; | ||
const testFuncFirstLine = getFunctionFirstLine(testFuncBody); | ||
const testFuncFirstLine = testFuncBody[0].expression; | ||
@@ -69,5 +72,48 @@ if (!isExpectAssertionsOrHasAssertionsCall(testFuncFirstLine)) { | ||
messageId: 'haveExpectAssertions', | ||
node | ||
node, | ||
suggest: suggestions.map(([messageId, text]) => ({ | ||
messageId, | ||
fix: fixer => fixer.insertTextBefore(testFuncBody[0], text) | ||
})) | ||
}); | ||
return; | ||
} | ||
if ((0, _utils.isSupportedAccessor)(testFuncFirstLine.callee.property, 'hasAssertions')) { | ||
if (testFuncFirstLine.arguments.length) { | ||
context.report({ | ||
messageId: 'hasAssertionsTakesNoArguments', | ||
node: testFuncFirstLine.callee.property, | ||
suggest: [suggestRemovingExtraArguments(testFuncFirstLine.arguments, 0)] | ||
}); | ||
} | ||
return; | ||
} | ||
if (!(0, _utils.hasOnlyOneArgument)(testFuncFirstLine)) { | ||
const report = { | ||
messageId: 'assertionsRequiresOneArgument', | ||
loc: testFuncFirstLine.callee.property.loc | ||
}; | ||
if (testFuncFirstLine.arguments.length) { | ||
report.loc = testFuncFirstLine.arguments[1].loc; | ||
report.suggest = [suggestRemovingExtraArguments(testFuncFirstLine.arguments, 1)]; | ||
} | ||
context.report(report); | ||
return; | ||
} | ||
const [arg] = testFuncFirstLine.arguments; | ||
if (arg.type === _experimentalUtils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) { | ||
return; | ||
} | ||
context.report({ | ||
messageId: 'assertionsRequiresNumberArgument', | ||
node: arg | ||
}); | ||
} | ||
@@ -74,0 +120,0 @@ |
@@ -16,8 +16,9 @@ "use strict"; | ||
description: 'Suggest using toStrictEqual()', | ||
recommended: false | ||
recommended: false, | ||
suggestion: true | ||
}, | ||
messages: { | ||
useToStrictEqual: 'Use toStrictEqual() instead' | ||
useToStrictEqual: 'Use `toStrictEqual()` instead', | ||
suggestReplaceWithStrictEqual: 'Replace with `toStrictEqual()`' | ||
}, | ||
fixable: 'code', | ||
type: 'suggestion', | ||
@@ -41,5 +42,8 @@ schema: [] | ||
context.report({ | ||
fix: fixer => [fixer.replaceText(matcher.node.property, _utils.EqualityMatcher.toStrictEqual)], | ||
messageId: 'useToStrictEqual', | ||
node: matcher.node.property | ||
node: matcher.node.property, | ||
suggest: [{ | ||
messageId: 'suggestReplaceWithStrictEqual', | ||
fix: fixer => [fixer.replaceText(matcher.node.property, _utils.EqualityMatcher.toStrictEqual)] | ||
}] | ||
}); | ||
@@ -46,0 +50,0 @@ } |
@@ -125,3 +125,3 @@ "use strict"; | ||
if (modifier && modifier.name === _utils.ModifierName.not) { | ||
if (modifier) { | ||
return getNegationFixes(includesCall, modifier, matcher, sourceCode, fixer, fileName).concat(fixArr); | ||
@@ -128,0 +128,0 @@ } |
@@ -47,7 +47,7 @@ "use strict"; | ||
* @param {Node} node | ||
* @param {V?} value | ||
* @param {V} [value] | ||
* | ||
* @return {node is StringLiteral<V>} | ||
* | ||
* @template {V}. | ||
* @template V | ||
*/ | ||
@@ -65,3 +65,3 @@ const isStringLiteral = (node, value) => node.type === _experimentalUtils.AST_NODE_TYPES.Literal && typeof node.value === 'string' && (value === undefined || node.value === value); | ||
* @param {Node} node | ||
* @param {V?} value | ||
* @param {V} [value] | ||
* | ||
@@ -79,3 +79,3 @@ * @return {node is TemplateLiteral<V>} | ||
* @param {Node} node | ||
* @param {V?} specifics | ||
* @param {V} [specifics] | ||
* | ||
@@ -118,3 +118,3 @@ * @return {node is StringNode} | ||
*/ | ||
const hasOnlyOneArgument = call => call.arguments && call.arguments.length === 1; | ||
const hasOnlyOneArgument = call => call.arguments.length === 1; | ||
/** | ||
@@ -134,3 +134,3 @@ * An `Identifier` with a known `name` value - i.e `expect`. | ||
* @param {Node} node | ||
* @param {V?} name | ||
* @param {V} [name] | ||
* | ||
@@ -158,3 +158,3 @@ * @return {node is KnownIdentifier<Name>} | ||
* @param {Node} node | ||
* @param {V?} value | ||
* @param {V} [value] | ||
* | ||
@@ -161,0 +161,0 @@ * @return {node is AccessorNode<V>} |
@@ -25,3 +25,3 @@ "use strict"; | ||
const getPromiseCallExpressionNode = node => { | ||
if (node && node.type === _experimentalUtils.AST_NODE_TYPES.ArrayExpression && node.parent && node.parent.type === _experimentalUtils.AST_NODE_TYPES.CallExpression) { | ||
if (node.type === _experimentalUtils.AST_NODE_TYPES.ArrayExpression && node.parent && node.parent.type === _experimentalUtils.AST_NODE_TYPES.CallExpression) { | ||
node = node.parent; | ||
@@ -28,0 +28,0 @@ } |
{ | ||
"name": "eslint-plugin-jest", | ||
"version": "23.13.2", | ||
"version": "23.14.0", | ||
"description": "Eslint rules for Jest", | ||
@@ -102,2 +102,3 @@ "keywords": [ | ||
"@semantic-release/git": "^7.0.17", | ||
"@types/dedent": "^0.7.0", | ||
"@types/eslint": "^6.1.3", | ||
@@ -110,5 +111,7 @@ "@types/jest": "^25.1.0", | ||
"babel-plugin-replace-ts-export-assignment": "^0.0.2", | ||
"dedent": "^0.7.0", | ||
"eslint": "^5.1.0 || ^6.0.0", | ||
"eslint-config-prettier": "^6.5.0", | ||
"eslint-plugin-eslint-comments": "^3.1.2", | ||
"eslint-plugin-eslint-config": "^1.0.2", | ||
"eslint-plugin-eslint-plugin": "^2.0.0", | ||
@@ -115,0 +118,0 @@ "eslint-plugin-import": "^2.20.2", |
@@ -151,3 +151,3 @@ <div align="center"> | ||
| [no-standalone-expect](docs/rules/no-standalone-expect.md) | Prevents expects that are outside of an it or test block. | ![recommended][] | | | ||
| [no-test-callback](docs/rules/no-test-callback.md) | Avoid using a callback in asynchronous tests | ![recommended][] | ![fixable][] | | ||
| [no-test-callback](docs/rules/no-test-callback.md) | Avoid using a callback in asynchronous tests | ![recommended][] | ![suggest][] | | ||
| [no-test-prefixes](docs/rules/no-test-prefixes.md) | Use `.only` and `.skip` over `f` and `x` | ![recommended][] | ![fixable][] | | ||
@@ -157,6 +157,6 @@ | [no-test-return-statement](docs/rules/no-test-return-statement.md) | Disallow explicitly returning from tests | | | | ||
| [prefer-called-with](docs/rules/prefer-called-with.md) | Suggest using `toBeCalledWith()` OR `toHaveBeenCalledWith()` | | | | ||
| [prefer-expect-assertions](docs/rules/prefer-expect-assertions.md) | Suggest using `expect.assertions()` OR `expect.hasAssertions()` | | | | ||
| [prefer-expect-assertions](docs/rules/prefer-expect-assertions.md) | Suggest using `expect.assertions()` OR `expect.hasAssertions()` | | ![suggest][] | | ||
| [prefer-hooks-on-top](docs/rules/prefer-hooks-on-top.md) | Suggest to have all hooks at top level | | | | ||
| [prefer-spy-on](docs/rules/prefer-spy-on.md) | Suggest using `jest.spyOn()` | | ![fixable][] | | ||
| [prefer-strict-equal](docs/rules/prefer-strict-equal.md) | Suggest using toStrictEqual() | | ![fixable][] | | ||
| [prefer-strict-equal](docs/rules/prefer-strict-equal.md) | Suggest using toStrictEqual() | | ![suggest][] | | ||
| [prefer-to-be-null](docs/rules/prefer-to-be-null.md) | Suggest using `toBeNull()` | ![style][] | ![fixable][] | | ||
@@ -191,3 +191,4 @@ | [prefer-to-be-undefined](docs/rules/prefer-to-be-undefined.md) | Suggest using `toBeUndefined()` | ![style][] | ![fixable][] | | ||
[recommended]: https://img.shields.io/badge/-recommended-lightgrey.svg | ||
[suggest]: https://img.shields.io/badge/-suggest-yellow.svg | ||
[fixable]: https://img.shields.io/badge/-fixable-green.svg | ||
[style]: https://img.shields.io/badge/-style-blue.svg |
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
218122
3694
192
37