Skip to content

date: 2026-06-10 tags: [testing, pest-browser, playwright, drag-drop, dnd] status: active graduated_to:

Playwright can't reliably assert native HTML5 drag-and-drop reorder

Symptom — a browser test that drags one card onto another and asserts the new order failed intermittently ("Failed asserting that 0 is greater than 1" — the order was unchanged), even though the drag registered (the organise-mode save bar appeared and the save succeeded).

Root causepest-plugin-browser's drag($from, $to) drives native HTML5 DnD through synthetic mouse events and drops at the target's centre. The component decides drop-before vs drop-after from the cursor's Y relative to the target's midpoint, so a centre drop is non-deterministic — the resulting order isn't stable enough to assert.

Fix — split the coverage by layer. The browser test asserts the gesture round-trips (enter organise mode → drag() → save → assertNoSmoke, both items still rendered) and that a Todoist-mirror miss on save still warns; the exact reorder persistence is asserted deterministically at the controller layer (DailyPlanControllerTest posts positions → asserts the DB rows). See tests/Browser/ReorderTest.php.

Guard — this learning + the ReorderTest header comment. Convention: don't position-assert HTML5 drag-and-drop in a browser test — prove the gesture wires up there, prove the persistence math in a feature test. Candidate to graduate into .claude/rules/testing.md if it recurs.