-
Notifications
You must be signed in to change notification settings - Fork 238
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: create
max-nested-describe
rule (#845)
* feat: create max-nested-describe rule * feat: support only object schema * refactor: simplify call expression type check * test: max 0 option * test: update number of rules * test: update snapshot * test: describe modifiers * docs: fix examples syntax * docs: fix syntax consistency * test: fix missing brackets * refactor: add spacing around message placeholders * feat: increase default max to 5 * docs: update with new default max of 5 * test: add cases for 5 max
- Loading branch information
1 parent
19e3a6e
commit 8067405
Showing
6 changed files
with
437 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# Enforces a maximum depth to nested describe calls (`max-nested-describe`) | ||
|
||
While it's useful to be able to group your tests together within the same file | ||
using `describe()`, having too many levels of nesting throughout your tests make | ||
them difficult to read. | ||
|
||
## Rule Details | ||
|
||
This rule enforces a maximum depth to nested `describe()` calls to improve code | ||
clarity in your tests. | ||
|
||
The following patterns are considered warnings (with the default option of | ||
`{ "max": 5 } `): | ||
|
||
```js | ||
describe('foo', () => { | ||
describe('bar', () => { | ||
describe('baz', () => { | ||
describe('qux', () => { | ||
describe('quxx', () => { | ||
describe('too many', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('foo', function () { | ||
describe('bar', function () { | ||
describe('baz', function () { | ||
describe('qux', function () { | ||
describe('quxx', function () { | ||
describe('too many', function () { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
``` | ||
|
||
The following patterns are **not** considered warnings (with the default option | ||
of `{ "max": 5 } `): | ||
|
||
```js | ||
describe('foo', () => { | ||
describe('bar', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
|
||
describe('qux', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('foo2', function () { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
|
||
describe('foo', function () { | ||
describe('bar', function () { | ||
describe('baz', function () { | ||
describe('qux', function () { | ||
describe('this is the limit', function () { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
``` | ||
|
||
## Options | ||
|
||
```json | ||
{ | ||
"jest/max-nested-describe": [ | ||
"error", | ||
{ | ||
"max": 5 | ||
} | ||
] | ||
} | ||
``` | ||
|
||
### `max` | ||
|
||
Enforces a maximum depth for nested `describe()`. | ||
|
||
This has a default value of `5`. | ||
|
||
Examples of patterns **not** considered warnings with options set to | ||
`{ "max": 2 }`: | ||
|
||
```js | ||
describe('foo', () => { | ||
describe('bar', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('foo2', function()) { | ||
describe('bar2', function() { | ||
it('should get something', function() { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
|
||
it('should get else', function() { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
import { TSESLint } from '@typescript-eslint/experimental-utils'; | ||
import dedent from 'dedent'; | ||
import resolveFrom from 'resolve-from'; | ||
import rule from '../max-nested-describe'; | ||
|
||
const ruleTester = new TSESLint.RuleTester({ | ||
parser: resolveFrom(require.resolve('eslint'), 'espree'), | ||
parserOptions: { | ||
ecmaVersion: 2017, | ||
}, | ||
}); | ||
|
||
ruleTester.run('max-nested-describe', rule, { | ||
valid: [ | ||
dedent` | ||
describe('foo', function() { | ||
describe('bar', function () { | ||
describe('baz', function () { | ||
describe('qux', function () { | ||
describe('qux', function () { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}) | ||
}) | ||
}) | ||
}) | ||
}); | ||
`, | ||
dedent` | ||
describe('foo', function() { | ||
describe('bar', function () { | ||
describe('baz', function () { | ||
describe('qux', function () { | ||
describe('qux', function () { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
fdescribe('qux', () => { | ||
it('something', async () => { | ||
expect('something').toBe('something'); | ||
}); | ||
}); | ||
}) | ||
}) | ||
}) | ||
}); | ||
`, | ||
dedent` | ||
describe('foo', () => { | ||
describe('bar', () => { | ||
it('hello', async () => { | ||
expect('hello').toBe('hello'); | ||
}); | ||
}); | ||
}); | ||
xdescribe('foo', function() { | ||
describe('bar', function() { | ||
it('something', async () => { | ||
expect('something').toBe('something'); | ||
}); | ||
}); | ||
}); | ||
`, | ||
{ | ||
code: dedent` | ||
describe('foo', () => { | ||
describe.only('bar', () => { | ||
describe.skip('baz', () => { | ||
it('something', async () => { | ||
expect('something').toBe('something'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
`, | ||
options: [{ max: 3 }], | ||
}, | ||
{ | ||
code: dedent` | ||
it('something', async () => { | ||
expect('something').toBe('something'); | ||
}); | ||
`, | ||
options: [{ max: 0 }], | ||
}, | ||
dedent` | ||
describe('foo', () => { | ||
describe.each(['hello', 'world'])("%s", (a) => {}); | ||
}); | ||
`, | ||
dedent` | ||
describe('foo', () => { | ||
describe.each\` | ||
foo | bar | ||
${1} | ${2} | ||
\`('$foo $bar', ({ foo, bar }) => {}); | ||
}); | ||
`, | ||
], | ||
invalid: [ | ||
{ | ||
code: dedent` | ||
describe('foo', function() { | ||
describe('bar', function () { | ||
describe('baz', function () { | ||
describe('qux', function () { | ||
describe('quxx', function () { | ||
describe('over limit', function () { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
`, | ||
errors: [{ messageId: 'exceededMaxDepth', line: 6, column: 11 }], | ||
}, | ||
{ | ||
code: dedent` | ||
describe('foo', () => { | ||
describe('bar', () => { | ||
describe('baz', () => { | ||
describe('baz1', () => { | ||
describe('baz2', () => { | ||
describe('baz3', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
describe('baz4', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('qux', function () { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}) | ||
}); | ||
`, | ||
errors: [ | ||
{ messageId: 'exceededMaxDepth', line: 6, column: 11 }, | ||
{ messageId: 'exceededMaxDepth', line: 12, column: 11 }, | ||
], | ||
}, | ||
{ | ||
code: dedent` | ||
fdescribe('foo', () => { | ||
describe.only('bar', () => { | ||
describe.skip('baz', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
describe('baz', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
}); | ||
}); | ||
xdescribe('qux', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
`, | ||
options: [{ max: 2 }], | ||
errors: [ | ||
{ messageId: 'exceededMaxDepth', line: 3, column: 5 }, | ||
{ messageId: 'exceededMaxDepth', line: 9, column: 5 }, | ||
], | ||
}, | ||
{ | ||
code: dedent` | ||
describe('qux', () => { | ||
it('should get something', () => { | ||
expect(getSomething()).toBe('Something'); | ||
}); | ||
}); | ||
`, | ||
options: [{ max: 0 }], | ||
errors: [{ messageId: 'exceededMaxDepth', line: 1, column: 1 }], | ||
}, | ||
{ | ||
code: dedent` | ||
describe('foo', () => { | ||
describe.each(['hello', 'world'])("%s", (a) => {}); | ||
}); | ||
`, | ||
options: [{ max: 1 }], | ||
errors: [{ messageId: 'exceededMaxDepth', line: 2, column: 3 }], | ||
}, | ||
{ | ||
code: dedent` | ||
describe('foo', () => { | ||
describe.each\` | ||
foo | bar | ||
${1} | ${2} | ||
\`('$foo $bar', ({ foo, bar }) => {}); | ||
}); | ||
`, | ||
options: [{ max: 1 }], | ||
errors: [{ messageId: 'exceededMaxDepth', line: 2, column: 3 }], | ||
}, | ||
], | ||
}); |
Oops, something went wrong.