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(rules): add require-top-level-describe rule #407
Merged
SimenB
merged 5 commits into
jest-community:master
from
thomaslombart:feature/require-top-level-describe
Aug 29, 2019
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
babf037
feat(rules): add require-top-level-describe rule
3e3415a
chore(require-top-level-describe): improve code readability
9ad6cfe
docs(require-top-level-describe): add rule details in main README
83794bc
feat(require-top-level-describe): separate test and hook error message
503a488
test(require-top-level-describe): add test case simple CallExpression
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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,52 @@ | ||
# Require top-level describe block (require-top-level-describe) | ||
|
||
Jest allows you to organise your test files the way you want it. However, the | ||
more your codebase grows, the more it becomes hard to navigate in your test | ||
files. This rule makes sure that you provide at least a top-level describe block | ||
in your test file. | ||
|
||
## Rule Details | ||
|
||
This rule triggers a warning if a test case (`test` and `it`) or a hook | ||
(`beforeAll`, `beforeEach`, `afterEach`, `afterAll`) is not located in a | ||
top-level describe block. | ||
|
||
The following patterns are considered warnings: | ||
|
||
```js | ||
// Above a describe block | ||
test('my test', () => {}); | ||
describe('test suite', () => { | ||
it('test', () => {}); | ||
}); | ||
|
||
// Below a describe block | ||
describe('test suite', () => {}); | ||
test('my test', () => {}); | ||
|
||
// Same for hooks | ||
beforeAll('my beforeAll', () => {}); | ||
describe('test suite', () => {}); | ||
afterEach('my afterEach', () => {}); | ||
``` | ||
|
||
The following patterns are **not** considered warnings: | ||
|
||
```js | ||
// In a describe block | ||
describe('test suite', () => { | ||
test('my test', () => {}); | ||
}); | ||
|
||
// In a nested describe block | ||
describe('test suite', () => { | ||
test('my test', () => {}); | ||
describe('another test suite', () => { | ||
test('my other test', () => {}); | ||
}); | ||
}); | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
Don't use this rule on non-jest test files. |
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,58 @@ | ||
import { TSESLint } from '@typescript-eslint/experimental-utils'; | ||
import rule from '../require-top-level-describe'; | ||
|
||
const ruleTester = new TSESLint.RuleTester({ | ||
parserOptions: { | ||
ecmaVersion: 2015, | ||
}, | ||
}); | ||
|
||
ruleTester.run('no-standalone-hook', rule, { | ||
valid: [ | ||
'describe("test suite", () => { test("my test") });', | ||
'describe("test suite", () => { it("my test") });', | ||
` | ||
describe("test suite", () => { | ||
beforeEach("a", () => {}); | ||
describe("b", () => {}); | ||
test("c", () => {}) | ||
}); | ||
`, | ||
'describe("test suite", () => { beforeAll("my beforeAll") });', | ||
'describe("test suite", () => { afterEach("my afterEach") });', | ||
'describe("test suite", () => { afterAll("my afterAll") });', | ||
` | ||
describe("test suite", () => { | ||
it("my test", () => {}) | ||
describe("another test suite", () => { | ||
}); | ||
test("my other test", () => {}) | ||
}); | ||
`, | ||
], | ||
invalid: [ | ||
{ | ||
code: ` | ||
test("my test", () => {}) | ||
describe("test suite", () => {}); | ||
`, | ||
errors: [{ messageId: 'unexpectedTestCase' }], | ||
}, | ||
{ | ||
code: ` | ||
test("my test", () => {}) | ||
describe("test suite", () => { | ||
it("test", () => {}) | ||
}); | ||
`, | ||
errors: [{ messageId: 'unexpectedTestCase' }], | ||
}, | ||
{ | ||
code: ` | ||
describe("test suite", () => {}); | ||
afterAll("my test", () => {}) | ||
`, | ||
errors: [{ messageId: 'unexpectedHook' }], | ||
}, | ||
], | ||
}); |
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,50 @@ | ||
import { TSESTree } from '@typescript-eslint/experimental-utils'; | ||
|
||
import { createRule, isDescribe, isHook, isTestCase } from './utils'; | ||
|
||
export default createRule({ | ||
name: __filename, | ||
meta: { | ||
docs: { | ||
category: 'Best Practices', | ||
description: | ||
'Prevents test cases and hooks to be outside of a describe block', | ||
recommended: false, | ||
}, | ||
messages: { | ||
unexpectedTestCase: 'All test cases must be wrapped in a describe block.', | ||
unexpectedHook: 'All hooks must be wrapped in a describe block.', | ||
}, | ||
type: 'suggestion', | ||
schema: [], | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
let numberOfDescribeBlocks = 0; | ||
return { | ||
CallExpression(node) { | ||
if (isDescribe(node)) { | ||
numberOfDescribeBlocks++; | ||
return; | ||
} | ||
|
||
if (numberOfDescribeBlocks === 0) { | ||
if (isTestCase(node)) { | ||
context.report({ node, messageId: 'unexpectedTestCase' }); | ||
return; | ||
} | ||
|
||
if (isHook(node)) { | ||
context.report({ node, messageId: 'unexpectedHook' }); | ||
return; | ||
} | ||
} | ||
}, | ||
'CallExpression:exit'(node: TSESTree.CallExpression) { | ||
if (isDescribe(node)) { | ||
numberOfDescribeBlocks--; | ||
} | ||
}, | ||
}; | ||
}, | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI complains that this is not covered. Maybe the
else
branch? A test with aCallExpression
inside adescribe
that's neither a test nor a hook should probably hit it?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed! I added a dummy test in the valid cases to fix it:
But thinking of it, should we trigger a warning if the user uses a
CallExpression
that's neither a test or a hook or can we leave it as is?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, that's fine, I think. Jest itself uses it to e.g. skip tests on windows, or run some other sort of helper 🙂