"""Regression tests for issue #3820 chat activity display mode.""" import json from pathlib import Path ROOT = Path(__file__).resolve().parents[1] UI_JS = (ROOT / "static" / "ui.js").read_text(encoding="utf-8") BOOT_JS = (ROOT / "static" / "boot.js").read_text(encoding="utf-8") PANELS_JS = (ROOT / "static" / "panels.js").read_text(encoding="utf-8") INDEX_HTML = (ROOT / "static" / "index.html").read_text(encoding="utf-8") I18N_JS = (ROOT / "static" / "i18n.js").read_text(encoding="utf-8") STYLE_CSS = (ROOT / "static" / "style.css").read_text(encoding="utf-8") def _transparentEventCountLabelBlock(ui_js): """Return the body of `_transparentEventCountLabel` as a string slice.""" start = ui_js.index("function _transparentEventCountLabel") end = ui_js.index("\nfunction ", start + 1) return ui_js[start:end] def test_chat_activity_display_mode_defaults_to_compact_worklog(monkeypatch, tmp_path): import api.config as config settings_path = tmp_path / "settings.json" monkeypatch.setattr(config, "SETTINGS_FILE", settings_path) loaded = config.load_settings() assert loaded["chat_activity_display_mode"] == "compact_worklog" def test_chat_activity_display_mode_persists_transparent_stream_and_rejects_invalid(monkeypatch, tmp_path): import api.config as config settings_path = tmp_path / "settings.json" monkeypatch.setattr(config, "SETTINGS_FILE", settings_path) saved = config.save_settings({"chat_activity_display_mode": "transparent_stream"}) assert saved["chat_activity_display_mode"] == "transparent_stream" assert json.loads(settings_path.read_text(encoding="utf-8"))["chat_activity_display_mode"] == "transparent_stream" saved = config.save_settings({"chat_activity_display_mode": "invalid_mode"}) assert saved["chat_activity_display_mode"] == "transparent_stream" assert json.loads(settings_path.read_text(encoding="utf-8"))["chat_activity_display_mode"] == "transparent_stream" def test_transparent_stream_uses_dedicated_mode_not_simplified_tool_calling(): assert "function chatActivityMode()" in UI_JS assert "function isTransparentStream()" in UI_JS assert "function isCompactWorklogMode()" in UI_JS assert "chatActivityMode()==='transparent_stream'" in UI_JS assert "window._chatActivityDisplayMode" in BOOT_JS assert "window._chatActivityDisplayMode" in PANELS_JS assert "window._simplifiedToolCalling=true" in BOOT_JS assert "window._simplifiedToolCalling=true" in PANELS_JS def test_transparent_stream_live_branch_uses_direct_rows(): decorator_start = UI_JS.index("function _decorateTransparentEventRow(row, opts){") decorator_end = UI_JS.index("function _setTransparentRowsExpanded", decorator_start) decorator_block = UI_JS[decorator_start:decorator_end] assert "data-transparent-event-row" in decorator_block assert "transparent-event-status" in decorator_block # Title carries the simple tool name (short form for MCP); status text # is only shown for non-default states. assert "_toolShortName(name)" in decorator_block assert "if(status==='Completed'){" in decorator_block assert "function _syncTransparentEventControls" in UI_JS assert "function _transparentEventCountLabel" in UI_JS assert "data-transparent-tool-count" in UI_JS assert "data-tool-count" in UI_JS # Transparent mode labels the event controls as a trace, not a Worklog # Activity summary. assert "return toolCount?`Trace: ${toolCount} ${toolCount===1?'tool':'tools'}`:'Trace';" in UI_JS assert "return `Activity: ${toolCount} ${toolCount===1?'tool':'tools'}`" not in UI_JS assert "Activity: ${parts.join(' · ')}" not in UI_JS # The summary must not list thinking count (DESIGN.md:75 forbids a second # trailing count badge, and thinking rows render as their own rows). assert "thinkingCount" not in _transparentEventCountLabelBlock(UI_JS) assert "function _setTransparentRowsExpanded" in UI_JS assert "function _setTransparentCardOpen" in UI_JS assert "function _wireTransparentHeaderToggle" in UI_JS assert "function _transparentToolDetailHtml" in UI_JS assert "function _setTransparentDetailMode" in UI_JS assert "transparent-detail-modes" in UI_JS # Spec R4: key on own line, value on next line, no inline pair. assert 'class="tool-arg-pair"' in UI_JS assert 'class="tool-arg-key"' in UI_JS assert 'class="tool-arg-val"' in UI_JS # Spec R5: controls are span[role=button], not