diff --git a/lib/detect-testing-library-utils.ts b/lib/detect-testing-library-utils.ts index 7d04d424..8b4e0cc9 100644 --- a/lib/detect-testing-library-utils.ts +++ b/lib/detect-testing-library-utils.ts @@ -5,8 +5,9 @@ import { } from '@typescript-eslint/experimental-utils'; import { getAssertNodeInfo, - getIdentifierNode, getImportModuleName, + getPropertyIdentifierNode, + getReferenceNode, ImportModuleNode, isImportDeclaration, isImportNamespaceSpecifier, @@ -23,7 +24,7 @@ import { } from './utils'; export type TestingLibrarySettings = { - 'testing-library/module'?: string; + 'testing-library/utils-module'?: string; 'testing-library/filename-pattern'?: string; 'testing-library/custom-renders'?: string[]; }; @@ -47,32 +48,54 @@ export type EnhancedRuleCreate< detectionHelpers: Readonly ) => TRuleListener; -export type DetectionHelpers = { - getTestingLibraryImportNode: () => ImportModuleNode | null; - getCustomModuleImportNode: () => ImportModuleNode | null; - getTestingLibraryImportName: () => string | undefined; - getCustomModuleImportName: () => string | undefined; - isTestingLibraryImported: () => boolean; - isValidFilename: () => boolean; - isGetQueryVariant: (node: TSESTree.Identifier) => boolean; - isQueryQueryVariant: (node: TSESTree.Identifier) => boolean; - isFindQueryVariant: (node: TSESTree.Identifier) => boolean; - isSyncQuery: (node: TSESTree.Identifier) => boolean; - isAsyncQuery: (node: TSESTree.Identifier) => boolean; - isCustomQuery: (node: TSESTree.Identifier) => boolean; - isAsyncUtil: (node: TSESTree.Identifier) => boolean; - isFireEventMethod: (node: TSESTree.Identifier) => boolean; - isRenderUtil: (node: TSESTree.Node) => boolean; - isPresenceAssert: (node: TSESTree.MemberExpression) => boolean; - isAbsenceAssert: (node: TSESTree.MemberExpression) => boolean; - canReportErrors: () => boolean; - findImportedUtilSpecifier: ( - specifierName: string - ) => TSESTree.ImportClause | TSESTree.Identifier | undefined; - isNodeComingFromTestingLibrary: ( - node: TSESTree.MemberExpression | TSESTree.Identifier - ) => boolean; -}; +// Helpers methods +type GetTestingLibraryImportNodeFn = () => ImportModuleNode | null; +type GetCustomModuleImportNodeFn = () => ImportModuleNode | null; +type GetTestingLibraryImportNameFn = () => string | undefined; +type GetCustomModuleImportNameFn = () => string | undefined; +type IsTestingLibraryImportedFn = () => boolean; +type IsValidFilenameFn = () => boolean; +type IsGetQueryVariantFn = (node: TSESTree.Identifier) => boolean; +type IsQueryQueryVariantFn = (node: TSESTree.Identifier) => boolean; +type IsFindQueryVariantFn = (node: TSESTree.Identifier) => boolean; +type IsSyncQueryFn = (node: TSESTree.Identifier) => boolean; +type IsAsyncQueryFn = (node: TSESTree.Identifier) => boolean; +type IsCustomQueryFn = (node: TSESTree.Identifier) => boolean; +type IsAsyncUtilFn = (node: TSESTree.Identifier) => boolean; +type IsFireEventMethodFn = (node: TSESTree.Identifier) => boolean; +type IsRenderUtilFn = (node: TSESTree.Identifier) => boolean; +type IsPresenceAssertFn = (node: TSESTree.MemberExpression) => boolean; +type IsAbsenceAssertFn = (node: TSESTree.MemberExpression) => boolean; +type CanReportErrorsFn = () => boolean; +type FindImportedUtilSpecifierFn = ( + specifierName: string +) => TSESTree.ImportClause | TSESTree.Identifier | undefined; +type IsNodeComingFromTestingLibraryFn = ( + node: TSESTree.MemberExpression | TSESTree.Identifier +) => boolean; + +export interface DetectionHelpers { + getTestingLibraryImportNode: GetTestingLibraryImportNodeFn; + getCustomModuleImportNode: GetCustomModuleImportNodeFn; + getTestingLibraryImportName: GetTestingLibraryImportNameFn; + getCustomModuleImportName: GetCustomModuleImportNameFn; + isTestingLibraryImported: IsTestingLibraryImportedFn; + isValidFilename: IsValidFilenameFn; + isGetQueryVariant: IsGetQueryVariantFn; + isQueryQueryVariant: IsQueryQueryVariantFn; + isFindQueryVariant: IsFindQueryVariantFn; + isSyncQuery: IsSyncQueryFn; + isAsyncQuery: IsAsyncQueryFn; + isCustomQuery: IsCustomQueryFn; + isAsyncUtil: IsAsyncUtilFn; + isFireEventMethod: IsFireEventMethodFn; + isRenderUtil: IsRenderUtilFn; + isPresenceAssert: IsPresenceAssertFn; + isAbsenceAssert: IsAbsenceAssertFn; + canReportErrors: CanReportErrorsFn; + findImportedUtilSpecifier: FindImportedUtilSpecifierFn; + isNodeComingFromTestingLibrary: IsNodeComingFromTestingLibraryFn; +} const DEFAULT_FILENAME_PATTERN = '^.*\\.(test|spec)\\.[jt]sx?$'; @@ -95,12 +118,33 @@ export function detectTestingLibraryUtils< let importedCustomModuleNode: ImportModuleNode | null = null; // Init options based on shared ESLint settings - const customModule = context.settings['testing-library/module']; + const customModule = context.settings['testing-library/utils-module']; const filenamePattern = context.settings['testing-library/filename-pattern'] ?? DEFAULT_FILENAME_PATTERN; const customRenders = context.settings['testing-library/custom-renders']; + /** + * Small method to extract common checks to determine whether a node is + * related to Testing Library or not. + */ + function isTestingLibraryUtil( + node: TSESTree.Identifier, + isUtilCallback: (identifierNode: TSESTree.Identifier) => boolean + ): boolean { + if (!isUtilCallback(node)) { + return false; + } + + const referenceNode = getReferenceNode(node); + const referenceNodeIdentifier = getPropertyIdentifierNode(referenceNode); + + return ( + isAggressiveModuleReportingEnabled() || + isNodeComingFromTestingLibrary(referenceNodeIdentifier) + ); + } + /** * Determines whether aggressive module reporting is enabled or not. * @@ -126,21 +170,22 @@ export function detectTestingLibraryUtils< !Array.isArray(customRenders) || customRenders.length === 0; // Helpers for Testing Library detection. - const getTestingLibraryImportNode: DetectionHelpers['getTestingLibraryImportNode'] = () => { + const getTestingLibraryImportNode: GetTestingLibraryImportNodeFn = () => { return importedTestingLibraryNode; }; - const getCustomModuleImportNode: DetectionHelpers['getCustomModuleImportNode'] = () => { + const getCustomModuleImportNode: GetCustomModuleImportNodeFn = () => { return importedCustomModuleNode; }; - const getTestingLibraryImportName: DetectionHelpers['getTestingLibraryImportName'] = () => { + const getTestingLibraryImportName: GetTestingLibraryImportNameFn = () => { return getImportModuleName(importedTestingLibraryNode); }; - const getCustomModuleImportName: DetectionHelpers['getCustomModuleImportName'] = () => { + const getCustomModuleImportName: GetCustomModuleImportNameFn = () => { return getImportModuleName(importedCustomModuleNode); }; + /** * Determines whether Testing Library utils are imported or not for * current file being analyzed. @@ -150,23 +195,23 @@ export function detectTestingLibraryUtils< * custom modules. * * However, there is a setting to customize the module where TL utils can - * be imported from: "testing-library/module". If this setting is enabled, + * be imported from: "testing-library/utils-module". If this setting is enabled, * then this method will return `true` ONLY IF a testing-library package * or custom module are imported. */ - const isTestingLibraryImported: DetectionHelpers['isTestingLibraryImported'] = () => { - if (isAggressiveModuleReportingEnabled()) { - return true; - } - - return !!importedTestingLibraryNode || !!importedCustomModuleNode; + const isTestingLibraryImported: IsTestingLibraryImportedFn = () => { + return ( + isAggressiveModuleReportingEnabled() || + !!importedTestingLibraryNode || + !!importedCustomModuleNode + ); }; /** * Determines whether filename is valid or not for current file * being analyzed based on "testing-library/filename-pattern" setting. */ - const isValidFilename: DetectionHelpers['isValidFilename'] = () => { + const isValidFilename: IsValidFilenameFn = () => { const fileName = context.getFilename(); return !!fileName.match(filenamePattern); }; @@ -174,43 +219,39 @@ export function detectTestingLibraryUtils< /** * Determines whether a given node is `get*` query variant or not. */ - const isGetQueryVariant: DetectionHelpers['isGetQueryVariant'] = (node) => { + const isGetQueryVariant: IsGetQueryVariantFn = (node) => { return /^get(All)?By.+$/.test(node.name); }; /** * Determines whether a given node is `query*` query variant or not. */ - const isQueryQueryVariant: DetectionHelpers['isQueryQueryVariant'] = ( - node - ) => { + const isQueryQueryVariant: IsQueryQueryVariantFn = (node) => { return /^query(All)?By.+$/.test(node.name); }; /** * Determines whether a given node is `find*` query variant or not. */ - const isFindQueryVariant: DetectionHelpers['isFindQueryVariant'] = ( - node - ) => { + const isFindQueryVariant: IsFindQueryVariantFn = (node) => { return /^find(All)?By.+$/.test(node.name); }; /** * Determines whether a given node is sync query or not. */ - const isSyncQuery: DetectionHelpers['isSyncQuery'] = (node) => { + const isSyncQuery: IsSyncQueryFn = (node) => { return isGetQueryVariant(node) || isQueryQueryVariant(node); }; /** * Determines whether a given node is async query or not. */ - const isAsyncQuery: DetectionHelpers['isAsyncQuery'] = (node) => { + const isAsyncQuery: IsAsyncQueryFn = (node) => { return isFindQueryVariant(node); }; - const isCustomQuery: DetectionHelpers['isCustomQuery'] = (node) => { + const isCustomQuery: IsCustomQueryFn = (node) => { return ( (isSyncQuery(node) || isAsyncQuery(node)) && !ALL_QUERIES_COMBINATIONS.includes(node.name) @@ -218,16 +259,28 @@ export function detectTestingLibraryUtils< }; /** - * Determines whether a given node is async util or not. + * Determines whether a given node is a valid async util or not. + * + * A node will be interpreted as a valid async util based on two conditions: + * the name matches with some Testing Library async util, and the node is + * coming from Testing Library module. + * + * The latter depends on Aggressive module reporting: + * if enabled, then it doesn't matter from where the given node was imported + * from as it will be considered part of Testing Library. + * Otherwise, it means `custom-module` has been set up, so only those nodes + * coming from Testing Library will be considered as valid. */ - const isAsyncUtil: DetectionHelpers['isAsyncUtil'] = (node) => { - return ASYNC_UTILS.includes(node.name); + const isAsyncUtil: IsAsyncUtilFn = (node) => { + return isTestingLibraryUtil(node, (identifierNode) => + ASYNC_UTILS.includes(identifierNode.name) + ); }; /** * Determines whether a given node is fireEvent method or not */ - const isFireEventMethod: DetectionHelpers['isFireEventMethod'] = (node) => { + const isFireEventMethod: IsFireEventMethodFn = (node) => { const fireEventUtil = findImportedUtilSpecifier(FIRE_EVENT_NAME); let fireEventUtilName: string | undefined; @@ -293,29 +346,14 @@ export function detectTestingLibraryUtils< * Testing Library. Otherwise, it means `custom-module` has been set up, so * only those nodes coming from Testing Library will be considered as valid. */ - const isRenderUtil: DetectionHelpers['isRenderUtil'] = (node) => { - const identifier = getIdentifierNode(node); - - if (!identifier) { - return false; - } - - const isNameMatching = (function () { + const isRenderUtil: IsRenderUtilFn = (node) => { + return isTestingLibraryUtil(node, (identifierNode) => { if (isAggressiveRenderReportingEnabled()) { - return identifier.name.toLowerCase().includes(RENDER_NAME); + return identifierNode.name.toLowerCase().includes(RENDER_NAME); } - return [RENDER_NAME, ...customRenders].includes(identifier.name); - })(); - - if (!isNameMatching) { - return false; - } - - return ( - isAggressiveModuleReportingEnabled() || - isNodeComingFromTestingLibrary(identifier) - ); + return [RENDER_NAME, ...customRenders].includes(identifierNode.name); + }); }; /** @@ -325,7 +363,7 @@ export function detectTestingLibraryUtils< * - expect(element).toBeInTheDocument() * - expect(element).not.toBeNull() */ - const isPresenceAssert: DetectionHelpers['isPresenceAssert'] = (node) => { + const isPresenceAssert: IsPresenceAssertFn = (node) => { const { matcher, isNegated } = getAssertNodeInfo(node); if (!matcher) { @@ -344,7 +382,7 @@ export function detectTestingLibraryUtils< * - expect(element).toBeNull() * - expect(element).not.toBeInTheDocument() */ - const isAbsenceAssert: DetectionHelpers['isAbsenceAssert'] = (node) => { + const isAbsenceAssert: IsAbsenceAssertFn = (node) => { const { matcher, isNegated } = getAssertNodeInfo(node); if (!matcher) { @@ -360,7 +398,7 @@ export function detectTestingLibraryUtils< * Gets a string and verifies if it was imported/required by Testing Library * related module. */ - const findImportedUtilSpecifier: DetectionHelpers['findImportedUtilSpecifier'] = ( + const findImportedUtilSpecifier: FindImportedUtilSpecifierFn = ( specifierName ) => { const node = getCustomModuleImportNode() ?? getTestingLibraryImportNode(); @@ -398,32 +436,23 @@ export function detectTestingLibraryUtils< /** * Determines if file inspected meets all conditions to be reported by rules or not. */ - const canReportErrors: DetectionHelpers['canReportErrors'] = () => { + const canReportErrors: CanReportErrorsFn = () => { return isTestingLibraryImported() && isValidFilename(); }; /** * Takes a MemberExpression or an Identifier and verifies if its name comes from the import in TL * @param node a MemberExpression (in "foo.property" it would be property) or an Identifier */ - const isNodeComingFromTestingLibrary: DetectionHelpers['isNodeComingFromTestingLibrary'] = ( + const isNodeComingFromTestingLibrary: IsNodeComingFromTestingLibraryFn = ( node ) => { - let identifierName: string | undefined; - - if (ASTUtils.isIdentifier(node)) { - identifierName = node.name; - } else if (ASTUtils.isIdentifier(node.object)) { - identifierName = node.object.name; - } - - if (!identifierName) { - return; - } + const identifierName: string | undefined = getPropertyIdentifierNode(node) + .name; return !!findImportedUtilSpecifier(identifierName); }; - const helpers = { + const helpers: DetectionHelpers = { getTestingLibraryImportNode, getCustomModuleImportNode, getTestingLibraryImportName, diff --git a/lib/node-utils.ts b/lib/node-utils.ts index 148bc8ef..2fcd4e75 100644 --- a/lib/node-utils.ts +++ b/lib/node-utils.ts @@ -151,7 +151,7 @@ export function isCallExpressionCallee( node: TSESTree.CallExpression, identifier: TSESTree.Identifier ): boolean { - const nodeInnerIdentifier = getIdentifierNode(node); + const nodeInnerIdentifier = getDeepestIdentifierNode(node); if (nodeInnerIdentifier) { return nodeInnerIdentifier.name === identifier.name; @@ -363,7 +363,45 @@ export function getFunctionReturnStatementNode( return null; } -export function getIdentifierNode( +/** + * Gets the property identifier node of a given property node. + * + * Not to be confused with {@link getDeepestIdentifierNode} + * + * An example: + * Having `const a = rtl.within('foo').getByRole('button')`: + * if we call `getPropertyIdentifierNode` with `rtl` property node, + * it will return `rtl` identifier node + */ +export function getPropertyIdentifierNode( + node: TSESTree.Node +): TSESTree.Identifier | null { + if (ASTUtils.isIdentifier(node)) { + return node; + } + + if (isMemberExpression(node)) { + return getPropertyIdentifierNode(node.object); + } + + if (isCallExpression(node)) { + return getPropertyIdentifierNode(node.callee); + } + + return null; +} + +/** + * Gets the deepest identifier node from a given node. + * + * Opposite of {@link getReferenceNode} + * + * An example: + * Having `const a = rtl.within('foo').getByRole('button')`: + * if we call `getDeepestIdentifierNode` with `rtl` node, + * it will return `getByRole` identifier + */ +export function getDeepestIdentifierNode( node: TSESTree.Node ): TSESTree.Identifier | null { if (ASTUtils.isIdentifier(node)) { @@ -375,12 +413,35 @@ export function getIdentifierNode( } if (isCallExpression(node)) { - return getIdentifierNode(node.callee); + return getDeepestIdentifierNode(node.callee); } return null; } +/** + * Gets the farthest node from a given node. + * + * Opposite of {@link getDeepestIdentifierNode} + + * An example: + * Having `const a = rtl.within('foo').getByRole('button')`: + * if we call `getReferenceNode` with `getByRole` identifier, + * it will return `rtl` node + */ +export function getReferenceNode( + node: + | TSESTree.CallExpression + | TSESTree.MemberExpression + | TSESTree.Identifier +): TSESTree.CallExpression | TSESTree.MemberExpression | TSESTree.Identifier { + if (isMemberExpression(node.parent) || isCallExpression(node.parent)) { + return getReferenceNode(node.parent); + } + + return node; +} + export function getFunctionName( node: | TSESTree.FunctionDeclaration @@ -549,7 +610,9 @@ export function getInnermostReturningFunction( return; } - const returnStatementIdentifier = getIdentifierNode(returnStatementNode); + const returnStatementIdentifier = getDeepestIdentifierNode( + returnStatementNode + ); if (returnStatementIdentifier?.name !== node.name) { return; diff --git a/lib/rules/await-async-utils.ts b/lib/rules/await-async-utils.ts index c23a8877..27e8033b 100644 --- a/lib/rules/await-async-utils.ts +++ b/lib/rules/await-async-utils.ts @@ -4,7 +4,6 @@ import { getFunctionName, getInnermostReturningFunction, getVariableReferences, - isMemberExpression, isPromiseHandled, } from '../node-utils'; import { createTestingLibraryRule } from '../create-testing-library-rule'; @@ -46,16 +45,6 @@ export default createTestingLibraryRule({ return { 'CallExpression Identifier'(node: TSESTree.Identifier) { if (helpers.isAsyncUtil(node)) { - if ( - !helpers.isNodeComingFromTestingLibrary(node) && - !( - isMemberExpression(node.parent) && - helpers.isNodeComingFromTestingLibrary(node.parent) - ) - ) { - return; - } - // detect async query used within wrapper function for later analysis detectAsyncUtilWrapper(node); diff --git a/lib/rules/no-promise-in-fire-event.ts b/lib/rules/no-promise-in-fire-event.ts index e83500fe..40be4ece 100644 --- a/lib/rules/no-promise-in-fire-event.ts +++ b/lib/rules/no-promise-in-fire-event.ts @@ -2,7 +2,7 @@ import { ASTUtils, TSESTree } from '@typescript-eslint/experimental-utils'; import { createTestingLibraryRule } from '../create-testing-library-rule'; import { findClosestCallExpressionNode, - getIdentifierNode, + getDeepestIdentifierNode, isCallExpression, isNewExpression, isPromiseIdentifier, @@ -50,7 +50,7 @@ export default createTestingLibraryRule({ } if (isCallExpression(node)) { - const domElementIdentifier = getIdentifierNode(node); + const domElementIdentifier = getDeepestIdentifierNode(node); if ( helpers.isAsyncQuery(domElementIdentifier) || diff --git a/lib/rules/no-wait-for-snapshot.ts b/lib/rules/no-wait-for-snapshot.ts index 723dfb2a..2963e0e7 100644 --- a/lib/rules/no-wait-for-snapshot.ts +++ b/lib/rules/no-wait-for-snapshot.ts @@ -37,7 +37,6 @@ export default createTestingLibraryRule({ const callExpression = findClosestCallExpressionNode(n); if ( ASTUtils.isIdentifier(callExpression.callee) && - helpers.isNodeComingFromTestingLibrary(callExpression.callee) && helpers.isAsyncUtil(callExpression.callee) ) { return callExpression.callee; @@ -45,7 +44,7 @@ export default createTestingLibraryRule({ if ( isMemberExpression(callExpression.callee) && ASTUtils.isIdentifier(callExpression.callee.property) && - helpers.isNodeComingFromTestingLibrary(callExpression.callee) + helpers.isAsyncUtil(callExpression.callee.property) ) { return callExpression.callee.property; } diff --git a/lib/rules/render-result-naming-convention.ts b/lib/rules/render-result-naming-convention.ts index 3d4bb171..f68e5170 100644 --- a/lib/rules/render-result-naming-convention.ts +++ b/lib/rules/render-result-naming-convention.ts @@ -1,5 +1,5 @@ import { createTestingLibraryRule } from '../create-testing-library-rule'; -import { isObjectPattern } from '../node-utils'; +import { getDeepestIdentifierNode, isObjectPattern } from '../node-utils'; import { ASTUtils } from '@typescript-eslint/experimental-utils'; export const RULE_NAME = 'render-result-naming-convention'; @@ -32,7 +32,13 @@ export default createTestingLibraryRule({ create(context, _, helpers) { return { VariableDeclarator(node) { - if (!helpers.isRenderUtil(node.init)) { + const initIdentifierNode = getDeepestIdentifierNode(node.init); + + if (!initIdentifierNode) { + return; + } + + if (!helpers.isRenderUtil(initIdentifierNode)) { return; } diff --git a/tests/create-testing-library-rule.test.ts b/tests/create-testing-library-rule.test.ts index 5d820df7..68c119cb 100644 --- a/tests/create-testing-library-rule.test.ts +++ b/tests/create-testing-library-rule.test.ts @@ -30,7 +30,7 @@ ruleTester.run(RULE_NAME, rule, { const utils = render(); `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, }, { @@ -41,7 +41,7 @@ ruleTester.run(RULE_NAME, rule, { const utils = render(); `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, }, { @@ -51,7 +51,7 @@ ruleTester.run(RULE_NAME, rule, { import { foo } from 'report-me' `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, }, { @@ -61,7 +61,7 @@ ruleTester.run(RULE_NAME, rule, { const { foo } = require('report-me') `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, }, { @@ -108,35 +108,22 @@ ruleTester.run(RULE_NAME, rule, { const utils = customRender() `, }, - - // Test Cases for all settings mixed { - settings: { - 'testing-library/module': 'test-utils', - 'testing-library/filename-pattern': 'testing-library\\.js', - }, + settings: { 'testing-library/utils-module': 'test-utils' }, code: ` - // case: matching custom settings partially - module but not filename - import { render } from 'test-utils' - import { somethingElse } from 'another-module' - const foo = require('bar') + // case: aggressive render enabled, but module disabled - not coming from TL + import { render } from 'somewhere-else' - const utils = render(); + const utils = render() `, }, { - settings: { - 'testing-library/module': 'test-utils', - 'testing-library/filename-pattern': 'testing-library\\.js', - }, - filename: 'MyComponent.testing-library.js', + filename: 'file.not.matching.js', code: ` - // case: matching custom settings partially - filename but not module - import { render } from 'other-utils' - import { somethingElse } from 'another-module' - const foo = require('bar') + // case: aggressive render and module enabled, but file name not matching + import { render } from '@testing-library/react' - const utils = render(); + const utils = render() `, }, @@ -160,21 +147,39 @@ ruleTester.run(RULE_NAME, rule, { getSomeElement('button') `, }, + { + code: ` + // case: custom method not matching "getBy*" variant pattern using within + within(container).getSomeElement('button') + `, + }, { code: ` // case: custom method not matching "queryBy*" variant pattern querySomeElement('button') `, }, + { + code: ` + // case: custom method not matching "queryBy*" variant pattern using within + within(container).querySomeElement('button') + `, + }, { code: ` // case: custom method not matching "findBy*" variant pattern findSomeElement('button') `, }, + { + code: ` + // case: custom method not matching "findBy*" variant pattern using within + within(container).findSomeElement('button') + `, + }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "getBy*" query not reported because custom module not imported @@ -184,7 +189,17 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', + }, + code: ` + // case: built-in "getBy*" query not reported because custom module not imported using within + import { render } from 'other-module' + within(container).getByRole('button') + `, + }, + { + settings: { + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "queryBy*" query not reported because custom module not imported @@ -194,7 +209,17 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', + }, + code: ` + // case: built-in "queryBy*" query not reported because custom module not imported using within + import { render } from 'other-module' + within(container).queryByRole('button') + `, + }, + { + settings: { + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "findBy*" query not reported because custom module not imported @@ -202,6 +227,16 @@ ruleTester.run(RULE_NAME, rule, { findByRole('button') `, }, + { + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` + // case: built-in "findBy*" query not reported because custom module not imported using within + import { render } from 'other-module' + within(container).findByRole('button') + `, + }, { settings: { 'testing-library/filename-pattern': 'testing-library\\.js', @@ -229,32 +264,69 @@ ruleTester.run(RULE_NAME, rule, { findByRole('button') `, }, + + // Test Cases for async utils { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` - import * as tl from 'test-utils' - const obj = { tl } - obj.tl.waitFor(() => {}) + import { waitFor } from 'some-other-library'; + test( + 'aggressive reporting disabled - util waitFor not related to testing library is valid', + () => { waitFor() } + ); `, }, { - settings: { 'testing-library/module': 'test-utils' }, + filename: 'file.not.matching.js', code: ` - // case: aggressive render enabled, but module disabled - not coming from TL - import { render } from 'somewhere-else' + // case: waitFor util found, but file name not matching + import { waitFor } from '@testing-library/react' - const utils = render() + waitFor() `, }, + + // Test Cases for all settings mixed { - filename: 'file.not.matching.js', + settings: { + 'testing-library/utils-module': 'test-utils', + 'testing-library/filename-pattern': 'testing-library\\.js', + }, code: ` - // case: aggressive render and module enabled, but file name not matching + // case: matching custom settings partially - module but not filename + import { render } from 'test-utils' + import { somethingElse } from 'another-module' + const foo = require('bar') + + const utils = render(); + `, + }, + { + settings: { + 'testing-library/utils-module': 'test-utils', + 'testing-library/filename-pattern': 'testing-library\\.js', + }, + filename: 'MyComponent.testing-library.js', + code: ` + // case: matching custom settings partially - filename but not module + import { render } from 'other-utils' + import { somethingElse } from 'another-module' + const foo = require('bar') + + const utils = render(); + `, + }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + // case: aggressive module disabled and render coming from non-related module + import * as somethingElse from '@somewhere/else' import { render } from '@testing-library/react' - const utils = render() + // somethingElse.render is not coming from any module related to TL + const utils = somethingElse.render() `, }, ], @@ -346,7 +418,7 @@ ruleTester.run(RULE_NAME, rule, { const utils = render(); `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, errors: [ { @@ -366,7 +438,7 @@ ruleTester.run(RULE_NAME, rule, { const utils = render(); `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, errors: [ { @@ -387,7 +459,7 @@ ruleTester.run(RULE_NAME, rule, { const utils = render(); `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, errors: [ { @@ -408,7 +480,7 @@ ruleTester.run(RULE_NAME, rule, { const utils = render(); `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, errors: [ { @@ -420,7 +492,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'custom-module-forced-report', + 'testing-library/utils-module': 'custom-module-forced-report', }, code: ` // case: import custom module forced to be reported with custom module setting @@ -429,24 +501,6 @@ ruleTester.run(RULE_NAME, rule, { errors: [{ line: 3, column: 7, messageId: 'fakeError' }], }, - // Test Cases for all settings mixed - { - settings: { - 'testing-library/module': 'test-utils', - 'testing-library/filename-pattern': 'testing-library\\.js', - }, - filename: 'MyComponent.testing-library.js', - code: ` - // case: matching all custom settings - import { render } from 'test-utils' - import { somethingElse } from 'another-module' - const foo = require('bar') - - const utils = render(); - `, - errors: [{ line: 7, column: 21, messageId: 'renderError' }], - }, - // Test Cases for renders { code: ` @@ -464,10 +518,7 @@ ruleTester.run(RULE_NAME, rule, { const utils = rtl.render() `, - errors: [ - { line: 5, column: 21, messageId: 'fakeError' }, - { line: 5, column: 25, messageId: 'renderError' }, - ], + errors: [{ line: 5, column: 25, messageId: 'renderError' }], }, { code: ` @@ -512,6 +563,16 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 5, column: 21, messageId: 'renderError' }], }, + { + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` + // case: aggressive module disabled and render wildcard-imported from related module + import * as rtl from '@testing-library/react' + + const utils = rtl.render() + `, + errors: [{ line: 5, column: 25, messageId: 'renderError' }], + }, // Test Cases for presence/absence assertions { @@ -543,6 +604,83 @@ ruleTester.run(RULE_NAME, rule, { errors: [{ line: 3, column: 7, messageId: 'absenceAssertError' }], }, + // Test Cases for async utils + { + code: ` + import { waitFor } from 'test-utils'; + test( + 'aggressive reporting enabled - util waitFor reported no matter where is coming from', + () => { waitFor() } + ); + `, + errors: [ + { + line: 5, + column: 19, + messageId: 'asyncUtilError', + data: { utilName: 'waitFor' }, + }, + ], + }, + { + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` + import { waitFor } from 'test-utils'; + test( + 'aggressive reporting disabled - util waitFor related to testing library', + () => { waitFor() } + ); + `, + errors: [ + { + line: 5, + column: 19, + messageId: 'asyncUtilError', + data: { utilName: 'waitFor' }, + }, + ], + }, + { + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` + // case: waitFor from object property shadowed name is checked correctly + import * as tl from 'test-utils' + const obj = { tl } + + obj.module.waitFor(() => {}) + `, + errors: [ + { + line: 6, + column: 20, + messageId: 'asyncUtilError', + data: { utilName: 'waitFor' }, + }, + ], + }, + { + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` + // case: aggressive reporting disabled - waitFor from wildcard import related to TL + import * as tl from 'test-utils' + tl.waitFor(() => {}) + `, + errors: [ + { + line: 4, + column: 12, + messageId: 'asyncUtilError', + data: { utilName: 'waitFor' }, + }, + ], + }, + // Test Cases for Queries and Aggressive Queries Reporting { code: ` @@ -551,6 +689,13 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 3, column: 7, messageId: 'getByError' }], }, + { + code: ` + // case: built-in "getBy*" query reported without import using within (aggressive reporting) + within(container).getByRole('button') + `, + errors: [{ line: 3, column: 25, messageId: 'getByError' }], + }, { code: ` // case: built-in "queryBy*" query reported without import (aggressive reporting) @@ -558,6 +703,13 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 3, column: 7, messageId: 'queryByError' }], }, + { + code: ` + // case: built-in "queryBy*" query reported without import using within (aggressive reporting) + within(container).queryByRole('button') + `, + errors: [{ line: 3, column: 25, messageId: 'queryByError' }], + }, { code: ` // case: built-in "findBy*" query reported without import (aggressive reporting) @@ -565,6 +717,13 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 3, column: 7, messageId: 'findByError' }], }, + { + code: ` + // case: built-in "findBy*" query reported without import using within (aggressive reporting) + within(container).findByRole('button') + `, + errors: [{ line: 3, column: 25, messageId: 'findByError' }], + }, { filename: 'MyComponent.spec.js', code: ` @@ -573,6 +732,14 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 3, column: 7, messageId: 'customQueryError' }], }, + { + filename: 'MyComponent.spec.js', + code: ` + // case: custom "getBy*" query reported without import using within (aggressive reporting) + within(container).getByIcon('search') + `, + errors: [{ line: 3, column: 25, messageId: 'customQueryError' }], + }, { code: ` // case: custom "queryBy*" query reported without import (aggressive reporting) @@ -580,6 +747,13 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 3, column: 7, messageId: 'customQueryError' }], }, + { + code: ` + // case: custom "queryBy*" query reported without import using within (aggressive reporting) + within(container).queryByIcon('search') + `, + errors: [{ line: 3, column: 25, messageId: 'customQueryError' }], + }, { code: ` // case: custom "findBy*" query reported without import (aggressive reporting) @@ -587,9 +761,16 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 3, column: 7, messageId: 'customQueryError' }], }, + { + code: ` + // case: custom "findBy*" query reported without import using within (aggressive reporting) + within(container).findByIcon('search') + `, + errors: [{ line: 3, column: 25, messageId: 'customQueryError' }], + }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "getBy*" query reported with custom module + Testing Library package import @@ -601,7 +782,7 @@ ruleTester.run(RULE_NAME, rule, { { filename: 'MyComponent.spec.js', settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "queryBy*" query reported with custom module + Testing Library package import @@ -613,7 +794,7 @@ ruleTester.run(RULE_NAME, rule, { { filename: 'MyComponent.spec.js', settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "findBy*" query reported with custom module + Testing Library package import @@ -624,7 +805,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "getBy*" query reported with custom module + custom module import @@ -636,7 +817,7 @@ ruleTester.run(RULE_NAME, rule, { { filename: 'MyComponent.spec.js', settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "queryBy*" query reported with custom module + custom module import @@ -648,7 +829,7 @@ ruleTester.run(RULE_NAME, rule, { { filename: 'MyComponent.spec.js', settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: built-in "queryBy*" query reported with custom module + custom module import @@ -660,7 +841,7 @@ ruleTester.run(RULE_NAME, rule, { { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: custom "getBy*" query reported with custom module + Testing Library package import @@ -672,7 +853,7 @@ ruleTester.run(RULE_NAME, rule, { { filename: 'MyComponent.spec.js', settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: custom "queryBy*" query reported with custom module + Testing Library package import @@ -684,7 +865,7 @@ ruleTester.run(RULE_NAME, rule, { { filename: 'MyComponent.spec.js', settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: custom "findBy*" query reported with custom module + Testing Library package import @@ -695,7 +876,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: custom "getBy*" query reported with custom module + custom module import @@ -707,7 +888,7 @@ ruleTester.run(RULE_NAME, rule, { { filename: 'MyComponent.spec.js', settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: custom "queryBy*" query reported with custom module + custom module import @@ -719,7 +900,7 @@ ruleTester.run(RULE_NAME, rule, { { filename: 'MyComponent.spec.js', settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: custom "findBy*" query reported with custom module + custom module import @@ -728,23 +909,13 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 4, column: 7, messageId: 'customQueryError' }], }, - { - settings: { - 'testing-library/module': 'test-utils', - }, - code: ` - import * as tl from 'test-utils' - tl.waitFor(() => {}) - `, - errors: [{ line: 3, column: 9, messageId: 'fakeError' }], - }, // Test Cases for all settings mixed { filename: 'MyComponent.custom-suffix.js', settings: { 'testing-library/custom-renders': ['customRender', 'renderWithRedux'], - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', 'testing-library/filename-pattern': 'custom-suffix\\.js', }, code: ` @@ -753,11 +924,34 @@ ruleTester.run(RULE_NAME, rule, { const { getByRole } = renderWithRedux() const el = getByRole('button') + waitFor(() => {}) `, errors: [ { line: 5, column: 29, messageId: 'renderError' }, { line: 6, column: 18, messageId: 'getByError' }, + { + line: 7, + column: 7, + messageId: 'asyncUtilError', + data: { utilName: 'waitFor' }, + }, ], }, + { + settings: { + 'testing-library/utils-module': 'test-utils', + 'testing-library/filename-pattern': 'testing-library\\.js', + }, + filename: 'MyComponent.testing-library.js', + code: ` + // case: matching all custom settings + import { render } from 'test-utils' + import { somethingElse } from 'another-module' + const foo = require('bar') + + const utils = render(); + `, + errors: [{ line: 7, column: 21, messageId: 'renderError' }], + }, ], }); diff --git a/tests/fake-rule.ts b/tests/fake-rule.ts index 0851d6b9..ece0ccbd 100644 --- a/tests/fake-rule.ts +++ b/tests/fake-rule.ts @@ -10,6 +10,7 @@ type Options = []; type MessageIds = | 'fakeError' | 'renderError' + | 'asyncUtilError' | 'getByError' | 'queryByError' | 'findByError' @@ -29,6 +30,8 @@ export default createTestingLibraryRule({ messages: { fakeError: 'fake error reported', renderError: 'some error related to render util reported', + asyncUtilError: + 'some error related to {{ utilName }} async util reported', getByError: 'some error related to getBy reported', queryByError: 'some error related to queryBy reported', findByError: 'some error related to findBy reported', @@ -47,11 +50,20 @@ export default createTestingLibraryRule({ return context.report({ node, messageId: 'renderError' }); } + // force async utils to be reported + if (helpers.isAsyncUtil(node)) { + return context.report({ + node, + messageId: 'asyncUtilError', + data: { utilName: node.name }, + }); + } + + // force queries to be reported if (helpers.isCustomQuery(node)) { return context.report({ node, messageId: 'customQueryError' }); } - // force queries to be reported if (helpers.isGetQueryVariant(node)) { return context.report({ node, messageId: 'getByError' }); } @@ -87,12 +99,6 @@ export default createTestingLibraryRule({ return { 'CallExpression Identifier': reportCallExpressionIdentifier, MemberExpression: reportMemberExpression, - 'CallExpression > MemberExpression'(node: TSESTree.MemberExpression) { - if (!helpers.isNodeComingFromTestingLibrary(node)) { - return; - } - context.report({ node, messageId: 'fakeError' }); - }, ImportDeclaration: reportImportDeclaration, 'Program:exit'() { const importNode = helpers.getCustomModuleImportNode(); diff --git a/tests/lib/rules/await-async-query.test.ts b/tests/lib/rules/await-async-query.test.ts index 3c00a59a..a13a14ab 100644 --- a/tests/lib/rules/await-async-query.test.ts +++ b/tests/lib/rules/await-async-query.test.ts @@ -207,7 +207,7 @@ ruleTester.run(RULE_NAME, rule, { // unresolved async queries with aggressive reporting opted-out are valid ...ALL_ASYNC_COMBINATIONS_TO_TEST.map((query) => ({ - settings: { 'testing-library/module': 'test-utils' }, + settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { render } from "another-library" diff --git a/tests/lib/rules/await-async-utils.test.ts b/tests/lib/rules/await-async-utils.test.ts index 506f800f..b99565d6 100644 --- a/tests/lib/rules/await-async-utils.test.ts +++ b/tests/lib/rules/await-async-utils.test.ts @@ -103,18 +103,28 @@ ruleTester.run(RULE_NAME, rule, { `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import { ${asyncUtil} } from 'some-other-library'; - test('util "${asyncUtil}" which is not related to testing library is valid', async () => { + test( + 'aggressive reporting disabled - util "${asyncUtil}" which is not related to testing library is valid', + async () => { doSomethingElse(); ${asyncUtil}(); }); `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import * as asyncUtils from 'some-other-library'; - test('util "asyncUtils.${asyncUtil}" which is not related to testing library is valid', async () => { + test( + 'aggressive reporting disabled - util "asyncUtils.${asyncUtil}" which is not related to testing library is valid', + async () => { doSomethingElse(); asyncUtils.${asyncUtil}(); }); @@ -174,16 +184,6 @@ ruleTester.run(RULE_NAME, rule, { }); `, }, - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` - import { ${asyncUtil} } from '@somewhere/else'; - test('util unhandled but not related to testing library is valid', async () => { - doSomethingElse(); - ${asyncUtil}('not related to testing library') - waitForNotRelatedToTestingLibrary() - }); - `, - })), ...ASYNC_UTILS.map((asyncUtil) => ({ code: ` import { ${asyncUtil} } from '@testing-library/dom'; @@ -301,5 +301,29 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ messageId: 'asyncUtilWrapper', line: 10, column: 11 }], })), + ...ASYNC_UTILS.map((asyncUtil) => ({ + code: ` + import { ${asyncUtil} } from 'some-other-library'; + test( + 'aggressive reporting - util "${asyncUtil}" which is not related to testing library is invalid', + async () => { + doSomethingElse(); + ${asyncUtil}(); + }); + `, + errors: [{ line: 7, column: 11, messageId: 'awaitAsyncUtil' }], + })), + ...ASYNC_UTILS.map((asyncUtil) => ({ + code: ` + import * as asyncUtils from 'some-other-library'; + test( + 'aggressive reporting - util "asyncUtils.${asyncUtil}" which is not related to testing library is invalid', + async () => { + doSomethingElse(); + asyncUtils.${asyncUtil}(); + }); + `, + errors: [{ line: 7, column: 22, messageId: 'awaitAsyncUtil' }], + })), ], }); diff --git a/tests/lib/rules/await-fire-event.test.ts b/tests/lib/rules/await-fire-event.test.ts index 2b62147a..e6a4f8fc 100644 --- a/tests/lib/rules/await-fire-event.test.ts +++ b/tests/lib/rules/await-fire-event.test.ts @@ -101,7 +101,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent } from 'somewhere-else' @@ -112,7 +112,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent } from 'test-utils' @@ -215,7 +215,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent } from '@testing-library/vue' @@ -234,7 +234,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent } from 'test-utils' @@ -255,7 +255,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent } from '@testing-library/vue' diff --git a/tests/lib/rules/no-await-sync-query.test.ts b/tests/lib/rules/no-await-sync-query.test.ts index cb31c4a6..2bef1ab9 100644 --- a/tests/lib/rules/no-await-sync-query.test.ts +++ b/tests/lib/rules/no-await-sync-query.test.ts @@ -59,7 +59,7 @@ ruleTester.run(RULE_NAME, rule, { // sync query awaited but not related to custom module is invalid but not reported { - settings: { 'testing-library/module': 'test-utils' }, + settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { screen } from 'somewhere-else' () => { @@ -69,7 +69,7 @@ ruleTester.run(RULE_NAME, rule, { }, // sync query awaited but not matching filename pattern is invalid but not reported { - settings: { 'testing-library/filename-pattern': '^.*\\.(nope)\\.js$' }, + settings: { 'testing-library/filename-pattern': 'nope\\.js' }, code: ` () => { const element = await getByRole('button') @@ -194,7 +194,7 @@ ruleTester.run(RULE_NAME, rule, { // sync query awaited and related to testing library module // with custom module setting is not valid { - settings: { 'testing-library/module': 'test-utils' }, + settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { screen } from '@testing-library/react' () => { @@ -205,7 +205,7 @@ ruleTester.run(RULE_NAME, rule, { }, // sync query awaited and related to custom module is not valid { - settings: { 'testing-library/module': 'test-utils' }, + settings: { 'testing-library/utils-module': 'test-utils' }, code: ` import { screen } from 'test-utils' () => { diff --git a/tests/lib/rules/no-dom-import.test.ts b/tests/lib/rules/no-dom-import.test.ts index 01ba26c1..d459f9e7 100644 --- a/tests/lib/rules/no-dom-import.test.ts +++ b/tests/lib/rules/no-dom-import.test.ts @@ -23,7 +23,7 @@ ruleTester.run(RULE_NAME, rule, { 'require("@testing-library/react")', { code: 'import { fireEvent } from "test-utils"', - settings: { 'testing-library/module': 'test-utils' }, + settings: { 'testing-library/utils-module': 'test-utils' }, }, { code: 'import { fireEvent } from "dom-testing-library"', @@ -31,7 +31,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: 'import { fireEvent } from "dom-testing-library"', - settings: { 'testing-library/filename-pattern': '^.*\\.(nope)\\.js$' }, + settings: { 'testing-library/filename-pattern': 'nope\\.js' }, }, { code: 'const { fireEvent } = require("dom-testing-library")', @@ -39,7 +39,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: 'const { fireEvent } = require("dom-testing-library")', - settings: { 'testing-library/filename-pattern': '^.*\\.(nope)\\.js$' }, + settings: { 'testing-library/filename-pattern': 'nope\\.js' }, }, { code: 'import { fireEvent } from "@testing-library/dom"', @@ -47,7 +47,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: 'import { fireEvent } from "@testing-library/dom"', - settings: { 'testing-library/filename-pattern': '^.*\\.(nope)\\.js$' }, + settings: { 'testing-library/filename-pattern': 'nope\\.js' }, }, { code: 'const { fireEvent } = require("@testing-library/dom")', @@ -55,7 +55,7 @@ ruleTester.run(RULE_NAME, rule, { }, { code: 'const { fireEvent } = require("@testing-library/dom")', - settings: { 'testing-library/filename-pattern': '^.*\\.(nope)\\.js$' }, + settings: { 'testing-library/filename-pattern': 'nope\\.js' }, }, ], invalid: [ @@ -70,7 +70,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: dom-testing-library imported with custom module setting @@ -122,7 +122,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: dom-testing-library wildcard imported with custom module setting @@ -144,7 +144,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: @testing-library/dom imported with custom module setting @@ -190,7 +190,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: dom-testing-library required with custom module setting @@ -225,7 +225,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: @testing-library/dom required with custom module setting diff --git a/tests/lib/rules/no-manual-cleanup.test.ts b/tests/lib/rules/no-manual-cleanup.test.ts index f50e036c..3c681b27 100644 --- a/tests/lib/rules/no-manual-cleanup.test.ts +++ b/tests/lib/rules/no-manual-cleanup.test.ts @@ -77,7 +77,7 @@ ruleTester.run(RULE_NAME, rule, { ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ // official testing-library packages should be reported with custom module setting settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { cleanup, render } from "${lib}"`, errors: [ @@ -90,7 +90,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { render, cleanup } from 'test-utils' @@ -109,7 +109,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { cleanup as myCustomCleanup } from 'test-utils' @@ -128,7 +128,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import utils, { cleanup } from 'test-utils' @@ -150,7 +150,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import utils from 'test-utils' @@ -183,7 +183,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` const { render, cleanup } = require('test-utils') diff --git a/tests/lib/rules/no-node-access.test.ts b/tests/lib/rules/no-node-access.test.ts index d8693ee4..c8a9e3f7 100644 --- a/tests/lib/rules/no-node-access.test.ts +++ b/tests/lib/rules/no-node-access.test.ts @@ -64,7 +64,7 @@ ruleTester.run(RULE_NAME, rule, { expect(closestButton).toBeInTheDocument(); `, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, }, ], diff --git a/tests/lib/rules/no-promise-in-fire-event.test.ts b/tests/lib/rules/no-promise-in-fire-event.test.ts index 99eff5cc..66023be2 100644 --- a/tests/lib/rules/no-promise-in-fire-event.test.ts +++ b/tests/lib/rules/no-promise-in-fire-event.test.ts @@ -41,7 +41,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `// invalid usage but aggressive reporting opted-out import { fireEvent } from 'somewhere-else' diff --git a/tests/lib/rules/no-wait-for-snapshot.test.ts b/tests/lib/rules/no-wait-for-snapshot.test.ts index 70e44c03..200584a4 100644 --- a/tests/lib/rules/no-wait-for-snapshot.test.ts +++ b/tests/lib/rules/no-wait-for-snapshot.test.ts @@ -51,73 +51,101 @@ ruleTester.run(RULE_NAME, rule, { `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import { ${asyncUtil} } from 'some-other-library'; - test('snapshot calls within ${asyncUtil} are not valid', async () => { + test('aggressive reporting disabled - snapshot calls within ${asyncUtil} not related to Testing Library are valid', async () => { await ${asyncUtil}(() => expect(foo).toMatchSnapshot()); }); `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import { ${asyncUtil} } from 'some-other-library'; - test('snapshot calls within ${asyncUtil} are not valid', async () => { + test('(alt) aggressive reporting disabled - snapshot calls within ${asyncUtil} not related to Testing Library are valid', async () => { await ${asyncUtil}(() => { - expect(foo).toMatchSnapshot() + // this alt version doesn't return from callback passed to async util + expect(foo).toMatchSnapshot() }); }); `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import * as asyncUtils from 'some-other-library'; - test('snapshot calls within ${asyncUtil} are not valid', async () => { + test('aggressive reporting disabled - snapshot calls within ${asyncUtil} from wildcard import not related to Testing Library are valid', async () => { await asyncUtils.${asyncUtil}(() => expect(foo).toMatchSnapshot()); }); `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import * as asyncUtils from 'some-other-library'; - test('snapshot calls within ${asyncUtil} are not valid', async () => { + test('(alt) aggressive reporting disabled - snapshot calls within ${asyncUtil} from wildcard import not related to Testing Library are valid', async () => { await asyncUtils.${asyncUtil}(() => { - expect(foo).toMatchSnapshot() + // this alt version doesn't return from callback passed to async util + expect(foo).toMatchSnapshot() }); }); `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import { ${asyncUtil} } from 'some-other-library'; - test('snapshot calls within ${asyncUtil} are not valid', async () => { + test('aggressive reporting disabled - inline snapshot calls within ${asyncUtil} import not related to Testing Library are valid', async () => { await ${asyncUtil}(() => expect(foo).toMatchInlineSnapshot()); }); `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import { ${asyncUtil} } from 'some-other-library'; - test('snapshot calls within ${asyncUtil} are not valid', async () => { + test('(alt) aggressive reporting disabled - inline snapshot calls within ${asyncUtil} import not related to Testing Library are valid', async () => { await ${asyncUtil}(() => { - expect(foo).toMatchInlineSnapshot() + // this alt version doesn't return from callback passed to async util + expect(foo).toMatchInlineSnapshot() }); }); `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import * as asyncUtils from 'some-other-library'; - test('snapshot calls within ${asyncUtil} are not valid', async () => { + test('aggressive reporting disabled - inline snapshot calls within ${asyncUtil} from wildcard import not related to Testing Library are valid', async () => { await asyncUtils.${asyncUtil}(() => expect(foo).toMatchInlineSnapshot()); }); `, })), ...ASYNC_UTILS.map((asyncUtil) => ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, code: ` import * as asyncUtils from 'some-other-library'; - test('snapshot calls within ${asyncUtil} are not valid', async () => { + test('(alt) aggressive reporting disabled - inline snapshot calls within ${asyncUtil} from wildcard import not related to Testing Library are valid', async () => { await asyncUtils.${asyncUtil}(() => { - expect(foo).toMatchInlineSnapshot() + // this alt version doesn't return from callback passed to async util + expect(foo).toMatchInlineSnapshot() }); }); `, diff --git a/tests/lib/rules/prefer-explicit-assert.test.ts b/tests/lib/rules/prefer-explicit-assert.test.ts index db8c664f..d5834739 100644 --- a/tests/lib/rules/prefer-explicit-assert.test.ts +++ b/tests/lib/rules/prefer-explicit-assert.test.ts @@ -11,7 +11,7 @@ ruleTester.run(RULE_NAME, rule, { ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ code: `get${queryMethod}('Hello')`, settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, })), ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ @@ -153,7 +153,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import "test-utils" diff --git a/tests/lib/rules/prefer-presence-queries.test.ts b/tests/lib/rules/prefer-presence-queries.test.ts index 637d1aec..e4497b1b 100644 --- a/tests/lib/rules/prefer-presence-queries.test.ts +++ b/tests/lib/rules/prefer-presence-queries.test.ts @@ -52,7 +52,7 @@ ruleTester.run(RULE_NAME, rule, { `expect(getElement('foo')).not.toBeInTheDocument()`, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: invalid presence assert but not reported because custom module is not imported @@ -61,7 +61,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: invalid absence assert but not reported because custom module is not imported @@ -664,7 +664,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: asserting presence incorrectly importing custom module @@ -675,7 +675,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // case: asserting absence incorrectly importing custom module diff --git a/tests/lib/rules/prefer-user-event.test.ts b/tests/lib/rules/prefer-user-event.test.ts index 171c1968..f3c3bab8 100644 --- a/tests/lib/rules/prefer-user-event.test.ts +++ b/tests/lib/rules/prefer-user-event.test.ts @@ -105,7 +105,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { screen } from 'test-utils' @@ -114,7 +114,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { render } from 'test-utils' @@ -124,7 +124,7 @@ ruleTester.run(RULE_NAME, rule, { }, ...UserEventMethods.map((userEventMethod) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import userEvent from 'test-utils' @@ -134,7 +134,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` // fireEvent method used but not imported from TL related module @@ -145,7 +145,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent } from 'test-utils' @@ -156,7 +156,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent as fireEventAliased } from 'test-utils' @@ -167,7 +167,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import * as dom from 'test-utils' @@ -231,7 +231,7 @@ ruleTester.run(RULE_NAME, rule, { ), ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import * as dom from 'test-utils' @@ -241,7 +241,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent } from 'test-utils' @@ -260,7 +260,7 @@ ruleTester.run(RULE_NAME, rule, { })), ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: ` import { fireEvent as fireEventAliased } from 'test-utils' diff --git a/tests/lib/rules/prefer-wait-for.test.ts b/tests/lib/rules/prefer-wait-for.test.ts index 4e7ea7a3..e905c328 100644 --- a/tests/lib/rules/prefer-wait-for.test.ts +++ b/tests/lib/rules/prefer-wait-for.test.ts @@ -22,7 +22,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitFor, render } from 'test-utils'; @@ -32,7 +32,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitFor, render } = require('test-utils'); @@ -56,7 +56,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitForElementToBeRemoved, render } from 'test-utils'; @@ -66,7 +66,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitForElementToBeRemoved, render } = require('test-utils'); @@ -90,7 +90,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import * as testingLibrary from 'test-utils'; @@ -100,7 +100,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const testingLibrary = require('test-utils'); @@ -126,7 +126,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { render } from 'test-utils'; import { waitForSomethingElse } from 'other-module'; @@ -137,7 +137,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { render } = require('test-utils'); const { waitForSomethingElse } = require('other-module'); @@ -162,7 +162,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import * as testingLibrary from 'test-utils'; @@ -172,7 +172,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const testingLibrary = require('test-utils'); @@ -295,7 +295,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { wait, render } from 'test-utils'; @@ -322,7 +322,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { wait, render } = require('test-utils'); @@ -389,7 +389,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import * as testingLibrary from 'test-utils'; @@ -411,7 +411,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const testingLibrary = require('test-utils'); @@ -473,7 +473,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import * as testingLibrary from 'test-utils'; @@ -495,7 +495,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const testingLibrary = require('test-utils'); @@ -565,7 +565,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { render, wait } from 'test-utils' @@ -592,7 +592,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { render, wait } = require('test-utils'); @@ -677,7 +677,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { render, wait, screen } from "test-utils"; @@ -708,7 +708,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { render, wait, screen } = require('test-utils'); @@ -787,7 +787,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { render, waitForElement, screen } from 'test-utils' @@ -814,7 +814,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { render, waitForElement, screen } = require('test-utils'); @@ -897,7 +897,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitForElement } from 'test-utils'; @@ -928,7 +928,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitForElement } = require('test-utils'); @@ -1007,7 +1007,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitForDomChange } from 'test-utils'; @@ -1034,7 +1034,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitForDomChange } = require('test-utils'); @@ -1109,7 +1109,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitForDomChange } from 'test-utils'; @@ -1136,7 +1136,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitForDomChange } = require('test-utils'); @@ -1211,7 +1211,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitForDomChange } from 'test-utils'; @@ -1238,7 +1238,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitForDomChange } = require('test-utils'); @@ -1359,7 +1359,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitForDomChange, wait, waitForElement } from 'test-utils'; import userEvent from '@testing-library/user-event'; @@ -1409,7 +1409,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitForDomChange, wait, waitForElement } = require('test-utils'); const userEvent = require('@testing-library/user-event'); @@ -1549,7 +1549,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { render, waitForDomChange, wait, waitForElement } from 'test-utils'; @@ -1597,7 +1597,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { render, waitForDomChange, wait, waitForElement } = require('test-utils'); @@ -1735,7 +1735,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitForDomChange, wait, render, waitForElement } from 'test-utils'; @@ -1783,7 +1783,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitForDomChange, wait, render, waitForElement } = require('test-utils'); @@ -1931,7 +1931,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `import { waitForDomChange, @@ -1984,7 +1984,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, code: `const { waitForDomChange, @@ -2091,7 +2091,7 @@ ruleTester.run(RULE_NAME, rule, { })), { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, // if already importing waitFor then it's not imported twice code: `import { wait, waitFor, render } from 'test-utils'; @@ -2121,7 +2121,7 @@ ruleTester.run(RULE_NAME, rule, { }, { settings: { - 'testing-library/module': 'test-utils', + 'testing-library/utils-module': 'test-utils', }, // if already importing waitFor then it's not imported twice code: `const { wait, waitFor, render } = require('test-utils');