name: Tests on: push: branches: [ main ] # Run on every PR regardless of its base branch (e.g. PRs stacked onto a # `claude/*` working branch, not just those targeting main). pull_request: branches: [ '**' ] jobs: # ------------------------------------------------------------------ # Fast lane: every backend test that does NOT need the graphviz # `dot` binary. Skips the system-package install entirely (which # used to hang for ~8 minutes on the Azure apt mirror) and runs the # ~720 pytest items in ~15 seconds. # ------------------------------------------------------------------ test-backend: name: Backend tests (no graphviz) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python 3.10 uses: actions/setup-python@v5 with: python-version: "3.10" cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip pip install ".[test]" # Pin expert_op4grid_recommender to the exact version in # recommender-pin.txt (QW8) so an upstream release can't silently turn # a green PR red; the weekly canary.yml floats to latest and flags # regressions. --no-deps skips the recommender's heavy transitive # stack (pypowsybl already comes from co_study4grid's own deps). pip install --no-deps -r recommender-pin.txt - name: Run Pytest (excluding graphviz-dependent tests) # Coverage GATES at fail_under=72 (pyproject [tool.coverage.report]). # See docs/architecture/code-quality-analysis.md §20. run: >- pytest --ignore=expert_backend/tests/test_overflow_html_dim_logic.py --cov=expert_backend --cov-report=xml --cov-report=term-missing - name: Upload backend coverage if: always() uses: actions/upload-artifact@v4 with: name: backend-coverage path: coverage.xml if-no-files-found: ignore retention-days: 30 # ------------------------------------------------------------------ # Data-pipeline + benchmark supply chain (D8). Runs the HERMETIC slice # of the PyPSA-EUR pipeline suite (scripts/pypsa_eur) and the Codabench # scorer parity guard (scripts/game_mode). These live outside # pytest.ini's testpaths (expert_backend/tests), so they need an # explicit path. Tests that require the uncommitted raw OSM CSVs skip # gracefully (conftest osm_dir / regenerate_grid_layout guards), so the # suite is green from a fresh clone. scripts/game_mode/test_score.py is # pure stdlib and pins score.py to the shared golden fixture the # frontend's scoring.test.ts also asserts — locking cross-language parity. # ------------------------------------------------------------------ test-data-pipeline: name: Data pipeline + scorer parity runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python 3.10 uses: actions/setup-python@v5 with: python-version: "3.10" cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip pip install ".[test]" - name: Run pipeline + scorer + config-consistency tests (hermetic slice) run: >- pytest scripts/pypsa_eur scripts/game_mode scripts/test_recommender_pin_consistency.py scripts/test_extract_network_zip.py -q test-frontend: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: Install dependencies run: | cd frontend npm install - name: Run Vitest + coverage gate # Runs the full suite WITH coverage and enforces the floor in # vite.config.ts (coverage.thresholds). Replaces the plain run — # same tests, plus the gate. See §19. run: | cd frontend npm run test:coverage - name: Upload frontend coverage if: always() continue-on-error: true uses: actions/upload-artifact@v4 with: name: frontend-coverage path: frontend/coverage if-no-files-found: ignore retention-days: 30 - name: Run Linter run: | cd frontend npm run lint # ------------------------------------------------------------------ # Slow lane: the small subset of backend tests that exercise the # upstream interactive-HTML viewer through pydot → graphviz `dot`. # Gated behind the fast lanes so a regression in non-graphviz code # is reported in ~1 minute, and only the prod/load-layer fixtures # pay the (cached) apt install cost. # # `awalsh128/cache-apt-pkgs-action` caches the resolved .deb files # across runs — first run is ~30 s, subsequent runs restore from # cache in ~5 s, vs. the ~8 minutes the bare `apt-get update` was # taking on the Azure mirror. # ------------------------------------------------------------------ test-backend-graphviz: name: Backend tests requiring graphviz needs: [test-backend, test-frontend] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python 3.10 uses: actions/setup-python@v5 with: python-version: "3.10" cache: 'pip' - name: Install Graphviz # Direct ``apt-get install`` skips the slow ``apt-get update`` # (the original 8-minute Azure-mirror hang) — the GH runner # image already ships an up-to-date apt cache. We previously # used ``awalsh128/cache-apt-pkgs-action`` but the cached # ``.deb`` ended up out of sync with the runner's libstdc++ # / libltdl, making ``dot`` exit 1 on every render. A direct # install lets apt resolve the packages against the current # runner image so dot links cleanly every time. run: sudo apt-get install -y --no-install-recommends graphviz - name: Install dependencies run: | python -m pip install --upgrade pip pip install ".[test]" # Pin expert_op4grid_recommender to the exact version in # recommender-pin.txt (QW8) so an upstream release can't silently turn # a green PR red; the weekly canary.yml floats to latest and flags # regressions. --no-deps skips the recommender's heavy transitive # stack (pypowsybl already comes from co_study4grid's own deps). pip install --no-deps -r recommender-pin.txt - name: Run graphviz-dependent Pytest subset run: pytest expert_backend/tests/test_overflow_html_dim_logic.py