fischer-agentkit/tests/integration/test_gap_closure.py

164 lines
5.8 KiB
Python

"""Gap closure integration tests — dark theme, @-mention API, LocalComputerUseSession."""
import pytest
from unittest.mock import MagicMock, patch
from agentkit.quality.cascade_state_store import (
InMemoryCascadeStateStore,
create_cascade_state_store,
)
from agentkit.llm.providers.usage_store import (
InMemoryUsageStore,
create_usage_store,
)
from agentkit.tools.computer_use_session import (
InMemoryComputerUseSession,
LocalComputerUseSession,
ComputerUseSessionManager,
)
# ---------------------------------------------------------------------------
# Dark theme: CSS token validation (smoke test)
# ---------------------------------------------------------------------------
class TestDarkThemeTokens:
"""Verify dark theme CSS tokens exist in tokens.css."""
def test_dark_theme_tokens_file_contains_dark_selector(self):
import pathlib
tokens_path = pathlib.Path(__file__).parent.parent.parent / (
"src/agentkit/server/frontend/src/styles/tokens.css"
)
if not tokens_path.exists():
pytest.skip("Frontend tokens.css not found")
content = tokens_path.read_text()
assert '[data-theme="dark"]' in content
assert '--bg-primary: #1a1a1a' in content
assert '--text-primary: #fbfbfa' in content
assert '--border-color: #3a3a3a' in content
def test_theme_store_exists(self):
import pathlib
store_path = pathlib.Path(__file__).parent.parent.parent / (
"src/agentkit/server/frontend/src/stores/theme.ts"
)
if not store_path.exists():
pytest.skip("Theme store not found")
content = store_path.read_text()
assert 'useThemeStore' in content
assert 'toggle' in content
assert 'resolvedMode' in content
assert 'localStorage' in content
# ---------------------------------------------------------------------------
# @-mention API: mention-suggest endpoint
# ---------------------------------------------------------------------------
class TestMentionSuggestAPI:
"""Test the /skills/mention-suggest endpoint logic."""
def _make_skill(self, name, description):
skill = MagicMock()
skill.name = name
skill.config.description = description
return skill
def test_mention_suggest_filters_by_name(self):
"""Verify the filtering logic used by the endpoint."""
skills = [
self._make_skill("geo_pipeline", "GEO pipeline skill"),
self._make_skill("code_reviewer", "Code review skill"),
self._make_skill("data_analyst", "Data analysis skill"),
]
query = "geo"
filtered = [
s for s in skills
if query in s.name.lower()
or (s.config.description and query in s.config.description.lower())
]
assert len(filtered) == 1
assert filtered[0].name == "geo_pipeline"
def test_mention_suggest_filters_by_description(self):
skills = [
self._make_skill("skill_a", "GEO pipeline skill"),
self._make_skill("skill_b", "Code review skill"),
]
query = "review"
filtered = [
s for s in skills
if query in s.name.lower()
or (s.config.description and query in s.config.description.lower())
]
assert len(filtered) == 1
assert filtered[0].name == "skill_b"
def test_mention_suggest_limits_to_8(self):
skills = [self._make_skill(f"skill_{i}", "") for i in range(20)]
result = skills[:8]
assert len(result) == 8
def test_mention_suggest_empty_query(self):
skills = [
self._make_skill("skill_a", "desc"),
self._make_skill("skill_b", "desc"),
]
query = ""
filtered = [
s for s in skills
if query in s.name.lower()
or (s.config.description and query in s.config.description.lower())
]
assert len(filtered) == 2
# ---------------------------------------------------------------------------
# LocalComputerUseSession
# ---------------------------------------------------------------------------
class TestLocalComputerUseSession:
"""Test LocalComputerUseSession (without actual pyautogui)."""
def test_inherits_from_base(self):
assert issubclass(LocalComputerUseSession, InMemoryComputerUseSession.__mro__[1])
def test_start_without_pyautogui_raises(self):
"""If pyautogui is not installed, start should raise RuntimeError."""
import asyncio
session = LocalComputerUseSession()
with patch.dict("sys.modules", {"pyautogui": None}):
with pytest.raises(RuntimeError, match="pyautogui"):
asyncio.run(session.start())
def test_session_manager_with_local_factory(self):
manager = ComputerUseSessionManager(session_factory=LocalComputerUseSession)
session = manager.get_or_create(session_id="test-local")
assert isinstance(session, LocalComputerUseSession)
# ---------------------------------------------------------------------------
# Factory session_ttl propagation (regression test)
# ---------------------------------------------------------------------------
class TestFactorySessionTTL:
"""Ensure session_ttl is propagated through factories."""
def test_cascade_store_memory_with_custom_ttl(self):
store = create_cascade_state_store(backend="memory", session_ttl=7200)
assert isinstance(store, InMemoryCascadeStateStore)
assert store._session_ttl == 7200
def test_usage_store_memory_backend(self):
store = create_usage_store(backend="memory")
assert isinstance(store, InMemoryUsageStore)
def test_cascade_store_auto_backend(self):
store = create_cascade_state_store(backend="auto")
assert store._session_ttl == 86400 # default