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',