eslint-plugin-jest 26.0.0 → 26.1.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/README.md CHANGED
@@ -158,6 +158,7 @@ installations requiring long-term consistency.
158
158
  | [no-alias-methods](docs/rules/no-alias-methods.md) | Disallow alias methods | ![style][] | ![fixable][] |
159
159
  | [no-commented-out-tests](docs/rules/no-commented-out-tests.md) | Disallow commented out tests | ![recommended][] | |
160
160
  | [no-conditional-expect](docs/rules/no-conditional-expect.md) | Prevent calling `expect` conditionally | ![recommended][] | |
161
+ | [no-conditional-in-test](docs/rules/no-conditional-in-test.md) | Disallow conditional logic in tests | | |
161
162
  | [no-deprecated-functions](docs/rules/no-deprecated-functions.md) | Disallow use of deprecated functions | ![recommended][] | ![fixable][] |
162
163
  | [no-disabled-tests](docs/rules/no-disabled-tests.md) | Disallow disabled tests | ![recommended][] | |
163
164
  | [no-done-callback](docs/rules/no-done-callback.md) | Avoid using a callback in asynchronous tests and hooks | ![recommended][] | ![suggest][] |
@@ -166,7 +167,6 @@ installations requiring long-term consistency.
166
167
  | [no-focused-tests](docs/rules/no-focused-tests.md) | Disallow focused tests | ![recommended][] | ![suggest][] |
167
168
  | [no-hooks](docs/rules/no-hooks.md) | Disallow setup and teardown hooks | | |
168
169
  | [no-identical-title](docs/rules/no-identical-title.md) | Disallow identical titles | ![recommended][] | |
169
- | [no-if](docs/rules/no-if.md) | Disallow conditional logic | | |
170
170
  | [no-interpolation-in-snapshots](docs/rules/no-interpolation-in-snapshots.md) | Disallow string interpolation inside snapshots | ![recommended][] | |
171
171
  | [no-jasmine-globals](docs/rules/no-jasmine-globals.md) | Disallow Jasmine globals | ![recommended][] | ![fixable][] |
172
172
  | [no-jest-import](docs/rules/no-jest-import.md) | Disallow importing Jest | ![recommended][] | |
@@ -183,6 +183,7 @@ installations requiring long-term consistency.
183
183
  | [prefer-expect-resolves](docs/rules/prefer-expect-resolves.md) | Prefer `await expect(...).resolves` over `expect(await ...)` syntax | | ![fixable][] |
184
184
  | [prefer-hooks-on-top](docs/rules/prefer-hooks-on-top.md) | Suggest having hooks before any test cases | | |
185
185
  | [prefer-lowercase-title](docs/rules/prefer-lowercase-title.md) | Enforce lowercase test names | | ![fixable][] |
186
+ | [prefer-snapshot-hint](docs/rules/prefer-snapshot-hint.md) | Prefer including a hint with external snapshots | | |
186
187
  | [prefer-spy-on](docs/rules/prefer-spy-on.md) | Suggest using `jest.spyOn()` | | ![fixable][] |
187
188
  | [prefer-strict-equal](docs/rules/prefer-strict-equal.md) | Suggest using `toStrictEqual()` | | ![suggest][] |
188
189
  | [prefer-to-be](docs/rules/prefer-to-be.md) | Suggest using `toBe()` for primitive literals | ![style][] | ![fixable][] |
