@@ -111,6 +111,230 @@ export default createTestingLibraryRule<Options, MessageIds>({
111111 } ) ;
112112 }
113113
114+ function getWrongQueryNameInAssertion (
115+ node : TSESTree . ArrowFunctionExpression
116+ ) {
117+ if (
118+ ! isCallExpression ( node . body ) ||
119+ ! isMemberExpression ( node . body . callee )
120+ ) {
121+ return null ;
122+ }
123+
124+ // expect(getByText).toBeInTheDocument() shape
125+ if (
126+ isCallExpression ( node . body . callee . object ) &&
127+ isCallExpression ( node . body . callee . object . arguments [ 0 ] ) &&
128+ ASTUtils . isIdentifier ( node . body . callee . object . arguments [ 0 ] . callee )
129+ ) {
130+ return node . body . callee . object . arguments [ 0 ] . callee . name ;
131+ }
132+
133+ if ( ! ASTUtils . isIdentifier ( node . body . callee . property ) ) {
134+ return null ;
135+ }
136+
137+ // expect(screen.getByText).toBeInTheDocument() shape
138+ if (
139+ isCallExpression ( node . body . callee . object ) &&
140+ isCallExpression ( node . body . callee . object . arguments [ 0 ] ) &&
141+ isMemberExpression ( node . body . callee . object . arguments [ 0 ] . callee ) &&
142+ ASTUtils . isIdentifier (
143+ node . body . callee . object . arguments [ 0 ] . callee . property
144+ )
145+ ) {
146+ return node . body . callee . object . arguments [ 0 ] . callee . property . name ;
147+ }
148+
149+ // expect(screen.getByText).not shape
150+ if (
151+ isMemberExpression ( node . body . callee . object ) &&
152+ isCallExpression ( node . body . callee . object . object ) &&
153+ isCallExpression ( node . body . callee . object . object . arguments [ 0 ] ) &&
154+ isMemberExpression (
155+ node . body . callee . object . object . arguments [ 0 ] . callee
156+ ) &&
157+ ASTUtils . isIdentifier (
158+ node . body . callee . object . object . arguments [ 0 ] . callee . property
159+ )
160+ ) {
161+ return node . body . callee . object . object . arguments [ 0 ] . callee . property . name ;
162+ }
163+
164+ // expect(getByText).not shape
165+ if (
166+ isMemberExpression ( node . body . callee . object ) &&
167+ isCallExpression ( node . body . callee . object . object ) &&
168+ isCallExpression ( node . body . callee . object . object . arguments [ 0 ] ) &&
169+ ASTUtils . isIdentifier (
170+ node . body . callee . object . object . arguments [ 0 ] . callee
171+ )
172+ ) {
173+ return node . body . callee . object . object . arguments [ 0 ] . callee . name ;
174+ }
175+
176+ return node . body . callee . property . name ;
177+ }
178+
179+ function getWrongQueryName ( node : TSESTree . ArrowFunctionExpression ) {
180+ if ( ! isCallExpression ( node . body ) ) {
181+ return null ;
182+ }
183+
184+ // expect(() => getByText) and expect(() => screen.getByText) shape
185+ if (
186+ ASTUtils . isIdentifier ( node . body . callee ) &&
187+ helpers . isSyncQuery ( node . body . callee )
188+ ) {
189+ return node . body . callee . name ;
190+ }
191+
192+ return getWrongQueryNameInAssertion ( node ) ;
193+ }
194+
195+ function getCaller ( node : TSESTree . ArrowFunctionExpression ) {
196+ if (
197+ ! isCallExpression ( node . body ) ||
198+ ! isMemberExpression ( node . body . callee )
199+ ) {
200+ return null ;
201+ }
202+
203+ if ( ASTUtils . isIdentifier ( node . body . callee . object ) ) {
204+ // () => screen.getByText
205+ return node . body . callee . object . name ;
206+ }
207+
208+ if (
209+ // expect()
210+ isCallExpression ( node . body . callee . object ) &&
211+ ASTUtils . isIdentifier ( node . body . callee . object . callee ) &&
212+ isCallExpression ( node . body . callee . object . arguments [ 0 ] ) &&
213+ isMemberExpression ( node . body . callee . object . arguments [ 0 ] . callee ) &&
214+ ASTUtils . isIdentifier (
215+ node . body . callee . object . arguments [ 0 ] . callee . object
216+ )
217+ ) {
218+ return node . body . callee . object . arguments [ 0 ] . callee . object . name ;
219+ }
220+
221+ if (
222+ // expect().not
223+ isMemberExpression ( node . body . callee . object ) &&
224+ isCallExpression ( node . body . callee . object . object ) &&
225+ isCallExpression ( node . body . callee . object . object . arguments [ 0 ] ) &&
226+ isMemberExpression (
227+ node . body . callee . object . object . arguments [ 0 ] . callee
228+ ) &&
229+ ASTUtils . isIdentifier (
230+ node . body . callee . object . object . arguments [ 0 ] . callee . object
231+ )
232+ ) {
233+ return node . body . callee . object . object . arguments [ 0 ] . callee . object . name ;
234+ }
235+
236+ return null ;
237+ }
238+
239+ function isSyncQuery ( node : TSESTree . ArrowFunctionExpression ) {
240+ if ( ! isCallExpression ( node . body ) ) {
241+ return false ;
242+ }
243+
244+ const isQuery =
245+ ASTUtils . isIdentifier ( node . body . callee ) &&
246+ helpers . isSyncQuery ( node . body . callee ) ;
247+
248+ const isWrappedInPresenceAssert =
249+ isMemberExpression ( node . body . callee ) &&
250+ isCallExpression ( node . body . callee . object ) &&
251+ isCallExpression ( node . body . callee . object . arguments [ 0 ] ) &&
252+ ASTUtils . isIdentifier ( node . body . callee . object . arguments [ 0 ] . callee ) &&
253+ helpers . isSyncQuery ( node . body . callee . object . arguments [ 0 ] . callee ) &&
254+ helpers . isPresenceAssert ( node . body . callee ) ;
255+
256+ const isWrappedInNegatedPresenceAssert =
257+ isMemberExpression ( node . body . callee ) &&
258+ isMemberExpression ( node . body . callee . object ) &&
259+ isCallExpression ( node . body . callee . object . object ) &&
260+ isCallExpression ( node . body . callee . object . object . arguments [ 0 ] ) &&
261+ ASTUtils . isIdentifier (
262+ node . body . callee . object . object . arguments [ 0 ] . callee
263+ ) &&
264+ helpers . isSyncQuery (
265+ node . body . callee . object . object . arguments [ 0 ] . callee
266+ ) &&
267+ helpers . isPresenceAssert ( node . body . callee . object ) ;
268+
269+ return (
270+ isQuery || isWrappedInPresenceAssert || isWrappedInNegatedPresenceAssert
271+ ) ;
272+ }
273+
274+ function isScreenSyncQuery ( node : TSESTree . ArrowFunctionExpression ) {
275+ if ( ! isArrowFunctionExpression ( node ) || ! isCallExpression ( node . body ) ) {
276+ return false ;
277+ }
278+
279+ if (
280+ ! isMemberExpression ( node . body . callee ) ||
281+ ! ASTUtils . isIdentifier ( node . body . callee . property )
282+ ) {
283+ return false ;
284+ }
285+
286+ if (
287+ ! ASTUtils . isIdentifier ( node . body . callee . object ) &&
288+ ! isCallExpression ( node . body . callee . object ) &&
289+ ! isMemberExpression ( node . body . callee . object )
290+ ) {
291+ return false ;
292+ }
293+
294+ const isWrappedInPresenceAssert =
295+ helpers . isPresenceAssert ( node . body . callee ) &&
296+ isCallExpression ( node . body . callee . object ) &&
297+ isCallExpression ( node . body . callee . object . arguments [ 0 ] ) &&
298+ isMemberExpression ( node . body . callee . object . arguments [ 0 ] . callee ) &&
299+ ASTUtils . isIdentifier (
300+ node . body . callee . object . arguments [ 0 ] . callee . object
301+ ) ;
302+
303+ const isWrappedInNegatedPresenceAssert =
304+ isMemberExpression ( node . body . callee . object ) &&
305+ helpers . isPresenceAssert ( node . body . callee . object ) &&
306+ isCallExpression ( node . body . callee . object . object ) &&
307+ isCallExpression ( node . body . callee . object . object . arguments [ 0 ] ) &&
308+ isMemberExpression ( node . body . callee . object . object . arguments [ 0 ] . callee ) ;
309+
310+ return (
311+ helpers . isSyncQuery ( node . body . callee . property ) ||
312+ isWrappedInPresenceAssert ||
313+ isWrappedInNegatedPresenceAssert
314+ ) ;
315+ }
316+
317+ function getQueryArguments ( node : TSESTree . CallExpression ) {
318+ if (
319+ isMemberExpression ( node . callee ) &&
320+ isCallExpression ( node . callee . object ) &&
321+ isCallExpression ( node . callee . object . arguments [ 0 ] )
322+ ) {
323+ return node . callee . object . arguments [ 0 ] . arguments ;
324+ }
325+
326+ if (
327+ isMemberExpression ( node . callee ) &&
328+ isMemberExpression ( node . callee . object ) &&
329+ isCallExpression ( node . callee . object . object ) &&
330+ isCallExpression ( node . callee . object . object . arguments [ 0 ] )
331+ ) {
332+ return node . callee . object . object . arguments [ 0 ] . arguments ;
333+ }
334+
335+ return node . arguments ;
336+ }
337+
114338 return {
115339 'AwaitExpression > CallExpression' ( node : TSESTree . CallExpression ) {
116340 if (
@@ -122,27 +346,32 @@ export default createTestingLibraryRule<Options, MessageIds>({
122346 // ensure the only argument is an arrow function expression - if the arrow function is a block
123347 // we skip it
124348 const argument = node . arguments [ 0 ] ;
125- if ( ! isArrowFunctionExpression ( argument ) ) {
126- return ;
127- }
128- if ( ! isCallExpression ( argument . body ) ) {
349+ if (
350+ ! isArrowFunctionExpression ( argument ) ||
351+ ! isCallExpression ( argument . body )
352+ ) {
129353 return ;
130354 }
131355
132356 const waitForMethodName = node . callee . name ;
133357
134358 // ensure here it's one of the sync methods that we are calling
135- if (
136- isMemberExpression ( argument . body . callee ) &&
137- ASTUtils . isIdentifier ( argument . body . callee . property ) &&
138- ASTUtils . isIdentifier ( argument . body . callee . object ) &&
139- helpers . isSyncQuery ( argument . body . callee . property )
140- ) {
359+ if ( isScreenSyncQuery ( argument ) ) {
360+ const caller = getCaller ( argument ) ;
361+
362+ if ( ! caller ) {
363+ return ;
364+ }
365+
141366 // shape of () => screen.getByText
142- const fullQueryMethod = argument . body . callee . property . name ;
143- const caller = argument . body . callee . object . name ;
367+ const fullQueryMethod = getWrongQueryName ( argument ) ;
368+
369+ if ( ! fullQueryMethod ) {
370+ return ;
371+ }
372+
144373 const queryVariant = getFindByQueryVariant ( fullQueryMethod ) ;
145- const callArguments = argument . body . arguments ;
374+ const callArguments = getQueryArguments ( argument . body ) ;
146375 const queryMethod = fullQueryMethod . split ( 'By' ) [ 1 ] ;
147376
148377 reportInvalidUsage ( node , {
@@ -166,17 +395,21 @@ export default createTestingLibraryRule<Options, MessageIds>({
166395 } ) ;
167396 return ;
168397 }
169- if (
170- ! ASTUtils . isIdentifier ( argument . body . callee ) ||
171- ! helpers . isSyncQuery ( argument . body . callee )
172- ) {
398+
399+ if ( ! isSyncQuery ( argument ) ) {
173400 return ;
174401 }
402+
175403 // shape of () => getByText
176- const fullQueryMethod = argument . body . callee . name ;
404+ const fullQueryMethod = getWrongQueryName ( argument ) ;
405+
406+ if ( ! fullQueryMethod ) {
407+ return ;
408+ }
409+
177410 const queryMethod = fullQueryMethod . split ( 'By' ) [ 1 ] ;
178411 const queryVariant = getFindByQueryVariant ( fullQueryMethod ) ;
179- const callArguments = argument . body . arguments ;
412+ const callArguments = getQueryArguments ( argument . body ) ;
180413
181414 reportInvalidUsage ( node , {
182415 queryMethod,
0 commit comments