Skip to content

Commit 256cd21

Browse files
committed
feat(no-wait-for-side-effects): report render in waitFor
1 parent 610b3b9 commit 256cd21

File tree

4 files changed

+411
-29
lines changed

4 files changed

+411
-29
lines changed

lib/create-testing-library-rule/detect-testing-library-utils.ts

+27-16
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ type IsAsyncUtilFn = (
7575
) => boolean;
7676
type IsFireEventMethodFn = (node: TSESTree.Identifier) => boolean;
7777
type IsUserEventMethodFn = (node: TSESTree.Identifier) => boolean;
78-
type IsRenderUtilFn = (node: TSESTree.Identifier) => boolean;
78+
type IsRenderUtilFn = (node: TSESTree.Identifier | null) => boolean;
7979
type IsRenderVariableDeclaratorFn = (
8080
node: TSESTree.VariableDeclarator
8181
) => boolean;
@@ -105,8 +105,8 @@ export interface DetectionHelpers {
105105
isCustomQuery: IsCustomQueryFn;
106106
isBuiltInQuery: IsBuiltInQueryFn;
107107
isAsyncUtil: IsAsyncUtilFn;
108-
isFireEventUtil: (node: TSESTree.Identifier) => boolean;
109-
isUserEventUtil: (node: TSESTree.Identifier) => boolean;
108+
isFireEventUtil: (node: TSESTree.Identifier | null) => boolean;
109+
isUserEventUtil: (node: TSESTree.Identifier | null) => boolean;
110110
isFireEventMethod: IsFireEventMethodFn;
111111
isUserEventMethod: IsUserEventMethodFn;
112112
isRenderUtil: IsRenderUtilFn;
@@ -429,7 +429,9 @@ export function detectTestingLibraryUtils<
429429
*
430430
* Not to be confused with {@link isFireEventMethod}
431431
*/
432-
const isFireEventUtil = (node: TSESTree.Identifier): boolean => {
432+
const isFireEventUtil = (node: TSESTree.Identifier | null): boolean => {
433+
if (!node) return false;
434+
433435
return isTestingLibraryUtil(
434436
node,
435437
(identifierNodeName, originalNodeName) => {
@@ -443,7 +445,9 @@ export function detectTestingLibraryUtils<
443445
*
444446
* Not to be confused with {@link isUserEventMethod}
445447
*/
446-
const isUserEventUtil = (node: TSESTree.Identifier): boolean => {
448+
const isUserEventUtil = (node: TSESTree.Identifier | null): boolean => {
449+
if (!node) return false;
450+
447451
const userEvent = findImportedUserEventSpecifier();
448452
let userEventName: string | undefined;
449453

@@ -569,18 +573,25 @@ export function detectTestingLibraryUtils<
569573
* Testing Library. Otherwise, it means `custom-module` has been set up, so
570574
* only those nodes coming from Testing Library will be considered as valid.
571575
*/
572-
const isRenderUtil: IsRenderUtilFn = (node) =>
573-
isTestingLibraryUtil(node, (identifierNodeName, originalNodeName) => {
574-
if (isAggressiveRenderReportingEnabled()) {
575-
return identifierNodeName.toLowerCase().includes(RENDER_NAME);
576-
}
576+
const isRenderUtil: IsRenderUtilFn = (node) => {
577+
if (!node) return false;
577578

578-
return [RENDER_NAME, ...getCustomRenders()].some(
579-
(validRenderName) =>
580-
validRenderName === identifierNodeName ||
581-
(Boolean(originalNodeName) && validRenderName === originalNodeName)
582-
);
583-
});
579+
return isTestingLibraryUtil(
580+
node,
581+
(identifierNodeName, originalNodeName) => {
582+
if (isAggressiveRenderReportingEnabled()) {
583+
return identifierNodeName.toLowerCase().includes(RENDER_NAME);
584+
}
585+
586+
return [RENDER_NAME, ...getCustomRenders()].some(
587+
(validRenderName) =>
588+
validRenderName === identifierNodeName ||
589+
(Boolean(originalNodeName) &&
590+
validRenderName === originalNodeName)
591+
);
592+
}
593+
);
594+
};
584595

585596
const isRenderVariableDeclarator: IsRenderVariableDeclaratorFn = (node) => {
586597
if (!node.init) {

lib/node-utils/is-node-of-type.ts

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ export const isCallExpression = isNodeOfType(AST_NODE_TYPES.CallExpression);
1616
export const isExpressionStatement = isNodeOfType(
1717
AST_NODE_TYPES.ExpressionStatement
1818
);
19+
export const isVariableDeclaration = isNodeOfType(
20+
AST_NODE_TYPES.VariableDeclaration
21+
);
22+
export const isAssignmentExpression = isNodeOfType(
23+
AST_NODE_TYPES.AssignmentExpression
24+
);
25+
export const isSequenceExpression = isNodeOfType(
26+
AST_NODE_TYPES.SequenceExpression
27+
);
1928
export const isImportDeclaration = isNodeOfType(
2029
AST_NODE_TYPES.ImportDeclaration
2130
);

lib/rules/no-wait-for-side-effects.ts

+52-13
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { TSESTree } from '@typescript-eslint/experimental-utils';
22
import {
33
getPropertyIdentifierNode,
44
isExpressionStatement,
5+
isVariableDeclaration,
6+
isAssignmentExpression,
7+
isCallExpression,
8+
isSequenceExpression,
59
} from '../node-utils';
610
import { createTestingLibraryRule } from '../create-testing-library-rule';
711

@@ -32,7 +36,11 @@ export default createTestingLibraryRule<Options, MessageIds>({
3236
defaultOptions: [],
3337
create: function (context, _, helpers) {
3438
function isCallerWaitFor(
35-
node: TSESTree.BlockStatement | TSESTree.CallExpression
39+
node:
40+
| TSESTree.BlockStatement
41+
| TSESTree.CallExpression
42+
| TSESTree.AssignmentExpression
43+
| TSESTree.SequenceExpression
3644
): boolean {
3745
if (!node.parent) {
3846
return false;
@@ -52,18 +60,31 @@ export default createTestingLibraryRule<Options, MessageIds>({
5260
body: TSESTree.Node[]
5361
): TSESTree.ExpressionStatement[] {
5462
return body.filter((node) => {
55-
if (!isExpressionStatement(node)) {
63+
if (!isExpressionStatement(node) && !isVariableDeclaration(node)) {
5664
return false;
5765
}
5866

5967
const expressionIdentifier = getPropertyIdentifierNode(node);
60-
if (!expressionIdentifier) {
61-
return false;
62-
}
68+
69+
const isRenderInVariableDeclaration =
70+
isVariableDeclaration(node) &&
71+
node.declarations.some((declaration) =>
72+
helpers.isRenderVariableDeclarator(declaration)
73+
);
74+
75+
const isRenderInAssignment =
76+
isExpressionStatement(node) &&
77+
isAssignmentExpression(node.expression) &&
78+
helpers.isRenderUtil(
79+
getPropertyIdentifierNode(node.expression.right)
80+
);
6381

6482
return (
6583
helpers.isFireEventUtil(expressionIdentifier) ||
66-
helpers.isUserEventUtil(expressionIdentifier)
84+
helpers.isUserEventUtil(expressionIdentifier) ||
85+
helpers.isRenderUtil(expressionIdentifier) ||
86+
isRenderInVariableDeclaration ||
87+
isRenderInAssignment
6788
);
6889
}) as TSESTree.ExpressionStatement[];
6990
}
@@ -86,19 +107,35 @@ export default createTestingLibraryRule<Options, MessageIds>({
86107
}
87108
}
88109

89-
function reportImplicitReturnSideEffect(node: TSESTree.CallExpression) {
110+
function reportImplicitReturnSideEffect(
111+
node:
112+
| TSESTree.CallExpression
113+
| TSESTree.AssignmentExpression
114+
| TSESTree.SequenceExpression
115+
) {
90116
if (!isCallerWaitFor(node)) {
91117
return;
92118
}
93119

94-
const expressionIdentifier = getPropertyIdentifierNode(node.callee);
95-
if (!expressionIdentifier) {
96-
return;
97-
}
120+
const expressionIdentifier =
121+
isCallExpression(node) && getPropertyIdentifierNode(node.callee);
122+
const isRenderInAssignment =
123+
isAssignmentExpression(node) &&
124+
helpers.isRenderUtil(getPropertyIdentifierNode(node.right));
125+
const isRenderInSequenceAssignment =
126+
isSequenceExpression(node) &&
127+
node.expressions.some(
128+
(expression) =>
129+
isAssignmentExpression(expression) &&
130+
helpers.isRenderUtil(getPropertyIdentifierNode(expression.right))
131+
);
98132

99133
if (
100-
!helpers.isFireEventUtil(expressionIdentifier) &&
101-
!helpers.isUserEventUtil(expressionIdentifier)
134+
!helpers.isFireEventUtil(expressionIdentifier || null) &&
135+
!helpers.isUserEventUtil(expressionIdentifier || null) &&
136+
!helpers.isRenderUtil(expressionIdentifier || null) &&
137+
!isRenderInAssignment &&
138+
!isRenderInSequenceAssignment
102139
) {
103140
return;
104141
}
@@ -112,6 +149,8 @@ export default createTestingLibraryRule<Options, MessageIds>({
112149
return {
113150
'CallExpression > ArrowFunctionExpression > BlockStatement': reportSideEffects,
114151
'CallExpression > ArrowFunctionExpression > CallExpression': reportImplicitReturnSideEffect,
152+
'CallExpression > ArrowFunctionExpression > AssignmentExpression': reportImplicitReturnSideEffect,
153+
'CallExpression > ArrowFunctionExpression > SequenceExpression': reportImplicitReturnSideEffect,
115154
'CallExpression > FunctionExpression > BlockStatement': reportSideEffects,
116155
};
117156
},

0 commit comments

Comments
 (0)