[Bug]: addLocatorHandler() appears to intercept its own action during expect().toPass() retries
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- playwright, typescript
- Domain
- testing-qa
Research direction
Start by reproducing the issue with the trace and Playwright 1.64.0, focusing on page.addLocatorHandler() actions inside expect().toPass() retries. Trace whether the handler can re-enter while its callback is running and identify whether the observed post-timeout actions share the same cause. Done means the cause is established and the handler can dismiss the modal without timing out, or the documented behavior and safe callback usage are clarified.
Written by the indexing model from the issue text.
Description
Version
1.64.0
Steps to reproduce
-
Inspect the trace at the handler's click action. As shown in the attached trace screenshots, the handler begins clicking YES, but Playwright logs the following message before the click completes:
found locator('body').getByText('Are you sure...'), intercepting action to run the handler. This suggests that the same handler is intercepting an action initiated by its own callback. -
Observe the resulting timeout. The modal is not dismissed as expected, and the test eventually fails with a timeout. The trace also appears to show other test actions occurring around or after the reported test failure. Take a look at the source panel which demonstrates the handler self-intercepting. (Can also be seen in images below.)
SUMMARY
I have a test in which a Past Date confirmation modal can appear intermittently during normal UI interactions. To handle this, I register a locator handler that clicks YES whenever the modal appears.
Later in the test, several UI interactions execute inside an expect(async () => { ... }).toPass() block. When the modal appears during these interactions, Playwright invokes the handler as expected. However, the trace indicates that the handler's attempt to click YES is itself intercepted by the same locator handler.
This appears to cause the handler to be invoked again before its current callback has completed, preventing the modal from being dismissed and eventually causing the test to time out.
Expected behavior
The handler should be able to dismiss the modal without recursively intercepting its own dismissal action. Once the modal is dismissed, the interrupted action should resume normally.
If repeated handler invocation is expected under these circumstances, the documentation should clarify the relevant behavior and how handler callbacks should safely interact with their own trigger elements.
Actual behavior
- The locator handler is triggered when the modal appears.
- While the handler is executing its dismissal click, the same locator is reported as intercepting the action to run the handler again.
- The dismissal action does not reliably complete.
- The test times out, and the trace makes it difficult to distinguish the original handler invocation from subsequent invocations.
Additional context
Questions for investigation
- Does Playwright prevent a locator handler from being re-entered while its callback is still executing?
- Can an action performed inside a handler trigger the same handler while the handler's locator remains visible?
- Can retries introduced by expect().toPass() expose a race condition involving an active locator handler?
- Are the apparent post-timeout actions a separate issue involving asynchronous cleanup or trace reporting?
Impact
Intermittent DOM modals can cause otherwise valid UI tests to time out when handled through page.addLocatorHandler(). The issue is particularly difficult to diagnose when the interactions are inside expect().toPass(), because the trace appears to show the handler intercepting its own action rather than completing the intended dismissal.
Environment
System:
OS: macOS 26.5.2
CPU: (14) arm64 Apple M4 Pro
Memory: 1.07 GB / 48.00 GB
Binaries:
Node: 24.7.0 - /Users/temi/.nvm/versions/node/v24.7.0/bin/node
npm: 11.5.1 - /Users/temi/.nvm/versions/node/v24.7.0/bin/npm
IDEs:
VSCode: 1.117.0 - /usr/local/bin/code
Languages:
Bash: 3.2.57 - /bin/bash
npmPackages:
@playwright/test: ^1.64.0 => 1.64.0
- Dominant language
- TypeScript
- Stars
- 98.5k
- Forks
- 6.7k
- Avg merge
- 15h 43m
- Merged PRs (30d)
- 279
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from microsoft/playwright
-
Difficulty 1/5 Under an hour Newbie friendliness 70/100
microsoft/playwright#43640 ·
Maintainers usually reply within 1 day
-
[Bug]: `playwright install` hangs silently for ~8 minutes when PLAYWRIGHT_BROWSERS_PATH is not writablePossibly taken @dcrousso claimed this 2 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
microsoft/playwright#43606 ·
Maintainers usually reply within 1 day
-
[Feature]: Set `this.name` in `TargetClosedError` constructorMay be free again @LeonxLJX claimed this 52 days ago, and no pull request is open. OpenP3-collecting-feedback
Difficulty 1/5 Under an hour Newbie friendliness 86/100
microsoft/playwright#42522 · 7 comments ·
Maintainers usually reply within 1 day
-
[Bug]: connectOverCDP kills the process with an uncaught assertion when an attached target has no browserContextIdPossibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 3/5 1-2 days Newbie friendliness 68/100
microsoft/playwright#43638 ·
Maintainers usually reply within 1 day
-
needs-triage-win
Difficulty 3/5 1-2 days Newbie friendliness 58/100
microsoft/playwright#43632 · 2 comments ·
Maintainers usually reply within 1 day
All issues in microsoft/playwright
Similar issues
-
a10y a10y-audit ai-driven-qa claude
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
linagora/twake-directory-manager#219 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 79/100
Maintainers usually reply within 1 day
-
0️⃣ phase/new
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
Pulse v7: buildPreferencesFromTelos() bypasses telosSectionOrFile(), renders empty on unified-TELOS installsPossibly taken @zephyr91 claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
danielmiessler/LifeOS#2393 ·
Maintainers usually reply within 4 days