mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 20:27:44 +02:00
* [haik]: ckpt, added in the test runner skelton i made in another repo -> still gotta make tweaks to fold it onto the current repo * [haik]: restructure backend test layout: move 37 test files from backend/tests/ into backend/tests/test_cases/, add backend/tests/run.sh one-command launcher that auto-provisions both runner and test venvs with stamp-based caching, update runner config.json to point test_paths at test_cases/ and fix venv_python path, revise runner README with run.sh usage and clearer setup instructions, and gitignore the .runner-venv directory * [haik]: refactor: reorganize backend/tests/test_cases from flat structure into domain subdirectories — moved 36 test files into auth/, browser/, labeling/, service/, settings/, and web_search/ for better discoverability and grouping * [haik]: overhaul test picker UI and add post-run rerun loop: replace checkbox glyphs with fzf-style row recolouring (coral=full, lighter coral=partial) and a right-pinned selection dot, add config-driven icon tiers (nerd/emoji/unicode/ascii) with per-glyph graceful degradation, replace the modal -k keyword screen with an inline live-filtering search bar that prunes the tree on every keystroke, add warm Anthropic-dark coral theme, toolbar flag chips replacing the old status line, and a floating help badge overlay; add rerun_prompt.py with inline Textual pill prompt (rerun all/failed/passed/exit) shown after each TTY run, wire it into main.py as a post-run loop; change run_tests to return (exit_code, RunSummary) tracking collected/passed/failed node IDs via new Dashboard methods; add icons field to config.py and config.json (set to nerd), document icon tiers and Nerd Font setup in README, set Hack Nerd Font in .vscode/settings.json, add .runner-venv to linter excludes
99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
"""Typer entrypoint: python -m tests.runner
|
|
|
|
Default (no args): discover tests → interactive Textual picker → run selection.
|
|
With paths / -k / --no-pick: skip the picker and run directly.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from typing import List, Optional
|
|
|
|
import typer
|
|
from rich.console import Console
|
|
|
|
from tests.runner.discovery import discover
|
|
from tests.runner.picker import run_picker
|
|
from tests.runner.rerun_prompt import prompt_actions
|
|
from tests.runner.run import RunOptions, run_tests
|
|
|
|
console = Console()
|
|
|
|
|
|
def main(
|
|
paths: Optional[List[str]] = typer.Argument(
|
|
None, help="pytest paths or node IDs to target (skips the picker)."
|
|
),
|
|
keyword: Optional[str] = typer.Option(
|
|
None, "-k", help="Only tests matching this keyword expression (skips the picker)."
|
|
),
|
|
cov: bool = typer.Option(False, "--cov", help="Measure and report coverage of backend/."),
|
|
exitfirst: bool = typer.Option(
|
|
False, "-x", "--exitfirst", help="Stop after the first failure."
|
|
),
|
|
last_failed: bool = typer.Option(
|
|
False, "--lf", "--last-failed", help="Run only the tests that failed last time."
|
|
),
|
|
failed_first: bool = typer.Option(
|
|
False, "--ff", "--failed-first", help="Run last-failed tests first, then the rest."
|
|
),
|
|
verbose: bool = typer.Option(
|
|
False, "-v", "--verbose", help="Richer failure output (untruncated assertions)."
|
|
),
|
|
no_capture: bool = typer.Option(
|
|
False, "-s", "--no-capture", help="Show test stdout / print() output live (pytest -s)."
|
|
),
|
|
show_output: bool = typer.Option(
|
|
False, "-O", "--show-output", help="Show captured output for passing tests too (not just failures)."
|
|
),
|
|
pick: bool = typer.Option(
|
|
True, "--pick/--no-pick", help="Open the interactive picker (default on)."
|
|
),
|
|
) -> None:
|
|
try:
|
|
node_ids = discover(paths, keyword)
|
|
except RuntimeError as exc:
|
|
console.print(f"[red]discovery failed:[/]\n{exc}")
|
|
raise typer.Exit(2)
|
|
|
|
if not node_ids:
|
|
console.print("[yellow]No tests found.[/]")
|
|
raise typer.Exit(5)
|
|
|
|
# CLI flags seed the picker's toggles and drive the non-interactive run.
|
|
opts = RunOptions(
|
|
cov=cov,
|
|
exitfirst=exitfirst,
|
|
last_failed=last_failed,
|
|
failed_first=failed_first,
|
|
verbose=verbose,
|
|
no_capture=no_capture,
|
|
show_output=show_output,
|
|
)
|
|
|
|
interactive = pick and not paths and not keyword
|
|
if interactive:
|
|
picked = run_picker(node_ids, opts)
|
|
if picked is None:
|
|
console.print("[dim]cancelled[/]")
|
|
raise typer.Exit(0)
|
|
node_ids, opts = picked
|
|
if not node_ids:
|
|
console.print("[yellow]Nothing selected.[/]")
|
|
raise typer.Exit(0)
|
|
|
|
code, summary = run_tests(node_ids, opts)
|
|
# On a TTY, offer the post-run action prompt (rerun all / failed / passed /
|
|
# exit) and loop on whatever the user picks, reusing the same run options.
|
|
# Skipped when output is redirected/CI so we never try to open a TUI there.
|
|
while sys.stdout.isatty() and summary.all_ids:
|
|
choice = prompt_actions(summary.all_ids, summary.failed_ids, summary.passed_ids)
|
|
if not choice:
|
|
break
|
|
code, summary = run_tests(choice, opts)
|
|
raise typer.Exit(code)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
typer.run(main)
|