Skip to content

Commit 9ce346d

Browse files
committed
fix(missing-playwright-await): prevent infinite recursion in checkValidity
1 parent 0d3c957 commit 9ce346d

File tree

2 files changed

+20
-5
lines changed

2 files changed

+20
-5
lines changed

src/rules/missing-playwright-await.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,5 +368,17 @@ runRuleTester('missing-playwright-await', rule, {
368368
},
369369
},
370370
},
371+
// Regression: variable passed to getByText (should not crash or false positive)
372+
{
373+
code: dedent(
374+
test(`
375+
const thisIsCausingTheBug = 'some text';
376+
const pageCover = page.getByText(thisIsCausingTheBug);
377+
const expectation = expect(pageCover, "message").toBeVisible();
378+
await page.clock.runFor(60_000);
379+
await expectation;
380+
`)
381+
),
382+
},
371383
],
372384
})

src/rules/missing-playwright-await.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,21 @@ export default createRule({
9494
...(options.customMatchers || []),
9595
])
9696

97-
function checkValidity(node: ESTree.Node) {
97+
function checkValidity(node: ESTree.Node, visited: Set<ESTree.Node>) {
9898
const parent = getParent(node)
9999
if (!parent) return false
100100

101+
if (visited.has(parent)) return false
102+
visited.add(parent)
103+
101104
// If the parent is a valid type (e.g. return or await), we don't need to
102105
// check any further.
103106
if (validTypes.has(parent.type)) return true
104107

105108
// If the parent is an array, we need to check the grandparent to see if
106109
// it's a Promise.all, or a variable.
107110
if (parent.type === 'ArrayExpression') {
108-
return checkValidity(parent)
111+
return checkValidity(parent, visited)
109112
}
110113

111114
// If the parent is a call expression, we need to check the grandparent
@@ -127,12 +130,12 @@ export default createRule({
127130

128131
for (const ref of scope.references) {
129132
const refParent = (ref.identifier as Rule.Node).parent
130-
133+
if (visited.has(refParent)) continue
131134
// If the parent of the reference is valid, we can immediately return
132135
// true. Otherwise, we'll check the validity of the parent to continue
133136
// the loop.
134137
if (validTypes.has(refParent.type)) return true
135-
if (checkValidity(refParent)) return true
138+
if (checkValidity(refParent, visited)) return true
136139
}
137140
}
138141

@@ -145,7 +148,7 @@ export default createRule({
145148
if (call?.type !== 'step' && call?.type !== 'expect') return
146149

147150
const result = getCallType(call, awaitableMatchers)
148-
const isValid = result ? checkValidity(node) : false
151+
const isValid = result ? checkValidity(node, new Set()) : false
149152

150153
if (result && !isValid) {
151154
context.report({

0 commit comments

Comments
 (0)