Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/rules/require-top-level-describe.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,34 @@ describe('test suite', () => {
});
```

You can also enforce a limit on the number of describes allowed at the top-level
using the `maxNumberOfTopLevelDescribes` option:

```json
{
"jest/require-top-level-describe": [
"error",
{
"maxNumberOfTopLevelDescribes": 2
}
]
}
```

Examples of **incorrect** code with the above config:

```js
describe('test suite', () => {
it('test', () => {});
});

describe('test suite', () => {});

describe('test suite', () => {});
```

This option defaults to `Infinity`, allowing any number of top-level describes.

## When Not To Use It

Don't use this rule on non-jest test files.
69 changes: 69 additions & 0 deletions src/rules/__tests__/require-top-level-describe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,72 @@ ruleTester.run('require-top-level-describe', rule, {
},
],
});

ruleTester.run(
'require-top-level-describe (enforce number of describes)',
rule,
{
valid: [
'describe("test suite", () => { test("my test") });',
'foo()',
'describe.each([1, true])("trues", value => { it("an it", () => expect(value).toBe(true) ); });',
dedent`
describe('one', () => {});
describe('two', () => {});
describe('three', () => {});
`,
{
code: dedent`
describe('one', () => {
describe('two', () => {});
describe('three', () => {});
});
`,
options: [{ maxNumberOfTopLevelDescribes: 1 }],
},
],
invalid: [
{
code: dedent`
describe('one', () => {});
describe('two', () => {});
describe('three', () => {});
`,
options: [{ maxNumberOfTopLevelDescribes: 2 }],
errors: [{ messageId: 'tooManyDescribes', line: 3 }],
},
{
code: dedent`
describe('one', () => {
describe('one (nested)', () => {});
describe('two (nested)', () => {});
});
describe('two', () => {
describe('one (nested)', () => {});
describe('two (nested)', () => {});
describe('three (nested)', () => {});
});
describe('three', () => {
describe('one (nested)', () => {});
describe('two (nested)', () => {});
describe('three (nested)', () => {});
});
`,
options: [{ maxNumberOfTopLevelDescribes: 2 }],
errors: [{ messageId: 'tooManyDescribes', line: 10 }],
},
{
code: dedent`
describe('one', () => {});
describe('two', () => {});
describe('three', () => {});
`,
options: [{ maxNumberOfTopLevelDescribes: 1 }],
errors: [
{ messageId: 'tooManyDescribes', line: 2 },
{ messageId: 'tooManyDescribes', line: 3 },
],
},
],
},
);
49 changes: 42 additions & 7 deletions src/rules/require-top-level-describe.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { TSESTree } from '@typescript-eslint/experimental-utils';
import { createRule, isDescribeCall, isHook, isTestCaseCall } from './utils';

export default createRule({
const messages = {
tooManyDescribes:
'There should not be more than {{ max }} describe{{ s }} at the top level',
unexpectedTestCase: 'All test cases must be wrapped in a describe block.',
unexpectedHook: 'All hooks must be wrapped in a describe block.',
};

export default createRule<
[Partial<{ maxNumberOfTopLevelDescribes: number }>],
keyof typeof messages
>({
name: __filename,
meta: {
docs: {
Expand All @@ -10,22 +20,47 @@ export default createRule({
'Require test cases and hooks to be inside 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.',
},
messages,
type: 'suggestion',
schema: [],
schema: [
{
type: 'object',
properties: {
maxNumberOfTopLevelDescribes: {
type: 'number',
minimum: 1,
},
},
additionalProperties: false,
},
],
},
defaultOptions: [],
defaultOptions: [{}],
create(context) {
const { maxNumberOfTopLevelDescribes = Infinity } =
context.options[0] ?? {};
let numberOfTopLevelDescribeBlocks = 0;
let numberOfDescribeBlocks = 0;

return {
CallExpression(node) {
if (isDescribeCall(node)) {
numberOfDescribeBlocks++;

if (numberOfDescribeBlocks === 1) {
numberOfTopLevelDescribeBlocks++;
if (numberOfTopLevelDescribeBlocks > maxNumberOfTopLevelDescribes) {
context.report({
node,
messageId: 'tooManyDescribes',
data: {
max: maxNumberOfTopLevelDescribes,
s: maxNumberOfTopLevelDescribes === 1 ? '' : 's',
},
});
}
}

return;
}

Expand Down