From 90e5eb69cae384246f54b584143f46d9c5cff58c Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Wed, 19 May 2021 18:16:36 +0100 Subject: [PATCH 01/14] feat: create max-nested-describe rule --- README.md | 1 + docs/rules/max-nested-describe.md | 111 ++++++++++++++ .../__tests__/max-nested-describe.test.ts | 135 ++++++++++++++++++ src/rules/max-nested-describe.ts | 79 ++++++++++ src/rules/utils.ts | 10 ++ 5 files changed, 336 insertions(+) create mode 100644 docs/rules/max-nested-describe.md create mode 100644 src/rules/__tests__/max-nested-describe.test.ts create mode 100644 src/rules/max-nested-describe.ts diff --git a/README.md b/README.md index cc8d97423..1b744f1bb 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,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][] | | | [lowercase-name](docs/rules/lowercase-name.md) | Enforce lowercase test names | | ![fixable][] | +| [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][] | | | [no-conditional-expect](docs/rules/no-conditional-expect.md) | Prevent calling `expect` conditionally | ![recommended][] | | diff --git a/docs/rules/max-nested-describe.md b/docs/rules/max-nested-describe.md new file mode 100644 index 000000000..22ea4a0d3 --- /dev/null +++ b/docs/rules/max-nested-describe.md @@ -0,0 +1,111 @@ +# 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": 2 } `): + +```js +describe('foo', () => { + describe('bar', () => { + describe('baz', () => { + it('should get something', () => { + expect(getSomething().toBe('Something')); + }); + }); + }); +}); + +describe('foo2', function () { + describe('bar2', function () { + describe('baz2', function () { + it('should get something', () => { + expect(getSomething().toBe('Something')); + }); + }); + }); +}); +``` + +The following patterns are **not** considered warnings (with the default option +of `{ "max": 2 } `): + +```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')); + }); +}); +``` + +## Options + +```json +{ + "jest/max-nested-describe": [ + "error", + { + "max": 3 + } + ] +} +``` + +### `max` + +Enforces a maximum depth for nested `describe()`. + +This has default value of `2`. + +Examples of patterns **not** considered warnings with options set to +`{ "max": 3 }`: + +```js +describe('foo', () => { + describe('bar', () => { + describe('baz', () => { + it('should get something', () => { + expect(getSomething().toBe('Something')) + }); + }); + }); +}); + +describe('foo2', function()) { + describe('bar2', function() { + describe('baz2', function() { + it('should get something', function() { + expect(getSomething().toBe('Something')) + }); + }); + + describe('qux2', function() { + it('should get something', function() { + expect(getSomething().toBe('Something')) + }); + }); + }); +}); + +``` diff --git a/src/rules/__tests__/max-nested-describe.test.ts b/src/rules/__tests__/max-nested-describe.test.ts new file mode 100644 index 000000000..5ed72ed2a --- /dev/null +++ b/src/rules/__tests__/max-nested-describe.test.ts @@ -0,0 +1,135 @@ +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', () => { + describe('bar', () => { + it('hello', async () => { + expect('hello').toBe('hello'); + }); + }); + }); + `, + dedent` + describe('foo', () => { + describe('bar', () => { + it('hello', async () => { + expect('hello').toBe('hello'); + }); + }); + + describe('qux', () => { + it('something', async () => { + expect('something').toBe('something'); + }); + }); + }); + `, + dedent` + describe('foo', () => { + describe('bar', () => { + it('hello', async () => { + expect('hello').toBe('hello'); + }); + }); + }); + + describe('foo', function() { + describe('bar', function() { + it('something', async () => { + expect('something').toBe('something'); + }); + }); + }); + `, + { + code: dedent` + describe('foo', () => { + describe('bar', () => { + describe('baz', () => { + it('something', async () => { + expect('something').toBe('something'); + }); + }); + }); + }); + `, + options: [{ max: 3 }], + }, + ], + invalid: [ + { + code: dedent` + describe('foo', function() { + describe('bar', function () { + describe('baz', function () { + describe('qux', function () { + it('should get something', () => { + expect(getSomething().toBe('Something')) + }); + }) + }) + }) + }); + `, + errors: [ + { messageId: 'exceededMaxDepth', line: 3, column: 5 }, + { messageId: 'exceededMaxDepth', line: 4, column: 7 }, + ], + }, + { + code: dedent` + describe('foo', () => { + describe('bar', () => { + describe('baz', () => { + it('should get something', () => { + expect(getSomething().toBe('Something')) + }); + }); + + describe('qux', function () { + it('should get something', () => { + expect(getSomething().toBe('Something')) + }); + }); + }) + }); + `, + errors: [ + { messageId: 'exceededMaxDepth', line: 3, column: 5 }, + { messageId: 'exceededMaxDepth', line: 9, column: 5 }, + ], + }, + { + code: dedent` + describe('foo', () => { + describe('bar', () => { + describe('baz', () => { + it('should get something', () => { + expect(getSomething().toBe('Something')) + }); + }); + }); + }); + + describe('qux', () => { + it('should get something', () => { + expect(getSomething().toBe('Something')) + }); + }); + `, + errors: [{ messageId: 'exceededMaxDepth', line: 3, column: 5 }], + }, + ], +}); diff --git a/src/rules/max-nested-describe.ts b/src/rules/max-nested-describe.ts new file mode 100644 index 000000000..4ca799902 --- /dev/null +++ b/src/rules/max-nested-describe.ts @@ -0,0 +1,79 @@ +import { TSESTree } from '@typescript-eslint/experimental-utils'; +import { createRule, isCallExpression, isDescribeCall } from './utils'; + +export default createRule({ + name: __filename, + meta: { + docs: { + category: 'Best Practices', + description: 'Enforces a maximum depth to nested describe calls', + recommended: false, + }, + messages: { + exceededMaxDepth: + 'Too many nested describe calls ({{depth}}). Maximum allowed is {{max}}.', + }, + type: 'suggestion', + schema: [ + { + oneOf: [ + { + type: 'integer', + minimum: 0, + }, + { + type: 'object', + properties: { + max: { + type: 'integer', + minimum: 0, + }, + }, + additionalProperties: false, + }, + ], + }, + ], + }, + defaultOptions: [{ max: 2 }], + create(context, [{ max }]) { + const describeCallbackStack: number[] = []; + + function pushDescribeCallback( + node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, + ) { + const { parent } = node; + + if (!isCallExpression(parent) || !isDescribeCall(parent)) { + return; + } + + describeCallbackStack.push(0); + + if (describeCallbackStack.length > max) { + context.report({ + node: parent, + messageId: 'exceededMaxDepth', + data: { depth: describeCallbackStack.length, max }, + }); + } + } + + function popDescribeCallback( + node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression, + ) { + const { parent } = node; + + if (isCallExpression(parent) && isDescribeCall(parent)) { + describeCallbackStack.pop(); + } + } + + return { + FunctionExpression: pushDescribeCallback, + 'FunctionExpression:exit': popDescribeCallback, + ArrowFunctionExpression: pushDescribeCallback, + 'ArrowFunctionExpression:exit': popDescribeCallback, + }; + }, +}); diff --git a/src/rules/utils.ts b/src/rules/utils.ts index 24ce68d34..c4d2d4134 100644 --- a/src/rules/utils.ts +++ b/src/rules/utils.ts @@ -648,6 +648,16 @@ export type FunctionExpression = | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression; +export const isCallExpression = ( + node: TSESTree.Node | undefined, +): node is TSESTree.CallExpression => { + if (!node) { + return false; + } + + return node.type === AST_NODE_TYPES.CallExpression; +}; + export const isFunction = (node: TSESTree.Node): node is FunctionExpression => node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.ArrowFunctionExpression; From 45af21d2d2e2e5acc83fa67843abb7e08e7759f5 Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 20:38:36 +0100 Subject: [PATCH 02/14] feat: support only object schema --- src/rules/max-nested-describe.ts | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/rules/max-nested-describe.ts b/src/rules/max-nested-describe.ts index 4ca799902..1f2878500 100644 --- a/src/rules/max-nested-describe.ts +++ b/src/rules/max-nested-describe.ts @@ -16,22 +16,14 @@ export default createRule({ type: 'suggestion', schema: [ { - oneOf: [ - { + type: 'object', + properties: { + max: { type: 'integer', minimum: 0, }, - { - type: 'object', - properties: { - max: { - type: 'integer', - minimum: 0, - }, - }, - additionalProperties: false, - }, - ], + }, + additionalProperties: false, }, ], }, From 90cb9123792d1aba9f02c2fb72973151b48fc2ce Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 20:42:28 +0100 Subject: [PATCH 03/14] refactor: simplify call expression type check --- src/rules/max-nested-describe.ts | 17 +++++++++++++---- src/rules/utils.ts | 10 ---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/rules/max-nested-describe.ts b/src/rules/max-nested-describe.ts index 1f2878500..f369e3622 100644 --- a/src/rules/max-nested-describe.ts +++ b/src/rules/max-nested-describe.ts @@ -1,5 +1,8 @@ -import { TSESTree } from '@typescript-eslint/experimental-utils'; -import { createRule, isCallExpression, isDescribeCall } from './utils'; +import { + AST_NODE_TYPES, + TSESTree, +} from '@typescript-eslint/experimental-utils'; +import { createRule, isDescribeCall } from './utils'; export default createRule({ name: __filename, @@ -36,7 +39,10 @@ export default createRule({ ) { const { parent } = node; - if (!isCallExpression(parent) || !isDescribeCall(parent)) { + if ( + parent?.type !== AST_NODE_TYPES.CallExpression || + !isDescribeCall(parent) + ) { return; } @@ -56,7 +62,10 @@ export default createRule({ ) { const { parent } = node; - if (isCallExpression(parent) && isDescribeCall(parent)) { + if ( + parent?.type === AST_NODE_TYPES.CallExpression && + isDescribeCall(parent) + ) { describeCallbackStack.pop(); } } diff --git a/src/rules/utils.ts b/src/rules/utils.ts index c4d2d4134..24ce68d34 100644 --- a/src/rules/utils.ts +++ b/src/rules/utils.ts @@ -648,16 +648,6 @@ export type FunctionExpression = | TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression; -export const isCallExpression = ( - node: TSESTree.Node | undefined, -): node is TSESTree.CallExpression => { - if (!node) { - return false; - } - - return node.type === AST_NODE_TYPES.CallExpression; -}; - export const isFunction = (node: TSESTree.Node): node is FunctionExpression => node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.ArrowFunctionExpression; From 70ce2668cb7084735cd418073e3504899f526d80 Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 20:47:12 +0100 Subject: [PATCH 04/14] test: max 0 option --- .../__tests__/max-nested-describe.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/rules/__tests__/max-nested-describe.test.ts b/src/rules/__tests__/max-nested-describe.test.ts index 5ed72ed2a..182c75905 100644 --- a/src/rules/__tests__/max-nested-describe.test.ts +++ b/src/rules/__tests__/max-nested-describe.test.ts @@ -67,6 +67,14 @@ ruleTester.run('max-nested-describe', rule, { `, options: [{ max: 3 }], }, + { + code: dedent` + it('something', async () => { + expect('something').toBe('something'); + }); + `, + options: [{ max: 0 }], + }, ], invalid: [ { @@ -131,5 +139,16 @@ ruleTester.run('max-nested-describe', rule, { `, errors: [{ messageId: 'exceededMaxDepth', line: 3, column: 5 }], }, + { + code: dedent` + describe('qux', () => { + it('should get something', () => { + expect(getSomething().toBe('Something')) + }); + }); + `, + options: [{ max: 0 }], + errors: [{ messageId: 'exceededMaxDepth', line: 1, column: 1 }], + }, ], }); From c4eab3e5f3692653c026c7a5e52995712c1bbd3a Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 20:48:19 +0100 Subject: [PATCH 05/14] test: update number of rules --- src/__tests__/rules.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__tests__/rules.test.ts b/src/__tests__/rules.test.ts index 6a8ff2df1..6703e7a13 100644 --- a/src/__tests__/rules.test.ts +++ b/src/__tests__/rules.test.ts @@ -2,7 +2,7 @@ import { existsSync } from 'fs'; import { resolve } from 'path'; import plugin from '../'; -const numberOfRules = 45; +const numberOfRules = 46; const ruleNames = Object.keys(plugin.rules); const deprecatedRules = Object.entries(plugin.rules) .filter(([, rule]) => rule.meta.deprecated) From 0fe42c0187fcbcb6b788171ca3953bbc4ef6a2a6 Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 21:04:41 +0100 Subject: [PATCH 06/14] test: update snapshot --- src/__tests__/__snapshots__/rules.test.ts.snap | 1 + 1 file changed, 1 insertion(+) diff --git a/src/__tests__/__snapshots__/rules.test.ts.snap b/src/__tests__/__snapshots__/rules.test.ts.snap index 414f67032..eb3178266 100644 --- a/src/__tests__/__snapshots__/rules.test.ts.snap +++ b/src/__tests__/__snapshots__/rules.test.ts.snap @@ -13,6 +13,7 @@ Object { "jest/consistent-test-it": "error", "jest/expect-expect": "error", "jest/lowercase-name": "error", + "jest/max-nested-describe": "error", "jest/no-alias-methods": "error", "jest/no-commented-out-tests": "error", "jest/no-conditional-expect": "error", From 454bf0be7fc0e2b96de85157f28b133439b195a0 Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 21:37:03 +0100 Subject: [PATCH 07/14] test: describe modifiers --- .../__tests__/max-nested-describe.test.ts | 67 +++++++++++++++---- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/src/rules/__tests__/max-nested-describe.test.ts b/src/rules/__tests__/max-nested-describe.test.ts index 182c75905..74f6da981 100644 --- a/src/rules/__tests__/max-nested-describe.test.ts +++ b/src/rules/__tests__/max-nested-describe.test.ts @@ -29,7 +29,7 @@ ruleTester.run('max-nested-describe', rule, { }); }); - describe('qux', () => { + fdescribe('qux', () => { it('something', async () => { expect('something').toBe('something'); }); @@ -45,7 +45,7 @@ ruleTester.run('max-nested-describe', rule, { }); }); - describe('foo', function() { + xdescribe('foo', function() { describe('bar', function() { it('something', async () => { expect('something').toBe('something'); @@ -55,15 +55,15 @@ ruleTester.run('max-nested-describe', rule, { `, { code: dedent` - describe('foo', () => { - describe('bar', () => { - describe('baz', () => { - it('something', async () => { - expect('something').toBe('something'); + describe('foo', () => { + describe.only('bar', () => { + describe.skip('baz', () => { + it('something', async () => { + expect('something').toBe('something'); + }); }); }); }); - }); `, options: [{ max: 3 }], }, @@ -75,6 +75,19 @@ ruleTester.run('max-nested-describe', rule, { `, 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: [ { @@ -121,8 +134,14 @@ ruleTester.run('max-nested-describe', rule, { }, { code: dedent` - describe('foo', () => { - describe('bar', () => { + 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')) @@ -131,13 +150,16 @@ ruleTester.run('max-nested-describe', rule, { }); }); - describe('qux', () => { + xdescribe('qux', () => { it('should get something', () => { expect(getSomething().toBe('Something')) }); }); `, - errors: [{ messageId: 'exceededMaxDepth', line: 3, column: 5 }], + errors: [ + { messageId: 'exceededMaxDepth', line: 3, column: 5 }, + { messageId: 'exceededMaxDepth', line: 9, column: 5 }, + ], }, { code: dedent` @@ -150,5 +172,26 @@ ruleTester.run('max-nested-describe', rule, { 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 }], + }, ], }); From 41c5dfcfe5686f340413bdccc943a74e2ef6cf28 Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 21:41:06 +0100 Subject: [PATCH 08/14] docs: fix examples syntax --- docs/rules/max-nested-describe.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/rules/max-nested-describe.md b/docs/rules/max-nested-describe.md index 22ea4a0d3..574818c1e 100644 --- a/docs/rules/max-nested-describe.md +++ b/docs/rules/max-nested-describe.md @@ -17,7 +17,7 @@ describe('foo', () => { describe('bar', () => { describe('baz', () => { it('should get something', () => { - expect(getSomething().toBe('Something')); + expect(getSomething()).toBe('Something'); }); }); }); @@ -27,7 +27,7 @@ describe('foo2', function () { describe('bar2', function () { describe('baz2', function () { it('should get something', () => { - expect(getSomething().toBe('Something')); + expect(getSomething()).toBe('Something'); }); }); }); @@ -41,20 +41,20 @@ of `{ "max": 2 } `): describe('foo', () => { describe('bar', () => { it('should get something', () => { - expect(getSomething().toBe('Something')); + expect(getSomething()).toBe('Something'); }); }); describe('qux', () => { it('should get something', () => { - expect(getSomething().toBe('Something')); + expect(getSomething()).toBe('Something'); }); }); }); describe('foo2', function () { it('should get something', () => { - expect(getSomething().toBe('Something')); + expect(getSomething()).toBe('Something'); }); }); ``` @@ -66,7 +66,7 @@ describe('foo2', function () { "jest/max-nested-describe": [ "error", { - "max": 3 + "max": 2 } ] } @@ -86,7 +86,7 @@ describe('foo', () => { describe('bar', () => { describe('baz', () => { it('should get something', () => { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something') }); }); }); @@ -96,13 +96,13 @@ describe('foo2', function()) { describe('bar2', function() { describe('baz2', function() { it('should get something', function() { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something') }); }); describe('qux2', function() { it('should get something', function() { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something') }); }); }); From efdc70f20b7d091e43b38d2f1f0bff38ac604dde Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 21:44:05 +0100 Subject: [PATCH 09/14] docs: fix syntax consistency --- docs/rules/max-nested-describe.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/rules/max-nested-describe.md b/docs/rules/max-nested-describe.md index 574818c1e..b57240dad 100644 --- a/docs/rules/max-nested-describe.md +++ b/docs/rules/max-nested-describe.md @@ -86,7 +86,7 @@ describe('foo', () => { describe('bar', () => { describe('baz', () => { it('should get something', () => { - expect(getSomething()).toBe('Something') + expect(getSomething()).toBe('Something'); }); }); }); @@ -96,13 +96,13 @@ describe('foo2', function()) { describe('bar2', function() { describe('baz2', function() { it('should get something', function() { - expect(getSomething()).toBe('Something') + expect(getSomething()).toBe('Something'); }); }); describe('qux2', function() { it('should get something', function() { - expect(getSomething()).toBe('Something') + expect(getSomething()).toBe('Something'); }); }); }); From 3fc92335facd2868245faa84d8a7f272c4b4a315 Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 21:48:37 +0100 Subject: [PATCH 10/14] test: fix missing brackets --- src/rules/__tests__/max-nested-describe.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rules/__tests__/max-nested-describe.test.ts b/src/rules/__tests__/max-nested-describe.test.ts index 74f6da981..e76bff8e7 100644 --- a/src/rules/__tests__/max-nested-describe.test.ts +++ b/src/rules/__tests__/max-nested-describe.test.ts @@ -97,7 +97,7 @@ ruleTester.run('max-nested-describe', rule, { describe('baz', function () { describe('qux', function () { it('should get something', () => { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something'); }); }) }) @@ -115,13 +115,13 @@ ruleTester.run('max-nested-describe', rule, { describe('bar', () => { describe('baz', () => { it('should get something', () => { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something'); }); }); describe('qux', function () { it('should get something', () => { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something'); }); }); }) @@ -138,13 +138,13 @@ ruleTester.run('max-nested-describe', rule, { describe.only('bar', () => { describe.skip('baz', () => { it('should get something', () => { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something'); }); }); describe('baz', () => { it('should get something', () => { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something'); }); }); }); @@ -152,7 +152,7 @@ ruleTester.run('max-nested-describe', rule, { xdescribe('qux', () => { it('should get something', () => { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something'); }); }); `, @@ -165,7 +165,7 @@ ruleTester.run('max-nested-describe', rule, { code: dedent` describe('qux', () => { it('should get something', () => { - expect(getSomething().toBe('Something')) + expect(getSomething()).toBe('Something'); }); }); `, From b4aa411878231c05c37be21b1fb95579ea94b0e6 Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Mon, 24 May 2021 21:57:04 +0100 Subject: [PATCH 11/14] refactor: add spacing around message placeholders --- src/rules/max-nested-describe.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/max-nested-describe.ts b/src/rules/max-nested-describe.ts index f369e3622..fe58e6859 100644 --- a/src/rules/max-nested-describe.ts +++ b/src/rules/max-nested-describe.ts @@ -14,7 +14,7 @@ export default createRule({ }, messages: { exceededMaxDepth: - 'Too many nested describe calls ({{depth}}). Maximum allowed is {{max}}.', + 'Too many nested describe calls ({{ depth }}). Maximum allowed is {{ max }}.', }, type: 'suggestion', schema: [ From 313f75a24abd68dc483f66ee86518f86016a5aed Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Sun, 4 Jul 2021 22:36:27 +0100 Subject: [PATCH 12/14] feat: increase default max to 5 --- src/rules/max-nested-describe.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/max-nested-describe.ts b/src/rules/max-nested-describe.ts index fe58e6859..d273072d5 100644 --- a/src/rules/max-nested-describe.ts +++ b/src/rules/max-nested-describe.ts @@ -30,7 +30,7 @@ export default createRule({ }, ], }, - defaultOptions: [{ max: 2 }], + defaultOptions: [{ max: 5 }], create(context, [{ max }]) { const describeCallbackStack: number[] = []; From 48053305aacc07443e0164938bbc440cc52f556c Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Sun, 4 Jul 2021 22:47:28 +0100 Subject: [PATCH 13/14] docs: update with new default max of 5 --- docs/rules/max-nested-describe.md | 68 ++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/docs/rules/max-nested-describe.md b/docs/rules/max-nested-describe.md index b57240dad..a0770e316 100644 --- a/docs/rules/max-nested-describe.md +++ b/docs/rules/max-nested-describe.md @@ -10,24 +10,36 @@ 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": 2 } `): +`{ "max": 5 } `): ```js describe('foo', () => { describe('bar', () => { describe('baz', () => { - it('should get something', () => { - expect(getSomething()).toBe('Something'); + describe('qux', () => { + describe('quxx', () => { + describe('too many', () => { + it('should get something', () => { + expect(getSomething()).toBe('Something'); + }); + }); + }); }); }); }); }); -describe('foo2', function () { - describe('bar2', function () { - describe('baz2', function () { - 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'); + }); + }); + }); }); }); }); @@ -35,7 +47,7 @@ describe('foo2', function () { ``` The following patterns are **not** considered warnings (with the default option -of `{ "max": 2 } `): +of `{ "max": 5 } `): ```js describe('foo', () => { @@ -57,6 +69,20 @@ describe('foo2', function () { 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 @@ -66,7 +92,7 @@ describe('foo2', function () { "jest/max-nested-describe": [ "error", { - "max": 2 + "max": 5 } ] } @@ -76,34 +102,28 @@ describe('foo2', function () { Enforces a maximum depth for nested `describe()`. -This has default value of `2`. +This has a default value of `5`. Examples of patterns **not** considered warnings with options set to -`{ "max": 3 }`: +`{ "max": 2 }`: ```js describe('foo', () => { describe('bar', () => { - describe('baz', () => { - it('should get something', () => { - expect(getSomething()).toBe('Something'); - }); + it('should get something', () => { + expect(getSomething()).toBe('Something'); }); }); }); describe('foo2', function()) { describe('bar2', function() { - describe('baz2', function() { - it('should get something', function() { - expect(getSomething()).toBe('Something'); - }); + it('should get something', function() { + expect(getSomething()).toBe('Something'); }); - describe('qux2', function() { - it('should get something', function() { - expect(getSomething()).toBe('Something'); - }); + it('should get else', function() { + expect(getSomething()).toBe('Something'); }); }); }); From d5bb697ff49a932c4191c8f1af5cb48f48ade369 Mon Sep 17 00:00:00 2001 From: Dominic Lee Date: Sun, 4 Jul 2021 23:01:58 +0100 Subject: [PATCH 14/14] test: add cases for 5 max --- .../__tests__/max-nested-describe.test.ts | 86 ++++++++++++------- 1 file changed, 56 insertions(+), 30 deletions(-) diff --git a/src/rules/__tests__/max-nested-describe.test.ts b/src/rules/__tests__/max-nested-describe.test.ts index e76bff8e7..b8e017357 100644 --- a/src/rules/__tests__/max-nested-describe.test.ts +++ b/src/rules/__tests__/max-nested-describe.test.ts @@ -13,27 +13,39 @@ const ruleTester = new TSESLint.RuleTester({ ruleTester.run('max-nested-describe', rule, { valid: [ dedent` - describe('foo', () => { - describe('bar', () => { - it('hello', async () => { - expect('hello').toBe('hello'); - }); - }); + 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', () => { - describe('bar', () => { - it('hello', async () => { - expect('hello').toBe('hello'); - }); - }); + 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'); - }); - }); + fdescribe('qux', () => { + it('something', async () => { + expect('something').toBe('something'); + }); + }); + }) + }) + }) }); `, dedent` @@ -96,26 +108,39 @@ ruleTester.run('max-nested-describe', rule, { describe('bar', function () { describe('baz', function () { describe('qux', function () { - it('should get something', () => { - expect(getSomething()).toBe('Something'); + describe('quxx', function () { + describe('over limit', function () { + it('should get something', () => { + expect(getSomething()).toBe('Something'); + }); + }); }); - }) - }) - }) + }); + }); + }); }); `, - errors: [ - { messageId: 'exceededMaxDepth', line: 3, column: 5 }, - { messageId: 'exceededMaxDepth', line: 4, column: 7 }, - ], + errors: [{ messageId: 'exceededMaxDepth', line: 6, column: 11 }], }, { code: dedent` describe('foo', () => { describe('bar', () => { describe('baz', () => { - it('should get something', () => { - expect(getSomething()).toBe('Something'); + describe('baz1', () => { + describe('baz2', () => { + describe('baz3', () => { + it('should get something', () => { + expect(getSomething()).toBe('Something'); + }); + }); + + describe('baz4', () => { + it('should get something', () => { + expect(getSomething()).toBe('Something'); + }); + }); + }); }); }); @@ -128,8 +153,8 @@ ruleTester.run('max-nested-describe', rule, { }); `, errors: [ - { messageId: 'exceededMaxDepth', line: 3, column: 5 }, - { messageId: 'exceededMaxDepth', line: 9, column: 5 }, + { messageId: 'exceededMaxDepth', line: 6, column: 11 }, + { messageId: 'exceededMaxDepth', line: 12, column: 11 }, ], }, { @@ -156,6 +181,7 @@ ruleTester.run('max-nested-describe', rule, { }); }); `, + options: [{ max: 2 }], errors: [ { messageId: 'exceededMaxDepth', line: 3, column: 5 }, { messageId: 'exceededMaxDepth', line: 9, column: 5 },