Skip to content

Commit acf80a0

Browse files
committed
feat: Add max-expects rule
1 parent 3f3113f commit acf80a0

File tree

5 files changed

+480
-1
lines changed

5 files changed

+480
-1
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@ command line option.\
118118
[suggestions](https://eslint.org/docs/latest/developer-guide/working-with-rules#providing-suggestions).
119119

120120
|| 🔧 | 💡 | Rule | Description |
121-
| :-: | :-: | :-: | --------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
121+
| :-: | :-: | :-: | --------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | --- |
122122
|| | | [expect-expect](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/expect-expect.md) | Enforce assertion to be made in a test body |
123+
|| | | [max-expects](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/max-expects.md) | Enforces a maximum number assertion calls in a test body | |
123124
|| | | [max-nested-describe](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/max-nested-describe.md) | Enforces a maximum depth to nested describe calls |
124125
|| 🔧 | | [missing-playwright-await](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/missing-playwright-await.md) | Enforce Playwright APIs to be awaited |
125126
| | | | [no-commented-out-test](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-commented-out-test.md) | Disallow commented out tests |

docs/rules/max-expects.md

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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+
25+
The following patterns are **not** considered warnings (with the default option
26+
of `{ "max": 5 } `):
27+
28+
```js
29+
test('shout pass');
30+
31+
test('shout pass', () => {});
32+
33+
test.skip('shout pass', () => {});
34+
35+
test('should pass', function () {
36+
expect(true).toBeDefined();
37+
});
38+
39+
test('should pass', () => {
40+
expect(true).toBeDefined();
41+
expect(true).toBeDefined();
42+
expect(true).toBeDefined();
43+
expect(true).toBeDefined();
44+
expect(true).toBeDefined();
45+
});
46+
```
47+
48+
## Options
49+
50+
```json
51+
{
52+
"playwright/max-expects": [
53+
"error",
54+
{
55+
"max": 5
56+
}
57+
]
58+
}
59+
```
60+
61+
### `max`
62+
63+
Enforces a maximum number of `expect()`.
64+
65+
This has a default value of `5`.

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import globals from 'globals';
22
import expectExpect from './rules/expect-expect';
3+
import maxExpects from './rules/max-expects';
34
import maxNestedDescribe from './rules/max-nested-describe';
45
import missingPlaywrightAwait from './rules/missing-playwright-await';
56
import noCommentedOutTests from './rules/no-commented-out-tests';
@@ -42,6 +43,7 @@ const index = {
4243
configs: {},
4344
rules: {
4445
'expect-expect': expectExpect,
46+
'max-expects': maxExpects,
4547
'max-nested-describe': maxNestedDescribe,
4648
'missing-playwright-await': missingPlaywrightAwait,
4749
'no-commented-out-tests': noCommentedOutTests,

src/rules/max-expects.ts

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Rule } from 'eslint';
2+
import * as ESTree from 'estree';
3+
import { getExpectType, getParent, isTestCall } from '../utils/ast';
4+
5+
export default {
6+
create(context) {
7+
const options = {
8+
max: 5,
9+
...((context.options?.[0] as Record<string, unknown>) ?? {}),
10+
};
11+
12+
let count = 0;
13+
14+
const maybeResetCount = (node: ESTree.Node) => {
15+
const parent = getParent(node);
16+
const isTestFn =
17+
parent?.type !== 'CallExpression' || isTestCall(context, parent);
18+
19+
if (isTestFn) {
20+
count = 0;
21+
}
22+
};
23+
24+
return {
25+
ArrowFunctionExpression: maybeResetCount,
26+
'ArrowFunctionExpression:exit': maybeResetCount,
27+
CallExpression(node) {
28+
if (!getExpectType(context, node)) return;
29+
30+
count += 1;
31+
32+
if (count > options.max) {
33+
context.report({
34+
data: {
35+
count: count.toString(),
36+
max: options.max.toString(),
37+
},
38+
messageId: 'exceededMaxAssertion',
39+
node,
40+
});
41+
}
42+
},
43+
FunctionExpression: maybeResetCount,
44+
'FunctionExpression:exit': maybeResetCount,
45+
};
46+
},
47+
meta: {
48+
docs: {
49+
category: 'Best Practices',
50+
description: 'Enforces a maximum number assertion calls in a test body',
51+
recommended: false,
52+
url: 'https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/max-expects.md',
53+
},
54+
messages: {
55+
exceededMaxAssertion:
56+
'Too many assertion calls ({{ count }}) - maximum allowed is {{ max }}',
57+
},
58+
schema: [
59+
{
60+
additionalProperties: false,
61+
properties: {
62+
max: {
63+
minimum: 1,
64+
type: 'integer',
65+
},
66+
},
67+
type: 'object',
68+
},
69+
],
70+
type: 'suggestion',
71+
},
72+
} as Rule.RuleModule;

0 commit comments

Comments
 (0)