Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create max-expects rule #1166

Merged
merged 11 commits into from Jul 14, 2022
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -201,6 +201,7 @@ installations requiring long-term consistency.
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------------- | ------------ |
| [consistent-test-it](docs/rules/consistent-test-it.md) | Have control over `test` and `it` usages | | ![fixable][] |
| [expect-expect](docs/rules/expect-expect.md) | Enforce assertion to be made in a test body | ![recommended][] | |
| [max-expects](docs/rules/max-expects.md) | Enforces a maximum number assertion calls in a test body | | |
| [max-nested-describe](docs/rules/max-nested-describe.md) | Enforces a maximum depth to nested describe calls | | |
| [no-alias-methods](docs/rules/no-alias-methods.md) | Disallow alias methods | ![style][] | ![fixable][] |
| [no-commented-out-tests](docs/rules/no-commented-out-tests.md) | Disallow commented out tests | ![recommended][] | |
Expand Down
74 changes: 74 additions & 0 deletions docs/rules/max-expects.md
@@ -0,0 +1,74 @@
# Enforces a maximum number assertion calls in a test body (`max-expects`)

As more assertions are made, there is a possible tendency for the test to be
more likely to mix multiple objectives. To avoid this, this rule reports when
the maximum number of assertions is exceeded.

## Rule Details

This rule enforces a maximum number of `expect()` calls.

The following patterns are considered warnings (with the default option of
`{ "max": 5 } `):

```js
test('should not pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});

it('should not pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
```

The following patterns are **not** considered warnings (with the default option
of `{ "max": 5 } `):

```js
test('shout pass');

test('shout pass', () => {});

test.skip('shout pass', () => {});

test('should pass', function () {
expect(true).toBeDefined();
});

test('should pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
```

## Options

```json
{
"jest/max-expects": [
"error",
{
"max": 5
}
]
}
```

### `max`

Enforces a maximum number of `expect()`.

This has a default value of `5`.
1 change: 1 addition & 0 deletions src/__tests__/__snapshots__/rules.test.ts.snap
Expand Up @@ -12,6 +12,7 @@ Object {
"rules": Object {
"jest/consistent-test-it": "error",
"jest/expect-expect": "error",
"jest/max-expects": "error",
"jest/max-nested-describe": "error",
"jest/no-alias-methods": "error",
"jest/no-commented-out-tests": "error",
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/rules.test.ts
Expand Up @@ -2,7 +2,7 @@ import { existsSync } from 'fs';
import { resolve } from 'path';
import plugin from '../';

const numberOfRules = 48;
const numberOfRules = 49;
const ruleNames = Object.keys(plugin.rules);
const deprecatedRules = Object.entries(plugin.rules)
.filter(([, rule]) => rule.meta.deprecated)
Expand Down
284 changes: 284 additions & 0 deletions src/rules/__tests__/max-expects.test.ts
@@ -0,0 +1,284 @@
import { TSESLint } from '@typescript-eslint/utils';
import dedent from 'dedent';
import rule from '../max-expects';
import { espreeParser } from './test-utils';

const ruleTester = new TSESLint.RuleTester({
parser: espreeParser,
parserOptions: {
ecmaVersion: 2017,
},
});

ruleTester.run('max-expects', rule, {
valid: [
`test('should pass')`,
`test('should pass', () => {})`,
`test.skip('should pass', () => {})`,
dedent`
test('should pass', function () {
expect(true).toBeDefined();
});
`,
dedent`
test('should pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
dedent`
test('should pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
// expect(true).toBeDefined();
});
`,
dedent`
it('should pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
dedent`
test('should pass', async () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
dedent`
describe('test', () => {
test('should pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
});
`,
dedent`
test.each(['should', 'pass'], () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
dedent`
test('should pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
test('should pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
{
code: dedent`
test('should pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
options: [
{
max: 10,
},
],
},
],
invalid: [
{
code: dedent`
test('should not pass', function () {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
errors: [
{
messageId: 'exceededMaxAssertion',
line: 7,
column: 3,
},
],
},
{
code: dedent`
test('should not pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
errors: [
{
messageId: 'exceededMaxAssertion',
line: 7,
column: 3,
},
],
},
{
code: dedent`
it('should not pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
errors: [
{
messageId: 'exceededMaxAssertion',
line: 7,
column: 3,
},
],
},
{
code: dedent`
it('should not pass', async () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
errors: [
{
messageId: 'exceededMaxAssertion',
line: 7,
column: 3,
},
],
},
{
code: dedent`
test('should not pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
test('should not pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
errors: [
{
messageId: 'exceededMaxAssertion',
line: 7,
column: 3,
},
{
messageId: 'exceededMaxAssertion',
line: 15,
column: 3,
},
],
},
{
code: dedent`
describe('test', () => {
test('should not pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
});
`,
errors: [
{
messageId: 'exceededMaxAssertion',
line: 8,
column: 5,
},
],
},
{
code: dedent`
test.each(['should', 'not', 'pass'], () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
errors: [
{
messageId: 'exceededMaxAssertion',
line: 7,
column: 3,
},
],
},
{
code: dedent`
test('should not pass', () => {
expect(true).toBeDefined();
expect(true).toBeDefined();
});
`,
options: [
{
max: 1,
},
],
errors: [
{
messageId: 'exceededMaxAssertion',
line: 3,
column: 3,
},
],
},
],
});