193 lines
7.3 KiB
Python
193 lines
7.3 KiB
Python
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
|
|
def test_build_filter_bar_text_includes_search_context(tui_modules: SimpleNamespace) -> None:
|
|
text = tui_modules.cli_tui_search.TUI_SEARCH_SERVICE.build_filter_bar_text(
|
|
tui_modules.cli_tui_search.JOB_FILTER_OPTIONS,
|
|
'failed',
|
|
search_query='sync',
|
|
search_placeholder='按任务名搜索',
|
|
search_suggestions=['sync-job', 'sync-user'],
|
|
)
|
|
|
|
assert '当前筛选 · 失败' in text
|
|
assert '搜索器 · [/] 按任务名搜索' in text
|
|
assert '当前搜索 · sync | [Backspace] 清空' in text
|
|
assert '候选建议 · sync-job sync-user' in text
|
|
|
|
|
|
def test_tui_search_service_builds_filter_context_and_section_filtering(
|
|
tui_modules: SimpleNamespace,
|
|
) -> None:
|
|
service = tui_modules.cli_tui_search.TuiSearchService(
|
|
tui_modules.cli_tui_search.TuiSearchSuggestionProviderRegistry(
|
|
providers={
|
|
'jobs': tui_modules.cli_tui_search.SearchSuggestionProviderSpec(
|
|
'按任务名搜索',
|
|
lambda incomplete: ['sync-user', 'sync-role', 'cleanup'],
|
|
),
|
|
'app': tui_modules.cli_tui_search.SearchSuggestionProviderSpec('按分区或内容搜索'),
|
|
}
|
|
)
|
|
)
|
|
|
|
option = service.resolve_filter_option(tui_modules.cli_tui_search.JOB_FILTER_OPTIONS, 'failed')
|
|
filter_bar = service.build_filter_bar_text(
|
|
tui_modules.cli_tui_search.JOB_FILTER_OPTIONS,
|
|
'failed',
|
|
search_query='sync',
|
|
search_placeholder='按任务名搜索',
|
|
search_suggestions=['sync-user', 'sync-role'],
|
|
)
|
|
search_context = service.resolve_search_context('jobs', 'sync')
|
|
default_context = service.resolve_search_context('app', '总览', default_suggestions=['总览判断', '应用配置'])
|
|
sections = service.filter_detail_sections(
|
|
[
|
|
tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='总览判断', status='ok', lines=['应用正常']),
|
|
tui_modules.cli_tui_adapters.DetailSectionSnapshot(title='路由摘要', status='warn', lines=['同步任务接口']),
|
|
],
|
|
'同步',
|
|
)
|
|
|
|
assert option is not None
|
|
assert option.key == 'failed'
|
|
assert '当前筛选 · 失败' in filter_bar
|
|
assert search_context is not None
|
|
assert search_context.placeholder == '按任务名搜索'
|
|
assert search_context.suggestions[:2] == ['sync-user', 'sync-role']
|
|
assert default_context is not None
|
|
assert default_context.suggestions == ['总览判断']
|
|
assert [section.title for section in sections] == ['路由摘要']
|
|
|
|
|
|
def test_tui_search_service_skips_provider_when_query_is_empty(
|
|
tui_modules: SimpleNamespace,
|
|
) -> None:
|
|
provider_calls: list[str] = []
|
|
|
|
def record_provider(incomplete: str) -> list[str]:
|
|
provider_calls.append(incomplete)
|
|
return ['site_name']
|
|
|
|
service = tui_modules.cli_tui_search.TuiSearchService(
|
|
tui_modules.cli_tui_search.TuiSearchSuggestionProviderRegistry(
|
|
providers={
|
|
'configs': tui_modules.cli_tui_search.SearchSuggestionProviderSpec(
|
|
'按配置键搜索',
|
|
record_provider,
|
|
)
|
|
}
|
|
)
|
|
)
|
|
|
|
search_context = service.resolve_search_context('configs', '')
|
|
|
|
assert search_context is not None
|
|
assert search_context.placeholder == '按配置键搜索'
|
|
assert search_context.suggestions == []
|
|
assert provider_calls == []
|
|
|
|
|
|
def test_search_highlight_helper_wraps_matches(tui_modules: SimpleNamespace) -> None:
|
|
highlighted = tui_modules.cli_tui_search.TUI_SEARCH_HIGHLIGHTER.highlight('sync-user job', 'sync')
|
|
|
|
assert highlighted == '【sync】-user job'
|
|
|
|
|
|
def test_dashboard_screen_support_builds_summary_signal_and_status_track(
|
|
tui_modules: SimpleNamespace,
|
|
) -> None:
|
|
support = tui_modules.cli_tui_dashboard.DashboardScreenSupport()
|
|
snapshot = tui_modules.cli_tui_app.DashboardSnapshot(
|
|
env='dev',
|
|
metrics=[],
|
|
panels=[
|
|
tui_modules.cli_tui_adapters.DashboardPanelSnapshot(title='应用', status='ok', lines=['ok']),
|
|
tui_modules.cli_tui_adapters.DashboardPanelSnapshot(title='任务', status='warn', lines=['warn']),
|
|
tui_modules.cli_tui_adapters.DashboardPanelSnapshot(title='数据库', status='fail', lines=['fail']),
|
|
],
|
|
)
|
|
|
|
summary = support.build_summary_text(snapshot)
|
|
status_track = support.build_status_track(snapshot)
|
|
signal_lines = support.build_signal_lines(snapshot)
|
|
|
|
assert '共 3 个面板' in summary
|
|
assert status_track == 'o!x'
|
|
assert any('失败 01' in line for line in signal_lines)
|
|
|
|
|
|
def test_dashboard_screen_focus_service_moves_and_scrolls_between_focus_targets(
|
|
tui_modules: SimpleNamespace,
|
|
) -> None:
|
|
focus_service = tui_modules.cli_tui_dashboard.DashboardScreenFocusService()
|
|
focused: list[str] = []
|
|
sidebar = SimpleNamespace(focus=lambda: focused.append('sidebar'))
|
|
workspace_main = SimpleNamespace(focus=lambda: focused.append('main'))
|
|
fake_app = SimpleNamespace(focused=None)
|
|
fake_screen = SimpleNamespace(
|
|
app=fake_app,
|
|
query_one=lambda selector, widget_type=None: {
|
|
tui_modules.cli_tui_widgets.WorkspaceSidebar: sidebar,
|
|
'#workspace-main': workspace_main,
|
|
}[selector],
|
|
)
|
|
|
|
focus_service.move_focus(fake_screen, 1)
|
|
fake_app.focused = sidebar
|
|
focus_service.move_focus(fake_screen, 1)
|
|
fake_app.focused = object()
|
|
scroll_target = focus_service.get_scroll_target(fake_screen)
|
|
|
|
assert focused == ['sidebar', 'main']
|
|
assert scroll_target is workspace_main
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_dashboard_grid_expands_to_fit_status_panels(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
tui_modules: SimpleNamespace,
|
|
) -> None:
|
|
expected_dashboard_panel_count = 8
|
|
min_expanded_dashboard_grid_height = 20
|
|
snapshot = tui_modules.cli_tui_app.DashboardSnapshot(
|
|
env='dev',
|
|
metrics=[],
|
|
panels=[
|
|
tui_modules.cli_tui_adapters.DashboardPanelSnapshot(
|
|
title=f'面板 {index + 1}',
|
|
status='ok' if index % 2 == 0 else 'warn',
|
|
lines=[
|
|
'## 巡检摘要',
|
|
f'当前面板: {index + 1}',
|
|
'状态说明: 这里需要展示多行内容',
|
|
'',
|
|
'## 建议动作',
|
|
'进入对应分区继续查看详情',
|
|
],
|
|
)
|
|
for index in range(8)
|
|
],
|
|
)
|
|
|
|
monkeypatch.setitem(
|
|
tui_modules.cli_tui_app.TUI_SNAPSHOT_COLLECTOR_REGISTRY.collectors, 'dashboard', lambda env: snapshot
|
|
)
|
|
|
|
app = tui_modules.cli_tui_app.ShierfengTuiApp('dev')
|
|
async with app.run_test(size=(160, 60)) as pilot:
|
|
await pilot.pause()
|
|
await pilot.pause()
|
|
|
|
grid = app.screen.query_one('#dashboard-grid')
|
|
panels = list(
|
|
app.screen.query(tui_modules.cli_tui_widgets.StatusPanel).results(tui_modules.cli_tui_widgets.StatusPanel)
|
|
)
|
|
|
|
assert len(panels) == expected_dashboard_panel_count
|
|
assert grid.virtual_size.height > min_expanded_dashboard_grid_height
|
|
assert all(panel.content_size.height > 0 for panel in panels)
|
|
assert len({panel.region.height for panel in panels}) == 1
|