mix test.qlover (qlover v0.1.0)

Copy Markdown View Source

Runs the test suite with incremental line-coverage gating in one command:

mix test.qlover

Plain mix test is left untouched, so single-file runs and ad-hoc flags keep working exactly as before. mix test.qlover decides by itself:

  • Baseline exists and non-test gate inputs (priv/repo/, config/, mix.exs, mix.lock) match: runs exactly the affected test files with coverage, then gates (mix test --no-stale <files> --cover --export-coverage .qlover_fresh + mix qlover). Test-only edits stay incremental through per-test attribution.
  • Otherwise — first run, missing/invalid baseline, or changed non-test inputs — runs the full suite with coverage and snapshots a new baseline (mix test --no-stale --cover + mix qlover --write-baseline). An info message says which path was taken.

There is no stale manifest involved: the file list comes from qlover's own content-keyed reference graph, so selection is deterministic across worktrees and machines, and a hostile host test alias injecting --stale cannot shrink it (--no-stale is passed first, which wins the duplicate-flag resolution).

Extra arguments are appended to the selection (mix test.qlover --seed 0); extra file arguments widen it, which stays sound because all coverage still comes from one code version. The flags --stale, --no-stale, --cover, --no-cover, --export-coverage, --failed, --partitions, --dry-run, --no-compile are managed by the task and rejected when passed explicitly.

Path overrides (mirroring mix qlover):

  • --baseline PATH - baseline file (default: cover/.qlover_baseline)
  • --export PATH - scratch export (default: cover/.qlover_fresh.coverdata); custom paths must live under the test_coverage output dir with a .coverdata suffix.
  • --expansion-export PATH - second scratch export accepted by the gate (default: cover/.qlover_expansion.coverdata).

Test failures abort before gating and never update the baseline. Scratch exports are deleted after gating (and any leftovers removed before each run), so a later mix test.coverage never unions a stale partial into a full report. When test files change but reference data is available, only the affected tests rerun in the focused run instead of the full suite (see Mix.Tasks.Qlover).

The --qlover flag spelling

Mix does not let dependencies add flags to mix test, but the same spelling is one alias away in your own mix.exs:

defp aliases do
  [
    test: fn
      args ->
        if "--qlover" in args do
          Mix.Task.run("test.qlover", args -- ["--qlover"])
        else
          Mix.Tasks.Test.run(args)
        end
    end
  ]
end

With that, mix test --qlover gates while bare mix test (including mix test test/foo_test.exs) stays vanilla.