ps-qa 0.3.1

Drive a running Blitz app through its MCP control socket and assert what the renderer did
name: CI

# The unit tests only. Running the *checks* needs a live application with a
# window server, which lives in the app's own repository as a manually
# triggered job (`qa-panel.yml` in agencyzero), because it needs macOS and
# minutes. `cargo test` here is the engine: the coverage arithmetic, the
# reach rules, the sweep's verdicts.
on:
  push:
    branches: [master]
  pull_request:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always

jobs:
  test:
    name: Build and test
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4

      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - uses: Swatinem/rust-cache@v2

      - name: Format
        run: cargo fmt --check

      # `-D warnings` against whatever `stable` is today, which is deliberately
      # stricter than a pinned version: a lint added upstream should surface
      # here rather than the first time someone upgrades.
      #
      # The cost is that a local clippy on an older toolchain passes code this
      # rejects. That happened on the run that introduced this file: local
      # rustc 1.97.1 had no `chunks_exact_to_as_chunks` lint, 1.98.0 did, and
      # the PR went red having been checked clean. If this step fails on
      # something you cannot reproduce, compare `rustc --version` with the
      # `Rust toolchain` step above before assuming the workflow is wrong.
      - name: Clippy
        run: |
          rustc --version
          cargo clippy --version
          cargo clippy --all-targets -- -D warnings

      - name: Test
        run: cargo test --locked

      # The loader reads an application's checks, and this repository has none:
      # they belong to the application under test. So the guard is that a
      # fixture parses and a missing directory fails honestly, which is what
      # `list` does without needing an app.
      - name: The check loader works
        run: |
          mkdir -p /tmp/fixture-checks
          cat > /tmp/fixture-checks/smoke.ron <<'RON'
          [
              (
                  id: "smoke",
                  group: "smoke",
                  what: "the loader parses a check",
                  open: None,
                  hover: None,
                  click: None,
                  subject: "button",
                  expect: Paints,
              ),
          ]
          RON
          cargo run --release -- list --checks /tmp/fixture-checks | tee /tmp/list.txt
          grep -qE '1 checks in 1 groups' /tmp/list.txt

          # A missing directory must say so rather than report zero checks.
          if cargo run --release -- list --checks /tmp/definitely-absent 2>/tmp/err.txt; then
            echo "a missing check directory should have failed" >&2
            exit 1
          fi
          grep -q 'no checks at' /tmp/err.txt