Skip to content

Commit a5f66c2

Browse files
authored
fix(no-unnecessary-act): handle optional chaining calls (#1104)
Fixes: #686
1 parent b87e733 commit a5f66c2

File tree

3 files changed

+62
-32
lines changed

3 files changed

+62
-32
lines changed

lib/node-utils/index.ts

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
isArrayExpression,
77
isArrowFunctionExpression,
88
isAssignmentExpression,
9+
isChainExpression,
910
isBlockStatement,
1011
isCallExpression,
1112
isExpressionStatement,
@@ -379,7 +380,7 @@ export function getPropertyIdentifierNode(
379380
return getPropertyIdentifierNode(node.callee);
380381
}
381382

382-
if (isExpressionStatement(node)) {
383+
if (isExpressionStatement(node) || isChainExpression(node)) {
383384
return getPropertyIdentifierNode(node.expression);
384385
}
385386

@@ -407,6 +408,10 @@ export function getDeepestIdentifierNode(
407408
return node;
408409
}
409410

411+
if (isChainExpression(node)) {
412+
return getDeepestIdentifierNode(node.expression);
413+
}
414+
410415
if (isMemberExpression(node) && ASTUtils.isIdentifier(node.property)) {
411416
return node.property;
412417
}
@@ -615,48 +620,45 @@ export function hasImportMatch(
615620
return importNode.local.name === identifierName;
616621
}
617622

618-
export function getStatementCallExpression(
619-
statement: TSESTree.Statement
620-
): TSESTree.CallExpression | undefined {
621-
if (isExpressionStatement(statement)) {
622-
const { expression } = statement;
623-
if (isCallExpression(expression)) {
624-
return expression;
625-
}
623+
function getCallExpressionFromNode(
624+
node: TSESTree.Node | null
625+
): TSESTree.CallExpression | null {
626+
if (isCallExpression(node)) {
627+
return node;
628+
}
626629

627-
if (
628-
ASTUtils.isAwaitExpression(expression) &&
629-
isCallExpression(expression.argument)
630-
) {
631-
return expression.argument;
632-
}
630+
if (isChainExpression(node)) {
631+
return getCallExpressionFromNode(node.expression);
632+
}
633633

634-
if (isAssignmentExpression(expression)) {
635-
if (isCallExpression(expression.right)) {
636-
return expression.right;
637-
}
634+
if (ASTUtils.isAwaitExpression(node)) {
635+
return getCallExpressionFromNode(node.argument);
636+
}
638637

639-
if (
640-
ASTUtils.isAwaitExpression(expression.right) &&
641-
isCallExpression(expression.right.argument)
642-
) {
643-
return expression.right.argument;
644-
}
645-
}
638+
if (isAssignmentExpression(node)) {
639+
return getCallExpressionFromNode(node.right);
646640
}
647641

648-
if (isReturnStatement(statement) && isCallExpression(statement.argument)) {
649-
return statement.argument;
642+
return null;
643+
}
644+
645+
export function getStatementCallExpression(
646+
statement: TSESTree.Statement
647+
): TSESTree.CallExpression | null {
648+
if (isExpressionStatement(statement)) {
649+
return getCallExpressionFromNode(statement.expression);
650+
}
651+
652+
if (isReturnStatement(statement)) {
653+
return getCallExpressionFromNode(statement.argument);
650654
}
651655

652656
if (isVariableDeclaration(statement)) {
653657
for (const declaration of statement.declarations) {
654-
if (isCallExpression(declaration.init)) {
655-
return declaration.init;
656-
}
658+
return getCallExpressionFromNode(declaration.init);
657659
}
658660
}
659-
return undefined;
661+
return null;
660662
}
661663

662664
/**

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ export const isVariableDeclaration = ASTUtils.isNodeOfType(
2121
export const isAssignmentExpression = ASTUtils.isNodeOfType(
2222
AST_NODE_TYPES.AssignmentExpression
2323
);
24+
export const isChainExpression = ASTUtils.isNodeOfType(
25+
AST_NODE_TYPES.ChainExpression
26+
);
2427
export const isSequenceExpression = ASTUtils.isNodeOfType(
2528
AST_NODE_TYPES.SequenceExpression
2629
);

tests/lib/rules/no-unnecessary-act.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ const validNonStrictTestCases: RuleValidTestCase[] = [
7878
})
7979
`,
8080
},
81+
{
82+
code: `// case: RTL act wrapping optional chaining call without RTL usage
83+
import { act, render } from '@testing-library/react'
84+
85+
test('valid case', async () => {
86+
act(() => {
87+
render(element);
88+
callback?.();
89+
});
90+
});
91+
`,
92+
},
8193
];
8294

8395
const validTestCases: RuleValidTestCase[] = [
@@ -140,6 +152,19 @@ const validTestCases: RuleValidTestCase[] = [
140152
act(() => stuffThatDoesNotUseRTL()).then(() => {})
141153
act(stuffThatDoesNotUseRTL().then(() => {}))
142154
});
155+
`,
156+
})),
157+
...SUPPORTED_TESTING_FRAMEWORKS.map(([testingFramework, shortName]) => ({
158+
code: `// case: ${shortName} act wrapping non-${shortName} calls
159+
import { act } from '${testingFramework}'
160+
161+
let callback: undefined | (() => void);
162+
163+
test('valid case', async () => {
164+
act(() => {
165+
callback?.();
166+
});
167+
});
143168
`,
144169
})),
145170
{

0 commit comments

Comments
 (0)