diff --git a/jest.config.js b/jest.config.js index a355a05e..650de922 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,12 +6,6 @@ module.exports = { }, coverageThreshold: { global: { - branches: 100, - functions: 100, - lines: 100, - statements: 100, - }, - './lib/node-utils.ts': { branches: 90, functions: 90, lines: 90, diff --git a/lib/detect-testing-library-utils.ts b/lib/detect-testing-library-utils.ts index e3d9b570..322398dc 100644 --- a/lib/detect-testing-library-utils.ts +++ b/lib/detect-testing-library-utils.ts @@ -135,7 +135,8 @@ export function detectTestingLibraryUtils< // Init options based on shared ESLint settings const customModule = context.settings['testing-library/utils-module']; - const customRenders = context.settings['testing-library/custom-renders']; + const customRenders = + context.settings['testing-library/custom-renders'] ?? []; /** * Small method to extract common checks to determine whether a node is @@ -160,6 +161,11 @@ export function detectTestingLibraryUtils< const referenceNode = getReferenceNode(node); const referenceNodeIdentifier = getPropertyIdentifierNode(referenceNode); + + if (!referenceNodeIdentifier) { + return false; + } + const importedUtilSpecifier = getImportedUtilSpecifier( referenceNodeIdentifier ); @@ -309,7 +315,8 @@ export function detectTestingLibraryUtils< (identifierNodeName, originalNodeName) => { return ( (validNames as string[]).includes(identifierNodeName) || - (validNames as string[]).includes(originalNodeName) + (!!originalNodeName && + (validNames as string[]).includes(originalNodeName)) ); } ); @@ -370,9 +377,10 @@ export function detectTestingLibraryUtils< return false; } - const parentMemberExpression: - | TSESTree.MemberExpression - | undefined = isMemberExpression(node.parent) ? node.parent : undefined; + const parentMemberExpression: TSESTree.MemberExpression | undefined = + node.parent && isMemberExpression(node.parent) + ? node.parent + : undefined; if (!parentMemberExpression) { return false; @@ -417,9 +425,10 @@ export function detectTestingLibraryUtils< return false; } - const parentMemberExpression: - | TSESTree.MemberExpression - | undefined = isMemberExpression(node.parent) ? node.parent : undefined; + const parentMemberExpression: TSESTree.MemberExpression | undefined = + node.parent && isMemberExpression(node.parent) + ? node.parent + : undefined; if (!parentMemberExpression) { return false; @@ -483,8 +492,15 @@ export function detectTestingLibraryUtils< }; const isRenderVariableDeclarator: IsRenderVariableDeclaratorFn = (node) => { + if (!node.init) { + return false; + } const initIdentifierNode = getDeepestIdentifierNode(node.init); + if (!initIdentifierNode) { + return false; + } + return isRenderUtil(initIdentifierNode); }; @@ -547,7 +563,7 @@ export function detectTestingLibraryUtils< const node = getCustomModuleImportNode() ?? getTestingLibraryImportNode(); if (!node) { - return null; + return undefined; } if (isImportDeclaration(node)) { @@ -613,7 +629,11 @@ export function detectTestingLibraryUtils< node: TSESTree.MemberExpression | TSESTree.Identifier ): TSESTree.ImportClause | TSESTree.Identifier | undefined => { const identifierName: string | undefined = getPropertyIdentifierNode(node) - .name; + ?.name; + + if (!identifierName) { + return undefined; + } return findImportedUtilSpecifier(identifierName); }; @@ -641,7 +661,11 @@ export function detectTestingLibraryUtils< } const identifierName: string | undefined = getPropertyIdentifierNode(node) - .name; + ?.name; + + if (!identifierName) { + return false; + } return hasImportMatch(importNode, identifierName); }; @@ -696,6 +720,7 @@ export function detectTestingLibraryUtils< // check only if custom module import not found yet so we avoid // to override importedCustomModuleNode after it's found if ( + customModule && !importedCustomModuleNode && String(node.source.value).endsWith(customModule) ) { @@ -735,6 +760,7 @@ export function detectTestingLibraryUtils< !importedCustomModuleNode && args.some( (arg) => + customModule && isLiteral(arg) && typeof arg.value === 'string' && arg.value.endsWith(customModule) @@ -770,11 +796,11 @@ export function detectTestingLibraryUtils< allKeys.forEach((instruction) => { enhancedRuleInstructions[instruction] = (node) => { if (instruction in detectionInstructions) { - detectionInstructions[instruction](node); + detectionInstructions[instruction]?.(node); } if (canReportErrors() && ruleInstructions[instruction]) { - return ruleInstructions[instruction](node); + return ruleInstructions[instruction]?.(node); } }; }); diff --git a/lib/node-utils.ts b/lib/node-utils.ts index 8c1ce28c..453f7c98 100644 --- a/lib/node-utils.ts +++ b/lib/node-utils.ts @@ -42,13 +42,13 @@ export function isCallExpression( } export function isNewExpression( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.NewExpression { return node?.type === 'NewExpression'; } export function isMemberExpression( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.MemberExpression { return node?.type === AST_NODE_TYPES.MemberExpression; } @@ -60,31 +60,31 @@ export function isLiteral( } export function isImportSpecifier( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.ImportSpecifier { return node?.type === AST_NODE_TYPES.ImportSpecifier; } export function isImportNamespaceSpecifier( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.ImportNamespaceSpecifier { return node?.type === AST_NODE_TYPES.ImportNamespaceSpecifier; } export function isImportDefaultSpecifier( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.ImportDefaultSpecifier { return node?.type === AST_NODE_TYPES.ImportDefaultSpecifier; } export function isBlockStatement( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.BlockStatement { return node?.type === AST_NODE_TYPES.BlockStatement; } export function isObjectPattern( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.ObjectPattern { return node?.type === AST_NODE_TYPES.ObjectPattern; } @@ -96,13 +96,13 @@ export function isProperty( } export function isJSXAttribute( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.JSXAttribute { return node?.type === AST_NODE_TYPES.JSXAttribute; } export function isExpressionStatement( - node: TSESTree.Node + node: TSESTree.Node | null | undefined ): node is TSESTree.ExpressionStatement { return node?.type === AST_NODE_TYPES.ExpressionStatement; } @@ -137,7 +137,7 @@ export function findClosestCallExpressionNode( export function findClosestCallNode( node: TSESTree.Node, name: string -): TSESTree.CallExpression { +): TSESTree.CallExpression | null { if (!node.parent) { return null; } @@ -195,12 +195,12 @@ export function hasChainedThen(node: TSESTree.Node): boolean { const parent = node.parent; // wait(...).then(...) - if (isCallExpression(parent)) { + if (isCallExpression(parent) && parent.parent) { return hasThenProperty(parent.parent); } // promise.then(...) - return hasThenProperty(parent); + return !!parent && hasThenProperty(parent); } export function isPromiseIdentifier( @@ -239,6 +239,7 @@ export function isPromisesArrayResolved(node: TSESTree.Node): boolean { } return ( + !!closestCallExpression.parent && isArrayExpression(closestCallExpression.parent) && isCallExpression(closestCallExpression.parent.parent) && (isPromiseAll(closestCallExpression.parent.parent) || @@ -268,6 +269,9 @@ export function isPromiseHandled(nodeIdentifier: TSESTree.Identifier): boolean { ); for (const node of suspiciousNodes) { + if (!node || !node.parent) { + continue; + } if (ASTUtils.isAwaitExpression(node.parent)) { return true; } @@ -436,7 +440,10 @@ export function getReferenceNode( | TSESTree.MemberExpression | TSESTree.Identifier ): TSESTree.CallExpression | TSESTree.MemberExpression | TSESTree.Identifier { - if (isMemberExpression(node.parent) || isCallExpression(node.parent)) { + if ( + node.parent && + (isMemberExpression(node.parent) || isCallExpression(node.parent)) + ) { return getReferenceNode(node.parent); } @@ -505,9 +512,10 @@ export function getAssertNodeInfo( let matcher = ASTUtils.getPropertyName(node); const isNegated = matcher === 'not'; if (isNegated) { - matcher = isMemberExpression(node.parent) - ? ASTUtils.getPropertyName(node.parent) - : null; + matcher = + node.parent && isMemberExpression(node.parent) + ? ASTUtils.getPropertyName(node.parent) + : null; } if (!matcher) { @@ -526,6 +534,7 @@ export function hasClosestExpectResolvesRejects(node: TSESTree.Node): boolean { if ( isCallExpression(node) && ASTUtils.isIdentifier(node.callee) && + node.parent && isMemberExpression(node.parent) && node.callee.name === 'expect' ) { diff --git a/lib/rules/await-async-query.ts b/lib/rules/await-async-query.ts index f49ff174..6acf99ca 100644 --- a/lib/rules/await-async-query.ts +++ b/lib/rules/await-async-query.ts @@ -26,7 +26,6 @@ export default createTestingLibraryRule({ asyncQueryWrapper: 'promise returned from {{ name }} wrapper over async query must be handled', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -52,7 +51,7 @@ export default createTestingLibraryRule({ true ); - if (!closestCallExpressionNode) { + if (!closestCallExpressionNode || !closestCallExpressionNode.parent) { return; } diff --git a/lib/rules/await-async-utils.ts b/lib/rules/await-async-utils.ts index dfb59e66..c4e40373 100644 --- a/lib/rules/await-async-utils.ts +++ b/lib/rules/await-async-utils.ts @@ -26,7 +26,6 @@ export default createTestingLibraryRule({ asyncUtilWrapper: 'Promise returned from {{ name }} wrapper over async util must be handled', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -53,7 +52,7 @@ export default createTestingLibraryRule({ true ); - if (!closestCallExpression) { + if (!closestCallExpression || !closestCallExpression.parent) { return; } diff --git a/lib/rules/await-fire-event.ts b/lib/rules/await-fire-event.ts index c127112a..7f635bc8 100644 --- a/lib/rules/await-fire-event.ts +++ b/lib/rules/await-fire-event.ts @@ -27,7 +27,6 @@ export default createTestingLibraryRule({ fireEventWrapper: 'Promise returned from `fireEvent.{{ wrapperName }}` wrapper over fire event method must be handled', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -67,7 +66,7 @@ export default createTestingLibraryRule({ true ); - if (!closestCallExpression) { + if (!closestCallExpression || !closestCallExpression.parent) { return; } diff --git a/lib/rules/consistent-data-testid.ts b/lib/rules/consistent-data-testid.ts index 6ca2220d..f31a7b53 100644 --- a/lib/rules/consistent-data-testid.ts +++ b/lib/rules/consistent-data-testid.ts @@ -30,7 +30,6 @@ export default ESLintUtils.RuleCreator(getDocsUrl)({ messages: { consistentDataTestId: '`{{attr}}` "{{value}}" should match `{{regex}}`', }, - fixable: null, schema: [ { type: 'object', @@ -72,7 +71,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)({ function getFileNameData() { const splitPath = getFilename().split('/'); - const fileNameWithExtension = splitPath.pop(); + const fileNameWithExtension = splitPath.pop() ?? ''; const parent = splitPath.pop(); const fileName = fileNameWithExtension.split('.').shift(); @@ -85,17 +84,18 @@ export default ESLintUtils.RuleCreator(getDocsUrl)({ return new RegExp(testIdPattern.replace(FILENAME_PLACEHOLDER, fileName)); } - function isTestIdAttribute(name: string) { + function isTestIdAttribute(name: string): boolean { if (typeof attr === 'string') { return attr === name; } else { - return attr.includes(name); + return attr?.includes(name) ?? false; } } return { JSXIdentifier: (node) => { if ( + !node.parent || !isJSXAttribute(node.parent) || !isLiteral(node.parent.value) || !isTestIdAttribute(node.name) @@ -105,7 +105,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)({ const value = node.parent.value.value; const { fileName } = getFileNameData(); - const regex = getTestIdValidator(fileName); + const regex = getTestIdValidator(fileName ?? ''); if (value && typeof value === 'string' && !regex.test(value)) { context.report({ diff --git a/lib/rules/no-await-sync-events.ts b/lib/rules/no-await-sync-events.ts index 07081c46..1e5e4770 100644 --- a/lib/rules/no-await-sync-events.ts +++ b/lib/rules/no-await-sync-events.ts @@ -27,7 +27,6 @@ export default createTestingLibraryRule({ noAwaitSyncEvents: '`{{ name }}` is sync and does not need `await` operator', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -42,6 +41,10 @@ export default createTestingLibraryRule({ 'AwaitExpression > CallExpression'(node: TSESTree.CallExpression) { const simulateEventFunctionIdentifier = getDeepestIdentifierNode(node); + if (!simulateEventFunctionIdentifier) { + return; + } + const isSimulateEventMethod = helpers.isUserEventMethod(simulateEventFunctionIdentifier) || helpers.isFireEventMethod(simulateEventFunctionIdentifier); @@ -56,11 +59,12 @@ export default createTestingLibraryRule({ isObjectExpression(lastArg) && lastArg.properties.some( (property) => - isProperty(property) && - ASTUtils.isIdentifier(property.key) && - property.key.name === 'delay' && - isLiteral(property.value) && - property.value.value > 0 + (isProperty(property) && + ASTUtils.isIdentifier(property.key) && + property.key.name === 'delay' && + isLiteral(property.value) && + property.value.value) ?? + 0 > 0 ); const simulateEventFunctionName = simulateEventFunctionIdentifier.name; @@ -77,7 +81,7 @@ export default createTestingLibraryRule({ messageId: 'noAwaitSyncEvents', data: { name: `${ - getPropertyIdentifierNode(node).name + getPropertyIdentifierNode(node)?.name }.${simulateEventFunctionName}`, }, }); diff --git a/lib/rules/no-await-sync-query.ts b/lib/rules/no-await-sync-query.ts index 8d5ba30f..f3604ce9 100644 --- a/lib/rules/no-await-sync-query.ts +++ b/lib/rules/no-await-sync-query.ts @@ -19,7 +19,6 @@ export default createTestingLibraryRule({ noAwaitSyncQuery: '`{{ name }}` query is sync so it does not need to be awaited', }, - fixable: null, schema: [], }, defaultOptions: [], diff --git a/lib/rules/no-container.ts b/lib/rules/no-container.ts index d50923c2..781b8762 100644 --- a/lib/rules/no-container.ts +++ b/lib/rules/no-container.ts @@ -26,7 +26,6 @@ export default createTestingLibraryRule({ noContainer: 'Avoid using container methods. Prefer using the methods from Testing Library, such as "getByRole()"', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -34,8 +33,8 @@ export default createTestingLibraryRule({ create(context, [], helpers) { const destructuredContainerPropNames: string[] = []; const renderWrapperNames: string[] = []; - let renderResultVarName: string = null; - let containerName: string = null; + let renderResultVarName: string | null = null; + let containerName: string | null = null; let containerCallsMethod = false; function detectRenderWrapper(node: TSESTree.Identifier): void { @@ -84,6 +83,11 @@ export default createTestingLibraryRule({ return { CallExpression(node) { const callExpressionIdentifier = getDeepestIdentifierNode(node); + + if (!callExpressionIdentifier) { + return; + } + if (helpers.isRenderUtil(callExpressionIdentifier)) { detectRenderWrapper(callExpressionIdentifier); } @@ -100,9 +104,16 @@ export default createTestingLibraryRule({ } }, - VariableDeclarator(node) { + VariableDeclarator: function (node) { + if (!node.init) { + return; + } const initIdentifierNode = getDeepestIdentifierNode(node.init); + if (!initIdentifierNode) { + return; + } + const isRenderWrapperVariableDeclarator = initIdentifierNode ? renderWrapperNames.includes(initIdentifierNode.name) : false; @@ -125,6 +136,10 @@ export default createTestingLibraryRule({ const nodeValue = containerIndex !== -1 && node.id.properties[containerIndex].value; + if (!nodeValue) { + return; + } + if (ASTUtils.isIdentifier(nodeValue)) { containerName = nodeValue.name; } else { @@ -136,8 +151,8 @@ export default createTestingLibraryRule({ destructuredContainerPropNames.push(property.key.name) ); } - } else { - renderResultVarName = ASTUtils.isIdentifier(node.id) && node.id.name; + } else if (ASTUtils.isIdentifier(node.id)) { + renderResultVarName = node.id.name; } }, }; diff --git a/lib/rules/no-debug.ts b/lib/rules/no-debug.ts index 53107de6..5e2222e5 100644 --- a/lib/rules/no-debug.ts +++ b/lib/rules/no-debug.ts @@ -26,7 +26,6 @@ export default createTestingLibraryRule({ messages: { noDebug: 'Unexpected debug statement', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -46,8 +45,15 @@ export default createTestingLibraryRule({ return { VariableDeclarator(node) { + if (!node.init) { + return; + } const initIdentifierNode = getDeepestIdentifierNode(node.init); + if (!initIdentifierNode) { + return; + } + const isRenderWrapperVariableDeclarator = initIdentifierNode ? renderWrapperNames.includes(initIdentifierNode.name) : false; @@ -68,9 +74,11 @@ export default createTestingLibraryRule({ ASTUtils.isIdentifier(property.key) && property.key.name === 'debug' ) { - suspiciousDebugVariableNames.push( - getDeepestIdentifierNode(property.value).name - ); + const identifierNode = getDeepestIdentifierNode(property.value); + + if (identifierNode) { + suspiciousDebugVariableNames.push(identifierNode.name); + } } } } @@ -83,6 +91,11 @@ export default createTestingLibraryRule({ }, CallExpression(node) { const callExpressionIdentifier = getDeepestIdentifierNode(node); + + if (!callExpressionIdentifier) { + return; + } + if (helpers.isRenderUtil(callExpressionIdentifier)) { detectRenderWrapper(callExpressionIdentifier); } @@ -90,6 +103,10 @@ export default createTestingLibraryRule({ const referenceNode = getReferenceNode(node); const referenceIdentifier = getPropertyIdentifierNode(referenceNode); + if (!referenceIdentifier) { + return; + } + const isDebugUtil = helpers.isDebugUtil(callExpressionIdentifier); const isDeclaredDebugVariable = suspiciousDebugVariableNames.includes( callExpressionIdentifier.name diff --git a/lib/rules/no-manual-cleanup.ts b/lib/rules/no-manual-cleanup.ts index 841cfc47..a49a9836 100644 --- a/lib/rules/no-manual-cleanup.ts +++ b/lib/rules/no-manual-cleanup.ts @@ -34,16 +34,17 @@ export default createTestingLibraryRule({ noManualCleanup: "`cleanup` is performed automatically by your test runner, you don't need manual cleanups.", }, - fixable: null, schema: [], }, defaultOptions: [], create(context, _, helpers) { function reportImportReferences(references: TSESLint.Scope.Reference[]) { - references.forEach((reference) => { + for (const reference of references) { const utilsUsage = reference.identifier.parent; + if ( + utilsUsage && isMemberExpression(utilsUsage) && ASTUtils.isIdentifier(utilsUsage.property) && utilsUsage.property.name === 'cleanup' @@ -53,7 +54,7 @@ export default createTestingLibraryRule({ messageId: 'noManualCleanup', }); } - }); + } } function reportCandidateModule(moduleNode: ImportModuleNode) { diff --git a/lib/rules/no-node-access.ts b/lib/rules/no-node-access.ts index 9b71ceac..ca3acf59 100644 --- a/lib/rules/no-node-access.ts +++ b/lib/rules/no-node-access.ts @@ -19,7 +19,6 @@ export default createTestingLibraryRule({ noNodeAccess: 'Avoid direct Node access. Prefer using the methods from Testing Library.', }, - fixable: null, schema: [], }, defaultOptions: [], diff --git a/lib/rules/no-promise-in-fire-event.ts b/lib/rules/no-promise-in-fire-event.ts index 40be4ece..4a765e6b 100644 --- a/lib/rules/no-promise-in-fire-event.ts +++ b/lib/rules/no-promise-in-fire-event.ts @@ -26,7 +26,6 @@ export default createTestingLibraryRule({ noPromiseInFireEvent: "A promise shouldn't be passed to a `fireEvent` method, instead pass the DOM element", }, - fixable: null, schema: [], }, defaultOptions: [], @@ -52,6 +51,10 @@ export default createTestingLibraryRule({ if (isCallExpression(node)) { const domElementIdentifier = getDeepestIdentifierNode(node); + if (!domElementIdentifier) { + return; + } + if ( helpers.isAsyncQuery(domElementIdentifier) || isPromiseIdentifier(domElementIdentifier) @@ -74,7 +77,9 @@ export default createTestingLibraryRule({ for (const definition of nodeVariable.defs) { const variableDeclarator = definition.node as TSESTree.VariableDeclarator; - checkSuspiciousNode(variableDeclarator.init, node); + if (variableDeclarator.init) { + checkSuspiciousNode(variableDeclarator.init, node); + } } } } diff --git a/lib/rules/no-render-in-setup.ts b/lib/rules/no-render-in-setup.ts index 6bc5bb0e..37f96f5b 100644 --- a/lib/rules/no-render-in-setup.ts +++ b/lib/rules/no-render-in-setup.ts @@ -32,7 +32,14 @@ export function findClosestBeforeHook( return node.callee; } - return findClosestBeforeHook(node.parent, testingFrameworkSetupHooksToFilter); + if (node.parent) { + return findClosestBeforeHook( + node.parent, + testingFrameworkSetupHooksToFilter + ); + } + + return null; } export default createTestingLibraryRule({ @@ -49,7 +56,6 @@ export default createTestingLibraryRule({ noRenderInSetup: 'Forbidden usage of `render` within testing framework `{{ name }}` setup', }, - fixable: null, schema: [ { type: 'object', @@ -84,6 +90,11 @@ export default createTestingLibraryRule({ (hook) => hook !== allowTestingFrameworkSetupHook ); const callExpressionIdentifier = getDeepestIdentifierNode(node); + + if (!callExpressionIdentifier) { + return; + } + const isRenderIdentifier = helpers.isRenderUtil( callExpressionIdentifier ); diff --git a/lib/rules/no-wait-for-empty-callback.ts b/lib/rules/no-wait-for-empty-callback.ts index 1b88fc98..04a622a4 100644 --- a/lib/rules/no-wait-for-empty-callback.ts +++ b/lib/rules/no-wait-for-empty-callback.ts @@ -24,7 +24,6 @@ export default createTestingLibraryRule({ noWaitForEmptyCallback: 'Avoid passing empty callback to `{{ methodName }}`. Insert an assertion instead.', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -35,6 +34,10 @@ export default createTestingLibraryRule({ const parentCallExpression = node.parent as TSESTree.CallExpression; const parentIdentifier = getPropertyIdentifierNode(parentCallExpression); + if (!parentIdentifier) { + return false; + } + return helpers.isAsyncUtil(parentIdentifier, [ 'waitFor', 'waitForElementToBeRemoved', diff --git a/lib/rules/no-wait-for-multiple-assertions.ts b/lib/rules/no-wait-for-multiple-assertions.ts index 2e505aa1..aff2f943 100644 --- a/lib/rules/no-wait-for-multiple-assertions.ts +++ b/lib/rules/no-wait-for-multiple-assertions.ts @@ -22,7 +22,6 @@ export default createTestingLibraryRule({ noWaitForMultipleAssertion: 'Avoid using multiple assertions within `waitFor` callback', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -45,11 +44,18 @@ export default createTestingLibraryRule({ } function reportMultipleAssertion(node: TSESTree.BlockStatement) { + if (!node.parent) { + return; + } const callExpressionNode = node.parent.parent as TSESTree.CallExpression; const callExpressionIdentifier = getPropertyIdentifierNode( callExpressionNode ); + if (!callExpressionIdentifier) { + return; + } + if (!helpers.isAsyncUtil(callExpressionIdentifier, ['waitFor'])) { return; } diff --git a/lib/rules/no-wait-for-side-effects.ts b/lib/rules/no-wait-for-side-effects.ts index 916d2fa7..10dcf5c8 100644 --- a/lib/rules/no-wait-for-side-effects.ts +++ b/lib/rules/no-wait-for-side-effects.ts @@ -22,7 +22,6 @@ export default createTestingLibraryRule({ noSideEffectsWaitFor: 'Avoid using side effects within `waitFor` callback', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -48,11 +47,18 @@ export default createTestingLibraryRule({ } function reportSideEffects(node: TSESTree.BlockStatement) { + if (!node.parent) { + return; + } const callExpressionNode = node.parent.parent as TSESTree.CallExpression; const callExpressionIdentifier = getPropertyIdentifierNode( callExpressionNode ); + if (!callExpressionIdentifier) { + return; + } + if (!helpers.isAsyncUtil(callExpressionIdentifier, ['waitFor'])) { return; } diff --git a/lib/rules/no-wait-for-snapshot.ts b/lib/rules/no-wait-for-snapshot.ts index 2963e0e7..7637748a 100644 --- a/lib/rules/no-wait-for-snapshot.ts +++ b/lib/rules/no-wait-for-snapshot.ts @@ -25,16 +25,22 @@ export default createTestingLibraryRule({ noWaitForSnapshot: "A snapshot can't be generated inside of a `{{ name }}` call", }, - fixable: null, schema: [], }, defaultOptions: [], create(context, _, helpers) { - function getClosestAsyncUtil(node: TSESTree.Node) { - let n = node; + function getClosestAsyncUtil( + node: TSESTree.Node + ): TSESTree.Identifier | null { + let n: TSESTree.Node | null = node; do { const callExpression = findClosestCallExpressionNode(n); + + if (!callExpression) { + return null; + } + if ( ASTUtils.isIdentifier(callExpression.callee) && helpers.isAsyncUtil(callExpression.callee) @@ -48,7 +54,9 @@ export default createTestingLibraryRule({ ) { return callExpression.callee.property; } - n = findClosestCallExpressionNode(callExpression.parent); + if (callExpression.parent) { + n = findClosestCallExpressionNode(callExpression.parent); + } } while (n !== null); return null; } diff --git a/lib/rules/prefer-explicit-assert.ts b/lib/rules/prefer-explicit-assert.ts index f85a3cf8..209c9a88 100644 --- a/lib/rules/prefer-explicit-assert.ts +++ b/lib/rules/prefer-explicit-assert.ts @@ -15,7 +15,7 @@ type Options = [ ]; const isAtTopLevel = (node: TSESTree.Node) => - node.parent.parent.type === 'ExpressionStatement'; + !!node?.parent?.parent && node.parent.parent.type === 'ExpressionStatement'; export default createTestingLibraryRule({ name: RULE_NAME, @@ -33,7 +33,6 @@ export default createTestingLibraryRule({ preferExplicitAssertAssertion: '`getBy*` queries must be asserted with `{{assertion}}`', }, - fixable: null, schema: [ { type: 'object', diff --git a/lib/rules/prefer-find-by.ts b/lib/rules/prefer-find-by.ts index f3819c5e..93d71dc0 100644 --- a/lib/rules/prefer-find-by.ts +++ b/lib/rules/prefer-find-by.ts @@ -1,9 +1,8 @@ -import { TSESTree, ASTUtils } from '@typescript-eslint/experimental-utils'; import { - ReportFixFunction, - RuleFix, - Scope, -} from '@typescript-eslint/experimental-utils/dist/ts-eslint'; + TSESTree, + ASTUtils, + TSESLint, +} from '@typescript-eslint/experimental-utils'; import { isArrowFunctionExpression, isCallExpression, @@ -26,7 +25,7 @@ export function getFindByQueryVariant( } function findRenderDefinitionDeclaration( - scope: Scope.Scope | null, + scope: TSESLint.Scope.Scope | null, query: string ): TSESTree.Identifier | null { if (!scope) { @@ -34,14 +33,16 @@ function findRenderDefinitionDeclaration( } const variable = scope.variables.find( - (v: Scope.Variable) => v.name === query + (v: TSESLint.Scope.Variable) => v.name === query ); if (variable) { - return variable.defs - .map(({ name }) => name) - .filter(ASTUtils.isIdentifier) - .find(({ name }) => name === query); + return ( + variable.defs + .map(({ name }) => name) + .filter(ASTUtils.isIdentifier) + .find(({ name }) => name === query) ?? null + ); } return findRenderDefinitionDeclaration(scope.upper, query); @@ -86,7 +87,7 @@ export default createTestingLibraryRule({ queryMethod: string; prevQuery: string; waitForMethodName: string; - fix: ReportFixFunction; + fix: TSESLint.ReportFixFunction; } ) { const { @@ -152,7 +153,7 @@ export default createTestingLibraryRule({ const property = ((argument.body as TSESTree.CallExpression) .callee as TSESTree.MemberExpression).property; if (helpers.isCustomQuery(property as TSESTree.Identifier)) { - return; + return null; } const newCode = `${caller}.${queryVariant}${queryMethod}(${callArguments .map((node) => sourceCode.getText(node)) @@ -187,10 +188,10 @@ export default createTestingLibraryRule({ .callee as TSESTree.Identifier ) ) { - return; + return null; } const findByMethod = `${queryVariant}${queryMethod}`; - const allFixes: RuleFix[] = []; + const allFixes: TSESLint.RuleFix[] = []; // this updates waitFor with findBy* const newCode = `${findByMethod}(${callArguments .map((node) => sourceCode.getText(node)) @@ -207,7 +208,10 @@ export default createTestingLibraryRule({ return allFixes; } // check the declaration is part of a destructuring - if (isObjectPattern(definition.parent.parent)) { + if ( + definition.parent && + isObjectPattern(definition.parent.parent) + ) { const allVariableDeclarations = definition.parent.parent; // verify if the findBy* method was already declared if ( diff --git a/lib/rules/prefer-presence-queries.ts b/lib/rules/prefer-presence-queries.ts index 8c00233c..97d4d329 100644 --- a/lib/rules/prefer-presence-queries.ts +++ b/lib/rules/prefer-presence-queries.ts @@ -23,7 +23,6 @@ export default createTestingLibraryRule({ }, schema: [], type: 'suggestion', - fixable: null, }, defaultOptions: [], diff --git a/lib/rules/prefer-screen-queries.ts b/lib/rules/prefer-screen-queries.ts index 86f85da8..38a5e23a 100644 --- a/lib/rules/prefer-screen-queries.ts +++ b/lib/rules/prefer-screen-queries.ts @@ -43,7 +43,6 @@ export default createTestingLibraryRule({ preferScreenQueries: 'Use screen to query DOM elements, `screen.{{ name }}`', }, - fixable: null, schema: [], }, defaultOptions: [], @@ -61,18 +60,15 @@ export default createTestingLibraryRule({ function saveSafeDestructuredQueries(node: TSESTree.VariableDeclarator) { if (isObjectPattern(node.id)) { - const identifiers = node.id.properties - .filter( - (property) => - isProperty(property) && - ASTUtils.isIdentifier(property.key) && - helpers.isQuery(property.key) - ) - .map( - (property: TSESTree.Property) => - (property.key as TSESTree.Identifier).name - ); - safeDestructuredQueries.push(...identifiers); + for (const property of node.id.properties) { + if ( + isProperty(property) && + ASTUtils.isIdentifier(property.key) && + helpers.isQuery(property.key) + ) { + safeDestructuredQueries.push(property.key.name); + } + } } } diff --git a/lib/rules/prefer-user-event.ts b/lib/rules/prefer-user-event.ts index 7e4b8350..2043498f 100644 --- a/lib/rules/prefer-user-event.ts +++ b/lib/rules/prefer-user-event.ts @@ -82,7 +82,6 @@ export default createTestingLibraryRule({ }, }, ], - fixable: null, }, defaultOptions: [{ allowedMethods: [] }], diff --git a/lib/rules/prefer-wait-for.ts b/lib/rules/prefer-wait-for.ts index e3fef31a..8fe9c37c 100644 --- a/lib/rules/prefer-wait-for.ts +++ b/lib/rules/prefer-wait-for.ts @@ -78,14 +78,13 @@ export default createTestingLibraryRule({ // get all import names excluding all testing library `wait*` utils... const newImports = node.specifiers - .filter( + .map( (specifier) => isImportSpecifier(specifier) && - !excludedImports.includes(specifier.imported.name) + !excludedImports.includes(specifier.imported.name) && + specifier.imported.name ) - .map( - (specifier: TSESTree.ImportSpecifier) => specifier.imported.name - ); + .filter(Boolean) as string[]; // ... and append `waitFor` newImports.push('waitFor'); @@ -109,6 +108,9 @@ export default createTestingLibraryRule({ }, fix(fixer) { const callExpressionNode = findClosestCallExpressionNode(node); + if (!callExpressionNode) { + return null; + } const [arg] = callExpressionNode.arguments; const fixers = []; @@ -188,7 +190,7 @@ export default createTestingLibraryRule({ return; } reportRequire(parent.id); - } else { + } else if (testingLibraryNode) { if ( testingLibraryNode.specifiers.length === 1 && isImportNamespaceSpecifier(testingLibraryNode.specifiers[0]) diff --git a/lib/rules/render-result-naming-convention.ts b/lib/rules/render-result-naming-convention.ts index b6907864..90dbbc20 100644 --- a/lib/rules/render-result-naming-convention.ts +++ b/lib/rules/render-result-naming-convention.ts @@ -29,7 +29,6 @@ export default createTestingLibraryRule({ messages: { renderResultNamingConvention: `\`{{ renderResultName }}\` is not a recommended name for \`render\` returned value. Instead, you should destructure it, or name it using one of: ${ALLOWED_VAR_NAMES_TEXT}`, }, - fixable: null, schema: [], }, defaultOptions: [], @@ -48,11 +47,19 @@ export default createTestingLibraryRule({ return { CallExpression(node) { const callExpressionIdentifier = getDeepestIdentifierNode(node); + + if (!callExpressionIdentifier) { + return; + } + if (helpers.isRenderUtil(callExpressionIdentifier)) { detectRenderWrapper(callExpressionIdentifier); } }, VariableDeclarator(node) { + if (!node.init) { + return; + } const initIdentifierNode = getDeepestIdentifierNode(node.init); if (!initIdentifierNode) { @@ -73,6 +80,10 @@ export default createTestingLibraryRule({ const renderResultName = ASTUtils.isIdentifier(node.id) && node.id.name; + if (!renderResultName) { + return; + } + const isAllowedRenderResultName = ALLOWED_VAR_NAMES.includes( renderResultName ); diff --git a/tests/create-testing-library-rule.test.ts b/tests/create-testing-library-rule.test.ts index 39158e9c..575af623 100644 --- a/tests/create-testing-library-rule.test.ts +++ b/tests/create-testing-library-rule.test.ts @@ -307,6 +307,10 @@ ruleTester.run(RULE_NAME, rule, { const utils = somethingElse.render() `, }, + + // Weird edge cases + `(window as any).__THING = false;`, + `thing.method.lastCall.args[0]();`, ], invalid: [ // Test Cases for Imports diff --git a/tests/fake-rule.ts b/tests/fake-rule.ts index 38513a4e..e76cb61e 100644 --- a/tests/fake-rule.ts +++ b/tests/fake-rule.ts @@ -41,7 +41,6 @@ export default createTestingLibraryRule({ presenceAssertError: 'some error related to presence assert reported', absenceAssertError: 'some error related to absence assert reported', }, - fixable: null, schema: [], }, defaultOptions: [], diff --git a/tests/lib/rules/await-async-query.test.ts b/tests/lib/rules/await-async-query.test.ts index a13a14ab..fa56dfd7 100644 --- a/tests/lib/rules/await-async-query.test.ts +++ b/tests/lib/rules/await-async-query.test.ts @@ -257,73 +257,126 @@ ruleTester.run(RULE_NAME, rule, { ], invalid: [ - // async queries without await operator or then method are not valid - ...createTestCase((query) => ({ - code: ` + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: `// async queries without await operator or then method are not valid + import { render } from '@testing-library/react' + + test("An example test", async () => { doSomething() const foo = ${query}('foo') + }); `, - errors: [{ messageId: 'awaitAsyncQuery', line: 6, column: 21 }], - })), + errors: [{ messageId: 'awaitAsyncQuery', line: 6, column: 21 }], + } as const) + ), + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: `// async screen queries without await operator or then method are not valid + import { render } from '@testing-library/react' + + test("An example test", async () => { + screen.${query}('foo') + }); + `, + errors: [ + { + messageId: 'awaitAsyncQuery', + line: 5, + column: 16, + data: { name: query }, + }, + ], + } as const) + ), + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: ` + import { render } from '@testing-library/react' - // async screen queries without await operator or then method are not valid - ...createTestCase((query) => ({ - code: `screen.${query}('foo')`, - errors: [{ messageId: 'awaitAsyncQuery', line: 4, column: 14 }], - })), + test("An example test", async () => { + doSomething() + const foo = ${query}('foo') + }); + `, + errors: [ + { + messageId: 'awaitAsyncQuery', + line: 6, + column: 21, + data: { name: query }, + }, + ], + } as const) + ), + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: ` + import { render } from '@testing-library/react' - ...createTestCase((query) => ({ - code: ` + test("An example test", async () => { const foo = ${query}('foo') expect(foo).toBeInTheDocument() expect(foo).toHaveAttribute('src', 'bar'); + }); `, - errors: [ - { - line: 5, - column: 21, - messageId: 'awaitAsyncQuery', - data: { - name: query, - }, - }, - ], - })), + errors: [ + { + messageId: 'awaitAsyncQuery', + line: 5, + column: 21, + data: { name: query }, + }, + ], + } as const) + ), // unresolved async queries are not valid (aggressive reporting) - ...ALL_ASYNC_COMBINATIONS_TO_TEST.map((query) => ({ - code: ` + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: ` import { render } from "another-library" test('An example test', async () => { const example = ${query}("my example") }) `, - errors: [{ messageId: 'awaitAsyncQuery', line: 5, column: 27 }], - })), + errors: [{ messageId: 'awaitAsyncQuery', line: 5, column: 27 }], + } as const) + ), // unhandled promise from async query function wrapper is invalid - ...ALL_ASYNC_COMBINATIONS_TO_TEST.map((query) => ({ - code: ` + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: ` function queryWrapper() { doSomethingElse(); - + return screen.${query}('foo') } - + test("An invalid example test", () => { const element = queryWrapper() }) - + test("An valid example test", async () => { const element = await queryWrapper() }) `, - errors: [{ messageId: 'asyncQueryWrapper', line: 9, column: 27 }], - })), + errors: [{ messageId: 'asyncQueryWrapper', line: 9, column: 27 }], + } as const) + ), // unhandled promise from async query arrow function wrapper is invalid - ...ALL_ASYNC_COMBINATIONS_TO_TEST.map((query) => ({ - code: ` + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: ` const queryWrapper = () => { doSomethingElse(); @@ -338,11 +391,14 @@ ruleTester.run(RULE_NAME, rule, { const element = await queryWrapper() }) `, - errors: [{ messageId: 'asyncQueryWrapper', line: 9, column: 27 }], - })), + errors: [{ messageId: 'asyncQueryWrapper', line: 9, column: 27 }], + } as const) + ), // unhandled promise implicitly returned from async query arrow function wrapper is invalid - ...ALL_ASYNC_COMBINATIONS_TO_TEST.map((query) => ({ - code: ` + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: ` const queryWrapper = () => screen.${query}('foo') test("An invalid example test", () => { @@ -353,7 +409,8 @@ ruleTester.run(RULE_NAME, rule, { const element = await queryWrapper() }) `, - errors: [{ messageId: 'asyncQueryWrapper', line: 5, column: 27 }], - })), + errors: [{ messageId: 'asyncQueryWrapper', line: 5, column: 27 }], + } as const) + ), ], }); diff --git a/tests/lib/rules/await-async-utils.test.ts b/tests/lib/rules/await-async-utils.test.ts index 88cac56c..99f39ccb 100644 --- a/tests/lib/rules/await-async-utils.test.ts +++ b/tests/lib/rules/await-async-utils.test.ts @@ -242,76 +242,90 @@ ruleTester.run(RULE_NAME, rule, { `, ], invalid: [ - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from '@testing-library/dom'; test('${asyncUtil} util not waited is invalid', () => { doSomethingElse(); ${asyncUtil}(() => getByLabelText('email')); }); `, - errors: [ - { - line: 5, - column: 11, - messageId: 'awaitAsyncUtil', - data: { name: asyncUtil }, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 5, + column: 11, + messageId: 'awaitAsyncUtil', + data: { name: asyncUtil }, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from '@testing-library/dom'; test('${asyncUtil} util not waited is invalid', () => { doSomethingElse(); const el = ${asyncUtil}(() => getByLabelText('email')); }); `, - errors: [ - { - line: 5, - column: 22, - messageId: 'awaitAsyncUtil', - data: { name: asyncUtil }, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 5, + column: 22, + messageId: 'awaitAsyncUtil', + data: { name: asyncUtil }, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import * as asyncUtil from '@testing-library/dom'; test('asyncUtil.${asyncUtil} util not handled is invalid', () => { doSomethingElse(); asyncUtil.${asyncUtil}(() => getByLabelText('email')); }); `, - errors: [ - { - line: 5, - column: 21, - messageId: 'awaitAsyncUtil', - data: { name: asyncUtil }, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 5, + column: 21, + messageId: 'awaitAsyncUtil', + data: { name: asyncUtil }, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from '@testing-library/dom'; test('${asyncUtil} util promise saved not handled is invalid', () => { doSomethingElse(); const aPromise = ${asyncUtil}(() => getByLabelText('email')); }); `, - errors: [ - { - line: 5, - column: 28, - messageId: 'awaitAsyncUtil', - data: { name: asyncUtil }, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 5, + column: 28, + messageId: 'awaitAsyncUtil', + data: { name: asyncUtil }, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from '@testing-library/dom'; test('several ${asyncUtil} utils not handled are invalid', () => { const aPromise = ${asyncUtil}(() => getByLabelText('username')); @@ -319,23 +333,26 @@ ruleTester.run(RULE_NAME, rule, { ${asyncUtil}(() => getByLabelText('email')); }); `, - errors: [ - { - line: 4, - column: 28, - messageId: 'awaitAsyncUtil', - data: { name: asyncUtil }, - }, - { - line: 6, - column: 11, - messageId: 'awaitAsyncUtil', - data: { name: asyncUtil }, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 4, + column: 28, + messageId: 'awaitAsyncUtil', + data: { name: asyncUtil }, + }, + { + line: 6, + column: 11, + messageId: 'awaitAsyncUtil', + data: { name: asyncUtil }, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil}, render } from '@testing-library/dom'; function waitForSomethingAsync() { @@ -347,17 +364,20 @@ ruleTester.run(RULE_NAME, rule, { waitForSomethingAsync() }); `, - errors: [ - { - messageId: 'asyncUtilWrapper', - line: 10, - column: 11, - data: { name: 'waitForSomethingAsync' }, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + messageId: 'asyncUtilWrapper', + line: 10, + column: 11, + data: { name: 'waitForSomethingAsync' }, + }, + ], + } as const) + ), + ...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', @@ -366,17 +386,20 @@ ruleTester.run(RULE_NAME, rule, { ${asyncUtil}(); }); `, - errors: [ - { - line: 7, - column: 11, - messageId: 'awaitAsyncUtil', - data: { name: asyncUtil }, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 7, + column: 11, + messageId: 'awaitAsyncUtil', + data: { name: asyncUtil }, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil}, render } from '@testing-library/dom'; function waitForSomethingAsync() { @@ -388,17 +411,20 @@ ruleTester.run(RULE_NAME, rule, { const el = waitForSomethingAsync() }); `, - errors: [ - { - messageId: 'asyncUtilWrapper', - line: 10, - column: 22, - data: { name: 'waitForSomethingAsync' }, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + messageId: 'asyncUtilWrapper', + line: 10, + column: 22, + data: { name: 'waitForSomethingAsync' }, + }, + ], + } as const) + ), + ...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', @@ -407,14 +433,15 @@ ruleTester.run(RULE_NAME, rule, { asyncUtils.${asyncUtil}(); }); `, - errors: [ - { - line: 7, - column: 22, - messageId: 'awaitAsyncUtil', - data: { name: asyncUtil }, - }, - ], - })), + errors: [ + { + line: 7, + column: 22, + messageId: 'awaitAsyncUtil', + data: { name: asyncUtil }, + }, + ], + } as const) + ), ], }); diff --git a/tests/lib/rules/await-fire-event.test.ts b/tests/lib/rules/await-fire-event.test.ts index e6a4f8fc..4918ebc0 100644 --- a/tests/lib/rules/await-fire-event.test.ts +++ b/tests/lib/rules/await-fire-event.test.ts @@ -139,104 +139,121 @@ ruleTester.run(RULE_NAME, rule, { ], invalid: [ - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - code: ` + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + code: ` import { fireEvent } from '@testing-library/vue' test('unhandled promise from fire event method is invalid', async () => { fireEvent.${fireEventMethod}(getByLabelText('username')) }) `, - errors: [ - { - line: 4, - column: 9, - endColumn: 19 + fireEventMethod.length, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - ], - })), - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - code: ` + errors: [ + { + line: 4, + column: 9, + endColumn: 19 + fireEventMethod.length, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + code: ` import { fireEvent as testingLibraryFireEvent } from '@testing-library/vue' test('unhandled promise from aliased fire event method is invalid', async () => { testingLibraryFireEvent.${fireEventMethod}(getByLabelText('username')) }) `, - errors: [ - { - line: 4, - column: 9, - endColumn: 33 + fireEventMethod.length, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - ], - })), - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - code: ` + errors: [ + { + line: 4, + column: 9, + endColumn: 33 + fireEventMethod.length, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + code: ` import * as testingLibrary from '@testing-library/vue' test('unhandled promise from wildcard imported fire event method is invalid', async () => { testingLibrary.fireEvent.${fireEventMethod}(getByLabelText('username')) }) `, - errors: [ - { - line: 4, - column: 9, - endColumn: 34 + fireEventMethod.length, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - ], - })), - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - code: ` + errors: [ + { + line: 4, + column: 9, + endColumn: 34 + fireEventMethod.length, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + code: ` import { fireEvent } from '@testing-library/vue' test('several unhandled promises from fire event methods is invalid', async () => { fireEvent.${fireEventMethod}(getByLabelText('username')) fireEvent.${fireEventMethod}(getByLabelText('username')) }) `, - errors: [ - { - line: 4, - column: 9, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - { - line: 5, - column: 9, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - ], - })), - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - settings: { - 'testing-library/utils-module': 'test-utils', - }, - code: ` + errors: [ + { + line: 4, + column: 9, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + { + line: 5, + column: 9, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` import { fireEvent } from '@testing-library/vue' test('unhandled promise from fire event method with aggressive reporting opted-out is invalid', async () => { fireEvent.${fireEventMethod}(getByLabelText('username')) }) `, - errors: [ - { - line: 4, - column: 9, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - ], - })), - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - settings: { - 'testing-library/utils-module': 'test-utils', - }, - code: ` + errors: [ + { + line: 4, + column: 9, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` import { fireEvent } from 'test-utils' test( 'unhandled promise from fire event method imported from custom module with aggressive reporting opted-out is invalid', @@ -244,20 +261,23 @@ ruleTester.run(RULE_NAME, rule, { fireEvent.${fireEventMethod}(getByLabelText('username')) }) `, - errors: [ - { - line: 6, - column: 9, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - ], - })), - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - settings: { - 'testing-library/utils-module': 'test-utils', - }, - code: ` + errors: [ + { + line: 6, + column: 9, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` import { fireEvent } from '@testing-library/vue' test( 'unhandled promise from fire event method imported from default module with aggressive reporting opted-out is invalid', @@ -265,18 +285,21 @@ ruleTester.run(RULE_NAME, rule, { fireEvent.${fireEventMethod}(getByLabelText('username')) }) `, - errors: [ - { - line: 6, - column: 9, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - ], - })), + errors: [ + { + line: 6, + column: 9, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - code: ` + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + code: ` import { fireEvent } from '@testing-library/vue' test( 'unhandled promise from fire event method kept in a var is invalid', @@ -284,17 +307,20 @@ ruleTester.run(RULE_NAME, rule, { const promise = fireEvent.${fireEventMethod}(getByLabelText('username')) }) `, - errors: [ - { - line: 6, - column: 25, - messageId: 'awaitFireEvent', - data: { name: fireEventMethod }, - }, - ], - })), - ...COMMON_FIRE_EVENT_METHODS.map((fireEventMethod) => ({ - code: ` + errors: [ + { + line: 6, + column: 25, + messageId: 'awaitFireEvent', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), + ...COMMON_FIRE_EVENT_METHODS.map( + (fireEventMethod) => + ({ + code: ` import { fireEvent } from '@testing-library/vue' test('unhandled promise returned from function wrapping fire event method is invalid', () => { function triggerEvent() { @@ -305,14 +331,15 @@ ruleTester.run(RULE_NAME, rule, { triggerEvent() }) `, - errors: [ - { - line: 9, - column: 9, - messageId: 'fireEventWrapper', - data: { name: fireEventMethod }, - }, - ], - })), + errors: [ + { + line: 9, + column: 9, + messageId: 'fireEventWrapper', + data: { name: fireEventMethod }, + }, + ], + } as const) + ), ], }); diff --git a/tests/lib/rules/no-await-sync-events.test.ts b/tests/lib/rules/no-await-sync-events.test.ts index 5289b9b4..63679459 100644 --- a/tests/lib/rules/no-await-sync-events.test.ts +++ b/tests/lib/rules/no-await-sync-events.test.ts @@ -170,39 +170,46 @@ ruleTester.run(RULE_NAME, rule, { invalid: [ // sync fireEvent methods with await operator are not valid - ...FIRE_EVENT_FUNCTIONS.map((func) => ({ - code: ` + ...FIRE_EVENT_FUNCTIONS.map( + (func) => + ({ + code: ` import { fireEvent } from '@testing-library/framework'; test('should report fireEvent.${func} sync event awaited', async() => { await fireEvent.${func}('foo'); }); `, - errors: [ - { - line: 4, - column: 17, - messageId: 'noAwaitSyncEvents', - data: { name: `fireEvent.${func}` }, - }, - ], - })), + errors: [ + { + line: 4, + column: 17, + messageId: 'noAwaitSyncEvents', + data: { name: `fireEvent.${func}` }, + }, + ], + } as const) + ), // sync userEvent sync methods with await operator are not valid - ...USER_EVENT_SYNC_FUNCTIONS.map((func) => ({ - code: ` + ...USER_EVENT_SYNC_FUNCTIONS.map( + (func) => + ({ + code: ` import userEvent from '@testing-library/user-event'; test('should report userEvent.${func} sync event awaited', async() => { await userEvent.${func}('foo'); }); `, - errors: [ - { - line: 4, - column: 17, - messageId: 'noAwaitSyncEvents', - data: { name: `userEvent.${func}` }, - }, - ], - })), + errors: [ + { + line: 4, + column: 17, + messageId: 'noAwaitSyncEvents', + data: { name: `userEvent.${func}` }, + }, + ], + } as const) + ), + { code: ` import userEvent from '@testing-library/user-event'; diff --git a/tests/lib/rules/no-await-sync-query.test.ts b/tests/lib/rules/no-await-sync-query.test.ts index 3ebb147a..a3a27751 100644 --- a/tests/lib/rules/no-await-sync-query.test.ts +++ b/tests/lib/rules/no-await-sync-query.test.ts @@ -107,19 +107,22 @@ ruleTester.run(RULE_NAME, rule, { invalid: [ // sync queries with await operator are not valid - ...SYNC_QUERIES_COMBINATIONS.map((query) => ({ - code: `async () => { + ...SYNC_QUERIES_COMBINATIONS.map( + (query) => + ({ + code: `async () => { const element = await ${query}('foo') } `, - errors: [ - { - messageId: 'noAwaitSyncQuery', - line: 2, - column: 31, - }, - ], - })), + errors: [ + { + messageId: 'noAwaitSyncQuery', + line: 2, + column: 31, + }, + ], + } as const) + ), // custom sync queries with await operator are not valid { code: ` @@ -154,49 +157,58 @@ ruleTester.run(RULE_NAME, rule, { errors: [{ messageId: 'noAwaitSyncQuery', line: 3, column: 38 }], }, // sync queries with await operator inside assert are not valid - ...SYNC_QUERIES_COMBINATIONS.map((query) => ({ - code: `async () => { + ...SYNC_QUERIES_COMBINATIONS.map( + (query) => + ({ + code: `async () => { expect(await ${query}('foo')).toBeEnabled() } `, - errors: [ - { - messageId: 'noAwaitSyncQuery', - line: 2, - column: 22, - }, - ], - })), + errors: [ + { + messageId: 'noAwaitSyncQuery', + line: 2, + column: 22, + }, + ], + } as const) + ), // sync queries in screen with await operator are not valid - ...SYNC_QUERIES_COMBINATIONS.map((query) => ({ - code: `async () => { + ...SYNC_QUERIES_COMBINATIONS.map( + (query) => + ({ + code: `async () => { const element = await screen.${query}('foo') } `, - errors: [ - { - messageId: 'noAwaitSyncQuery', - line: 2, - column: 38, - }, - ], - })), + errors: [ + { + messageId: 'noAwaitSyncQuery', + line: 2, + column: 38, + }, + ], + } as const) + ), // sync queries in screen with await operator inside assert are not valid - ...SYNC_QUERIES_COMBINATIONS.map((query) => ({ - code: `async () => { + ...SYNC_QUERIES_COMBINATIONS.map( + (query) => + ({ + code: `async () => { expect(await screen.${query}('foo')).toBeEnabled() } `, - errors: [ - { - messageId: 'noAwaitSyncQuery', - line: 2, - column: 29, - }, - ], - })), + errors: [ + { + messageId: 'noAwaitSyncQuery', + line: 2, + column: 29, + }, + ], + } as const) + ), // sync query awaited and related to testing library module // with custom module setting is not valid diff --git a/tests/lib/rules/no-debug.test.ts b/tests/lib/rules/no-debug.test.ts index d2e3f589..fda5faab 100644 --- a/tests/lib/rules/no-debug.test.ts +++ b/tests/lib/rules/no-debug.test.ts @@ -139,6 +139,10 @@ ruleTester.run(RULE_NAME, rule, { debug() `, }, + + `// cover edge case for https://github.com/testing-library/eslint-plugin-testing-library/issues/306 + thing.method.lastCall.args[0](); + `, ], invalid: [ diff --git a/tests/lib/rules/no-manual-cleanup.test.ts b/tests/lib/rules/no-manual-cleanup.test.ts index 6bd57074..d89eb3b2 100644 --- a/tests/lib/rules/no-manual-cleanup.test.ts +++ b/tests/lib/rules/no-manual-cleanup.test.ts @@ -56,30 +56,36 @@ ruleTester.run(RULE_NAME, rule, { }, ], invalid: [ - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - code: `import { render, cleanup } from "${lib}"`, - errors: [ - { - line: 1, - column: 18, // error points to `cleanup` - messageId: 'noManualCleanup', - }, - ], - })), - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - // official testing-library packages should be reported with custom module setting - settings: { - 'testing-library/utils-module': 'test-utils', - }, - code: `import { cleanup, render } from "${lib}"`, - errors: [ - { - line: 1, - column: 10, // error points to `cleanup` - messageId: 'noManualCleanup', - }, - ], - })), + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + code: `import { render, cleanup } from "${lib}"`, + errors: [ + { + line: 1, + column: 18, // error points to `cleanup` + messageId: 'noManualCleanup', + }, + ], + } as const) + ), + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + // official testing-library packages should be reported with custom module setting + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: `import { cleanup, render } from "${lib}"`, + errors: [ + { + line: 1, + column: 10, // error points to `cleanup` + messageId: 'noManualCleanup', + }, + ], + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -89,16 +95,19 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 2, column: 26, messageId: 'noManualCleanup' }], }, - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - code: `import { cleanup as myCustomCleanup } from "${lib}"`, - errors: [ - { - line: 1, - column: 10, // error points to `cleanup` - messageId: 'noManualCleanup', - }, - ], - })), + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + code: `import { cleanup as myCustomCleanup } from "${lib}"`, + errors: [ + { + line: 1, + column: 10, // error points to `cleanup` + messageId: 'noManualCleanup', + }, + ], + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -108,16 +117,19 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 2, column: 18, messageId: 'noManualCleanup' }], }, - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - code: `import utils, { cleanup } from "${lib}"`, - errors: [ - { - line: 1, - column: 17, // error points to `cleanup` - messageId: 'noManualCleanup', - }, - ], - })), + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + code: `import utils, { cleanup } from "${lib}"`, + errors: [ + { + line: 1, + column: 17, // error points to `cleanup` + messageId: 'noManualCleanup', + }, + ], + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -127,19 +139,22 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 2, column: 25, messageId: 'noManualCleanup' }], }, - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - code: ` + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + code: ` import utils from "${lib}" afterEach(() => utils.cleanup()) `, - errors: [ - { - line: 3, - column: 31, - messageId: 'noManualCleanup', - }, - ], - })), + errors: [ + { + line: 3, + column: 31, + messageId: 'noManualCleanup', + }, + ], + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -150,29 +165,35 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 3, column: 31, messageId: 'noManualCleanup' }], }, - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - code: ` + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + code: ` import utils from "${lib}" afterEach(utils.cleanup) `, - errors: [ - { - line: 3, - column: 25, - messageId: 'noManualCleanup', - }, - ], - })), - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - code: `const { cleanup } = require("${lib}")`, - errors: [ - { - line: 1, - column: 9, // error points to `cleanup` - messageId: 'noManualCleanup', - }, - ], - })), + errors: [ + { + line: 3, + column: 25, + messageId: 'noManualCleanup', + }, + ], + } as const) + ), + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + code: `const { cleanup } = require("${lib}")`, + errors: [ + { + line: 1, + column: 9, // error points to `cleanup` + messageId: 'noManualCleanup', + }, + ], + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -182,31 +203,37 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 2, column: 25, messageId: 'noManualCleanup' }], }, - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - code: ` + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + code: ` const utils = require("${lib}") afterEach(() => utils.cleanup()) `, - errors: [ - { - line: 3, - column: 31, - messageId: 'noManualCleanup', - }, - ], - })), - ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map((lib) => ({ - code: ` + errors: [ + { + line: 3, + column: 31, + messageId: 'noManualCleanup', + }, + ], + } as const) + ), + ...ALL_TESTING_LIBRARIES_WITH_CLEANUP.map( + (lib) => + ({ + code: ` const utils = require("${lib}") afterEach(utils.cleanup) `, - errors: [ - { - line: 3, - column: 25, - messageId: 'noManualCleanup', - }, - ], - })), + errors: [ + { + line: 3, + column: 25, + messageId: 'noManualCleanup', + }, + ], + } as const) + ), ], }); diff --git a/tests/lib/rules/no-render-in-setup.test.ts b/tests/lib/rules/no-render-in-setup.test.ts index 38a8553b..8633e280 100644 --- a/tests/lib/rules/no-render-in-setup.test.ts +++ b/tests/lib/rules/no-render-in-setup.test.ts @@ -95,59 +95,70 @@ ruleTester.run(RULE_NAME, rule, { ], invalid: [ - ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ - code: ` + ...TESTING_FRAMEWORK_SETUP_HOOKS.map( + (setupHook) => + ({ + code: ` import { render } from '@testing-library/foo'; ${setupHook}(() => { render() }) `, - errors: [ - { - line: 4, - column: 11, - messageId: 'noRenderInSetup', - }, - ], - })), - ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ - code: ` + errors: [ + { + line: 4, + column: 11, + messageId: 'noRenderInSetup', + }, + ], + } as const) + ), + ...TESTING_FRAMEWORK_SETUP_HOOKS.map( + (setupHook) => + ({ + code: ` import { render } from '@testing-library/foo'; ${setupHook}(function() { render() }) `, - errors: [ - { - line: 4, - column: 11, - messageId: 'noRenderInSetup', - }, - ], - })), + errors: [ + { + line: 4, + column: 11, + messageId: 'noRenderInSetup', + }, + ], + } as const) + ), // custom render function - ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ - settings: { - 'testing-library/utils-module': 'test-utils', - 'testing-library/custom-renders': ['show', 'renderWithRedux'], - }, - code: ` + ...TESTING_FRAMEWORK_SETUP_HOOKS.map( + (setupHook) => + ({ + settings: { + 'testing-library/utils-module': 'test-utils', + 'testing-library/custom-renders': ['show', 'renderWithRedux'], + }, + code: ` import { show } from '../test-utils'; ${setupHook}(() => { show() }) `, - errors: [ - { - line: 5, - column: 11, - messageId: 'noRenderInSetup', - }, - ], - })), - ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ - code: `// call render within a wrapper function + errors: [ + { + line: 5, + column: 11, + messageId: 'noRenderInSetup', + }, + ], + } as const) + ), + ...TESTING_FRAMEWORK_SETUP_HOOKS.map( + (setupHook) => + ({ + code: `// call render within a wrapper function import { render } from '@testing-library/foo'; const wrapper = () => render() @@ -156,14 +167,15 @@ ruleTester.run(RULE_NAME, rule, { wrapper() }) `, - errors: [ - { - line: 7, - column: 9, - messageId: 'noRenderInSetup', - }, - ], - })), + errors: [ + { + line: 7, + column: 9, + messageId: 'noRenderInSetup', + }, + ], + } as const) + ), ...TESTING_FRAMEWORK_SETUP_HOOKS.map((allowedSetupHook) => { const [disallowedHook] = TESTING_FRAMEWORK_SETUP_HOOKS.filter( (setupHook) => setupHook !== allowedSetupHook @@ -187,26 +199,31 @@ ruleTester.run(RULE_NAME, rule, { messageId: 'noRenderInSetup', }, ], - }; + } as const; }), - ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ - code: ` + ...TESTING_FRAMEWORK_SETUP_HOOKS.map( + (setupHook) => + ({ + code: ` import * as testingLibrary from '@testing-library/foo'; ${setupHook}(() => { testingLibrary.render() }) `, - errors: [ - { - line: 4, - column: 26, - messageId: 'noRenderInSetup', - }, - ], - })), - ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ - settings: { 'testing-library/utils-module': 'test-utils' }, - code: ` + errors: [ + { + line: 4, + column: 26, + messageId: 'noRenderInSetup', + }, + ], + } as const) + ), + ...TESTING_FRAMEWORK_SETUP_HOOKS.map( + (setupHook) => + ({ + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` import { render } from 'imNoTestingLibrary'; import * as testUtils from '../test-utils'; ${setupHook}(() => { @@ -216,29 +233,33 @@ ruleTester.run(RULE_NAME, rule, { render() }) `, - errors: [ - { - line: 5, - column: 21, - messageId: 'noRenderInSetup', - }, - ], - })), - ...TESTING_FRAMEWORK_SETUP_HOOKS.map((setupHook) => ({ - code: ` + errors: [ + { + line: 5, + column: 21, + messageId: 'noRenderInSetup', + }, + ], + } as const) + ), + ...TESTING_FRAMEWORK_SETUP_HOOKS.map( + (setupHook) => + ({ + code: ` const { render } = require('@testing-library/foo') ${setupHook}(() => { render() }) `, - errors: [ - { - line: 5, - column: 11, - messageId: 'noRenderInSetup', - }, - ], - })), + errors: [ + { + line: 5, + column: 11, + messageId: 'noRenderInSetup', + }, + ], + } as const) + ), ], }); diff --git a/tests/lib/rules/no-wait-for-empty-callback.test.ts b/tests/lib/rules/no-wait-for-empty-callback.test.ts index 76e57789..87bbd3fc 100644 --- a/tests/lib/rules/no-wait-for-empty-callback.test.ts +++ b/tests/lib/rules/no-wait-for-empty-callback.test.ts @@ -50,138 +50,165 @@ ruleTester.run(RULE_NAME, rule, { ], invalid: [ - ...ALL_WAIT_METHODS.map((m) => ({ - code: `${m}(() => {})`, - errors: [ - { - line: 1, - column: 8 + m.length, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: m, - }, - }, - ], - })), - ...ALL_WAIT_METHODS.map((m) => ({ - settings: { 'testing-library/utils-module': 'test-utils' }, - code: ` + ...ALL_WAIT_METHODS.map( + (m) => + ({ + code: `${m}(() => {})`, + errors: [ + { + line: 1, + column: 8 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), + ...ALL_WAIT_METHODS.map( + (m) => + ({ + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` import { ${m} } from 'test-utils'; ${m}(() => {}); `, - errors: [ - { - line: 3, - column: 16 + m.length, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: m, - }, - }, - ], - })), - ...ALL_WAIT_METHODS.map((m) => ({ - settings: { 'testing-library/utils-module': 'test-utils' }, - code: ` + errors: [ + { + line: 3, + column: 16 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), + ...ALL_WAIT_METHODS.map( + (m) => + ({ + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` import { ${m} as renamedAsyncUtil } from 'test-utils'; renamedAsyncUtil(() => {}); `, - errors: [ - { - line: 3, - column: 32, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: 'renamedAsyncUtil', - }, - }, - ], - })), - ...ALL_WAIT_METHODS.map((m) => ({ - code: `${m}((a, b) => {})`, - errors: [ - { - line: 1, - column: 12 + m.length, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: m, - }, - }, - ], - })), - ...ALL_WAIT_METHODS.map((m) => ({ - code: `${m}(() => { /* I'm empty anyway */ })`, - errors: [ - { - line: 1, - column: 8 + m.length, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: m, - }, - }, - ], - })), + errors: [ + { + line: 3, + column: 32, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: 'renamedAsyncUtil', + }, + }, + ], + } as const) + ), + ...ALL_WAIT_METHODS.map( + (m) => + ({ + code: `${m}((a, b) => {})`, + errors: [ + { + line: 1, + column: 12 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), + ...ALL_WAIT_METHODS.map( + (m) => + ({ + code: `${m}(() => { /* I'm empty anyway */ })`, + errors: [ + { + line: 1, + column: 8 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), - ...ALL_WAIT_METHODS.map((m) => ({ - code: `${m}(function() { + ...ALL_WAIT_METHODS.map( + (m) => + ({ + code: `${m}(function() { })`, - errors: [ - { - line: 1, - column: 13 + m.length, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: m, - }, - }, - ], - })), - ...ALL_WAIT_METHODS.map((m) => ({ - code: `${m}(function(a) { + errors: [ + { + line: 1, + column: 13 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), + ...ALL_WAIT_METHODS.map( + (m) => + ({ + code: `${m}(function(a) { })`, - errors: [ - { - line: 1, - column: 14 + m.length, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: m, - }, - }, - ], - })), - ...ALL_WAIT_METHODS.map((m) => ({ - code: `${m}(function() { + errors: [ + { + line: 1, + column: 14 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), + ...ALL_WAIT_METHODS.map( + (m) => + ({ + code: `${m}(function() { // another empty callback })`, - errors: [ - { - line: 1, - column: 13 + m.length, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: m, - }, - }, - ], - })), + errors: [ + { + line: 1, + column: 13 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), - ...ALL_WAIT_METHODS.map((m) => ({ - code: `${m}(noop)`, - errors: [ - { - line: 1, - column: 2 + m.length, - messageId: 'noWaitForEmptyCallback', - data: { - methodName: m, - }, - }, - ], - })), + ...ALL_WAIT_METHODS.map( + (m) => + ({ + code: `${m}(noop)`, + errors: [ + { + line: 1, + column: 2 + m.length, + messageId: 'noWaitForEmptyCallback', + data: { + methodName: m, + }, + }, + ], + } as const) + ), ], }); diff --git a/tests/lib/rules/no-wait-for-snapshot.test.ts b/tests/lib/rules/no-wait-for-snapshot.test.ts index 200584a4..6aae1adc 100644 --- a/tests/lib/rules/no-wait-for-snapshot.test.ts +++ b/tests/lib/rules/no-wait-for-snapshot.test.ts @@ -152,24 +152,29 @@ ruleTester.run(RULE_NAME, rule, { })), ], invalid: [ - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from '@testing-library/dom'; test('snapshot calls within ${asyncUtil} are not valid', async () => { await ${asyncUtil}(() => expect(foo).toMatchSnapshot()); }); `, - errors: [ - { - line: 4, - messageId: 'noWaitForSnapshot', - data: { name: asyncUtil }, - column: 36 + asyncUtil.length, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 4, + messageId: 'noWaitForSnapshot', + data: { name: asyncUtil }, + column: 36 + asyncUtil.length, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from '@testing-library/dom'; test('snapshot calls within ${asyncUtil} are not valid', async () => { await ${asyncUtil}(() => { @@ -177,33 +182,39 @@ ruleTester.run(RULE_NAME, rule, { }); }); `, - errors: [ - { - line: 5, - messageId: 'noWaitForSnapshot', - data: { name: asyncUtil }, - column: 27, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 5, + messageId: 'noWaitForSnapshot', + data: { name: asyncUtil }, + column: 27, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import * as asyncUtils from '@testing-library/dom'; test('snapshot calls within ${asyncUtil} are not valid', async () => { await asyncUtils.${asyncUtil}(() => expect(foo).toMatchSnapshot()); }); `, - errors: [ - { - line: 4, - messageId: 'noWaitForSnapshot', - data: { name: asyncUtil }, - column: 47 + asyncUtil.length, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 4, + messageId: 'noWaitForSnapshot', + data: { name: asyncUtil }, + column: 47 + asyncUtil.length, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import * as asyncUtils from '@testing-library/dom'; test('snapshot calls within ${asyncUtil} are not valid', async () => { await asyncUtils.${asyncUtil}(() => { @@ -211,33 +222,39 @@ ruleTester.run(RULE_NAME, rule, { }); }); `, - errors: [ - { - line: 5, - messageId: 'noWaitForSnapshot', - data: { name: asyncUtil }, - column: 27, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 5, + messageId: 'noWaitForSnapshot', + data: { name: asyncUtil }, + column: 27, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from '@testing-library/dom'; test('snapshot calls within ${asyncUtil} are not valid', async () => { await ${asyncUtil}(() => expect(foo).toMatchInlineSnapshot()); }); `, - errors: [ - { - line: 4, - messageId: 'noWaitForSnapshot', - data: { name: asyncUtil }, - column: 36 + asyncUtil.length, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 4, + messageId: 'noWaitForSnapshot', + data: { name: asyncUtil }, + column: 36 + asyncUtil.length, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from '@testing-library/dom'; test('snapshot calls within ${asyncUtil} are not valid', async () => { await ${asyncUtil}(() => { @@ -245,33 +262,39 @@ ruleTester.run(RULE_NAME, rule, { }); }); `, - errors: [ - { - line: 5, - messageId: 'noWaitForSnapshot', - data: { name: asyncUtil }, - column: 27, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 5, + messageId: 'noWaitForSnapshot', + data: { name: asyncUtil }, + column: 27, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import * as asyncUtils from '@testing-library/dom'; test('snapshot calls within ${asyncUtil} are not valid', async () => { await asyncUtils.${asyncUtil}(() => expect(foo).toMatchInlineSnapshot()); }); `, - errors: [ - { - line: 4, - messageId: 'noWaitForSnapshot', - data: { name: asyncUtil }, - column: 47 + asyncUtil.length, - }, - ], - })), - ...ASYNC_UTILS.map((asyncUtil) => ({ - code: ` + errors: [ + { + line: 4, + messageId: 'noWaitForSnapshot', + data: { name: asyncUtil }, + column: 47 + asyncUtil.length, + }, + ], + } as const) + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import * as asyncUtils from '@testing-library/dom'; test('snapshot calls within ${asyncUtil} are not valid', async () => { await asyncUtils.${asyncUtil}(() => { @@ -279,14 +302,15 @@ ruleTester.run(RULE_NAME, rule, { }); }); `, - errors: [ - { - line: 5, - messageId: 'noWaitForSnapshot', - data: { name: asyncUtil }, - column: 27, - }, - ], - })), + errors: [ + { + line: 5, + messageId: 'noWaitForSnapshot', + data: { name: asyncUtil }, + column: 27, + }, + ], + } as const) + ), ], }); diff --git a/tests/lib/rules/prefer-explicit-assert.test.ts b/tests/lib/rules/prefer-explicit-assert.test.ts index d5834739..11cdf141 100644 --- a/tests/lib/rules/prefer-explicit-assert.test.ts +++ b/tests/lib/rules/prefer-explicit-assert.test.ts @@ -99,39 +99,50 @@ ruleTester.run(RULE_NAME, rule, { })), ], invalid: [ - ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ - code: `get${queryMethod}('foo')`, - errors: [ - { - messageId: 'preferExplicitAssert', - }, - ], - })), - ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ - code: ` + ...COMBINED_QUERIES_METHODS.map( + (queryMethod) => + ({ + code: `get${queryMethod}('foo')`, + errors: [ + { + messageId: 'preferExplicitAssert', + }, + ], + } as const) + ), + ...COMBINED_QUERIES_METHODS.map( + (queryMethod) => + ({ + code: ` const utils = render() utils.get${queryMethod}('foo') `, - errors: [ - { - messageId: 'preferExplicitAssert', - line: 3, - column: 15, - }, - ], - })), - ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ - code: `screen.get${queryMethod}('foo')`, - errors: [ - { - messageId: 'preferExplicitAssert', - line: 1, - column: 8, - }, - ], - })), - ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ - code: ` + errors: [ + { + messageId: 'preferExplicitAssert', + line: 3, + column: 15, + }, + ], + } as const) + ), + ...COMBINED_QUERIES_METHODS.map( + (queryMethod) => + ({ + code: `screen.get${queryMethod}('foo')`, + errors: [ + { + messageId: 'preferExplicitAssert', + line: 1, + column: 8, + }, + ], + } as const) + ), + ...COMBINED_QUERIES_METHODS.map( + (queryMethod) => + ({ + code: ` () => { get${queryMethod}('foo') doSomething() @@ -140,31 +151,35 @@ ruleTester.run(RULE_NAME, rule, { const quxElement = get${queryMethod}('qux') } `, - errors: [ - { - messageId: 'preferExplicitAssert', - line: 3, - }, - { - messageId: 'preferExplicitAssert', - line: 6, - }, - ], - })), - ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ - settings: { - 'testing-library/utils-module': 'test-utils', - }, - code: ` + errors: [ + { + messageId: 'preferExplicitAssert', + line: 3, + }, + { + messageId: 'preferExplicitAssert', + line: 6, + }, + ], + } as const) + ), + ...COMBINED_QUERIES_METHODS.map( + (queryMethod) => + ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` import "test-utils" getBy${queryMethod}("Hello") `, - errors: [ - { - messageId: 'preferExplicitAssert', - }, - ], - })), + errors: [ + { + messageId: 'preferExplicitAssert', + }, + ], + } as const) + ), { code: `getByIcon('foo')`, // custom `getBy` query extended through options errors: [ @@ -173,47 +188,56 @@ ruleTester.run(RULE_NAME, rule, { }, ], }, - ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ - code: `expect(get${queryMethod}('foo')).toBeDefined()`, - options: [ - { - assertion: 'toBeInTheDocument', - }, - ], - errors: [ - { - messageId: 'preferExplicitAssertAssertion', - data: { assertion: 'toBeInTheDocument' }, - }, - ], - })), - ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ - code: `expect(get${queryMethod}('foo')).not.toBeNull()`, - options: [ - { - assertion: 'toBeInTheDocument', - }, - ], - errors: [ - { - messageId: 'preferExplicitAssertAssertion', - data: { assertion: 'toBeInTheDocument' }, - }, - ], - })), - ...COMBINED_QUERIES_METHODS.map((queryMethod) => ({ - code: `expect(get${queryMethod}('foo')).not.toBeFalsy()`, - options: [ - { - assertion: 'toBeInTheDocument', - }, - ], - errors: [ - { - messageId: 'preferExplicitAssertAssertion', - data: { assertion: 'toBeInTheDocument' }, - }, - ], - })), + ...COMBINED_QUERIES_METHODS.map( + (queryMethod) => + ({ + code: `expect(get${queryMethod}('foo')).toBeDefined()`, + options: [ + { + assertion: 'toBeInTheDocument', + }, + ], + errors: [ + { + messageId: 'preferExplicitAssertAssertion', + data: { assertion: 'toBeInTheDocument' }, + }, + ], + } as const) + ), + ...COMBINED_QUERIES_METHODS.map( + (queryMethod) => + ({ + code: `expect(get${queryMethod}('foo')).not.toBeNull()`, + options: [ + { + assertion: 'toBeInTheDocument', + }, + ], + errors: [ + { + messageId: 'preferExplicitAssertAssertion', + data: { assertion: 'toBeInTheDocument' }, + }, + ], + } as const) + ), + ...COMBINED_QUERIES_METHODS.map( + (queryMethod) => + ({ + code: `expect(get${queryMethod}('foo')).not.toBeFalsy()`, + options: [ + { + assertion: 'toBeInTheDocument', + }, + ], + errors: [ + { + messageId: 'preferExplicitAssertAssertion', + data: { assertion: 'toBeInTheDocument' }, + }, + ], + } as const) + ), ], }); diff --git a/tests/lib/rules/prefer-find-by.test.ts b/tests/lib/rules/prefer-find-by.test.ts index bc4cad95..96e892e7 100644 --- a/tests/lib/rules/prefer-find-by.test.ts +++ b/tests/lib/rules/prefer-find-by.test.ts @@ -192,61 +192,67 @@ ruleTester.run(RULE_NAME, rule, { `, })), // // this scenario verifies it works when the render function is defined in another scope - ...WAIT_METHODS.map((waitMethod: string) => ({ - code: ` + ...WAIT_METHODS.map( + (waitMethod: string) => + ({ + code: ` import {${waitMethod}} from '@testing-library/foo'; const { getByText, queryByLabelText, findAllByRole } = customRender() it('tests', async () => { const submitButton = await ${waitMethod}(() => getByText('baz', { name: 'button' })) }) `, - errors: [ - { - messageId: 'preferFindBy', - data: { - queryVariant: 'findBy', - queryMethod: 'Text', - prevQuery: 'getByText', - waitForMethodName: waitMethod, - }, - }, - ], - output: ` + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: 'findBy', + queryMethod: 'Text', + prevQuery: 'getByText', + waitForMethodName: waitMethod, + }, + }, + ], + output: ` import {${waitMethod}} from '@testing-library/foo'; const { getByText, queryByLabelText, findAllByRole, findByText } = customRender() it('tests', async () => { const submitButton = await findByText('baz', { name: 'button' }) }) `, - })), + } as const) + ), // // this scenario verifies when findBy* were already defined (because it was used elsewhere) - ...WAIT_METHODS.map((waitMethod: string) => ({ - code: ` + ...WAIT_METHODS.map( + (waitMethod: string) => + ({ + code: ` import {${waitMethod}} from '@testing-library/foo'; const { getAllByRole, findAllByRole } = customRender() it('tests', async () => { const submitButton = await ${waitMethod}(() => getAllByRole('baz', { name: 'button' })) }) `, - errors: [ - { - messageId: 'preferFindBy', - data: { - queryVariant: 'findAllBy', - queryMethod: 'Role', - prevQuery: 'getAllByRole', - waitForMethodName: waitMethod, - }, - }, - ], - output: ` + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: 'findAllBy', + queryMethod: 'Role', + prevQuery: 'getAllByRole', + waitForMethodName: waitMethod, + }, + }, + ], + output: ` import {${waitMethod}} from '@testing-library/foo'; const { getAllByRole, findAllByRole } = customRender() it('tests', async () => { const submitButton = await findAllByRole('baz', { name: 'button' }) }) `, - })), + } as const) + ), // invalid code, as we need findBy* to be defined somewhere, but required for getting 100% coverage { code: `const submitButton = await waitFor(() => getByText('baz', { name: 'button' }))`, @@ -286,60 +292,66 @@ ruleTester.run(RULE_NAME, rule, { `, }, // custom query triggers the error but there is no fix - so output is the same - ...WAIT_METHODS.map((waitMethod: string) => ({ - code: ` + ...WAIT_METHODS.map( + (waitMethod: string) => + ({ + code: ` import {${waitMethod},render} from '@testing-library/foo'; it('tests', async () => { const { getByCustomQuery } = render() const submitButton = await ${waitMethod}(() => getByCustomQuery('baz')) }) `, - errors: [ - { - messageId: 'preferFindBy', - data: { - queryVariant: 'findBy', - queryMethod: 'CustomQuery', - prevQuery: 'getByCustomQuery', - waitForMethodName: waitMethod, - }, - }, - ], - output: ` + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: 'findBy', + queryMethod: 'CustomQuery', + prevQuery: 'getByCustomQuery', + waitForMethodName: waitMethod, + }, + }, + ], + output: ` import {${waitMethod},render} from '@testing-library/foo'; it('tests', async () => { const { getByCustomQuery } = render() const submitButton = await ${waitMethod}(() => getByCustomQuery('baz')) }) `, - })), + } as const) + ), // custom query triggers the error but there is no fix - so output is the same - ...WAIT_METHODS.map((waitMethod: string) => ({ - code: ` + ...WAIT_METHODS.map( + (waitMethod: string) => + ({ + code: ` import {${waitMethod},render,screen} from '@testing-library/foo'; it('tests', async () => { const { getByCustomQuery } = render() const submitButton = await ${waitMethod}(() => screen.getByCustomQuery('baz')) }) `, - errors: [ - { - messageId: 'preferFindBy', - data: { - queryVariant: 'findBy', - queryMethod: 'CustomQuery', - prevQuery: 'getByCustomQuery', - waitForMethodName: waitMethod, - }, - }, - ], - output: ` + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: 'findBy', + queryMethod: 'CustomQuery', + prevQuery: 'getByCustomQuery', + waitForMethodName: waitMethod, + }, + }, + ], + output: ` import {${waitMethod},render,screen} from '@testing-library/foo'; it('tests', async () => { const { getByCustomQuery } = render() const submitButton = await ${waitMethod}(() => screen.getByCustomQuery('baz')) }) `, - })), + } as const) + ), ], }); diff --git a/tests/lib/rules/prefer-presence-queries.test.ts b/tests/lib/rules/prefer-presence-queries.test.ts index e4497b1b..296b6903 100644 --- a/tests/lib/rules/prefer-presence-queries.test.ts +++ b/tests/lib/rules/prefer-presence-queries.test.ts @@ -4,6 +4,7 @@ import rule, { MessageIds, } from '../../../lib/rules/prefer-presence-queries'; import { ALL_QUERIES_METHODS } from '../../../lib/utils'; +import { TSESLint } from '@typescript-eslint/experimental-utils'; const ruleTester = createRuleTester(); @@ -14,6 +15,9 @@ const queryAllByQueries = ALL_QUERIES_METHODS.map( (method) => `queryAll${method}` ); +type RuleValidTestCase = TSESLint.ValidTestCase<[]>; +type RuleInvalidTestCase = TSESLint.InvalidTestCase; + type AssertionFnParams = { query: string; matcher: string; @@ -25,11 +29,11 @@ const getValidAssertion = ({ query, matcher, shouldUseScreen = false, -}: Omit) => { +}: Omit): RuleValidTestCase => { const finalQuery = shouldUseScreen ? `screen.${query}` : query; return { code: `expect(${finalQuery}('Hello'))${matcher}`, - }; + } as const; }; const getInvalidAssertion = ({ @@ -37,7 +41,7 @@ const getInvalidAssertion = ({ matcher, messageId, shouldUseScreen = false, -}: AssertionFnParams) => { +}: AssertionFnParams): RuleInvalidTestCase => { const finalQuery = shouldUseScreen ? `screen.${query}` : query; return { code: `expect(${finalQuery}('Hello'))${matcher}`, @@ -69,7 +73,7 @@ ruleTester.run(RULE_NAME, rule, { `, }, // cases: asserting presence correctly with `getBy*` queries - ...getByQueries.reduce( + ...getByQueries.reduce( (validRules, queryName) => [ ...validRules, getValidAssertion({ @@ -91,7 +95,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting presence correctly with `screen.getBy*` queries - ...getByQueries.reduce( + ...getByQueries.reduce( (validRules, queryName) => [ ...validRules, getValidAssertion({ @@ -143,7 +147,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting presence correctly with `getAllBy*` queries - ...getAllByQueries.reduce( + ...getAllByQueries.reduce( (validRules, queryName) => [ ...validRules, getValidAssertion({ @@ -165,7 +169,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting presence correctly with `screen.getAllBy*` queries - ...getAllByQueries.reduce( + ...getAllByQueries.reduce( (validRules, queryName) => [ ...validRules, getValidAssertion({ @@ -217,7 +221,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting absence correctly with `queryBy*` queries - ...queryByQueries.reduce( + ...queryByQueries.reduce( (validRules, queryName) => [ ...validRules, getValidAssertion({ query: queryName, matcher: '.toBeNull()' }), @@ -237,7 +241,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting absence correctly with `screen.queryBy*` queries - ...queryByQueries.reduce( + ...queryByQueries.reduce( (validRules, queryName) => [ ...validRules, getValidAssertion({ @@ -279,7 +283,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting absence correctly with `queryAllBy*` queries - ...queryAllByQueries.reduce( + ...queryAllByQueries.reduce( (validRules, queryName) => [ ...validRules, getValidAssertion({ query: queryName, matcher: '.toBeNull()' }), @@ -299,7 +303,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting absence correctly with `screen.queryAllBy*` queries - ...queryAllByQueries.reduce( + ...queryAllByQueries.reduce( (validRules, queryName) => [ ...validRules, getValidAssertion({ @@ -365,7 +369,7 @@ ruleTester.run(RULE_NAME, rule, { ], invalid: [ // cases: asserting absence incorrectly with `getBy*` queries - ...getByQueries.reduce( + ...getByQueries.reduce( (invalidRules, queryName) => [ ...invalidRules, getInvalidAssertion({ @@ -397,7 +401,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting absence incorrectly with `screen.getBy*` queries - ...getByQueries.reduce( + ...getByQueries.reduce( (invalidRules, queryName) => [ ...invalidRules, getInvalidAssertion({ @@ -434,7 +438,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting absence incorrectly with `getAllBy*` queries - ...getAllByQueries.reduce( + ...getAllByQueries.reduce( (invalidRules, queryName) => [ ...invalidRules, getInvalidAssertion({ @@ -466,7 +470,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting absence incorrectly with `screen.getAllBy*` queries - ...getAllByQueries.reduce( + ...getAllByQueries.reduce( (invalidRules, queryName) => [ ...invalidRules, getInvalidAssertion({ @@ -503,7 +507,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting presence incorrectly with `queryBy*` queries - ...queryByQueries.reduce( + ...queryByQueries.reduce( (validRules, queryName) => [ ...validRules, getInvalidAssertion({ @@ -535,7 +539,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting presence incorrectly with `screen.queryBy*` queries - ...queryByQueries.reduce( + ...queryByQueries.reduce( (validRules, queryName) => [ ...validRules, getInvalidAssertion({ @@ -572,7 +576,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting presence incorrectly with `queryAllBy*` queries - ...queryAllByQueries.reduce( + ...queryAllByQueries.reduce( (validRules, queryName) => [ ...validRules, getInvalidAssertion({ @@ -604,7 +608,7 @@ ruleTester.run(RULE_NAME, rule, { [] ), // cases: asserting presence incorrectly with `screen.queryAllBy*` queries - ...queryAllByQueries.reduce( + ...queryAllByQueries.reduce( (validRules, queryName) => [ ...validRules, getInvalidAssertion({ diff --git a/tests/lib/rules/prefer-screen-queries.test.ts b/tests/lib/rules/prefer-screen-queries.test.ts index b1a7f12a..23bb8135 100644 --- a/tests/lib/rules/prefer-screen-queries.test.ts +++ b/tests/lib/rules/prefer-screen-queries.test.ts @@ -171,192 +171,231 @@ ruleTester.run(RULE_NAME, rule, { ], invalid: [ - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: ` + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: ` const { ${queryMethod} } = render(foo) ${queryMethod}()`, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - settings: { 'testing-library/utils-module': 'test-utils' }, - code: ` + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` import { render } from 'test-utils' const { ${queryMethod} } = render(foo) ${queryMethod}()`, - errors: [ - { - line: 4, - column: 9, - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), + errors: [ + { + line: 4, + column: 9, + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - settings: { - 'testing-library/custom-renders': ['customRender'], - }, - code: ` + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + settings: { + 'testing-library/custom-renders': ['customRender'], + }, + code: ` import { customRender } from 'whatever' const { ${queryMethod} } = customRender(foo) ${queryMethod}()`, - errors: [ - { - line: 4, - column: 9, - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - settings: { 'testing-library/utils-module': 'test-utils' }, - code: ` + errors: [ + { + line: 4, + column: 9, + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` import { render as testingLibraryRender} from '@testing-library/react' const { ${queryMethod} } = testingLibraryRender(foo) ${queryMethod}()`, - errors: [ - { - line: 4, - column: 9, - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - settings: { 'testing-library/utils-module': 'test-utils' }, - code: ` + errors: [ + { + line: 4, + column: 9, + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + settings: { 'testing-library/utils-module': 'test-utils' }, + code: ` import { render } from 'test-utils' const { ${queryMethod} } = render(foo) ${queryMethod}()`, - errors: [ - { - line: 4, - column: 9, - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: `render().${queryMethod}()`, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: `render(foo, { hydrate: true }).${queryMethod}()`, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: `component.${queryMethod}()`, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: ` + errors: [ + { + line: 4, + column: 9, + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: `render().${queryMethod}()`, + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: `render(foo, { hydrate: true }).${queryMethod}()`, + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: `component.${queryMethod}()`, + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: ` const { ${queryMethod} } = render() ${queryMethod}(baz) `, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: ` + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: ` const myRenderVariable = render() myRenderVariable.${queryMethod}(baz) `, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: ` + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: ` const [myVariable] = render() myVariable.${queryMethod}(baz) `, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: ` + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: ` const { ${queryMethod} } = render(baz, { hydrate: true }) ${queryMethod}(baz) `, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), - ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map((queryMethod) => ({ - code: ` + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), + ...ALL_BUILTIN_AND_CUSTOM_QUERIES_COMBINATIONS.map( + (queryMethod) => + ({ + code: ` const [myVariable] = within() myVariable.${queryMethod}(baz) `, - errors: [ - { - messageId: 'preferScreenQueries', - data: { - name: queryMethod, - }, - }, - ], - })), + errors: [ + { + messageId: 'preferScreenQueries', + data: { + name: queryMethod, + }, + }, + ], + } as const) + ), ], }); diff --git a/tests/lib/rules/prefer-user-event.test.ts b/tests/lib/rules/prefer-user-event.test.ts index f3c3bab8..f707a9c2 100644 --- a/tests/lib/rules/prefer-user-event.test.ts +++ b/tests/lib/rules/prefer-user-event.test.ts @@ -229,49 +229,61 @@ ruleTester.run(RULE_NAME, rule, { errors: [{ messageId: 'preferUserEvent', line: 3, column: 9 }], }) ), - ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ - settings: { - 'testing-library/utils-module': 'test-utils', - }, - code: ` + ...Object.keys(MappingToUserEvent).map( + (fireEventMethod: string) => + ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` import * as dom from 'test-utils' dom.fireEvent.${fireEventMethod}(foo) `, - errors: [{ messageId: 'preferUserEvent', line: 3, column: 9 }], - })), - ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ - settings: { - 'testing-library/utils-module': 'test-utils', - }, - code: ` + errors: [{ messageId: 'preferUserEvent', line: 3, column: 9 }], + } as const) + ), + ...Object.keys(MappingToUserEvent).map( + (fireEventMethod: string) => + ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` import { fireEvent } from 'test-utils' fireEvent.${fireEventMethod}(foo) `, - errors: [{ messageId: 'preferUserEvent', line: 3, column: 9 }], - })), - ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ - code: ` + errors: [{ messageId: 'preferUserEvent', line: 3, column: 9 }], + } as const) + ), + ...Object.keys(MappingToUserEvent).map( + (fireEventMethod: string) => + ({ + code: ` // same as previous group of test cases but without custom module set // (aggressive reporting) import { fireEvent } from 'test-utils' fireEvent.${fireEventMethod}(foo) `, - errors: [{ messageId: 'preferUserEvent', line: 5, column: 9 }], - })), - ...Object.keys(MappingToUserEvent).map((fireEventMethod: string) => ({ - settings: { - 'testing-library/utils-module': 'test-utils', - }, - code: ` + errors: [{ messageId: 'preferUserEvent', line: 5, column: 9 }], + } as const) + ), + ...Object.keys(MappingToUserEvent).map( + (fireEventMethod: string) => + ({ + settings: { + 'testing-library/utils-module': 'test-utils', + }, + code: ` import { fireEvent as fireEventAliased } from 'test-utils' fireEventAliased.${fireEventMethod}(foo) `, - errors: [{ messageId: 'preferUserEvent', line: 3, column: 9 }], - })), + errors: [{ messageId: 'preferUserEvent', line: 3, column: 9 }], + } as const) + ), { code: ` // simple test to check error in detail import { fireEvent } from '@testing-library/react' - + fireEvent.click(element) `, errors: [ diff --git a/tests/lib/rules/prefer-wait-for.test.ts b/tests/lib/rules/prefer-wait-for.test.ts index f9a9ca8b..410934b1 100644 --- a/tests/lib/rules/prefer-wait-for.test.ts +++ b/tests/lib/rules/prefer-wait-for.test.ts @@ -260,54 +260,60 @@ ruleTester.run(RULE_NAME, rule, { ], invalid: [ - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { wait, render } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { wait, render } from '${libraryModule}'; async () => { await wait(); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { render,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { render,waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { wait, render } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { wait, render } = require('${libraryModule}'); async () => { await wait(); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `const { render,waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `const { render,waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -363,45 +369,51 @@ ruleTester.run(RULE_NAME, rule, { }`, }, // namespaced wait should be fixed but not its import - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import * as testingLibrary from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import * as testingLibrary from '${libraryModule}'; async () => { await testingLibrary.wait(); }`, - errors: [ - { - messageId: 'preferWaitForMethod', - line: 4, - column: 30, - }, - ], - output: `import * as testingLibrary from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForMethod', + line: 4, + column: 30, + }, + ], + output: `import * as testingLibrary from '${libraryModule}'; async () => { await testingLibrary.waitFor(() => {}); }`, - })), + } as const) + ), // namespaced wait should be fixed but not its import - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const testingLibrary = require('${libraryModule}'); + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const testingLibrary = require('${libraryModule}'); async () => { await testingLibrary.wait(); }`, - errors: [ - { - messageId: 'preferWaitForMethod', - line: 4, - column: 30, - }, - ], - output: `const testingLibrary = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForMethod', + line: 4, + column: 30, + }, + ], + output: `const testingLibrary = require('${libraryModule}'); async () => { await testingLibrary.waitFor(() => {}); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -447,45 +459,51 @@ ruleTester.run(RULE_NAME, rule, { }`, }, // namespaced waitForDomChange should be fixed but not its import - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import * as testingLibrary from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import * as testingLibrary from '${libraryModule}'; async () => { await testingLibrary.waitForDomChange({ timeout: 500 }); }`, - errors: [ - { - messageId: 'preferWaitForMethod', - line: 4, - column: 30, - }, - ], - output: `import * as testingLibrary from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForMethod', + line: 4, + column: 30, + }, + ], + output: `import * as testingLibrary from '${libraryModule}'; async () => { await testingLibrary.waitFor(() => {}, { timeout: 500 }); }`, - })), + } as const) + ), // namespaced waitForDomChange should be fixed but not its import - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const testingLibrary = require('${libraryModule}'); + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const testingLibrary = require('${libraryModule}'); async () => { await testingLibrary.waitForDomChange({ timeout: 500 }); }`, - errors: [ - { - messageId: 'preferWaitForMethod', - line: 4, - column: 30, - }, - ], - output: `const testingLibrary = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForMethod', + line: 4, + column: 30, + }, + ], + output: `const testingLibrary = require('${libraryModule}'); async () => { await testingLibrary.waitFor(() => {}, { timeout: 500 }); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -530,54 +548,60 @@ ruleTester.run(RULE_NAME, rule, { await testingLibrary.waitFor(() => {}, { timeout: 500 }); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { render, wait } from '${libraryModule}' + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { render, wait } from '${libraryModule}' async () => { await wait(() => {}); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { render,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { render,waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { render, wait } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { render, wait } = require('${libraryModule}'); async () => { await wait(() => {}); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `const { render,waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `const { render,waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -633,63 +657,69 @@ ruleTester.run(RULE_NAME, rule, { }`, }, // this import doesn't have trailing semicolon but fixer adds it - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { render, wait, screen } from "${libraryModule}"; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { render, wait, screen } from "${libraryModule}"; async () => { await wait(function cb() { doSomething(); }); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { render,screen,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { render,screen,waitFor } from '${libraryModule}'; async () => { await waitFor(function cb() { doSomething(); }); }`, - })), + } as const) + ), // this import doesn't have trailing semicolon but fixer adds it - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { render, wait, screen } from "${libraryModule}"; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { render, wait, screen } from "${libraryModule}"; async () => { await wait(function cb() { doSomething(); }); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { render,screen,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { render,screen,waitFor } from '${libraryModule}'; async () => { await waitFor(function cb() { doSomething(); }); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -752,54 +782,60 @@ ruleTester.run(RULE_NAME, rule, { }); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { render, waitForElement, screen } from '${libraryModule}' + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { render, waitForElement, screen } from '${libraryModule}' async () => { await waitForElement(() => {}); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { render,screen,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { render,screen,waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { render, waitForElement, screen } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { render, waitForElement, screen } = require('${libraryModule}'); async () => { await waitForElement(() => {}); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `const { render,screen,waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `const { render,screen,waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -854,62 +890,68 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { waitForElement } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { waitForElement } from '${libraryModule}'; async () => { await waitForElement(function cb() { doSomething(); }); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { waitFor } from '${libraryModule}'; async () => { await waitFor(function cb() { doSomething(); }); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { waitForElement } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { waitForElement } = require('${libraryModule}'); async () => { await waitForElement(function cb() { doSomething(); }); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `const { waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `const { waitFor } = require('${libraryModule}'); async () => { await waitFor(function cb() { doSomething(); }); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -972,54 +1014,60 @@ ruleTester.run(RULE_NAME, rule, { }); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { waitForDomChange } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { waitForDomChange } from '${libraryModule}'; async () => { await waitForDomChange(); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { waitForDomChange } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { waitForDomChange } = require('${libraryModule}'); async () => { await waitForDomChange(); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `const { waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `const { waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -1074,54 +1122,60 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { waitForDomChange } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { waitForDomChange } from '${libraryModule}'; async () => { await waitForDomChange(mutationObserverOptions); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}, mutationObserverOptions); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { waitForDomChange } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { waitForDomChange } = require('${libraryModule}'); async () => { await waitForDomChange(mutationObserverOptions); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `const { waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `const { waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}, mutationObserverOptions); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -1176,54 +1230,60 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}, mutationObserverOptions); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { waitForDomChange } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { waitForDomChange } from '${libraryModule}'; async () => { await waitForDomChange({ timeout: 5000 }); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}, { timeout: 5000 }); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { waitForDomChange } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { waitForDomChange } = require('${libraryModule}'); async () => { await waitForDomChange({ timeout: 5000 }); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `const { waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `const { waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}, { timeout: 5000 }); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -1278,8 +1338,10 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}, { timeout: 5000 }); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { waitForDomChange, wait, waitForElement } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { waitForDomChange, wait, waitForElement } from '${libraryModule}'; import userEvent from '@testing-library/user-event'; async () => { @@ -1288,34 +1350,34 @@ ruleTester.run(RULE_NAME, rule, { await wait(); await wait(() => { doSomething() }); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 5, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 6, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 7, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 8, - column: 15, - }, - ], - output: `import { waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 5, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 6, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 7, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 8, + column: 15, + }, + ], + output: `import { waitFor } from '${libraryModule}'; import userEvent from '@testing-library/user-event'; async () => { @@ -1324,9 +1386,12 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); await waitFor(() => { doSomething() }); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { waitForDomChange, wait, waitForElement } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { waitForDomChange, wait, waitForElement } = require('${libraryModule}'); const userEvent = require('@testing-library/user-event'); async () => { @@ -1335,34 +1400,34 @@ ruleTester.run(RULE_NAME, rule, { await wait(); await wait(() => { doSomething() }); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 5, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 6, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 7, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 8, - column: 15, - }, - ], - output: `const { waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 5, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 6, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 7, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 8, + column: 15, + }, + ], + output: `const { waitFor } = require('${libraryModule}'); const userEvent = require('@testing-library/user-event'); async () => { @@ -1371,7 +1436,8 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); await waitFor(() => { doSomething() }); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -1472,8 +1538,10 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => { doSomething() }); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { render, waitForDomChange, wait, waitForElement } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { render, waitForDomChange, wait, waitForElement } from '${libraryModule}'; async () => { await waitForDomChange({ timeout: 5000 }); @@ -1481,34 +1549,34 @@ ruleTester.run(RULE_NAME, rule, { await wait(); await wait(() => { doSomething() }); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 5, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 6, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 7, - column: 15, - }, - ], - output: `import { render,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 5, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 6, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 7, + column: 15, + }, + ], + output: `import { render,waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}, { timeout: 5000 }); @@ -1516,9 +1584,12 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); await waitFor(() => { doSomething() }); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { render, waitForDomChange, wait, waitForElement } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { render, waitForDomChange, wait, waitForElement } = require('${libraryModule}'); async () => { await waitForDomChange({ timeout: 5000 }); @@ -1526,34 +1597,34 @@ ruleTester.run(RULE_NAME, rule, { await wait(); await wait(() => { doSomething() }); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 5, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 6, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 7, - column: 15, - }, - ], - output: `const { render,waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 5, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 6, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 7, + column: 15, + }, + ], + output: `const { render,waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}, { timeout: 5000 }); @@ -1561,7 +1632,8 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); await waitFor(() => { doSomething() }); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -1658,8 +1730,10 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => { doSomething() }); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { waitForDomChange, wait, render, waitForElement } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { waitForDomChange, wait, render, waitForElement } from '${libraryModule}'; async () => { await waitForDomChange({ timeout: 5000 }); @@ -1667,34 +1741,34 @@ ruleTester.run(RULE_NAME, rule, { await wait(); await wait(() => { doSomething() }); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 5, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 6, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 7, - column: 15, - }, - ], - output: `import { render,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 5, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 6, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 7, + column: 15, + }, + ], + output: `import { render,waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}, { timeout: 5000 }); @@ -1702,9 +1776,12 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); await waitFor(() => { doSomething() }); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { waitForDomChange, wait, render, waitForElement } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { waitForDomChange, wait, render, waitForElement } = require('${libraryModule}'); async () => { await waitForDomChange({ timeout: 5000 }); @@ -1712,34 +1789,34 @@ ruleTester.run(RULE_NAME, rule, { await wait(); await wait(() => { doSomething() }); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 5, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 6, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 7, - column: 15, - }, - ], - output: `const { render,waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 5, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 6, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 7, + column: 15, + }, + ], + output: `const { render,waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}, { timeout: 5000 }); @@ -1747,7 +1824,8 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); await waitFor(() => { doSomething() }); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -1844,8 +1922,10 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => { doSomething() }); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `import { + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `import { waitForDomChange, wait, render, @@ -1858,34 +1938,34 @@ ruleTester.run(RULE_NAME, rule, { await wait(); await wait(() => { doSomething() }); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 9, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 10, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 11, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 12, - column: 15, - }, - ], - output: `import { render,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 9, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 10, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 11, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 12, + column: 15, + }, + ], + output: `import { render,waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}, { timeout: 5000 }); @@ -1893,9 +1973,12 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); await waitFor(() => { doSomething() }); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - code: `const { + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + code: `const { waitForDomChange, wait, render, @@ -1908,34 +1991,34 @@ ruleTester.run(RULE_NAME, rule, { await wait(); await wait(() => { doSomething() }); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 9, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 10, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 11, - column: 15, - }, - { - messageId: 'preferWaitForMethod', - line: 12, - column: 15, - }, - ], - output: `const { render,waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 9, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 10, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 11, + column: 15, + }, + { + messageId: 'preferWaitForMethod', + line: 12, + column: 15, + }, + ], + output: `const { render,waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}, { timeout: 5000 }); @@ -1943,7 +2026,8 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => {}); await waitFor(() => { doSomething() }); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', @@ -2050,60 +2134,66 @@ ruleTester.run(RULE_NAME, rule, { await waitFor(() => { doSomething() }); }`, }, - ...LIBRARY_MODULES.map((libraryModule) => ({ - // if already importing waitFor then it's not imported twice - code: `import { wait, waitFor, render } from '${libraryModule}'; + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + // if already importing waitFor then it's not imported twice + code: `import { wait, waitFor, render } from '${libraryModule}'; async () => { await wait(); await waitFor(someCallback); }`, - errors: [ - { - messageId: 'preferWaitForImport', - line: 1, - column: 1, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `import { render,waitFor } from '${libraryModule}'; + errors: [ + { + messageId: 'preferWaitForImport', + line: 1, + column: 1, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `import { render,waitFor } from '${libraryModule}'; async () => { await waitFor(() => {}); await waitFor(someCallback); }`, - })), - ...LIBRARY_MODULES.map((libraryModule) => ({ - // if already importing waitFor then it's not imported twice - code: `const { wait, waitFor, render } = require('${libraryModule}'); + } as const) + ), + ...LIBRARY_MODULES.map( + (libraryModule) => + ({ + // if already importing waitFor then it's not imported twice + code: `const { wait, waitFor, render } = require('${libraryModule}'); async () => { await wait(); await waitFor(someCallback); }`, - errors: [ - { - messageId: 'preferWaitForRequire', - line: 1, - column: 7, - }, - { - messageId: 'preferWaitForMethod', - line: 4, - column: 15, - }, - ], - output: `const { render,waitFor } = require('${libraryModule}'); + errors: [ + { + messageId: 'preferWaitForRequire', + line: 1, + column: 7, + }, + { + messageId: 'preferWaitForMethod', + line: 4, + column: 15, + }, + ], + output: `const { render,waitFor } = require('${libraryModule}'); async () => { await waitFor(() => {}); await waitFor(someCallback); }`, - })), + } as const) + ), { settings: { 'testing-library/utils-module': 'test-utils', diff --git a/tsconfig.json b/tsconfig.json index 1856daa6..863be8e7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "strict": true, "target": "es6", "module": "commonjs", "moduleResolution": "node",