From 22a080b948c05ad8b5e32a80696f99312abccad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Tue, 23 Mar 2021 19:09:09 +0100 Subject: [PATCH 01/11] docs: update rule description - remove references "renderFunctions" rule option - improve examples --- docs/rules/no-render-in-setup.md | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/rules/no-render-in-setup.md b/docs/rules/no-render-in-setup.md index d3ef5805..e1a42b21 100644 --- a/docs/rules/no-render-in-setup.md +++ b/docs/rules/no-render-in-setup.md @@ -20,6 +20,22 @@ it('Should have bar', () => { }); ``` +```js +const setup = () => render(); + +beforeEach(() => { + setup(); +}); + +it('Should have foo', () => { + expect(screen.getByText('foo')).toBeInTheDocument(); +}); + +it('Should have bar', () => { + expect(screen.getByText('bar')).toBeInTheDocument(); +}); +``` + ```js beforeAll(() => { render(); @@ -44,10 +60,18 @@ it('Should have foo and bar', () => { }); ``` -If you use [custom render functions](https://testing-library.com/docs/example-react-redux) then you can set a config option in your `.eslintrc` to look for these. +```js +const setup = () => render(); -``` - "testing-library/no-render-in-setup": ["error", {"renderFunctions": ["renderWithRedux", "renderWithRouter"]}], +beforeEach(() => { + // other stuff... +}); + +it('Should have foo and bar', () => { + setup(); + expect(screen.getByText('foo')).toBeInTheDocument(); + expect(screen.getByText('bar')).toBeInTheDocument(); +}); ``` If you would like to allow the use of `render` (or a custom render function) in _either_ `beforeAll` or `beforeEach`, this can be configured using the option `allowTestingFrameworkSetupHook`. This may be useful if you have configured your tests to [skip auto cleanup](https://testing-library.com/docs/react-testing-library/setup#skipping-auto-cleanup). `allowTestingFrameworkSetupHook` is an enum that accepts either `"beforeAll"` or `"beforeEach"`. From 93934d6b2b3b55799987a455eb4c3bc688e8b354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Tue, 23 Mar 2021 19:59:05 +0100 Subject: [PATCH 02/11] test: improve errors location asserts --- tests/lib/rules/no-render-in-setup.test.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/lib/rules/no-render-in-setup.test.ts b/tests/lib/rules/no-render-in-setup.test.ts index 1cf9867a..94046640 100644 --- a/tests/lib/rules/no-render-in-setup.test.ts +++ b/tests/lib/rules/no-render-in-setup.test.ts @@ -87,6 +87,8 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [ { + line: 4, + column: 11, messageId: 'noRenderInSetup', }, ], @@ -100,6 +102,8 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [ { + line: 4, + column: 11, messageId: 'noRenderInSetup', }, ], @@ -119,11 +123,16 @@ ruleTester.run(RULE_NAME, rule, { ], errors: [ { + line: 4, + column: 11, messageId: 'noRenderInSetup', }, ], })), // call render within a wrapper function + // TODO: update this test so: + // - the wrapper is outside the hook + // - the error is located in `wrapper()` call ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ code: ` import { render } from '@testing-library/foo'; @@ -136,6 +145,8 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [ { + line: 5, + column: 13, messageId: 'noRenderInSetup', }, ], @@ -158,6 +169,8 @@ ruleTester.run(RULE_NAME, rule, { ], errors: [ { + line: 4, + column: 13, messageId: 'noRenderInSetup', }, ], @@ -172,6 +185,8 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [ { + line: 4, + column: 11, messageId: 'noRenderInSetup', }, ], @@ -194,6 +209,8 @@ ruleTester.run(RULE_NAME, rule, { ], errors: [ { + line: 5, + column: 11, messageId: 'noRenderInSetup', }, ], @@ -208,6 +225,8 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [ { + line: 5, + column: 11, messageId: 'noRenderInSetup', }, ], From 9722abf96798538af625b1a5840a07df00fac979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Tue, 23 Mar 2021 20:01:40 +0100 Subject: [PATCH 03/11] refactor: use new rule creator --- lib/rules/no-render-in-setup.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/rules/no-render-in-setup.ts b/lib/rules/no-render-in-setup.ts index 66728e07..371ca333 100644 --- a/lib/rules/no-render-in-setup.ts +++ b/lib/rules/no-render-in-setup.ts @@ -1,17 +1,14 @@ +import { ASTUtils, TSESTree } from '@typescript-eslint/experimental-utils'; +import { TESTING_FRAMEWORK_SETUP_HOOKS } from '../utils'; import { - ESLintUtils, - TSESTree, - ASTUtils, -} from '@typescript-eslint/experimental-utils'; -import { getDocsUrl, TESTING_FRAMEWORK_SETUP_HOOKS } from '../utils'; -import { + isCallExpression, + isImportSpecifier, isLiteral, - isProperty, isObjectPattern, - isCallExpression, + isProperty, isRenderFunction, - isImportSpecifier, } from '../node-utils'; +import { createTestingLibraryRule } from '../create-testing-library-rule'; export const RULE_NAME = 'no-render-in-setup'; export type MessageIds = 'noRenderInSetup'; @@ -41,12 +38,13 @@ export function findClosestBeforeHook( return findClosestBeforeHook(node.parent, testingFrameworkSetupHooksToFilter); } -export default ESLintUtils.RuleCreator(getDocsUrl)({ +export default createTestingLibraryRule({ name: RULE_NAME, meta: { type: 'problem', docs: { - description: 'Disallow the use of `render` in setup functions', + description: + 'Disallow the use of `render` in testing frameworks setup functions', category: 'Best Practices', recommended: false, }, From 320870f27854016fab54efbe4d09baaf199207ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Tue, 23 Mar 2021 20:07:44 +0100 Subject: [PATCH 04/11] docs: update error message and description --- docs/rules/no-render-in-setup.md | 2 +- lib/rules/no-render-in-setup.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rules/no-render-in-setup.md b/docs/rules/no-render-in-setup.md index e1a42b21..0cdf4cc7 100644 --- a/docs/rules/no-render-in-setup.md +++ b/docs/rules/no-render-in-setup.md @@ -2,7 +2,7 @@ ## Rule Details -This rule disallows the usage of `render` (or a custom render function) in setup functions (`beforeEach` and `beforeAll`) in favor of moving `render` closer to test assertions. +This rule disallows the usage of `render` (or a custom render function) in testing framework setup functions (`beforeEach` and `beforeAll`) in favor of moving `render` closer to test assertions. Examples of **incorrect** code for this rule: diff --git a/lib/rules/no-render-in-setup.ts b/lib/rules/no-render-in-setup.ts index 371ca333..fa3119e7 100644 --- a/lib/rules/no-render-in-setup.ts +++ b/lib/rules/no-render-in-setup.ts @@ -50,7 +50,7 @@ export default createTestingLibraryRule({ }, messages: { noRenderInSetup: - 'Move `render` out of `{{name}}` and into individual tests.', + 'Forbidden usage of `render` within testing framework `{{ name }}` setup', }, fixable: null, schema: [ From bb2c287b851bbe6aaed84c67fff6c9659b18bd7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Tue, 23 Mar 2021 20:34:19 +0100 Subject: [PATCH 05/11] refactor(no-debug): remove option schema leftover --- lib/rules/no-debug.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/rules/no-debug.ts b/lib/rules/no-debug.ts index 3f5bb64e..53107de6 100644 --- a/lib/rules/no-debug.ts +++ b/lib/rules/no-debug.ts @@ -27,16 +27,7 @@ export default createTestingLibraryRule({ noDebug: 'Unexpected debug statement', }, fixable: null, - schema: [ - { - type: 'object', - properties: { - renderFunctions: { - type: 'array', - }, - }, - }, - ], + schema: [], }, defaultOptions: [], From d89198eb2c28c126e8cccbeb3074eff1b8fc17ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Tue, 23 Mar 2021 20:51:12 +0100 Subject: [PATCH 06/11] refactor: remove custom render option in favor of helper --- lib/rules/no-render-in-setup.ts | 104 ++++----------------- tests/lib/rules/no-render-in-setup.test.ts | 57 +++++------ 2 files changed, 49 insertions(+), 112 deletions(-) diff --git a/lib/rules/no-render-in-setup.ts b/lib/rules/no-render-in-setup.ts index fa3119e7..a6e69232 100644 --- a/lib/rules/no-render-in-setup.ts +++ b/lib/rules/no-render-in-setup.ts @@ -1,13 +1,6 @@ import { ASTUtils, TSESTree } from '@typescript-eslint/experimental-utils'; import { TESTING_FRAMEWORK_SETUP_HOOKS } from '../utils'; -import { - isCallExpression, - isImportSpecifier, - isLiteral, - isObjectPattern, - isProperty, - isRenderFunction, -} from '../node-utils'; +import { getDeepestIdentifierNode, isCallExpression } from '../node-utils'; import { createTestingLibraryRule } from '../create-testing-library-rule'; export const RULE_NAME = 'no-render-in-setup'; @@ -15,7 +8,6 @@ export type MessageIds = 'noRenderInSetup'; type Options = [ { allowTestingFrameworkSetupHook?: string; - renderFunctions?: string[]; } ]; @@ -56,81 +48,23 @@ export default createTestingLibraryRule({ schema: [ { type: 'object', + default: {}, properties: { - renderFunctions: { - type: 'array', - }, allowTestingFrameworkSetupHook: { enum: TESTING_FRAMEWORK_SETUP_HOOKS, }, }, - anyOf: [ - { - required: ['renderFunctions'], - }, - { - required: ['allowTestingFrameworkSetupHook'], - }, - ], }, ], }, defaultOptions: [ { - renderFunctions: [], allowTestingFrameworkSetupHook: '', }, ], - create(context, [{ renderFunctions, allowTestingFrameworkSetupHook }]) { - let renderImportedFromTestingLib = false; - let wildcardImportName: string | null = null; - + create(context, [{ allowTestingFrameworkSetupHook }], helpers) { return { - // checks if import has shape: - // import * as dtl from '@testing-library/dom'; - 'ImportDeclaration[source.value=/testing-library/] ImportNamespaceSpecifier'( - node: TSESTree.ImportNamespaceSpecifier - ) { - wildcardImportName = node.local && node.local.name; - }, - // checks if `render` is imported from a '@testing-library/foo' - 'ImportDeclaration[source.value=/testing-library/]'( - node: TSESTree.ImportDeclaration - ) { - renderImportedFromTestingLib = node.specifiers.some((specifier) => { - return ( - isImportSpecifier(specifier) && specifier.local.name === 'render' - ); - }); - }, - [`VariableDeclarator > CallExpression > Identifier[name="require"]`]( - node: TSESTree.Identifier - ) { - const { - arguments: callExpressionArgs, - } = node.parent as TSESTree.CallExpression; - const testingLibImport = callExpressionArgs.find( - (args) => - isLiteral(args) && - typeof args.value === 'string' && - RegExp(/testing-library/, 'g').test(args.value) - ); - if (!testingLibImport) { - return; - } - const declaratorNode = node.parent - .parent as TSESTree.VariableDeclarator; - - renderImportedFromTestingLib = - isObjectPattern(declaratorNode.id) && - declaratorNode.id.properties.some( - (property) => - isProperty(property) && - ASTUtils.isIdentifier(property.key) && - property.key.name === 'render' - ); - }, CallExpression(node) { let testingFrameworkSetupHooksToFilter = TESTING_FRAMEWORK_SETUP_HOOKS; if (allowTestingFrameworkSetupHook.length !== 0) { @@ -138,28 +72,28 @@ export default createTestingLibraryRule({ (hook) => hook !== allowTestingFrameworkSetupHook ); } + const callExpressionIdentifier = getDeepestIdentifierNode(node); + + if (!helpers.isRenderUtil(callExpressionIdentifier)) { + return; + } + const beforeHook = findClosestBeforeHook( node, testingFrameworkSetupHooksToFilter ); - // if `render` is imported from a @testing-library/foo or - // imported with a wildcard, add `render` to the list of - // disallowed render functions - const disallowedRenderFns = - renderImportedFromTestingLib || wildcardImportName - ? ['render', ...renderFunctions] - : renderFunctions; - - if (isRenderFunction(node, disallowedRenderFns) && beforeHook) { - context.report({ - node, - messageId: 'noRenderInSetup', - data: { - name: beforeHook.name, - }, - }); + if (!beforeHook) { + return; } + + context.report({ + node, + messageId: 'noRenderInSetup', + data: { + name: beforeHook.name, + }, + }); }, }; }, diff --git a/tests/lib/rules/no-render-in-setup.test.ts b/tests/lib/rules/no-render-in-setup.test.ts index 94046640..84f36142 100644 --- a/tests/lib/rules/no-render-in-setup.test.ts +++ b/tests/lib/rules/no-render-in-setup.test.ts @@ -15,22 +15,26 @@ ruleTester.run(RULE_NAME, rule, { `, }, // test config options - ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ + { code: ` - import { renderWithRedux } from '../test-utils'; - ${setupHook}(() => { - renderWithRedux() - }) - `, - options: [ - { - allowTestingFrameworkSetupHook: setupHook, - renderFunctions: ['renderWithRedux'], - }, - ], - })), - // test usage of a non-Testing Library render fn + import { render } from '@testing-library/foo'; + beforeAll(() => { + render(); + }); + `, + options: [{ allowTestingFrameworkSetupHook: 'beforeAll' }], + }, + { + code: ` + import { render } from '@testing-library/foo'; + beforeEach(() => { + render(); + }); + `, + options: [{ allowTestingFrameworkSetupHook: 'beforeEach' }], + }, ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ + settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from 'imNoTestingLibrary'; ${setupHook}(() => { @@ -43,11 +47,15 @@ ruleTester.run(RULE_NAME, rule, { (setupHook) => setupHook !== allowedSetupHook ); return { + settings: { + 'testing-library/utils-module': 'test-utils', + 'testing-library/custom-renders': ['show', 'renderWithRedux'], + }, code: ` import utils from 'imNoTestingLibrary'; - import { renderWithRedux } from '../test-utils'; + import { show } from '../test-utils'; ${allowedSetupHook}(() => { - renderWithRedux() + show() }) ${disallowedHook}(() => { utils.render() @@ -56,12 +64,12 @@ ruleTester.run(RULE_NAME, rule, { options: [ { allowTestingFrameworkSetupHook: allowedSetupHook, - renderFunctions: ['renderWithRedux'], }, ], }; }), ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ + settings: { 'testing-library/utils-module': 'test-utils' }, code: ` const { render } = require('imNoTestingLibrary') @@ -110,17 +118,16 @@ ruleTester.run(RULE_NAME, rule, { })), // custom render function ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + 'testing-library/custom-renders': ['customRender', 'renderWithRedux'], + }, code: ` import { renderWithRedux } from '../test-utils'; ${setupHook}(() => { renderWithRedux() }) `, - options: [ - { - renderFunctions: ['renderWithRedux'], - }, - ], errors: [ { line: 4, @@ -192,6 +199,7 @@ ruleTester.run(RULE_NAME, rule, { ], })), ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ + settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from 'imNoTestingLibrary'; import * as testUtils from '../test-utils'; @@ -202,11 +210,6 @@ ruleTester.run(RULE_NAME, rule, { render() }) `, - options: [ - { - renderFunctions: ['renderWithRedux'], - }, - ], errors: [ { line: 5, From 5e380730d0c153b50b4f8b4f2f275c6dca4ad98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Tue, 23 Mar 2021 21:02:53 +0100 Subject: [PATCH 07/11] refactor: improve error reported location --- lib/rules/no-render-in-setup.ts | 12 ++++-------- tests/lib/rules/no-render-in-setup.test.ts | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/rules/no-render-in-setup.ts b/lib/rules/no-render-in-setup.ts index a6e69232..6b810244 100644 --- a/lib/rules/no-render-in-setup.ts +++ b/lib/rules/no-render-in-setup.ts @@ -48,7 +48,6 @@ export default createTestingLibraryRule({ schema: [ { type: 'object', - default: {}, properties: { allowTestingFrameworkSetupHook: { enum: TESTING_FRAMEWORK_SETUP_HOOKS, @@ -66,12 +65,9 @@ export default createTestingLibraryRule({ create(context, [{ allowTestingFrameworkSetupHook }], helpers) { return { CallExpression(node) { - let testingFrameworkSetupHooksToFilter = TESTING_FRAMEWORK_SETUP_HOOKS; - if (allowTestingFrameworkSetupHook.length !== 0) { - testingFrameworkSetupHooksToFilter = TESTING_FRAMEWORK_SETUP_HOOKS.filter( - (hook) => hook !== allowTestingFrameworkSetupHook - ); - } + const testingFrameworkSetupHooksToFilter = TESTING_FRAMEWORK_SETUP_HOOKS.filter( + (hook) => hook !== allowTestingFrameworkSetupHook + ); const callExpressionIdentifier = getDeepestIdentifierNode(node); if (!helpers.isRenderUtil(callExpressionIdentifier)) { @@ -88,7 +84,7 @@ export default createTestingLibraryRule({ } context.report({ - node, + node: callExpressionIdentifier, messageId: 'noRenderInSetup', data: { name: beforeHook.name, diff --git a/tests/lib/rules/no-render-in-setup.test.ts b/tests/lib/rules/no-render-in-setup.test.ts index 84f36142..612fc998 100644 --- a/tests/lib/rules/no-render-in-setup.test.ts +++ b/tests/lib/rules/no-render-in-setup.test.ts @@ -193,7 +193,7 @@ ruleTester.run(RULE_NAME, rule, { errors: [ { line: 4, - column: 11, + column: 26, messageId: 'noRenderInSetup', }, ], @@ -213,7 +213,7 @@ ruleTester.run(RULE_NAME, rule, { errors: [ { line: 5, - column: 11, + column: 21, messageId: 'noRenderInSetup', }, ], From 92974ec6c8d34dfd22ee146f949c165f2726ab41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Tue, 23 Mar 2021 21:24:00 +0100 Subject: [PATCH 08/11] feat: detect wrapper functions around render --- lib/rules/no-render-in-setup.ts | 33 ++++++++++++++++++-- lib/rules/render-result-naming-convention.ts | 7 +++-- tests/lib/rules/no-render-in-setup.test.ts | 22 ++++++------- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/lib/rules/no-render-in-setup.ts b/lib/rules/no-render-in-setup.ts index 6b810244..b7685bb4 100644 --- a/lib/rules/no-render-in-setup.ts +++ b/lib/rules/no-render-in-setup.ts @@ -1,7 +1,13 @@ import { ASTUtils, TSESTree } from '@typescript-eslint/experimental-utils'; import { TESTING_FRAMEWORK_SETUP_HOOKS } from '../utils'; -import { getDeepestIdentifierNode, isCallExpression } from '../node-utils'; +import { + getDeepestIdentifierNode, + getFunctionName, + getInnermostReturningFunction, + isCallExpression, +} from '../node-utils'; import { createTestingLibraryRule } from '../create-testing-library-rule'; +import { RuleContext } from '@typescript-eslint/experimental-utils/dist/ts-eslint'; export const RULE_NAME = 'no-render-in-setup'; export type MessageIds = 'noRenderInSetup'; @@ -63,14 +69,37 @@ export default createTestingLibraryRule({ ], create(context, [{ allowTestingFrameworkSetupHook }], helpers) { + const renderWrapperNames: string[] = []; + + function detectRenderWrapper(node: TSESTree.Identifier): void { + const innerFunction = getInnermostReturningFunction( + (context as unknown) as RuleContext, + node + ); + + if (innerFunction) { + renderWrapperNames.push(getFunctionName(innerFunction)); + } + } + return { CallExpression(node) { const testingFrameworkSetupHooksToFilter = TESTING_FRAMEWORK_SETUP_HOOKS.filter( (hook) => hook !== allowTestingFrameworkSetupHook ); const callExpressionIdentifier = getDeepestIdentifierNode(node); + const isRenderIdentifier = helpers.isRenderUtil( + callExpressionIdentifier + ); + + if (isRenderIdentifier) { + detectRenderWrapper(callExpressionIdentifier); + } - if (!helpers.isRenderUtil(callExpressionIdentifier)) { + if ( + !isRenderIdentifier && + !renderWrapperNames.includes(callExpressionIdentifier.name) + ) { return; } diff --git a/lib/rules/render-result-naming-convention.ts b/lib/rules/render-result-naming-convention.ts index 9fb7adbb..b6907864 100644 --- a/lib/rules/render-result-naming-convention.ts +++ b/lib/rules/render-result-naming-convention.ts @@ -46,9 +46,10 @@ export default createTestingLibraryRule({ } return { - 'CallExpression Identifier'(node: TSESTree.Identifier) { - if (helpers.isRenderUtil(node)) { - detectRenderWrapper(node); + CallExpression(node) { + const callExpressionIdentifier = getDeepestIdentifierNode(node); + if (helpers.isRenderUtil(callExpressionIdentifier)) { + detectRenderWrapper(callExpressionIdentifier); } }, VariableDeclarator(node) { diff --git a/tests/lib/rules/no-render-in-setup.test.ts b/tests/lib/rules/no-render-in-setup.test.ts index 612fc998..57d93bc2 100644 --- a/tests/lib/rules/no-render-in-setup.test.ts +++ b/tests/lib/rules/no-render-in-setup.test.ts @@ -136,24 +136,20 @@ ruleTester.run(RULE_NAME, rule, { }, ], })), - // call render within a wrapper function - // TODO: update this test so: - // - the wrapper is outside the hook - // - the error is located in `wrapper()` call ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ - code: ` + code: `// call render within a wrapper function import { render } from '@testing-library/foo'; - ${setupHook}(() => { - const wrapper = () => { - render() - } - wrapper() - }) + + const wrapper = () => render() + + ${setupHook}(() => { + wrapper() + }) `, errors: [ { - line: 5, - column: 13, + line: 7, + column: 9, messageId: 'noRenderInSetup', }, ], From 3f4ebc1ef2e25bb33f71d9892ba7fa9bf72318e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Wed, 24 Mar 2021 21:12:22 +0100 Subject: [PATCH 09/11] refactor: improve utils types --- lib/node-utils.ts | 4 ++-- lib/rules/no-render-in-setup.ts | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/node-utils.ts b/lib/node-utils.ts index 4cda2a2e..8a0bd9f6 100644 --- a/lib/node-utils.ts +++ b/lib/node-utils.ts @@ -321,7 +321,7 @@ interface InnermostFunctionScope extends TSESLintScope.FunctionScope { } export function getInnermostFunctionScope( - context: RuleContext, + context: RuleContext, asyncQueryNode: TSESTree.Identifier ): InnermostFunctionScope | null { const innermostScope = ASTUtils.getInnermostScope( @@ -568,7 +568,7 @@ export function hasClosestExpectResolvesRejects(node: TSESTree.Node): boolean { * Gets the Function node which returns the given Identifier. */ export function getInnermostReturningFunction( - context: RuleContext, + context: RuleContext, node: TSESTree.Identifier ): | TSESTree.FunctionDeclaration diff --git a/lib/rules/no-render-in-setup.ts b/lib/rules/no-render-in-setup.ts index b7685bb4..6bc5bb0e 100644 --- a/lib/rules/no-render-in-setup.ts +++ b/lib/rules/no-render-in-setup.ts @@ -7,7 +7,6 @@ import { isCallExpression, } from '../node-utils'; import { createTestingLibraryRule } from '../create-testing-library-rule'; -import { RuleContext } from '@typescript-eslint/experimental-utils/dist/ts-eslint'; export const RULE_NAME = 'no-render-in-setup'; export type MessageIds = 'noRenderInSetup'; @@ -72,10 +71,7 @@ export default createTestingLibraryRule({ const renderWrapperNames: string[] = []; function detectRenderWrapper(node: TSESTree.Identifier): void { - const innerFunction = getInnermostReturningFunction( - (context as unknown) as RuleContext, - node - ); + const innerFunction = getInnermostReturningFunction(context, node); if (innerFunction) { renderWrapperNames.push(getFunctionName(innerFunction)); From aa25d142e64545e55d091e1ffeb0e351b7ad2493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Wed, 24 Mar 2021 21:14:35 +0100 Subject: [PATCH 10/11] refactor: remove unused node util --- lib/node-utils.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/lib/node-utils.ts b/lib/node-utils.ts index 8a0bd9f6..dc0dde00 100644 --- a/lib/node-utils.ts +++ b/lib/node-utils.ts @@ -459,24 +459,6 @@ export function getFunctionName( ); } -// TODO: should be removed after v4 is finished -export function isRenderFunction( - callNode: TSESTree.CallExpression, - renderFunctions: string[] -): boolean { - // returns true for `render` and e.g. `customRenderFn` - // as well as `someLib.render` and `someUtils.customRenderFn` - return renderFunctions.some((name) => { - return ( - (ASTUtils.isIdentifier(callNode.callee) && - name === callNode.callee.name) || - (isMemberExpression(callNode.callee) && - ASTUtils.isIdentifier(callNode.callee.property) && - name === callNode.callee.property.name) - ); - }); -} - // TODO: extract into types file? export type ImportModuleNode = | TSESTree.ImportDeclaration From 1f989364d559d2dd3b1940bcdce19408a4a41603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltr=C3=A1n=20Alarc=C3=B3n?= Date: Wed, 24 Mar 2021 21:22:11 +0100 Subject: [PATCH 11/11] test: improve test cases --- tests/lib/rules/no-render-in-setup.test.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/lib/rules/no-render-in-setup.test.ts b/tests/lib/rules/no-render-in-setup.test.ts index 57d93bc2..38a8553b 100644 --- a/tests/lib/rules/no-render-in-setup.test.ts +++ b/tests/lib/rules/no-render-in-setup.test.ts @@ -9,6 +9,15 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import { render } from '@testing-library/foo'; + + beforeAll(() => { + doOtherStuff(); + }); + + beforeEach(() => { + doSomethingElse(); + }); + it('Test', () => { render() }) @@ -120,17 +129,18 @@ ruleTester.run(RULE_NAME, rule, { ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ settings: { 'testing-library/utils-module': 'test-utils', - 'testing-library/custom-renders': ['customRender', 'renderWithRedux'], + 'testing-library/custom-renders': ['show', 'renderWithRedux'], }, code: ` - import { renderWithRedux } from '../test-utils'; + import { show } from '../test-utils'; + ${setupHook}(() => { - renderWithRedux() + show() }) `, errors: [ { - line: 4, + line: 5, column: 11, messageId: 'noRenderInSetup', },