Spaces:
Running
Running
| """Tests for agent_trace_refresh and agent_trace_search_filter. | |
| These two functions were missing in traces.py (causing NameError on | |
| ``app.build_app()``) and were implemented per the Gradio output | |
| contract documented in app.py: | |
| - ``agent_trace_refresh`` returns 5 values matching | |
| ``[trace_selector, trace_bootstrap_state, trace_timeline, | |
| trace_raw, trace_table]`` | |
| - ``agent_trace_search_filter`` returns 3 values matching | |
| ``[trace_selector, trace_timeline, trace_raw]`` | |
| This file pins the contract so that a future refactor cannot | |
| silently break the Gradio wiring. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import pytest | |
| from shopstack.ui.screens.traces import ( | |
| agent_trace_refresh, | |
| agent_trace_search_filter, | |
| ) | |
| def _setup_app_env(): | |
| """Initialize shopstack.app_context with an in-memory DB so traces can be saved.""" | |
| os.environ.setdefault("SHOPSTACK_DB_PATH", ":memory:") | |
| import app # noqa: F401 (initializes app_context) | |
| class TestAgentTraceRefresh: | |
| def test_returns_5_values(self): | |
| """Gradio expects 5 output values.""" | |
| result = agent_trace_refresh() | |
| assert len(result) == 5, f"Expected 5 outputs, got {len(result)}" | |
| def test_first_value_is_gr_update_or_dict(self): | |
| """First output is trace_selector (gr.update or dict with choices).""" | |
| result = agent_trace_refresh() | |
| assert isinstance(result[0], dict) | |
| def test_second_value_is_state_string(self): | |
| """Second output is trace_bootstrap_state (string trace_id).""" | |
| result = agent_trace_refresh() | |
| assert isinstance(result[1], str) | |
| def test_third_value_is_timeline_html(self): | |
| """Third output is trace_timeline (HTML string).""" | |
| result = agent_trace_refresh() | |
| assert isinstance(result[3], str) | |
| # Either timeline content or an empty/placeholder div | |
| assert len(result[3]) >= 0 # any string is valid | |
| def test_fourth_value_is_raw_html(self): | |
| """Fourth output is trace_raw (raw JSON in HTML pre tag).""" | |
| result = agent_trace_refresh() | |
| assert isinstance(result[3], str) | |
| class TestAgentTraceSearchFilter: | |
| def test_returns_3_values(self): | |
| """Gradio expects 3 output values.""" | |
| result = agent_trace_search_filter(search="", type_filter="") | |
| assert len(result) == 3, f"Expected 3 outputs, got {len(result)}" | |
| def test_first_value_is_gr_update(self): | |
| """First output is the trace_selector update.""" | |
| result = agent_trace_search_filter(search="", type_filter="") | |
| assert isinstance(result[0], dict) | |
| def test_accepts_empty_filters(self): | |
| """Empty search and type_filter must not raise.""" | |
| result = agent_trace_search_filter(search="", type_filter="") | |
| assert len(result) == 3 | |
| def test_accepts_text_search(self): | |
| """A non-empty search must not raise.""" | |
| result = agent_trace_search_filter(search="milk", type_filter="") | |
| assert len(result) == 3 | |
| def test_accepts_type_filter(self): | |
| """A non-empty type_filter must not raise.""" | |
| result = agent_trace_search_filter(search="", type_filter="text") | |
| assert len(result) == 3 | |