mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-10-27 08:12:22 +01:00
61 lines
3.2 KiB
Python
61 lines
3.2 KiB
Python
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
SRC = ROOT / "static/js/editor/clipboard-and-drop.js"
|
|
|
|
|
|
def test_editor_paste_owns_clipboard_images_while_editor_open():
|
|
"""Pasting an image with the editor open must not fall through to chat.
|
|
|
|
The editor wires a window-capture ``paste`` listener. The global chat
|
|
attach listener in ``static/app.js`` also listens on ``window`` (bubble)
|
|
and stages any ``item.kind === 'file'`` clipboard entry into the chatbox.
|
|
If the editor's listener bailed whenever the event target was *any*
|
|
input/textarea/``[role=dialog]``, then a paste whose focus sat on the chat
|
|
composer behind the editor modal went to the chatbox and never reached the
|
|
canvas. The guard must only defer to editable fields that live INSIDE the
|
|
editor container — and it must NOT include ``[role=dialog]``, because the
|
|
editor itself sits inside the gallery modal's ``role=dialog`` content.
|
|
"""
|
|
src = SRC.read_text(encoding="utf-8")
|
|
assert "wireClipboardAndDrop" in src
|
|
# The bail-out must be scoped to targets inside the editor.
|
|
assert "const insideEditor = target && container && container.contains(target);" in src
|
|
assert (
|
|
"if (insideEditor && (target.isContentEditable || "
|
|
"target.closest?.('input, textarea, select'))) return;"
|
|
) in src
|
|
# ``[role="dialog"]`` must NOT appear in the paste guard (the editor lives
|
|
# inside the gallery modal's role=dialog modal-content).
|
|
assert "target.closest?.('input, textarea, select, [role=\"dialog\"]')" not in src
|
|
# Capture-phase interception must preventDefault + stop the chat listener.
|
|
assert "e.stopImmediatePropagation();" in src
|
|
assert "e.preventDefault();" in src
|
|
|
|
|
|
def test_editor_ctrl_v_pastes_the_internal_selection_clipboard():
|
|
"""Ctrl/Cmd+V must not shadow a newer OS-clipboard image.
|
|
|
|
Intercepting the keystroke (preventDefault) bypasses the browser's paste
|
|
event and always re-pasted ``state.internalClipboard``, so a screenshot
|
|
taken outside the gallery could never be pasted. The key handler may only
|
|
fall back to the internal copy when the paste event delivered no image
|
|
(insecure origin: copy never reaches the OS clipboard).
|
|
"""
|
|
src = SRC.read_text(encoding="utf-8")
|
|
# Shared, hoisted paste helper (also used by the native paste listener).
|
|
assert "const pasteAsLayer = (imgSource, label, offset = { x: 0, y: 0 }) => {" in src
|
|
# The paste listener must prefer real clipboard images.
|
|
assert "const imageItem = Array.from(e.clipboardData?.items || [])" in src
|
|
# Deferred keyboard fallback for the internal clipboard.
|
|
assert "window.addEventListener('keydown', (e) => {" in src
|
|
assert "if (String(e.key || '').toLowerCase() !== 'v') return;" in src
|
|
assert "pasteKeyPending = true;" in src
|
|
assert "if (!pasteKeyPending) return;" in src
|
|
assert "pasteAsLayer(state.internalClipboard, 'Pasted Selection'" in src
|
|
# The key handler must NOT swallow the keystroke any more.
|
|
keydown = src[src.index("// ── Ctrl/Cmd+V ──"):src.index("// ── Drag-and-drop ──")]
|
|
assert "e.preventDefault();" not in keydown
|
|
assert "e.stopImmediatePropagation();" not in keydown
|