feat: run tests in background with progress polling

Improve the testing dashboard to run pytest in the background:

- Add background task execution using FastAPI's BackgroundTasks
- Create test_runner_tasks.py following existing background task pattern
- API now returns immediately after starting the test run
- Frontend polls for status every 2 seconds until completion
- Show running indicator with elapsed time counter
- Resume polling if user navigates away and returns while tests running
- Tests continue running even if user closes the page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-12 23:20:26 +01:00
parent 6e3ae4bebb
commit 0e6c9e3eea
5 changed files with 228 additions and 41 deletions

View File

@@ -3,13 +3,14 @@ Test Runner API Endpoints
RESTful API for running pytest and viewing test results
"""
from fastapi import APIRouter, Depends, Query
from fastapi import APIRouter, BackgroundTasks, Depends, Query
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from app.api.deps import get_current_admin_api
from app.core.database import get_db
from app.services.test_runner_service import test_runner_service
from app.tasks.test_runner_tasks import execute_test_run
from models.database.user import User
router = APIRouter()
@@ -96,27 +97,37 @@ class TestDashboardStatsResponse(BaseModel):
@router.post("/run", response_model=TestRunResponse)
async def run_tests(
background_tasks: BackgroundTasks,
request: RunTestsRequest | None = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_admin_api),
):
"""
Run pytest and store results
Start a pytest run in the background
Requires admin authentication. Runs pytest on the specified path
and stores results in the database.
Requires admin authentication. Creates a test run record and starts
pytest execution in the background. Returns immediately with the run ID.
Poll GET /runs/{run_id} to check status.
"""
test_path = request.test_path if request else "tests"
extra_args = request.extra_args if request else None
run = test_runner_service.run_tests(
# Create the test run record
run = test_runner_service.create_test_run(
db,
test_path=test_path,
triggered_by=f"manual:{current_user.username}",
extra_args=extra_args,
)
db.commit()
# Start background execution
background_tasks.add_task(
execute_test_run,
run.id,
test_path,
extra_args,
)
return TestRunResponse(
id=run.id,
timestamp=run.timestamp.isoformat(),