@@ -0,0 +1,79 @@
1
+ # Disallow conditional logic in tests (`no-conditional-in-test`)
2
+
3
+ Conditional logic in tests is usually an indication that a test is attempting to
4
+ cover too much, and not testing the logic it intends to. Each branch of code
5
+ executing within a conditional statement will usually be better served by a test
6
+ devoted to it.
7
+
8
+ ## Rule Details
9
+
10
+ This rule reports on any use of a conditional statement such as `if`, `switch`,
11
+ and ternary expressions.
12
+
13
+ Examples of **incorrect** code for this rule:
14
+
15
+ ```js
16
+ it('foo', () => {
17
+ if (true) {
18
+ doTheThing();
19
+ }
20
+ });
21
+
22
+ it('bar', () => {
23
+ switch (mode) {
24
+ case 'none':
25
+ generateNone();
26
+ case 'single':
27
+ generateOne();
28
+ case 'multiple':
29
+ generateMany();
30
+ }
31
+
32
+ expect(fixtures.length).toBeGreaterThan(-1);
33
+ });
34
+
35
+ it('baz', async () => {
36
+ const promiseValue = () => {
37
+ return something instanceof Promise
38
+ ? something
39
+ : Promise.resolve(something);
40
+ };
41
+
42
+ await expect(promiseValue()).resolves.toBe(1);
43
+ });
44
+ ```
45
+
46
+ Examples of **correct** code for this rule:
47
+
48
+ ```js
49
+ describe('my tests', () => {
50
+ if (true) {
51
+ it('foo', () => {
52
+ doTheThing();
53
+ });
54
+ }
55
+ });
56
+
57
+ beforeEach(() => {
58
+ switch (mode) {
59
+ case 'none':
60
+ generateNone();
61
+ case 'single':
62
+ generateOne();
63
+ case 'multiple':
64
+ generateMany();
65
+ }
66
+ });
67
+
68
+ it('bar', () => {
69
+ expect(fixtures.length).toBeGreaterThan(-1);
70
+ });
71
+
72
+ const promiseValue = something => {
73
+ return something instanceof Promise ? something : Promise.resolve(something);
74
+ };
75
+
76
+ it('baz', async () => {
77
+ await expect(promiseValue()).resolves.toBe(1);
78
+ });
79
+ ```
@@ -1,5 +1,10 @@
1
1
  # Disallow conditional logic (`no-if`)
2
2
 
3
+ ## Deprecated
4
+
5
+ This rule has been deprecated in favor of
6
+ [`no-conditional-in-test`](no-conditional-in-test.md).
7
+
3
8
  Conditional logic in tests is usually an indication that a test is attempting to
4
9
  cover too much, and not testing the logic it intends to. Each branch of code
5
10
  executing within an if statement will usually be better served by a test devoted
@@ -118,7 +118,7 @@ a native loop.
118
118
  "rules": {
119
119
  "jest/prefer-expect-assertions": [
120
120
  "warn",
121
- { "onlyFunctionsWithAsyncKeyword": true }
121
+ { "onlyFunctionsWithExpectInLoop": true }
122
122
  ]
123
123
  }
124
124
  }
