import subprocess
from zotero_kb.api import create_app
from zotero_kb.config import AppConfig
def _get_index_html(tmp_path) -> str:
app = create_app(
AppConfig(
workspace_dir=tmp_path / "workspace",
zotero_data_dir=tmp_path / "zotero",
bridge_file=tmp_path / "bridge.json",
)
)
for route in app.routes:
if getattr(route, "path", None) == "/" and "GET" in getattr(route, "methods", set()):
return route.endpoint()
raise AssertionError("GET / route not found")
def test_index_contains_base_page_forms(tmp_path) -> None:
html = _get_index_html(tmp_path)
assert 'id="create-project-form"' in html
assert 'id="recommend-form"' in html
assert 'id="plan-form"' in html
def test_index_contains_import_window_controls(tmp_path) -> None:
html = _get_index_html(tmp_path)
assert 'id="open-import-modal-button"' in html
assert 'id="import-window-shell"' in html
assert 'id="window-minimize-button"' in html
assert 'id="window-maximize-button"' in html
assert 'id="window-close-button"' in html
assert 'id="window-restore-button"' in html
assert 'id="import-window-minimized-bar"' in html
assert 'id="import-window-project-label"' in html
assert 'id="window-clear-selection-button"' in html
assert 'id="window-import-selected-items-button"' in html
assert 'id="window-collection-status"' in html
assert 'id="window-collection-tree"' in html
assert 'id="window-collection-items"' in html
assert 'class="window-toolbar-actions"' in html
assert 'class="window-action-cluster"' in html
assert 'class="window-control-cluster"' in html
assert 'isImportWindowOpen: false' in html
assert "function openImportWindow()" in html
assert "function closeImportWindow()" in html
assert "function updateImportActionState()" in html
assert 'document.body.classList.toggle("modal-open"' in html
def test_index_window_frame_css(tmp_path) -> None:
html = _get_index_html(tmp_path)
assert ".window-frame" in html
assert ".window-shell" in html
assert ".window-toolbar" in html
assert ".window-body" in html
assert ".window-minimized-bar" in html
assert '"zotero-kb.import-window"' in html
assert "startWindowDrag" in html
assert "minimizeWindow" in html
assert "maximizeWindow" in html
assert "restoreWindow" in html
assert "initWindowFromSession" in html
assert "persistWindowSessionState" in html
def test_index_import_window_has_collection_import_layout(tmp_path) -> None:
html = _get_index_html(tmp_path)
assert 'class="window-pane collections"' in html
assert 'class="window-pane items"' in html
assert 'id="window-collection-status"' in html
assert 'id="window-collection-tree"' in html
assert 'id="window-collection-items"' in html
assert ".window-pane.collections" in html
assert ".window-pane.items" in html
assert ".tree-list" in html
assert ".collection-items-list" in html
def test_index_has_collection_import_api_calls(tmp_path) -> None:
html = _get_index_html(tmp_path)
assert "function loadCollectionTree()" in html
assert "function loadCollectionItems(collectionKey)" in html
assert "/api/zotero/collections/tree" in html
assert "/api/zotero/collections/${collectionKey}/items" in html
assert "/api/projects/" in html
assert "imports/item-keys" in html
assert "function importSelectedItems()" in html
# openImportWindow calls loadCollectionTree
assert "openImportWindow()" in html
assert "await loadCollectionTree()" in html
def test_index_has_responsive_import_window_geometry_helpers(tmp_path) -> None:
html = _get_index_html(tmp_path)
assert "function computeResponsiveWindowRect()" in html
assert "function applyResponsiveWindowRect()" in html
assert "function syncWindowToViewport()" in html
assert 'window.addEventListener("resize"' in html
def test_index_has_responsive_import_window_layout_rules(tmp_path) -> None:
html = _get_index_html(tmp_path)
assert "@media (max-width: 980px)" in html
assert ".window-pane.items" in html
assert ".window-body {" in html
assert "grid-template-columns: 1fr;" in html
assert "border-bottom: 1px solid var(--line);" in html
def test_index_inline_script_is_valid_javascript(tmp_path) -> None:
html = _get_index_html(tmp_path)
script_start = html.rfind("")
assert script_start != -1
assert script_end != -1
script_path = tmp_path / "index-inline.js"
script_path.write_text(html[script_start + len("