Problem
src/tools.ts:511-534 — PlaywrightTools.dragAndDrop() uses a manual sequence:
sourceLocator.hover() → page.mouse.down() → targetLocator.hover() ×2 → page.mouse.up()
This has several issues:
- Layout-shift race: Between
hover() and mouse.down(), the page could re-render, moving the element. mouse.down() fires at stale coordinates.
- No element-under-cursor check: If
hover() succeeded but the element was already detached, mouse.down() silently presses at current position — nothing is actually grabbed.
- Double
hover() on target (line 527-528) is a hack to force dragover events, suggesting the event dispatch is unreliable.
- Silent success: The method always returns
{ success: true } — any failure in the drag sequence is swallowed.
- No tests:
tools.ts has zero test coverage (694 lines).
Suggested fix
Replace the manual sequence with Playwright's built-in locator.dragTo(target):
await sourceLocator.dragTo(targetLocator, { timeout: LOCATOR_ACTION_TIMEOUT });
Playwright's dragTo() handles correct event ordering (mousedown → mousemove → mouseup → dragstart → drag → dragenter → dragover → drop → dragend), cross-browser quirks, and throws on missing elements.
Impact
Reproducible in any test that uses the browser_drag_and_drop tool with dynamic content — e.g., drag-and-drop on a list that re-renders after the source hover.
Problem
src/tools.ts:511-534—PlaywrightTools.dragAndDrop()uses a manual sequence:sourceLocator.hover() → page.mouse.down() → targetLocator.hover() ×2 → page.mouse.up()
This has several issues:
hover()andmouse.down(), the page could re-render, moving the element.mouse.down()fires at stale coordinates.hover()succeeded but the element was already detached,mouse.down()silently presses at current position — nothing is actually grabbed.hover()on target (line 527-528) is a hack to forcedragoverevents, suggesting the event dispatch is unreliable.{ success: true }— any failure in the drag sequence is swallowed.tools.tshas zero test coverage (694 lines).Suggested fix
Replace the manual sequence with Playwright's built-in
locator.dragTo(target):