Skip to content

Commit 0f2eb34

Browse files
committed
feat(no-unnecessary-act): detect error for empty callbacks
1 parent 20795c5 commit 0f2eb34

File tree

2 files changed

+67
-5
lines changed

2 files changed

+67
-5
lines changed

lib/rules/no-unnecessary-act.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
getDeepestIdentifierNode,
55
getPropertyIdentifierNode,
66
getStatementCallExpression,
7+
isEmptyFunction,
78
} from '../node-utils';
89

910
export const RULE_NAME = 'no-unnecessary-act';
@@ -64,11 +65,15 @@ export default createTestingLibraryRule<[], MessageIds>({
6465
function checkNoUnnecessaryActFromBlockStatement(
6566
blockStatementNode: TSESTree.BlockStatement
6667
) {
67-
const callExpressionNode = blockStatementNode?.parent?.parent as
68+
const functionNode = blockStatementNode?.parent as
69+
| TSESTree.FunctionExpression
70+
| TSESTree.ArrowFunctionExpression
71+
| undefined;
72+
const callExpressionNode = functionNode?.parent as
6873
| TSESTree.CallExpression
6974
| undefined;
7075

71-
if (!callExpressionNode) {
76+
if (!callExpressionNode || !functionNode) {
7277
return;
7378
}
7479

@@ -84,7 +89,14 @@ export default createTestingLibraryRule<[], MessageIds>({
8489
return;
8590
}
8691

87-
// TODO: check if empty function body
92+
if (isEmptyFunction(functionNode)) {
93+
context.report({
94+
node: callExpressionIdentifier,
95+
messageId: 'noUnnecessaryActEmptyFunction',
96+
});
97+
98+
return;
99+
}
88100

89101
if (hasNonTestingLibraryCall(blockStatementNode.body)) {
90102
return;

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

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ ruleTester.run(RULE_NAME, rule, {
9696
9797
test('valid case', async () => {
9898
act(() => {
99-
render(<Foo />);
99+
render(element);
100100
stuffThatDoesNotUseRTL();
101101
});
102102
@@ -112,6 +112,39 @@ ruleTester.run(RULE_NAME, rule, {
112112
});
113113
`,
114114
},
115+
{
116+
settings: {
117+
'testing-library/utils-module': 'test-utils',
118+
},
119+
code: `// case: non-RTL act wrapping RTL - AGR disabled
120+
import { act } from 'somewhere-else'
121+
import { waitFor } from '@testing-library/react'
122+
123+
test('valid case', async () => {
124+
act(() => {
125+
waitFor();
126+
});
127+
128+
await act(async () => {
129+
waitFor();
130+
});
131+
132+
act(function() {
133+
waitFor();
134+
});
135+
136+
act(function() {
137+
return waitFor();
138+
});
139+
140+
act(() => waitFor());
141+
142+
act(() => {})
143+
await act(async () => {})
144+
act(function() {})
145+
});
146+
`,
147+
},
115148
],
116149
invalid: [
117150
{
@@ -317,8 +350,25 @@ ruleTester.run(RULE_NAME, rule, {
317350
},
318351
],
319352
},
353+
{
354+
code: `// case: RTL act wrapping empty callback
355+
import { act } from '@testing-library/react'
356+
357+
test('invalid case', async () => {
358+
await act(async () => {})
359+
act(() => {})
360+
await act(async function () {})
361+
act(function () {})
362+
})
363+
`,
364+
errors: [
365+
{ messageId: 'noUnnecessaryActEmptyFunction', line: 5, column: 15 },
366+
{ messageId: 'noUnnecessaryActEmptyFunction', line: 6, column: 9 },
367+
{ messageId: 'noUnnecessaryActEmptyFunction', line: 7, column: 15 },
368+
{ messageId: 'noUnnecessaryActEmptyFunction', line: 8, column: 9 },
369+
],
370+
},
320371

321-
// TODO case: RTL act wrapping empty callback
322372
// TODO case: RTU act wrapping RTL calls - callbacks with body (BlockStatement)
323373
// TODO case: RTU act wrapping RTL calls - callbacks with return
324374
// TODO case: RTU act wrapping empty callback

0 commit comments

Comments
 (0)