eslint-plugin-jest 23.14.0 → 23.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## [23.17.1](https://github.com/jest-community/eslint-plugin-jest/compare/v23.17.0...v23.17.1) (2020-06-23)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **lowercase-name:** ignore all top level describes when option is true ([#614](https://github.com/jest-community/eslint-plugin-jest/issues/614)) ([624018a](https://github.com/jest-community/eslint-plugin-jest/commit/624018aa181e7c0ce87457a4f9c212c7891987a8)), closes [#613](https://github.com/jest-community/eslint-plugin-jest/issues/613)
7
+
8
+ # [23.17.0](https://github.com/jest-community/eslint-plugin-jest/compare/v23.16.0...v23.17.0) (2020-06-23)
9
+
10
+
11
+ ### Features
12
+
13
+ * **lowercase-name:** support `ignoreTopLevelDescribe` option ([#611](https://github.com/jest-community/eslint-plugin-jest/issues/611)) ([36fdcc5](https://github.com/jest-community/eslint-plugin-jest/commit/36fdcc553ca40bc2ca2e9ca7e04f8e9e4a315274)), closes [#247](https://github.com/jest-community/eslint-plugin-jest/issues/247)
14
+
15
+ # [23.16.0](https://github.com/jest-community/eslint-plugin-jest/compare/v23.15.0...v23.16.0) (2020-06-21)
16
+
17
+
18
+ ### Features
19
+
20
+ * create `no-conditional-expect` rule ([aba53e4](https://github.com/jest-community/eslint-plugin-jest/commit/aba53e4061f3b636ab0c0270e183c355c6f301e0))
21
+ * deprecate `no-try-expect` in favor of `no-conditional-expect` ([6d07cad](https://github.com/jest-community/eslint-plugin-jest/commit/6d07cadd5f78ed7a64a86792931d49d3cd943d69))
22
+
23
+ # [23.15.0](https://github.com/jest-community/eslint-plugin-jest/compare/v23.14.0...v23.15.0) (2020-06-21)
24
+
25
+
26
+ ### Features
27
+
28
+ * **no-standalone-expect:** support `additionalTestBlockFunctions` ([#585](https://github.com/jest-community/eslint-plugin-jest/issues/585)) ([ed220b2](https://github.com/jest-community/eslint-plugin-jest/commit/ed220b2c515f2e97ce639dd1474c18a7f594c06c))
29
+
1
30
  # [23.14.0](https://github.com/jest-community/eslint-plugin-jest/compare/v23.13.2...v23.14.0) (2020-06-20)
2
31
 
3
32
 
package/README.md CHANGED
@@ -134,6 +134,7 @@ installations requiring long-term consistency.
134
134
  | [lowercase-name](docs/rules/lowercase-name.md) | Enforce lowercase test names | | ![fixable][] |
135
135
  | [no-alias-methods](docs/rules/no-alias-methods.md) | Disallow alias methods | ![style][] | ![fixable][] |
136
136
  | [no-commented-out-tests](docs/rules/no-commented-out-tests.md) | Disallow commented out tests | ![recommended][] | |
137
+ | [no-conditional-expect](docs/rules/no-conditional-expect.md) | Prevent calling `expect` conditionally | | |
137
138
  | [no-deprecated-functions](docs/rules/no-deprecated-functions.md) | Disallow use of deprecated functions | | ![fixable][] |
138
139
  | [no-disabled-tests](docs/rules/no-disabled-tests.md) | Disallow disabled tests | ![recommended][] | |
139
140
  | [no-duplicate-hooks](docs/rules/no-duplicate-hooks.md) | Disallow duplicate setup and teardown hooks | | |
@@ -151,7 +152,6 @@ installations requiring long-term consistency.
151
152
  | [no-test-callback](docs/rules/no-test-callback.md) | Avoid using a callback in asynchronous tests | ![recommended][] | ![suggest][] |
152
153
  | [no-test-prefixes](docs/rules/no-test-prefixes.md) | Use `.only` and `.skip` over `f` and `x` | ![recommended][] | ![fixable][] |
153
154
  | [no-test-return-statement](docs/rules/no-test-return-statement.md) | Disallow explicitly returning from tests | | |
154
- | [no-try-expect](docs/rules/no-try-expect.md) | Prefer using toThrow for exception tests | ![recommended][] | |
155
155
  | [prefer-called-with](docs/rules/prefer-called-with.md) | Suggest using `toBeCalledWith()` OR `toHaveBeenCalledWith()` | | |
156
156
  | [prefer-expect-assertions](docs/rules/prefer-expect-assertions.md) | Suggest using `expect.assertions()` OR `expect.hasAssertions()` | | ![suggest][] |
157
157
  | [prefer-hooks-on-top](docs/rules/prefer-hooks-on-top.md) | Suggest to have all hooks at top level | | |
@@ -86,3 +86,21 @@ Example of **correct** code for the `{ "allowedPrefixes": ["GET"] }` option:
86
86
 
87
87
  describe('GET /live');
88
88
  ```
89
+
90
+ ### `ignoreTopLevelDescribe`
91
+
92
+ This option can be set to allow only the top-level `describe` blocks to have a
93
+ title starting with an upper-case letter.
94
+
95
+ Example of **correct** code for the `{ "ignoreTopLevelDescribe": true }` option:
96
+
97
+ ```js
98
+ /* eslint jest/lowercase-name: ["error", { "ignoreTopLevelDescribe": true }] */
99
+ describe('MyClass', () => {
100
+ describe('#myMethod', () => {
101
+ it('does things', () => {
102
+ //
103
+ });
104
+ });
105
+ });
106
+ ```
@@ -0,0 +1,70 @@
1
+ # Prevent calling `expect` conditionally (`no-conditional-expect`)
2
+
3
+ This rule prevents the use of `expect` in conditional blocks, such as `if`s &
4
+ `catch`s.
5
+
6
+ ## Rule Details
7
+
8
+ Jest considered a test to have failed if it throws an error, rather than on if
9
+ any particular function is called, meaning conditional calls to `expect` could
10
+ result in tests silently being skipped.
11
+
12
+ Additionally, conditionals tend to make tests more brittle and complex, as they
13
+ increase the amount of mental thinking needed to understand what is actually
14
+ being tested.
15
+
16
+ While `expect.assertions` & `expect.hasAssertions` can help prevent tests from
17
+ silently being skipped, when combined with conditionals they typically result in
18
+ even more complexity being introduced.
19
+
20
+ The following patterns are warnings:
21
+
22
+ ```js
23
+ it('foo', () => {
24
+ doTest && expect(1).toBe(2);
25
+ });
26
+
27
+ it('bar', () => {
28
+ if (!skipTest) {
29
+ expect(1).toEqual(2);
30
+ }
31
+ });
32
+
33
+ it('baz', async () => {
34
+ try {
35
+ await foo();
36
+ } catch (err) {
37
+ expect(err).toMatchObject({ code: 'MODULE_NOT_FOUND' });
38
+ }
39
+ });
40
+ ```
41
+
42
+ The following patterns are not warnings:
43
+
44
+ ```js
45
+ it('foo', () => {
46
+ expect(!value).toBe(false);
47
+ });
48
+
49
+ function getValue() {
50
+ if (process.env.FAIL) {
51
+ return 1;
52
+ }
53
+
54
+ return 2;
55
+ }
56
+
57
+ it('foo', () => {
58
+ expect(getValue()).toBe(2);
59
+ });
60
+
61
+ it('validates the request', () => {
62
+ try {
63
+ processRequest(request);
64
+ } catch {
65
+ // ignore errors
66
+ } finally {
67
+ expect(validRequest).toHaveBeenCalledWith(request);
68
+ }
69
+ });
70
+ ```
@@ -64,6 +64,36 @@ describe('a test', () => {
64
64
  thought the `expect` will not execute. Rely on a rule like no-unused-vars for
65
65
  this case.
66
66
 
67
+ ### Options
68
+
69
+ #### `additionalTestBlockFunctions`
70
+
71
+ This array can be used to specify the names of functions that should also be
72
+ treated as test blocks:
73
+
74
+ ```json
75
+ {
76
+ "rules": {
77
+ "jest/no-standalone-expect": [
78
+ "error",
79
+ { "additionalTestBlockFunctions": ["each.test"] }
80
+ ]
81
+ }
82
+ }
83
+ ```
84
+
85
+ The following is _correct_ when using the above configuration:
86
+
87
+ ```js
88
+ each([
89
+ [1, 1, 2],
90
+ [1, 2, 3],
91
+ [2, 1, 3],
92
+ ]).test('returns the result of adding %d to %d', (a, b, expected) => {
93
+ expect(a + b).toBe(expected);
94
+ });
95
+ ```
96
+
67
97
  ## When Not To Use It
68
98
 
69
99
  Don't use this rule on non-jest test files.
@@ -1,5 +1,12 @@
1
1
  # Prevent catch assertions in tests (`no-try-expect`)
2
2
 
3
+ ## Deprecated
4
+
5
+ This rule has been deprecated in favor of
6
+ [`no-conditional-expect`](no-conditional-expect.md).
7
+
8
+ ---
9
+
3
10
  This rule prevents the use of `expect` inside `catch` blocks.
4
11
 
5
12
  ## Rule Details
@@ -58,6 +58,10 @@ var _default = (0, _utils.createRule)({
58
58
  type: 'string'
59
59
  },
60
60
  additionalItems: false
61
+ },
62
+ ignoreTopLevelDescribe: {
63
+ type: 'boolean',
64
+ default: false
61
65
  }
62
66
  },
63
67
  additionalProperties: false
@@ -65,19 +69,30 @@ var _default = (0, _utils.createRule)({
65
69
  },
66
70
  defaultOptions: [{
67
71
  ignore: [],
68
- allowedPrefixes: []
72
+ allowedPrefixes: [],
73
+ ignoreTopLevelDescribe: false
69
74
  }],
70
75
 
71
76
  create(context, [{
72
77
  ignore = [],
73
- allowedPrefixes = []
78
+ allowedPrefixes = [],
79
+ ignoreTopLevelDescribe
74
80
  }]) {
81
+ let numberOfDescribeBlocks = 0;
75
82
  return {
76
83
  CallExpression(node) {
77
84
  if (!isJestFunctionWithLiteralArg(node)) {
78
85
  return;
79
86
  }
80
87
 
88
+ if ((0, _utils.isDescribe)(node)) {
89
+ numberOfDescribeBlocks++;
90
+
91
+ if (ignoreTopLevelDescribe && numberOfDescribeBlocks === 1) {
92
+ return;
93
+ }
94
+ }
95
+
81
96
  const erroneousMethod = jestFunctionName(node, allowedPrefixes);
82
97
 
83
98
  if (erroneousMethod && !ignore.includes(node.callee.name)) {
@@ -98,6 +113,12 @@ var _default = (0, _utils.createRule)({
98
113
 
99
114
  });
100
115
  }
116
+ },
117
+
118
+ 'CallExpression:exit'(node) {
119
+ if ((0, _utils.isDescribe)(node)) {
120
+ numberOfDescribeBlocks--;
121
+ }
101
122
  }
102
123
 
103
124
  };
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _utils = require("./utils");
9
+
10
+ var _default = (0, _utils.createRule)({
11
+ name: __filename,
12
+ meta: {
13
+ docs: {
14
+ description: 'Prevent calling `expect` conditionally',
15
+ category: 'Best Practices',
16
+ recommended: false
17
+ },
18
+ messages: {
19
+ conditionalExpect: 'Avoid calling `expect` conditionally`'
20
+ },
21
+ type: 'problem',
22
+ schema: []
23
+ },
24
+ defaultOptions: [],
25
+
26
+ create(context) {
27
+ let conditionalDepth = 0;
28
+ let inTestCase = false;
29
+
30
+ const increaseConditionalDepth = () => inTestCase && conditionalDepth++;
31
+
32
+ const decreaseConditionalDepth = () => inTestCase && conditionalDepth--;
33
+
34
+ return {
35
+ FunctionDeclaration(node) {
36
+ const declaredVariables = context.getDeclaredVariables(node);
37
+ const testCallExpressions = (0, _utils.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
38
+
39
+ if (testCallExpressions.length > 0) {
40
+ inTestCase = true;
41
+ }
42
+ },
43
+
44
+ CallExpression(node) {
45
+ if ((0, _utils.isTestCase)(node)) {
46
+ inTestCase = true;
47
+ }
48
+
49
+ if (inTestCase && (0, _utils.isExpectCall)(node) && conditionalDepth > 0) {
50
+ context.report({
51
+ messageId: 'conditionalExpect',
52
+ node
53
+ });
54
+ }
55
+ },
56
+
57
+ 'CallExpression:exit'(node) {
58
+ if ((0, _utils.isTestCase)(node)) {
59
+ inTestCase = false;
60
+ }
61
+ },
62
+
63
+ CatchClause: increaseConditionalDepth,
64
+ 'CatchClause:exit': decreaseConditionalDepth,
65
+ IfStatement: increaseConditionalDepth,
66
+ 'IfStatement:exit': decreaseConditionalDepth,
67
+ SwitchStatement: increaseConditionalDepth,
68
+ 'SwitchStatement:exit': decreaseConditionalDepth,
69
+ ConditionalExpression: increaseConditionalDepth,
70
+ 'ConditionalExpression:exit': decreaseConditionalDepth,
71
+ LogicalExpression: increaseConditionalDepth,
72
+ 'LogicalExpression:exit': decreaseConditionalDepth
73
+ };
74
+ }
75
+
76
+ });
77
+
78
+ exports.default = _default;
@@ -104,6 +104,7 @@ var _default = (0, _utils.createRule)({
104
104
  node,
105
105
 
106
106
  fix(fixer) {
107
+ // eslint-disable-next-line prefer-const
107
108
  let [name, func] = replacement.split('.');
108
109
 
109
110
  if (callee.property.type === _experimentalUtils.AST_NODE_TYPES.Literal) {
@@ -9,8 +9,8 @@ var _experimentalUtils = require("@typescript-eslint/experimental-utils");
9
9
 
10
10
  var _utils = require("./utils");
11
11
 
12
- const getBlockType = stmt => {
13
- const func = stmt.parent;
12
+ const getBlockType = statement => {
13
+ const func = statement.parent;
14
14
  /* istanbul ignore if */
15
15
 
16
16
  if (!func) {
@@ -23,7 +23,7 @@ const getBlockType = stmt => {
23
23
  }
24
24
 
25
25
  if ((0, _utils.isFunction)(func) && func.parent) {
26
- const expr = func.parent; // arrowfunction or function expr
26
+ const expr = func.parent; // arrow function or function expr
27
27
 
28
28
  if (expr.type === _experimentalUtils.AST_NODE_TYPES.VariableDeclarator) {
29
29
  return 'function';
@@ -31,7 +31,7 @@ const getBlockType = stmt => {
31
31
 
32
32
 
33
33
  if (expr.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.isDescribe)(expr)) {
34
- return _utils.DescribeAlias.describe;
34
+ return 'describe';
35
35
  }
36
36
  }
37
37
 
@@ -52,12 +52,31 @@ var _default = (0, _utils.createRule)({
52
52
  unexpectedExpect: 'Expect must be inside of a test block.'
53
53
  },
54
54
  type: 'suggestion',
55
- schema: []
55
+ schema: [{
56
+ properties: {
57
+ additionalTestBlockFunctions: {
58
+ type: 'array',
59
+ items: {
60
+ type: 'string'
61
+ }
62
+ }
63
+ },
64
+ additionalProperties: false
65
+ }]
56
66
  },
57
- defaultOptions: [],
67
+ defaultOptions: [{
68
+ additionalTestBlockFunctions: []
69
+ }],
58
70
 
59
- create(context) {
71
+ create(context, [{
72
+ additionalTestBlockFunctions = []
73
+ }]) {
60
74
  const callStack = [];
75
+
76
+ const isCustomTestBlockFunction = node => additionalTestBlockFunctions.includes((0, _utils.getNodeName)(node) || '');
77
+
78
+ const isTestBlock = node => (0, _utils.isTestCase)(node) || isCustomTestBlockFunction(node);
79
+
61
80
  return {
62
81
  CallExpression(node) {
63
82
  if ((0, _utils.isExpectCall)(node)) {
@@ -73,8 +92,8 @@ var _default = (0, _utils.createRule)({
73
92
  return;
74
93
  }
75
94
 
76
- if ((0, _utils.isTestCase)(node)) {
77
- callStack.push(_utils.TestCaseName.test);
95
+ if (isTestBlock(node)) {
96
+ callStack.push('test');
78
97
  }
79
98
 
80
99
  if (node.callee.type === _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression) {
@@ -85,35 +104,35 @@ var _default = (0, _utils.createRule)({
85
104
  'CallExpression:exit'(node) {
86
105
  const top = callStack[callStack.length - 1];
87
106
 
88
- if (((0, _utils.isTestCase)(node) && node.callee.type !== _experimentalUtils.AST_NODE_TYPES.MemberExpression || isEach(node)) && top === _utils.TestCaseName.test || node.callee.type === _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression && top === 'template') {
107
+ if (top === 'test' && (isEach(node) || isTestBlock(node) && node.callee.type !== _experimentalUtils.AST_NODE_TYPES.MemberExpression) || top === 'template' && node.callee.type === _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression) {
89
108
  callStack.pop();
90
109
  }
91
110
  },
92
111
 
93
- BlockStatement(stmt) {
94
- const blockType = getBlockType(stmt);
112
+ BlockStatement(statement) {
113
+ const blockType = getBlockType(statement);
95
114
 
96
115
  if (blockType) {
97
116
  callStack.push(blockType);
98
117
  }
99
118
  },
100
119
 
101
- 'BlockStatement:exit'(stmt) {
102
- const blockType = getBlockType(stmt);
103
-
104
- if (blockType && blockType === callStack[callStack.length - 1]) {
120
+ 'BlockStatement:exit'(statement) {
121
+ if (callStack[callStack.length - 1] === getBlockType(statement)) {
105
122
  callStack.pop();
106
123
  }
107
124
  },
108
125
 
109
126
  ArrowFunctionExpression(node) {
110
- if (node.parent && node.parent.type !== _experimentalUtils.AST_NODE_TYPES.CallExpression) {
111
- callStack.push('arrowFunc');
127
+ var _node$parent;
128
+
129
+ if (((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) !== _experimentalUtils.AST_NODE_TYPES.CallExpression) {
130
+ callStack.push('arrow');
112
131
  }
113
132
  },
114
133
 
115
134
  'ArrowFunctionExpression:exit'() {
116
- if (callStack[callStack.length - 1] === 'arrowFunc') {
135
+ if (callStack[callStack.length - 1] === 'arrow') {
117
136
  callStack.pop();
118
137
  }
119
138
  }
@@ -15,6 +15,8 @@ var _default = (0, _utils.createRule)({
15
15
  category: 'Best Practices',
16
16
  recommended: false
17
17
  },
18
+ deprecated: true,
19
+ replacedBy: ['no-conditional-expect'],
18
20
  messages: {
19
21
  noTryExpect: ['Tests should use Jest‘s exception helpers.', 'Use "expect(() => yourFunction()).toThrow()" for synchronous tests,', 'or "await expect(yourFunction()).rejects.toThrow()" for async tests'].join(' ')
20
22
  },
@@ -87,17 +87,21 @@ var _default = (0, _utils.createRule)({
87
87
  }
88
88
 
89
89
  if (!(0, _utils.hasOnlyOneArgument)(testFuncFirstLine)) {
90
- const report = {
91
- messageId: 'assertionsRequiresOneArgument',
92
- loc: testFuncFirstLine.callee.property.loc
93
- };
90
+ let {
91
+ loc
92
+ } = testFuncFirstLine.callee.property;
93
+ const suggest = [];
94
94
 
95
95
  if (testFuncFirstLine.arguments.length) {
96
- report.loc = testFuncFirstLine.arguments[1].loc;
97
- report.suggest = [suggestRemovingExtraArguments(testFuncFirstLine.arguments, 1)];
96
+ loc = testFuncFirstLine.arguments[1].loc;
97
+ suggest.push(suggestRemovingExtraArguments(testFuncFirstLine.arguments, 1));
98
98
  }
99
99
 
100
- context.report(report);
100
+ context.report({
101
+ messageId: 'assertionsRequiresOneArgument',
102
+ suggest,
103
+ loc
104
+ });
101
105
  return;
102
106
  }
103
107
 
@@ -52,8 +52,7 @@ var _default = (0, _utils.createRule)({
52
52
  type: 'array',
53
53
  items: {
54
54
  type: 'string'
55
- },
56
- default: []
55
+ }
57
56
  }
58
57
  },
59
58
  additionalProperties: false
@@ -67,7 +66,7 @@ var _default = (0, _utils.createRule)({
67
66
 
68
67
  create(context, [{
69
68
  ignoreTypeOfDescribeName,
70
- disallowedWords
69
+ disallowedWords = []
71
70
  }]) {
72
71
  const disallowedWordsRegexp = new RegExp(`\\b(${disallowedWords.join('|')})\\b`, 'iu');
73
72
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-jest",
3
- "version": "23.14.0",
3
+ "version": "23.17.1",
4
4
  "description": "Eslint rules for Jest",
5
5
  "keywords": [
6
6
  "eslint",
@@ -53,6 +53,8 @@
53
53
  ]
54
54
  },
55
55
  "prettier": {
56
+ "arrowParens": "avoid",
57
+ "endOfLine": "auto",
56
58
  "proseWrap": "always",
57
59
  "singleQuote": true,
58
60
  "trailingComma": "all"
@@ -100,9 +102,9 @@
100
102
  "@semantic-release/changelog": "^3.0.5",
101
103
  "@semantic-release/git": "^7.0.17",
102
104
  "@types/dedent": "^0.7.0",
103
- "@types/eslint": "^6.1.3",
104
105
  "@types/jest": "^25.1.0",
105
106
  "@types/node": "^12.6.6",
107
+ "@types/prettier": "^1.19.0",
106
108
  "@typescript-eslint/eslint-plugin": "^2.5.0",
107
109
  "@typescript-eslint/parser": "^2.5.0",
108
110
  "babel-jest": "^25.2.0",
@@ -118,7 +120,7 @@
118
120
  "eslint-plugin-prettier": "^3.0.0",
119
121
  "husky": "^3.0.9",
120
122
  "jest": "^25.2.0",
121
- "jest-runner-eslint": "^0.8.0",
123
+ "jest-runner-eslint": "^0.9.0",
122
124
  "lint-staged": "^9.4.2",
123
125
  "prettier": "^1.19.1",
124
126
  "prettylint": "^1.0.0",