test(files): cover internal drag row to folder move
Drags server.cfg from the overlay root onto the cfg/ folder row,
asserts both that the file actually moved on disk AND that the tree
reflects the move after the debounced HTMX refresh of both parents.
Exercises the internal-drag path in uploads.js:332-366: the
custom-MIME setData/getData contract, the POST /files/move call,
and the dual scheduleRefresh(parentOf(src)) + scheduleRefresh(dst)
on success. Playwright's locator.drag_to() synthesizes setData
correctly — it relies on dataTransfer.getData(), NOT
webkitGetAsEntry which Playwright cannot fake.
Pitfalls handled inline: scoped the source/target locators to
li.file-tree-row-{file,dir} because action buttons inside the row
duplicate data-target-path + data-row-kind and would trip strict
mode. Used to_have_count instead of to_be_visible because cfg's
children div is collapsed (hidden) by default — the moved row is
in the DOM but not visually rendered until cfg is expanded.
Per docs/superpowers/plans/2026-05-17-files-overlay-e2e-handoff.md
(Tier 2 case C).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a6be29c6d2
commit
e89dd25cdd
1 changed files with 47 additions and 0 deletions
|
|
@ -453,3 +453,50 @@ def test_modal_close_on_escape_preserves_no_state(page: Page, files_overlay_serv
|
||||||
_wait_for_routed_editor(page)
|
_wait_for_routed_editor(page)
|
||||||
reopened = page.evaluate("() => window.__filesEditor.getValue()")
|
reopened = page.evaluate("() => window.__filesEditor.getValue()")
|
||||||
assert reopened == original_content
|
assert reopened == original_content
|
||||||
|
|
||||||
|
|
||||||
|
def test_drag_row_to_folder_moves_file(page: Page, files_overlay_server) -> None:
|
||||||
|
"""Drag the server.cfg row from the overlay root onto the cfg/
|
||||||
|
folder row. Asserts the file actually moved on disk AND the tree
|
||||||
|
reflects the move after the debounced HTMX refresh.
|
||||||
|
|
||||||
|
Exercises the internal-drag path in uploads.js:332-366 — the
|
||||||
|
`dataTransfer.setData("application/x-files-overlay", path)` →
|
||||||
|
`getData` round-trip → POST /files/move → schedule refresh of
|
||||||
|
both parents. Playwright's `locator.drag_to()` synthesizes the
|
||||||
|
`setData/getData` contract that this path relies on (it does NOT
|
||||||
|
require `webkitGetAsEntry`, which Playwright cannot fake).
|
||||||
|
|
||||||
|
Tree DOM gotcha: the cfg folder is collapsed by default, so its
|
||||||
|
children div is `hidden`. `scheduleRefresh("cfg")` still swaps
|
||||||
|
HTML into the hidden div — the new row exists in the DOM, just
|
||||||
|
not visible to a `to_be_visible` assertion. Using `to_have_count`
|
||||||
|
instead of `to_be_visible` accommodates this.
|
||||||
|
"""
|
||||||
|
base = files_overlay_server["base_url"]
|
||||||
|
overlay_id = files_overlay_server["overlay_id"]
|
||||||
|
overlay_root = files_overlay_server["overlay_root"]
|
||||||
|
original_content = (overlay_root / "server.cfg").read_text()
|
||||||
|
_open_overlay(page, base, overlay_id)
|
||||||
|
|
||||||
|
# Scope to the row <li>, not any inner button — delete-action
|
||||||
|
# buttons also carry data-target-path + data-row-kind, so a bare
|
||||||
|
# attribute selector resolves to multiple elements and trips
|
||||||
|
# strict mode.
|
||||||
|
source = page.locator('li.file-tree-row-file[data-target-path="server.cfg"]')
|
||||||
|
target = page.locator('li.file-tree-row-dir[data-target-path="cfg"]')
|
||||||
|
source.drag_to(target)
|
||||||
|
|
||||||
|
# Wait for both refreshes to land: old row gone from root, new row
|
||||||
|
# present (though hidden) inside cfg's children div.
|
||||||
|
expect(
|
||||||
|
page.locator('.file-tree-row-file[data-target-path="server.cfg"]')
|
||||||
|
).to_have_count(0, timeout=5000)
|
||||||
|
expect(
|
||||||
|
page.locator('.file-tree-row-file[data-target-path="cfg/server.cfg"]')
|
||||||
|
).to_have_count(1, timeout=5000)
|
||||||
|
|
||||||
|
# Disk is the load-bearing assertion — proves /files/move actually
|
||||||
|
# moved bytes, not just shuffled DOM rows.
|
||||||
|
assert not (overlay_root / "server.cfg").exists()
|
||||||
|
assert (overlay_root / "cfg" / "server.cfg").read_text() == original_content
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue