-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move rules settings to ESLint shared config: refactor no-wait-for-side-effects rule #300
Changes from 9 commits
56bbeae
98d5868
56d5dd4
dd333e5
4cbd073
d549af7
ed9fe56
a2e7d2d
d740d03
c2dee1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -96,6 +96,8 @@ export interface DetectionHelpers { | |
isQuery: IsQueryFn; | ||
isCustomQuery: IsCustomQueryFn; | ||
isAsyncUtil: IsAsyncUtilFn; | ||
isFireEventUtil: (node: TSESTree.Identifier) => boolean; | ||
isUserEventUtil: (node: TSESTree.Identifier) => boolean; | ||
isFireEventMethod: IsFireEventMethodFn; | ||
isRenderUtil: IsRenderUtilFn; | ||
isRenderVariableDeclarator: IsRenderVariableDeclaratorFn; | ||
|
@@ -107,7 +109,6 @@ export interface DetectionHelpers { | |
isNodeComingFromTestingLibrary: IsNodeComingFromTestingLibraryFn; | ||
} | ||
|
||
const FIRE_EVENT_NAME = 'fireEvent'; | ||
const RENDER_NAME = 'render'; | ||
|
||
/** | ||
|
@@ -173,6 +174,69 @@ export function detectTestingLibraryUtils< | |
return isNodeComingFromTestingLibrary(referenceNodeIdentifier); | ||
} | ||
|
||
/** | ||
* Determines whether a given node is a simulate event util related to | ||
* Testing Library or not. | ||
* | ||
* In order to determine this, the node must match: | ||
* - indicated simulate event name: fireEvent or userEvent | ||
* - imported from valid Testing Library module (depends on Aggressive | ||
* Reporting) | ||
* | ||
*/ | ||
function isTestingLibrarySimulateEventUtil( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Extracting generic logic from |
||
node: TSESTree.Identifier, | ||
utilName: 'fireEvent' | 'userEvent' | ||
): boolean { | ||
const simulateEventUtil = findImportedUtilSpecifier(utilName); | ||
let simulateEventUtilName: string | undefined; | ||
|
||
if (simulateEventUtil) { | ||
simulateEventUtilName = ASTUtils.isIdentifier(simulateEventUtil) | ||
? simulateEventUtil.name | ||
: simulateEventUtil.local.name; | ||
} else if (isAggressiveModuleReportingEnabled()) { | ||
simulateEventUtilName = utilName; | ||
} | ||
|
||
if (!simulateEventUtilName) { | ||
return false; | ||
} | ||
|
||
const parentMemberExpression: | ||
| TSESTree.MemberExpression | ||
| undefined = isMemberExpression(node.parent) ? node.parent : undefined; | ||
|
||
if (!parentMemberExpression) { | ||
return false; | ||
} | ||
|
||
// make sure that given node it's not fireEvent/userEvent object itself | ||
if ( | ||
[simulateEventUtilName, utilName].includes(node.name) || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm pretty sure this could be simplified by using |
||
(ASTUtils.isIdentifier(parentMemberExpression.object) && | ||
parentMemberExpression.object.name === node.name) | ||
) { | ||
return false; | ||
} | ||
|
||
// check fireEvent.click()/userEvent.click() usage | ||
const regularCall = | ||
ASTUtils.isIdentifier(parentMemberExpression.object) && | ||
parentMemberExpression.object.name === simulateEventUtilName; | ||
|
||
// check testingLibraryUtils.fireEvent.click() or | ||
// testingLibraryUtils.userEvent.click() usage | ||
const wildcardCall = | ||
isMemberExpression(parentMemberExpression.object) && | ||
ASTUtils.isIdentifier(parentMemberExpression.object.object) && | ||
parentMemberExpression.object.object.name === simulateEventUtilName && | ||
ASTUtils.isIdentifier(parentMemberExpression.object.property) && | ||
parentMemberExpression.object.property.name === utilName; | ||
|
||
return regularCall || wildcardCall; | ||
} | ||
|
||
/** | ||
* Determines whether aggressive module reporting is enabled or not. | ||
* | ||
|
@@ -308,55 +372,38 @@ export function detectTestingLibraryUtils< | |
}; | ||
|
||
/** | ||
* Determines whether a given node is fireEvent method or not | ||
* Determines whether a given node is fireEvent util itself or not. | ||
* | ||
* Not to be confused with {@link isFireEventMethod} | ||
*/ | ||
const isFireEventMethod: IsFireEventMethodFn = (node) => { | ||
const fireEventUtil = findImportedUtilSpecifier(FIRE_EVENT_NAME); | ||
let fireEventUtilName: string | undefined; | ||
|
||
if (fireEventUtil) { | ||
fireEventUtilName = ASTUtils.isIdentifier(fireEventUtil) | ||
? fireEventUtil.name | ||
: fireEventUtil.local.name; | ||
} else if (isAggressiveModuleReportingEnabled()) { | ||
fireEventUtilName = FIRE_EVENT_NAME; | ||
} | ||
|
||
if (!fireEventUtilName) { | ||
return false; | ||
} | ||
|
||
const parentMemberExpression: | ||
| TSESTree.MemberExpression | ||
| undefined = isMemberExpression(node.parent) ? node.parent : undefined; | ||
|
||
if (!parentMemberExpression) { | ||
return false; | ||
} | ||
|
||
// make sure that given node it's not fireEvent object itself | ||
if ( | ||
[fireEventUtilName, FIRE_EVENT_NAME].includes(node.name) || | ||
(ASTUtils.isIdentifier(parentMemberExpression.object) && | ||
parentMemberExpression.object.name === node.name) | ||
) { | ||
return false; | ||
} | ||
|
||
// check fireEvent.click() usage | ||
const regularCall = | ||
ASTUtils.isIdentifier(parentMemberExpression.object) && | ||
parentMemberExpression.object.name === fireEventUtilName; | ||
const isFireEventUtil = (node: TSESTree.Identifier): boolean => { | ||
return isTestingLibraryUtil( | ||
node, | ||
(identifierNodeName, originalNodeName) => { | ||
return [identifierNodeName, originalNodeName].includes('fireEvent'); | ||
} | ||
); | ||
}; | ||
|
||
// check testingLibraryUtils.fireEvent.click() usage | ||
const wildcardCall = | ||
isMemberExpression(parentMemberExpression.object) && | ||
ASTUtils.isIdentifier(parentMemberExpression.object.object) && | ||
parentMemberExpression.object.object.name === fireEventUtilName && | ||
ASTUtils.isIdentifier(parentMemberExpression.object.property) && | ||
parentMemberExpression.object.property.name === FIRE_EVENT_NAME; | ||
/** | ||
* Determines whether a given node is userEvent util itself or not. | ||
* | ||
* Not to be confused with {@link isUserEventMethod} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
*/ | ||
const isUserEventUtil = (node: TSESTree.Identifier): boolean => { | ||
return isTestingLibraryUtil( | ||
node, | ||
(identifierNodeName, originalNodeName) => { | ||
return [identifierNodeName, originalNodeName].includes('userEvent'); | ||
} | ||
); | ||
}; | ||
|
||
return regularCall || wildcardCall; | ||
/** | ||
* Determines whether a given node is fireEvent method or not | ||
*/ | ||
const isFireEventMethod: IsFireEventMethodFn = (node) => { | ||
return isTestingLibrarySimulateEventUtil(node, 'fireEvent'); | ||
}; | ||
|
||
/** | ||
|
@@ -557,6 +604,8 @@ export function detectTestingLibraryUtils< | |
isQuery, | ||
isCustomQuery, | ||
isAsyncUtil, | ||
isFireEventUtil, | ||
isUserEventUtil, | ||
isFireEventMethod, | ||
isRenderUtil, | ||
isRenderVariableDeclarator, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,6 +101,12 @@ export function isJSXAttribute( | |
return node?.type === AST_NODE_TYPES.JSXAttribute; | ||
} | ||
|
||
export function isExpressionStatement( | ||
node: TSESTree.Node | ||
): node is TSESTree.ExpressionStatement { | ||
return node?.type === AST_NODE_TYPES.ExpressionStatement; | ||
} | ||
|
||
/** | ||
* Finds the closest CallExpression node for a given node. | ||
* @param node | ||
|
@@ -388,6 +394,10 @@ export function getPropertyIdentifierNode( | |
return getPropertyIdentifierNode(node.callee); | ||
} | ||
|
||
if (isExpressionStatement(node)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Improving node checks here. |
||
return getPropertyIdentifierNode(node.expression); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I defined types inline here instead of extracting them. I'm not sure what was the advantage of that (not having to write it twice?) but both ways are pretty awful. I may refactor all types here to inline types.