From 9385bee4b72829e40f67e42b9e5f11b4016f32b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20Beltra=CC=81n=20Alarco=CC=81n?= <belco90@gmail.com> Date: Sun, 16 Aug 2020 17:38:40 +0200 Subject: [PATCH] docs: new utils commenting their approaches --- lib/node-utils.ts | 45 +++++++++ lib/rules/render-result-naming-convention.ts | 5 + .../render-result-naming-convention.test.ts | 93 +++++++++++++++---- 3 files changed, 126 insertions(+), 17 deletions(-) diff --git a/lib/node-utils.ts b/lib/node-utils.ts index f3abf18e..c8bca3c7 100644 --- a/lib/node-utils.ts +++ b/lib/node-utils.ts @@ -181,3 +181,48 @@ export function isRenderVariableDeclarator( return false; } + +type GetTestingLibraryUtilImportArgs = { + context: any, + utilName: string, + extraModules?: string[], +}; + +export function getTestingLibraryUtilImport(options: GetTestingLibraryUtilImportArgs): null | string { + + /* Here we need to: + - look for imports of shape: import { <utilName> } from '@testing-library/whatever'; + - look for imports of shape: import { <utilName> as <alias> } from '@testing-library/whatever'; + - look for imports of shape: import * as testingLibrary from '@testing-library/whatever'; + - look for imports of shape: const render = require('@testing-library/whatever').render; + + From 3rd case, this method can't return what's the imported name for `utilName` as it's contained within an object. + What should we do in that case? Return an object or array to indicate if `utilName` has been imported directly or + under a namespace? + */ + + + /* + Would be nice to be able to find everything from `context.getSourceCode()` but I haven't done that before. + This way, we don't have to look for different import methods in the rule implementation, and just call this method + before returning the object with corresponding AST selectors. + */ + + return null; +} + +export function getTestingLibraryRenderImport(context: any): null | string { + const customRenders = context.settings['testing-library/custom-renders'] || []; + const possibleRenderOptions = ['render', ...customRenders]; + + let importedRenderName = null; + + possibleRenderOptions.forEach((renderOption) => { + const importedRenderOption = getTestingLibraryUtilImport({ context, utilName: renderOption}); + if (importedRenderOption) { + importedRenderName = importedRenderOption + } + }) + + return importedRenderName +} diff --git a/lib/rules/render-result-naming-convention.ts b/lib/rules/render-result-naming-convention.ts index 5d63011f..e1d468e7 100644 --- a/lib/rules/render-result-naming-convention.ts +++ b/lib/rules/render-result-naming-convention.ts @@ -1,6 +1,7 @@ import { ESLintUtils, TSESTree } from '@typescript-eslint/experimental-utils'; import { getDocsUrl, hasTestingLibraryImportModule } from '../utils'; import { + getTestingLibraryRenderImport, isCallExpression, isIdentifier, isImportSpecifier, @@ -51,9 +52,12 @@ export default ESLintUtils.RuleCreator(getDocsUrl)({ let renderAlias: string | undefined; let wildcardImportName: string | undefined; + const testingLibraryRenderName = getTestingLibraryRenderImport(context); + return { // check named imports ImportDeclaration(node: TSESTree.ImportDeclaration) { + // <-- this check would disappear if (!hasTestingLibraryImportModule(node)) { return; } @@ -69,6 +73,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)({ }, // check wildcard imports 'ImportDeclaration ImportNamespaceSpecifier'( + // <-- this check would disappear node: TSESTree.ImportNamespaceSpecifier ) { if ( diff --git a/tests/lib/rules/render-result-naming-convention.test.ts b/tests/lib/rules/render-result-naming-convention.test.ts index f21959ff..f522a31a 100644 --- a/tests/lib/rules/render-result-naming-convention.test.ts +++ b/tests/lib/rules/render-result-naming-convention.test.ts @@ -97,11 +97,24 @@ ruleTester.run(RULE_NAME, rule, { const button = screen.getByText('some button'); }); `, - options: [ - { - renderFunctions: ['customRender'], - }, - ], + settings: { + 'testing-library/custom-renders': ['customRender'], + 'testing-library/custom-modules': ['test-utils'], + }, + }, + { + code: ` + import { render, screen } from 'test-utils'; + + test('should not report straight destructured render result from custom module', () => { + const { unmount } = render(<SomeComponent />); + const button = screen.getByText('some button'); + }); + `, + settings: { + 'testing-library/custom-renders': ['customRender'], + 'testing-library/custom-modules': ['test-utils'], + }, }, { code: ` @@ -112,11 +125,23 @@ ruleTester.run(RULE_NAME, rule, { await view.findByRole('button'); }); `, - options: [ - { - renderFunctions: ['customRender'], - }, - ], + settings: { + 'testing-library/custom-renders': ['customRender'], + 'testing-library/custom-modules': ['test-utils'], + }, + }, + { + code: ` + import { render } from 'test-utils'; + + test('should not report render result called "view" from custom module', async () => { + const view = render(); + await view.findByRole('button'); + }); + `, + settings: { + 'testing-library/custom-modules': ['test-utils'], + }, }, { code: ` @@ -127,11 +152,23 @@ ruleTester.run(RULE_NAME, rule, { await utils.findByRole('button'); }); `, - options: [ - { - renderFunctions: ['customRender'], - }, - ], + settings: { + 'testing-library/custom-renders': ['customRender'], + 'testing-library/custom-modules': ['test-utils'], + }, + }, + { + code: ` + import { render } from 'test-utils'; + + test('should not report render result called "utils" from custom module', async () => { + const utils = render(); + await utils.findByRole('button'); + }); + `, + settings: { + 'testing-library/custom-modules': ['test-utils'], + }, }, { code: ` @@ -327,11 +364,33 @@ ruleTester.run(RULE_NAME, rule, { const button = wrapper.getByText('some button'); }); `, - options: [ + settings: { + 'testing-library/custom-renders': ['customRender'], + 'testing-library/custom-modules': ['test-utils'], + }, + errors: [ { - renderFunctions: ['customRender'], + messageId: 'invalidRenderResultName', + data: { + varName: 'wrapper', + }, + line: 5, + column: 17, }, ], + }, + { + code: ` + import { render } from 'test-utils'; + + test('should report from custom render module ', () => { + const wrapper = render(<SomeComponent />); + const button = wrapper.getByText('some button'); + }); + `, + settings: { + 'testing-library/custom-modules': ['test-utils'], + }, errors: [ { messageId: 'invalidRenderResultName',