@@ -0,0 +1,188 @@
1
+ # Prefer including a hint with external snapshots (`prefer-snapshot-hint`)
2
+
3
+ When working with external snapshot matchers it's considered best practice to
4
+ provide a hint (as the last argument to the matcher) describing the expected
5
+ snapshot content that will be included in the snapshots name by Jest.
6
+
7
+ This makes it easier for reviewers to verify the snapshots during review, and
8
+ for anyone to know whether an outdated snapshot is the correct behavior before
9
+ updating.
10
+
11
+ ## Rule details
12
+
13
+ This rule looks for any use of an external snapshot matcher (e.g.
14
+ `toMatchSnapshot` and `toThrowErrorMatchingSnapshot`) and checks if they include
15
+ a snapshot hint.
16
+
17
+ ## Options
18
+
19
+ ### `'always'`
20
+
21
+ Require a hint to _always_ be provided when using external snapshot matchers.
22
+
23
+ Examples of **incorrect** code for the `'always'` option:
24
+
25
+ ```js
26
+ const snapshotOutput = ({ stdout, stderr }) => {
27
+ expect(stdout).toMatchSnapshot();
28
+ expect(stderr).toMatchSnapshot();
29
+ };
30
+
31
+ describe('cli', () => {
32
+ describe('--version flag', () => {
33
+ it('prints the version', async () => {
34
+ snapshotOutput(await runCli(['--version']));
35
+ });
36
+ });
37
+
38
+ describe('--config flag', () => {
39
+ it('reads the config', async () => {
40
+ const { stdout, parsedConfig } = await runCli([
41
+ '--config',
42
+ 'jest.config.js',
43
+ ]);
44
+
45
+ expect(stdout).toMatchSnapshot();
46
+ expect(parsedConfig).toMatchSnapshot();
47
+ });
48
+
49
+ it('prints nothing to stderr', async () => {
50
+ const { stderr } = await runCli(['--config', 'jest.config.js']);
51
+
52
+ expect(stderr).toMatchSnapshot();
53
+ });
54
+
55
+ describe('when the file does not exist', () => {
56
+ it('throws an error', async () => {
57
+ await expect(
58
+ runCli(['--config', 'does-not-exist.js']),
59
+ ).rejects.toThrowErrorMatchingSnapshot();
60
+ });
61
+ });
62
+ });
63
+ });
64
+ ```
65
+
66
+ Examples of **correct** code for the `'always'` option:
67
+
68
+ ```js
69
+ const snapshotOutput = ({ stdout, stderr }, hints) => {
70
+ expect(stdout).toMatchSnapshot({}, `stdout: ${hints.stdout}`);
71
+ expect(stderr).toMatchSnapshot({}, `stderr: ${hints.stderr}`);
72
+ };
73
+
74
+ describe('cli', () => {
75
+ describe('--version flag', () => {
76
+ it('prints the version', async () => {
77
+ snapshotOutput(await runCli(['--version']), {
78
+ stdout: 'version string',
79
+ stderr: 'empty',
80
+ });
81
+ });
82
+ });
83
+
84
+ describe('--config flag', () => {
85
+ it('reads the config', async () => {
86
+ const { stdout } = await runCli(['--config', 'jest.config.js']);
87
+
88
+ expect(stdout).toMatchSnapshot({}, 'stdout: config settings');
89
+ });
90
+
91
+ it('prints nothing to stderr', async () => {
92
+ const { stderr } = await runCli(['--config', 'jest.config.js']);
93
+
94
+ expect(stderr).toMatchInlineSnapshot();
95
+ });
96
+
97
+ describe('when the file does not exist', () => {
98
+ it('throws an error', async () => {
99
+ await expect(
100
+ runCli(['--config', 'does-not-exist.js']),
101
+ ).rejects.toThrowErrorMatchingSnapshot('stderr: config error');
102
+ });
103
+ });
104
+ });
105
+ });
106
+ ```
107
+
108
+ ### `'multi'` (default)
109
+
110
+ Require a hint to be provided when there are multiple external snapshot matchers
111
+ within the scope (meaning it includes nested calls).
112
+
113
+ Examples of **incorrect** code for the `'multi'` option:
114
+
115
+ ```js
116
+ const snapshotOutput = ({ stdout, stderr }) => {
117
+ expect(stdout).toMatchSnapshot();
118
+ expect(stderr).toMatchSnapshot();
119
+ };
120
+
121
+ describe('cli', () => {
122
+ describe('--version flag', () => {
123
+ it('prints the version', async () => {
124
+ snapshotOutput(await runCli(['--version']));
125
+ });
126
+ });
127
+
128
+ describe('--config flag', () => {
129
+ it('reads the config', async () => {
130
+ const { stdout, parsedConfig } = await runCli([
131
+ '--config',
132
+ 'jest.config.js',
133
+ ]);
134
+
135
+ expect(stdout).toMatchSnapshot();
136
+ expect(parsedConfig).toMatchSnapshot();
137
+ });
138
+
139
+ it('prints nothing to stderr', async () => {
140
+ const { stderr } = await runCli(['--config', 'jest.config.js']);
141
+
142
+ expect(stderr).toMatchSnapshot();
143
+ });
144
+ });
145
+ });
146
+ ```
147
+
148
+ Examples of **correct** code for the `'multi'` option:
149
+
150
+ ```js
151
+ const snapshotOutput = ({ stdout, stderr }, hints) => {
152
+ expect(stdout).toMatchSnapshot({}, `stdout: ${hints.stdout}`);
153
+ expect(stderr).toMatchSnapshot({}, `stderr: ${hints.stderr}`);
154
+ };
155
+
156
+ describe('cli', () => {
157
+ describe('--version flag', () => {
158
+ it('prints the version', async () => {
159
+ snapshotOutput(await runCli(['--version']), {
160
+ stdout: 'version string',
161
+ stderr: 'empty',
162
+ });
163
+ });
164
+ });
165
+
166
+ describe('--config flag', () => {
167
+ it('reads the config', async () => {
168
+ const { stdout } = await runCli(['--config', 'jest.config.js']);
169
+
170
+ expect(stdout).toMatchSnapshot();
171
+ });
172
+
173
+ it('prints nothing to stderr', async () => {
174
+ const { stderr } = await runCli(['--config', 'jest.config.js']);
175
+
176
+ expect(stderr).toMatchInlineSnapshot();
177
+ });
178
+
179
+ describe('when the file does not exist', () => {
180
+ it('throws an error', async () => {
181
+ await expect(
182
+ runCli(['--config', 'does-not-exist.js']),
183
+ ).rejects.toThrowErrorMatchingSnapshot();
184
+ });
185
+ });
186
+ });
187
+ });
188
+ ```
@@ -0,0 +1,60 @@
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: 'Disallow conditional logic in tests',
15
+ category: 'Best Practices',
16
+ recommended: false
17
+ },
18
+ messages: {
19
+ conditionalInTest: 'Avoid having conditionals in tests'
20
+ },
21
+ type: 'problem',
22
+ schema: []
23
+ },
24
+ defaultOptions: [],
25
+
26
+ create(context) {
27
+ let inTestCase = false;
28
+
29
+ const maybeReportConditional = node => {
30
+ if (inTestCase) {
31
+ context.report({
32
+ messageId: 'conditionalInTest',
33
+ node
34
+ });
35
+ }
36
+ };
37
+
38
+ return {
39
+ CallExpression(node) {
40
+ if ((0, _utils.isTestCaseCall)(node)) {
41
+ inTestCase = true;
42
+ }
43
+ },
44
+
45
+ 'CallExpression:exit'(node) {
46
+ if ((0, _utils.isTestCaseCall)(node)) {
47
+ inTestCase = false;
48
+ }
49
+ },
50
+
51
+ IfStatement: maybeReportConditional,
52
+ SwitchStatement: maybeReportConditional,
53
+ ConditionalExpression: maybeReportConditional,
54
+ LogicalExpression: maybeReportConditional
55
+ };
56
+ }
57
+
58
+ });
59
+
60
+ exports.default = _default;
@@ -30,6 +30,8 @@ var _default = (0, _utils2.createRule)({
30
30
  messages: {
31
31
  conditionalInTest: 'Test should not contain {{ condition }} statements.'
32
32
  },
33
+ deprecated: true,
34
+ replacedBy: ['no-conditional-in-test'],
33
35
  schema: [],
34
36
  type: 'suggestion'
35
37
  },
@@ -0,0 +1,112 @@
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
+ const snapshotMatchers = ['toMatchSnapshot', 'toThrowErrorMatchingSnapshot'];
11
+
12
+ const isSnapshotMatcher = matcher => {
13
+ return snapshotMatchers.includes(matcher.name);
14
+ };
15
+
16
+ const isSnapshotMatcherWithoutHint = matcher => {
17
+ var _matcher$arguments;
18
+
19
+ const expectedNumberOfArgumentsWithHint = 1 + Number(matcher.name === 'toMatchSnapshot');
20
+ return ((_matcher$arguments = matcher.arguments) === null || _matcher$arguments === void 0 ? void 0 : _matcher$arguments.length) !== expectedNumberOfArgumentsWithHint;
21
+ };
22
+
23
+ const messages = {
24
+ missingHint: 'You should provide a hint for this snapshot'
25
+ };
26
+
27
+ var _default = (0, _utils.createRule)({
28
+ name: __filename,
29
+ meta: {
30
+ docs: {
31
+ category: 'Best Practices',
32
+ description: 'Prefer including a hint with external snapshots',
33
+ recommended: false
34
+ },
35
+ messages,
36
+ type: 'suggestion',
37
+ schema: [{
38
+ type: 'string',
39
+ enum: ['always', 'multi']
40
+ }]
41
+ },
42
+ defaultOptions: ['multi'],
43
+
44
+ create(context, [mode]) {
45
+ const snapshotMatchers = [];
46
+ let expressionDepth = 0;
47
+
48
+ const reportSnapshotMatchersWithoutHints = () => {
49
+ for (const snapshotMatcher of snapshotMatchers) {
50
+ if (isSnapshotMatcherWithoutHint(snapshotMatcher)) {
51
+ context.report({
52
+ messageId: 'missingHint',
53
+ node: snapshotMatcher.node.property
54
+ });
55
+ }
56
+ }
57
+ };
58
+
59
+ const enterExpression = () => {
60
+ expressionDepth++;
61
+ };
62
+
63
+ const exitExpression = () => {
64
+ expressionDepth--;
65
+
66
+ if (mode === 'always') {
67
+ reportSnapshotMatchersWithoutHints();
68
+ snapshotMatchers.length = 0;
69
+ }
70
+
71
+ if (mode === 'multi' && expressionDepth === 0) {
72
+ if (snapshotMatchers.length > 1) {
73
+ reportSnapshotMatchersWithoutHints();
74
+ }
75
+
76
+ snapshotMatchers.length = 0;
77
+ }
78
+ };
79
+
80
+ return {
81
+ 'Program:exit'() {
82
+ enterExpression();
83
+ exitExpression();
84
+ },
85
+
86
+ FunctionExpression: enterExpression,
87
+ 'FunctionExpression:exit': exitExpression,
88
+ ArrowFunctionExpression: enterExpression,
89
+ 'ArrowFunctionExpression:exit': exitExpression,
90
+
91
+ CallExpression(node) {
92
+ if (!(0, _utils.isExpectCall)(node)) {
93
+ return;
94
+ }
95
+
96
+ const {
97
+ matcher
98
+ } = (0, _utils.parseExpectCall)(node);
99
+
100
+ if (!matcher || !isSnapshotMatcher(matcher)) {
101
+ return;
102
+ }
103
+
104
+ snapshotMatchers.push(matcher);
105
+ }
106
+
107
+ };
108
+ }
109
+
110
+ });
111
+
112
+ exports.default = _default;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-jest",
3
- "version": "26.0.0",
4
- "description": "Eslint rules for Jest",
3
+ "version": "26.1.1",
4
+ "description": "ESLint rules for Jest",
5
5
  "keywords": [
6
6
  "eslint",
7
7
  "eslintplugin",
@@ -112,7 +112,7 @@
112
112
  "eslint-plugin-node": "^11.0.0",
113
113
  "eslint-plugin-prettier": "^3.4.1",
114
114
  "eslint-remote-tester": "^2.1.0",
115
- "eslint-remote-tester-repositories": "^0.0.3",
115
+ "eslint-remote-tester-repositories": "^0.0.4",
116
116
  "husky": "^7.0.2",
117
117
  "is-ci": "^3.0.0",
118
118
  "jest": "^27.0.0",
@@ -121,7 +121,7 @@
121
121
  "pinst": "^2.0.0",
122
122
  "prettier": "^2.0.5",
123
123
  "rimraf": "^3.0.0",
124
- "semantic-release": "^18.0.0",
124
+ "semantic-release": "^19.0.0",
125
125
  "semver": "^7.3.5",
126
126
  "ts-node": "^10.2.1",
127
127
  "typescript": "^4.4.0"
@@ -159,7 +159,9 @@
159
159
  ]
160
160
  },
161
161
  "resolutions": {
162
- "@typescript-eslint/experimental-utils": "^5.0.0"
162
+ "@semantic-release/npm/npm": "7.20.6",
163
+ "@typescript-eslint/experimental-utils": "^5.0.0",
164
+ "fsevents/node-gyp": "^7.0.0"
163
165
  },
164
166
  "packageManager": "yarn@3.1.1"
165
167
  }