diff --git a/l4d2web/tests/e2e/test_files_overlay.py b/l4d2web/tests/e2e/test_files_overlay.py index ad80b01..f7a42b7 100644 --- a/l4d2web/tests/e2e/test_files_overlay.py +++ b/l4d2web/tests/e2e/test_files_overlay.py @@ -175,3 +175,60 @@ def test_create_new_file_409_askConflict_keep_both(page: Page, files_overlay_ser expect( page.locator('.file-tree-row-file[data-target-path="cfg (1)"]') ).to_be_visible(timeout=5000) + + +def test_open_binary_file_renders_replace_ui(page: Page, files_overlay_server) -> None: + """Open icon.png and assert the routed editor renders the binary + branch of overlay_file_editor.html — replace-zone present, save + button labelled "Replace" and disabled until a file is queued or + the filename is edited. + + The same `/files/edit?path=...` route serves both text and binary + modes; the server picks the template branch based on is_editable + + a magic-byte check. This test pins the binary contract: the user + cannot save by accident on a fresh open, and the queue UI is wired + correctly. + + Pins: + * .files-editor-binary[data-rel-path="icon.png"] exists (the + data-rel-path stable hook for save logic). + * Save button has visible text "Replace" + the `disabled` + attribute is set on open. + * .files-editor-replace-zone + .files-editor-replace-browse + + the hidden file exist. + * Download link points back at /files/download?path=icon.png. + """ + base = files_overlay_server["base_url"] + overlay_id = files_overlay_server["overlay_id"] + _open_overlay(page, base, overlay_id) + + page.click('button.file-tree-name-button[data-target-path="icon.png"]') + + fragment = page.locator("#files-editor-fragment") + expect(fragment).to_be_visible(timeout=5000) + + binary_panel = page.locator('.files-editor-binary[data-rel-path="icon.png"]') + expect(binary_panel).to_be_visible(timeout=5000) + + save_btn = page.locator(".files-editor-save") + expect(save_btn).to_have_text("Replace") + expect(save_btn).to_be_disabled() + + expect(page.locator(".files-editor-replace-zone")).to_be_visible() + expect(page.locator(".files-editor-replace-browse")).to_be_visible() + # The file input is type=file hidden — Playwright's "visible" + # assertions treat hidden inputs as not visible, so check + # attached + the type instead. + expect(page.locator(".files-editor-replace-input")).to_have_attribute( + "type", "file" + ) + # Download link points back at the overlay's /files/download. + download = page.locator("a.files-editor-download") + expect(download).to_have_attribute( + "href", f"/overlays/{overlay_id}/files/download?path=icon.png" + ) + # In binary mode there's no