Skip to content

Commit 63dfaa6

Browse files
committed
refactor: simplify a bit
1 parent e690b9b commit 63dfaa6

File tree

1 file changed

+72
-65
lines changed

1 file changed

+72
-65
lines changed

lib/rules/await-async-events.ts

Lines changed: 72 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ export default createTestingLibraryRule<Options, MessageIds>({
8989
// Track variables assigned from userEvent.setup() (directly or via destructuring)
9090
const userEventSetupVars = new Set<string>();
9191

92-
// Temporary: Map function names to property names that are assigned from userEvent.setup()
93-
const tempSetupFunctionProps = new Map<string, Set<string>>();
92+
// Track functions that return userEvent.setup() instances and their property names
93+
const setupFunctions = new Map<string, Set<string>>();
9494

9595
function reportUnhandledNode({
9696
node,
@@ -121,6 +121,32 @@ export default createTestingLibraryRule<Options, MessageIds>({
121121
}
122122
}
123123

124+
function isUserEventSetupCall(node: TSESTree.Node): boolean {
125+
return (
126+
node.type === AST_NODE_TYPES.CallExpression &&
127+
node.callee.type === AST_NODE_TYPES.MemberExpression &&
128+
node.callee.object.type === AST_NODE_TYPES.Identifier &&
129+
node.callee.object.name === USER_EVENT_NAME &&
130+
node.callee.property.type === AST_NODE_TYPES.Identifier &&
131+
node.callee.property.name === USER_EVENT_SETUP_FUNCTION_NAME
132+
);
133+
}
134+
135+
function findFunctionName(node: TSESTree.Node): string | null {
136+
let current: TSESTree.Node | undefined = node;
137+
while (current) {
138+
if (
139+
current.type === AST_NODE_TYPES.FunctionDeclaration ||
140+
current.type === AST_NODE_TYPES.FunctionExpression ||
141+
current.type === AST_NODE_TYPES.ArrowFunctionExpression
142+
) {
143+
return getFunctionName(current);
144+
}
145+
current = current.parent;
146+
}
147+
return null;
148+
}
149+
124150
const eventModules =
125151
typeof options.eventModule === 'string'
126152
? [options.eventModule]
@@ -131,39 +157,37 @@ export default createTestingLibraryRule<Options, MessageIds>({
131157
return {
132158
// Track variables assigned from userEvent.setup() and destructuring from setup functions
133159
VariableDeclarator(node: TSESTree.VariableDeclarator) {
160+
if (!isUserEventEnabled) return;
161+
134162
// Direct assignment: const user = userEvent.setup();
135163
if (
136-
isUserEventEnabled &&
137164
node.init &&
138-
node.init.type === AST_NODE_TYPES.CallExpression &&
139-
node.init.callee.type === AST_NODE_TYPES.MemberExpression &&
140-
node.init.callee.object.type === AST_NODE_TYPES.Identifier &&
141-
node.init.callee.object.name === USER_EVENT_NAME &&
142-
node.init.callee.property.type === AST_NODE_TYPES.Identifier &&
143-
node.init.callee.property.name === USER_EVENT_SETUP_FUNCTION_NAME &&
165+
isUserEventSetupCall(node.init) &&
144166
node.id.type === AST_NODE_TYPES.Identifier
145167
) {
146168
userEventSetupVars.add(node.id.name);
147169
}
148170

149171
// Destructuring: const { user, myUser: alias } = setup(...)
150172
if (
151-
isUserEventEnabled &&
152173
node.id.type === AST_NODE_TYPES.ObjectPattern &&
153174
node.init &&
154175
node.init.type === AST_NODE_TYPES.CallExpression &&
155-
node.init.callee.type === AST_NODE_TYPES.Identifier &&
156-
tempSetupFunctionProps.has(node.init.callee.name)
176+
node.init.callee.type === AST_NODE_TYPES.Identifier
157177
) {
158-
const setupProps = tempSetupFunctionProps.get(node.init.callee.name)!;
159-
for (const prop of node.id.properties) {
160-
if (
161-
prop.type === AST_NODE_TYPES.Property &&
162-
prop.key.type === AST_NODE_TYPES.Identifier &&
163-
setupProps.has(prop.key.name) &&
164-
prop.value.type === AST_NODE_TYPES.Identifier
165-
) {
166-
userEventSetupVars.add(prop.value.name);
178+
const functionName = node.init.callee.name;
179+
const setupProps = setupFunctions.get(functionName);
180+
181+
if (setupProps) {
182+
for (const prop of node.id.properties) {
183+
if (
184+
prop.type === AST_NODE_TYPES.Property &&
185+
prop.key.type === AST_NODE_TYPES.Identifier &&
186+
setupProps.has(prop.key.name) &&
187+
prop.value.type === AST_NODE_TYPES.Identifier
188+
) {
189+
userEventSetupVars.add(prop.value.name);
190+
}
167191
}
168192
}
169193
}
@@ -172,54 +196,37 @@ export default createTestingLibraryRule<Options, MessageIds>({
172196
// Track functions that return { ...: userEvent.setup(), ... }
173197
ReturnStatement(node: TSESTree.ReturnStatement) {
174198
if (
175-
isUserEventEnabled &&
176-
node.argument &&
177-
node.argument.type === AST_NODE_TYPES.ObjectExpression
199+
!isUserEventEnabled ||
200+
!node.argument ||
201+
node.argument.type !== AST_NODE_TYPES.ObjectExpression
178202
) {
179-
const setupProps = new Set<string>();
180-
for (const prop of node.argument.properties) {
181-
if (
182-
prop.type === AST_NODE_TYPES.Property &&
183-
prop.key.type === AST_NODE_TYPES.Identifier
203+
return;
204+
}
205+
206+
const setupProps = new Set<string>();
207+
for (const prop of node.argument.properties) {
208+
if (
209+
prop.type === AST_NODE_TYPES.Property &&
210+
prop.key.type === AST_NODE_TYPES.Identifier
211+
) {
212+
// Direct: foo: userEvent.setup()
213+
if (isUserEventSetupCall(prop.value)) {
214+
setupProps.add(prop.key.name);
215+
}
216+
// Indirect: foo: u, where u is a userEvent.setup() var
217+
else if (
218+
prop.value.type === AST_NODE_TYPES.Identifier &&
219+
userEventSetupVars.has(prop.value.name)
184220
) {
185-
// Direct: foo: userEvent.setup()
186-
if (
187-
prop.value.type === AST_NODE_TYPES.CallExpression &&
188-
prop.value.callee.type === AST_NODE_TYPES.MemberExpression &&
189-
prop.value.callee.object.type === AST_NODE_TYPES.Identifier &&
190-
prop.value.callee.object.name === USER_EVENT_NAME &&
191-
prop.value.callee.property.type === AST_NODE_TYPES.Identifier &&
192-
prop.value.callee.property.name ===
193-
USER_EVENT_SETUP_FUNCTION_NAME
194-
) {
195-
setupProps.add(prop.key.name);
196-
}
197-
// Indirect: foo: u, where u is a userEvent.setup() var
198-
else if (
199-
prop.value.type === AST_NODE_TYPES.Identifier &&
200-
userEventSetupVars.has(prop.value.name)
201-
) {
202-
setupProps.add(prop.key.name);
203-
}
221+
setupProps.add(prop.key.name);
204222
}
205223
}
206-
if (setupProps.size > 0) {
207-
// Find the function this return is in
208-
let parent: TSESTree.Node | undefined = node.parent;
209-
while (parent) {
210-
if (
211-
parent.type === AST_NODE_TYPES.FunctionDeclaration ||
212-
parent.type === AST_NODE_TYPES.FunctionExpression ||
213-
parent.type === AST_NODE_TYPES.ArrowFunctionExpression
214-
) {
215-
const name = getFunctionName(parent);
216-
if (name) {
217-
tempSetupFunctionProps.set(name, setupProps);
218-
}
219-
break;
220-
}
221-
parent = parent.parent;
222-
}
224+
}
225+
226+
if (setupProps.size > 0) {
227+
const functionName = findFunctionName(node);
228+
if (functionName) {
229+
setupFunctions.set(functionName, setupProps);
223230
}
224231
}
225232
},

0 commit comments

Comments
 (0)