Skip to content

Commit 5b6fd20

Browse files
makototG-Rath
andauthored
feat: create max-expects rule (#1166)
* feat: create max-expects * fix: fix test * chore: update README * fix: set proper minimum * refactor: remove unnecessary functions * refactor: reduce if * refactor: remove unnecessary type check * fix: incorrect error reported in case of multiple test blocks * chore: typo * refactor: remove unnecessary type check * chore: remove unneeded return Co-authored-by: Gareth Jones <[email protected]>
1 parent 5c9e908 commit 5b6fd20

File tree

6 files changed

+430
-1
lines changed

6 files changed

+430
-1
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ installations requiring long-term consistency.
201201
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------------- | ------------ |
202202
| [consistent-test-it](docs/rules/consistent-test-it.md) | Have control over `test` and `it` usages | | ![fixable][] |
203203
| [expect-expect](docs/rules/expect-expect.md) | Enforce assertion to be made in a test body | ![recommended][] | |
204+
| [max-expects](docs/rules/max-expects.md) | Enforces a maximum number assertion calls in a test body | | |
204205
| [max-nested-describe](docs/rules/max-nested-describe.md) | Enforces a maximum depth to nested describe calls | | |
205206
| [no-alias-methods](docs/rules/no-alias-methods.md) | Disallow alias methods | ![style][] | ![fixable][] |
206207
| [no-commented-out-tests](docs/rules/no-commented-out-tests.md) | Disallow commented out tests | ![recommended][] | |

docs/rules/max-expects.md

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Enforces a maximum number assertion calls in a test body (`max-expects`)
2+
3+
As more assertions are made, there is a possible tendency for the test to be
4+
more likely to mix multiple objectives. To avoid this, this rule reports when
5+
the maximum number of assertions is exceeded.
6+
7+
## Rule Details
8+
9+
This rule enforces a maximum number of `expect()` calls.
10+
11+
The following patterns are considered warnings (with the default option of
12+
`{ "max": 5 } `):
13+
14+
```js
15+
test('should not pass', () => {
16+
expect(true).toBeDefined();
17+
expect(true).toBeDefined();
18+
expect(true).toBeDefined();
19+
expect(true).toBeDefined();
20+
expect(true).toBeDefined();
21+
expect(true).toBeDefined();
22+
});
23+
24+
it('should not pass', () => {
25+
expect(true).toBeDefined();
26+
expect(true).toBeDefined();
27+
expect(true).toBeDefined();
28+
expect(true).toBeDefined();
29+
expect(true).toBeDefined();
30+
expect(true).toBeDefined();
31+
});
32+
```
33+
34+
The following patterns are **not** considered warnings (with the default option
35+
of `{ "max": 5 } `):
36+
37+
```js
38+
test('shout pass');
39+
40+
test('shout pass', () => {});
41+
42+
test.skip('shout pass', () => {});
43+
44+
test('should pass', function () {
45+
expect(true).toBeDefined();
46+
});
47+
48+
test('should pass', () => {
49+
expect(true).toBeDefined();
50+
expect(true).toBeDefined();
51+
expect(true).toBeDefined();
52+
expect(true).toBeDefined();
53+
expect(true).toBeDefined();
54+
});
55+
```
56+
57+
## Options
58+
59+
```json
60+
{
61+
"jest/max-expects": [
62+
"error",
63+
{
64+
"max": 5
65+
}
66+
]
67+
}
68+
```
69+
70+
### `max`
71+
72+
Enforces a maximum number of `expect()`.
73+
74+
This has a default value of `5`.

src/__tests__/__snapshots__/rules.test.ts.snap

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Object {
1212
"rules": Object {
1313
"jest/consistent-test-it": "error",
1414
"jest/expect-expect": "error",
15+
"jest/max-expects": "error",
1516
"jest/max-nested-describe": "error",
1617
"jest/no-alias-methods": "error",
1718
"jest/no-commented-out-tests": "error",

src/__tests__/rules.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { existsSync } from 'fs';
22
import { resolve } from 'path';
33
import plugin from '../';
44

5-
const numberOfRules = 48;
5+
const numberOfRules = 49;
66
const ruleNames = Object.keys(plugin.rules);
77
const deprecatedRules = Object.entries(plugin.rules)
88
.filter(([, rule]) => rule.meta.deprecated)
+284
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
import { TSESLint } from '@typescript-eslint/utils';
2+
import dedent from 'dedent';
3+
import rule from '../max-expects';
4+
import { espreeParser } from './test-utils';
5+
6+
const ruleTester = new TSESLint.RuleTester({
7+
parser: espreeParser,
8+
parserOptions: {
9+
ecmaVersion: 2017,
10+
},
11+
});
12+
13+
ruleTester.run('max-expects', rule, {
14+
valid: [
15+
`test('should pass')`,
16+
`test('should pass', () => {})`,
17+
`test.skip('should pass', () => {})`,
18+
dedent`
19+
test('should pass', function () {
20+
expect(true).toBeDefined();
21+
});
22+
`,
23+
dedent`
24+
test('should pass', () => {
25+
expect(true).toBeDefined();
26+
expect(true).toBeDefined();
27+
expect(true).toBeDefined();
28+
expect(true).toBeDefined();
29+
expect(true).toBeDefined();
30+
});
31+
`,
32+
dedent`
33+
test('should pass', () => {
34+
expect(true).toBeDefined();
35+
expect(true).toBeDefined();
36+
expect(true).toBeDefined();
37+
expect(true).toBeDefined();
38+
expect(true).toBeDefined();
39+
// expect(true).toBeDefined();
40+
});
41+
`,
42+
dedent`
43+
it('should pass', () => {
44+
expect(true).toBeDefined();
45+
expect(true).toBeDefined();
46+
expect(true).toBeDefined();
47+
expect(true).toBeDefined();
48+
expect(true).toBeDefined();
49+
});
50+
`,
51+
dedent`
52+
test('should pass', async () => {
53+
expect(true).toBeDefined();
54+
expect(true).toBeDefined();
55+
expect(true).toBeDefined();
56+
expect(true).toBeDefined();
57+
expect(true).toBeDefined();
58+
});
59+
`,
60+
dedent`
61+
describe('test', () => {
62+
test('should pass', () => {
63+
expect(true).toBeDefined();
64+
expect(true).toBeDefined();
65+
expect(true).toBeDefined();
66+
expect(true).toBeDefined();
67+
expect(true).toBeDefined();
68+
});
69+
});
70+
`,
71+
dedent`
72+
test.each(['should', 'pass'], () => {
73+
expect(true).toBeDefined();
74+
expect(true).toBeDefined();
75+
expect(true).toBeDefined();
76+
expect(true).toBeDefined();
77+
expect(true).toBeDefined();
78+
});
79+
`,
80+
dedent`
81+
test('should pass', () => {
82+
expect(true).toBeDefined();
83+
expect(true).toBeDefined();
84+
expect(true).toBeDefined();
85+
});
86+
test('should pass', () => {
87+
expect(true).toBeDefined();
88+
expect(true).toBeDefined();
89+
expect(true).toBeDefined();
90+
});
91+
`,
92+
{
93+
code: dedent`
94+
test('should pass', () => {
95+
expect(true).toBeDefined();
96+
expect(true).toBeDefined();
97+
expect(true).toBeDefined();
98+
expect(true).toBeDefined();
99+
expect(true).toBeDefined();
100+
expect(true).toBeDefined();
101+
expect(true).toBeDefined();
102+
expect(true).toBeDefined();
103+
expect(true).toBeDefined();
104+
expect(true).toBeDefined();
105+
});
106+
`,
107+
options: [
108+
{
109+
max: 10,
110+
},
111+
],
112+
},
113+
],
114+
invalid: [
115+
{
116+
code: dedent`
117+
test('should not pass', function () {
118+
expect(true).toBeDefined();
119+
expect(true).toBeDefined();
120+
expect(true).toBeDefined();
121+
expect(true).toBeDefined();
122+
expect(true).toBeDefined();
123+
expect(true).toBeDefined();
124+
});
125+
`,
126+
errors: [
127+
{
128+
messageId: 'exceededMaxAssertion',
129+
line: 7,
130+
column: 3,
131+
},
132+
],
133+
},
134+
{
135+
code: dedent`
136+
test('should not pass', () => {
137+
expect(true).toBeDefined();
138+
expect(true).toBeDefined();
139+
expect(true).toBeDefined();
140+
expect(true).toBeDefined();
141+
expect(true).toBeDefined();
142+
expect(true).toBeDefined();
143+
});
144+
`,
145+
errors: [
146+
{
147+
messageId: 'exceededMaxAssertion',
148+
line: 7,
149+
column: 3,
150+
},
151+
],
152+
},
153+
{
154+
code: dedent`
155+
it('should not pass', () => {
156+
expect(true).toBeDefined();
157+
expect(true).toBeDefined();
158+
expect(true).toBeDefined();
159+
expect(true).toBeDefined();
160+
expect(true).toBeDefined();
161+
expect(true).toBeDefined();
162+
});
163+
`,
164+
errors: [
165+
{
166+
messageId: 'exceededMaxAssertion',
167+
line: 7,
168+
column: 3,
169+
},
170+
],
171+
},
172+
{
173+
code: dedent`
174+
it('should not pass', async () => {
175+
expect(true).toBeDefined();
176+
expect(true).toBeDefined();
177+
expect(true).toBeDefined();
178+
expect(true).toBeDefined();
179+
expect(true).toBeDefined();
180+
expect(true).toBeDefined();
181+
});
182+
`,
183+
errors: [
184+
{
185+
messageId: 'exceededMaxAssertion',
186+
line: 7,
187+
column: 3,
188+
},
189+
],
190+
},
191+
{
192+
code: dedent`
193+
test('should not pass', () => {
194+
expect(true).toBeDefined();
195+
expect(true).toBeDefined();
196+
expect(true).toBeDefined();
197+
expect(true).toBeDefined();
198+
expect(true).toBeDefined();
199+
expect(true).toBeDefined();
200+
});
201+
test('should not pass', () => {
202+
expect(true).toBeDefined();
203+
expect(true).toBeDefined();
204+
expect(true).toBeDefined();
205+
expect(true).toBeDefined();
206+
expect(true).toBeDefined();
207+
expect(true).toBeDefined();
208+
});
209+
`,
210+
errors: [
211+
{
212+
messageId: 'exceededMaxAssertion',
213+
line: 7,
214+
column: 3,
215+
},
216+
{
217+
messageId: 'exceededMaxAssertion',
218+
line: 15,
219+
column: 3,
220+
},
221+
],
222+
},
223+
{
224+
code: dedent`
225+
describe('test', () => {
226+
test('should not pass', () => {
227+
expect(true).toBeDefined();
228+
expect(true).toBeDefined();
229+
expect(true).toBeDefined();
230+
expect(true).toBeDefined();
231+
expect(true).toBeDefined();
232+
expect(true).toBeDefined();
233+
});
234+
});
235+
`,
236+
errors: [
237+
{
238+
messageId: 'exceededMaxAssertion',
239+
line: 8,
240+
column: 5,
241+
},
242+
],
243+
},
244+
{
245+
code: dedent`
246+
test.each(['should', 'not', 'pass'], () => {
247+
expect(true).toBeDefined();
248+
expect(true).toBeDefined();
249+
expect(true).toBeDefined();
250+
expect(true).toBeDefined();
251+
expect(true).toBeDefined();
252+
expect(true).toBeDefined();
253+
});
254+
`,
255+
errors: [
256+
{
257+
messageId: 'exceededMaxAssertion',
258+
line: 7,
259+
column: 3,
260+
},
261+
],
262+
},
263+
{
264+
code: dedent`
265+
test('should not pass', () => {
266+
expect(true).toBeDefined();
267+
expect(true).toBeDefined();
268+
});
269+
`,
270+
options: [
271+
{
272+
max: 1,
273+
},
274+
],
275+
errors: [
276+
{
277+
messageId: 'exceededMaxAssertion',
278+
line: 3,
279+
column: 3,
280+
},
281+
],
282+
},
283+
],
284+
});

0 commit comments

Comments
 (0)