| 1 | from pathlib import Path |
| 2 | |
| 3 | |
| 4 | PROJECT_ROOT = Path(__file__).resolve().parents[1] |
| 5 | |
| 6 | |
| 7 | def test_chat_rows_have_hover_scoped_overflow_actions() -> None: |
| 8 | html = ( |
| 9 | PROJECT_ROOT / "webui/components/sidebar/chats/chats-list.html" |
| 10 | ).read_text(encoding="utf-8") |
| 11 | |
| 12 | assert html.count('aria-label="More chat actions"') == 2 |
| 13 | assert 'class="btn-icon-action chat-list-action-btn"' in html |
| 14 | assert '<x-icon name="more_vert"></x-icon>' in html |
| 15 | assert html.count("$store.sidebar.rowMenuToggle(") == 2 |
| 16 | |
| 17 | |
| 18 | def test_task_rows_have_overflow_actions_after_standard_buttons() -> None: |
| 19 | html = ( |
| 20 | PROJECT_ROOT / "webui/components/sidebar/tasks/tasks-list.html" |
| 21 | ).read_text(encoding="utf-8") |
| 22 | |
| 23 | delete_button = html.index('title="Delete task"') |
| 24 | menu_button = html.index('aria-label="More task actions"') |
| 25 | assert delete_button < menu_button |
| 26 | assert "$store.sidebar.rowMenuToggle(`task:${task.id}`" in html |
| 27 | |
| 28 | |
| 29 | def test_sidebar_uses_one_fixed_row_menu_with_standard_close_behavior() -> None: |
| 30 | html = ( |
| 31 | PROJECT_ROOT / "webui/components/sidebar/left-sidebar.html" |
| 32 | ).read_text(encoding="utf-8") |
| 33 | store = ( |
| 34 | PROJECT_ROOT / "webui/components/sidebar/sidebar-store.js" |
| 35 | ).read_text(encoding="utf-8") |
| 36 | |
| 37 | assert 'class="dropdown-menu sidebar-row-actions-menu"' in html |
| 38 | assert '<x-extension id="sidebar-row-actions-menu"></x-extension>' in html |
| 39 | assert '@click.window="$store.sidebar.rowMenuClick(' in html |
| 40 | assert '@keydown.escape.window="$store.sidebar.rowMenuClose()"' in html |
| 41 | assert "Rename Chat" not in html |
| 42 | assert "position: fixed;" in html |
| 43 | assert "z-index: 9999;" in html |
| 44 | assert "rowMenuOpenId" in store |
| 45 | assert "if (this.rowMenuOpenId === id)" in store |
| 46 | assert "const openUp = spaceBelow < 96 && spaceAbove > spaceBelow;" in store |
| 47 | |
| 48 | |
| 49 | def test_pin_plugin_contributes_the_menu_action_and_list_ordering() -> None: |
| 50 | extension = ( |
| 51 | PROJECT_ROOT |
| 52 | / "plugins/_pin_to_top/extensions/webui/sidebar-row-actions-menu/pin-to-top.html" |
| 53 | ).read_text(encoding="utf-8") |
| 54 | plugin_store = ( |
| 55 | PROJECT_ROOT / "plugins/_pin_to_top/webui/pin-to-top-store.js" |
| 56 | ).read_text(encoding="utf-8") |
| 57 | sidebar_store = ( |
| 58 | PROJECT_ROOT / "webui/components/sidebar/sidebar-store.js" |
| 59 | ).read_text(encoding="utf-8") |
| 60 | |
| 61 | assert "'Unpin from Top' : 'Pin to Top'" in extension |
| 62 | assert "'keep_off' : 'push_pin'" in extension |
| 63 | assert "registerRowListExtension" in plugin_store |
| 64 | assert "MutationObserver" not in plugin_store |
| 65 | assert "applyContexts =" not in plugin_store |
| 66 | assert "applyTasks =" not in plugin_store |
| 67 | assert "registerRowListExtension(kind, name, extension)" in sidebar_store |
| 68 | assert "hasRowDividerBefore(kind, item, index, rows)" in sidebar_store |
| 69 | |
| 70 | |
| 71 | def test_chat_naming_plugin_contributes_rename_action_and_standard_modal() -> None: |
| 72 | extension = ( |
| 73 | PROJECT_ROOT |
| 74 | / "plugins/_chat_naming/extensions/webui/sidebar-row-actions-menu/rename.html" |
| 75 | ).read_text(encoding="utf-8") |
| 76 | modal = ( |
| 77 | PROJECT_ROOT / "plugins/_chat_naming/webui/rename.html" |
| 78 | ).read_text(encoding="utf-8") |
| 79 | store = ( |
| 80 | PROJECT_ROOT / "plugins/_chat_naming/webui/chat-naming-store.js" |
| 81 | ).read_text(encoding="utf-8") |
| 82 | |
| 83 | assert "'Rename Task' : 'Rename Chat'" in extension |
| 84 | assert 'data-modal-footer' in modal |
| 85 | assert "chat-naming-secondary-actions" in modal |
| 86 | assert "Settings" in modal |
| 87 | assert "btn btn-ok" in modal |
| 88 | assert "btn btn-cancel" in modal |
| 89 | assert 'openModal(MODAL_PATH)' in store |
| 90 | assert 'store.openConfig(' in store |
| 91 | assert 'item?.project?.name' in store |
| 92 | assert 'item?.agent_profile' in store |
| 93 | assert 'callJsonApi(`/plugins/${PLUGIN_ID}/chat_name`' in store |