Skip to content

gnu-emacs-ru/test-flow

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

test-flow - Testing workflow in Emacs

Software is a conversation between what we intended and what actually runs. Tests translate between these two, but the loop “edit → run → read → fix → repeat” too often leaks our attention in tiny drips. Test-Flow exists to keep the loop flowing. It watches your project, runs tests when it makes sense (not when you sneeze), parses whatever your runner emits, and shows a crisp, actionable panel near your code.

./test-flow.png

Features at a glance

  • Right-side results panel grouped by suite; foldable sections with status icons.
  • Two runner modes:
    • external-command (default): robust, concurrent, parses stdout (JSON or ERT batch).
    • in-emacs-ert: synchronous, precise file/line/tags, instant goto-definition.
  • Parser modes: auto (JSON → batch fallback), JSON, or ERT batch.
  • Watcher: after-save or file-notify; debounce; auto-disable on idle sessions.
  • Concurrency: cap active runs; queue the rest; live counters in the Status block.
  • Header-line controls: run, run failed, watch toggle, detect command, copy failures, clear, goto, sessions, dashboard, logging toggle.
  • Copy failures: plain/org/markdown; includes full backtraces and optional stdout/stderr tails.
  • Multi-session aware: one panel per project; session list and dashboard across projects.
  • Unicode by default; optional all-the-icons for richer glyphs (with graceful degradation).
  • Defensive by design: parsers are tolerant, errors logged optionally, UI stays up.
  • Be invisible when all is well; be obvious and helpful when it isn’t.
  • Scale from tiny packages to larger suites by mixing in-Emacs speed with external-process robustness.
  • Offer humane ergonomics: a stable right-side panel, a readable header-line, clickable controls, and copy-pasteable failure reports.

Installation

Requirements

  • Emacs 27 or newer.
  • Optional: all-the-icons for fancy toolbar/header icons.

Package managers

  • package-vc-install:
(use-package test-flow
  :init
  (unless (package-installed-p 'test-flow)
    (package-vc-install
     '(test-flow
       :vc-backend Git
       :url "https://github.com/11111000000/test-flow"
       :branch "main"))))
  • Local checkout:
(use-package test-flow
  :load-path "~/Code/test-flow/lisp"
  :commands (test-flow-mode test-flow-open-panel)
  :custom
  (test-flow-run-on-open t))
  • straight.el:
    (use-package test-flow
      :straight (test-flow
                 :type git
                 :host github
                 :repo "11111000000/test-flow"
                 :branch "main"
                 :files ("lisp/*.el")
                 )
      :custom (test-flow-run-on-open t))
        

Manual

  • Place test-flow.el, test-flow-headerline.el, test-flow-view-controls.el, test-flow-controls-icons.el on your load-path.
    (require 'test-flow)
        

Optional fonts

  • For all-the-icons: install the fonts and the all-the-icons package. If not present, test-flow uses Unicode/text gracefully.

Quick start

  • In your project:
    • M-x test-flow-mode
    • M-x test-flow-open-panel
    • M-x test-flow-detect-runner (auto-finds tests/run-tests.el, nix flake, or Cask)
    • M-x test-flow-run
  • Panel keybindings (inside the results buffer):
    • r — Run tests
    • f — Run only failed (if external argv + failed-args are configured, else runs all)
    • w — Toggle watcher (after-save/file-notify per session config)
    • d — Detect runner
    • c — Copy last failures
    • x — Clear panel
    • o — Goto test definition
    • RET — Open details for test at point
    • TAB — Fold/unfold group (suite); S-TAB — fold/unfold all
    • n/p (or j/k) — Next/previous item
    • Filters: P/F/E/S/A — status filters; / — name regexp; T — tags; C — clear filters

Modular architecture and extension points

  • Entry points
    • test-flow.el — legacy monolith entry (stable public commands remain)
    • test-flow-modular.el — modular aggregator; (require ‘test-flow-modular) also provides ‘test-flow
  • Core modules (hard deps)
    • test-flow-core.el
      • Sessions: registry, cl-defstruct, safe accessors, per-session config (conf get/set)
      • Project root resolution, lightweight logging, utilities (suite-of, normalize-command, nix currentSystem)
    • test-flow-parse.el
      • Parsers: ERT batch и JSON; диспетчер test-flow-parse-output (‘auto|’json|’ert-batch)
      • Независим от UI/runner; устойчив к шумному выводу
    • test-flow-runner.el
      • Реализации очереди/процессов/сентинела, in-Emacs path; публичные команды
      • Хуки: test-flow-before-run-hook, test-flow-after-run-hook
    • test-flow-panel.el
      • Публичные команды панели (пока обёртки), фильтры, навигация
    • test-flow-render.el
      • Вынесен рендер: иконки/фейсы/счётчики, группировка/вставки, пайплайн рендера (context/insert/restore/render)
    • test-flow-watch.el
      • Реализации вотчера (after-save, file-notify, debounce, idle-GC); делегаты из монолита
    • test-flow-copy.el
      • Полноценная реализация copy-failures (monolith делегирует сюда)
  • Optional integrations/UI (soft deps)
    • test-flow-headerline.el — header-line renderer with caching and click handling
    • test-flow-view-controls.el — declarative controls and segment rendering
    • test-flow-controls-icons.el — graphic icons provider (all-the-icons)
    • test-flow-coverage.el — LCOV loader, overlays, panel block; auto-loads via test-flow-after-run-hook
    • test-flow-transient.el — global transient and keybindings
    • test-flow-i18n.el — localized labels/messages for controls and transient
  • Hooks and contracts
    • test-flow-before-run-hook (sess) — before a run starts
    • test-flow-after-run-hook (sess summary results) — after parsing and storage
    • Copy helpers accept user options: test-flow-copy-format, test-flow-copy-backtrace-limit, test-flow-copy-include-stdout/stderr
  • Migration notes
    • Monolith делегирует в модули (parse/watch/copy/runner/render); публичные имена команд сохранены
    • Панельный режим остаётся в монолите, но рендер целиком вынесен в test-flow-render (монолит делегирует)
    • Все опциональные модули тянутся мягко; без них доступен Unicode/text fallback

Concepts

  • Sessions
    • One session per project (project.el root). Each holds: panel buffer, details buffer, watcher state, last results/summary, process, queue.
  • Runner modes
    • external-command: launches an external process; robust for long suites; concurrent across sessions; parses stdout/stderr.
    • in-emacs-ert: runs ERT in-process; precise metadata; synchronous (may block UI for long runs).
  • Parsers
    • auto tries JSON first; falls back to batch ERT. You can force JSON or batch explicitly.
  • Watchers
    • after-save: cheap and simple; runs after relevant buffers are saved.
    • file-notify: OS-level directory watches; configurable depth; include/exclude regexps.
    • Debounce and auto-disable-on-idle keep noise and CPU down.
  • Concurrency
    • Global cap on concurrent runs with FIFO queue. Status block shows “Proc: active N, queued M”.
  • Header-line controls
    • Clickable, icon/text-based, with mouse-1 and tooltips; reflects toggle states (watch/logging).

Commands (interactive)

Core flow

  • test-flow-mode — global minor mode; opens panel on enable.
  • test-flow-open-panel — open/focus session panel for current project.
  • test-flow-run — run tests according to per-session runner.
  • test-flow-run-failed — re-run failures/errors only (when available), else run all.
  • test-flow-detect-runner — detect external command (tests/run-tests.el, nix flake, Cask).

Panel operations

  • test-flow-toggle-watch — toggle watcher for current session.
  • test-flow-copy-failures — copy failures with backtraces (plain/org/markdown).
  • test-flow-clear — clear panel and last results.
  • test-flow-open-details-at-point — show details view for current test.
  • test-flow-goto-definition-at-point — jump to test function if loaded.
  • Navigation: test-flow-next-item, test-flow-previous-item, test-flow-toggle-group-at-point, test-flow-toggle-all-groups.
  • Filters: test-flow-panel-filter-pass/fail/error/skip/all, test-flow-panel-set-name-filter, test-flow-panel-set-tags-filter, test-flow-panel-filter-clear.

Sessions and dashboard

  • test-flow-list-sessions — list sessions with quick actions.
  • test-flow-switch-session — jump to another session’s panel.
  • test-flow-kill-session / test-flow-kill-all-sessions — clean up.
  • test-flow-dashboard — global overview (processes, sessions, summaries).

Debugging and maintenance

  • test-flow-toggle-logging — toggle lightweight logs.
  • test-flow-dump-concurrency — print concurrency state to Messages.
  • test-flow-restart — restart test-flow (cleans sessions/queues/timers, re-opens panel).

Configuration reference (customize these)

Core runner and parsing

VariableTypeDefaultDescription
test-flow-runnerchoice: external-command/in-emacs-ertexternal-commandBackend to execute tests.
test-flow-parserchoice: auto/json/ert-batchautoParsing strategy for test output.
test-flow-external-commandlist argv or string (shell)nilExternal command to run tests. If string, executed via SHELL -lc.
test-flow-external-failed-args-functionfunction or nilnil(fn failed-names) → extra argv to run only failures (requires argv form).

Watcher and re-run ergonomics

VariableTypeDefaultDescription
test-flow-watch-modechoice: after-save/file-notify/nilafter-saveHow to watch the project for changes.
test-flow-debounce-secondsnumber0.7Delay before running after a triggering change.
test-flow-watch-include-regexpregexp or nil.el\’Only paths matching this are eligible (nil = include all).
test-flow-watch-exclude-regexpregexp or nilcommon dirsExclude matching paths (.git, .direnv, node_modules, build, dist…).
test-flow-file-notify-max-depthinteger3Recursion depth for file-notify watchers.
test-flow-session-idle-secondsinteger120Auto-disable watch for idle sessions after this many seconds.
test-flow-idle-gc-intervalinteger30Interval between idle GC checks.

Concurrency and resources

VariableTypeDefaultDescription
test-flow-max-concurrent-runsinteger3Global cap on parallel test processes (across sessions).
test-flow-max-raw-output-bytesint or nil1048576Cap stored raw stdout/stderr per session (nil = unlimited).

Panel, UI, and header-line

VariableTypeDefaultDescription
test-flow-panel-sidechoice: right/bottom/left/toprightWhere to display the side panel.
test-flow-panel-widthinteger42Panel width in columns.
test-flow-iconsbooleantShow per-test status icons (Unicode or all-the-icons).
test-flow-toolbar-stylechoice: auto/icons/textautoPrefer icons when available, force icons, or always text.
test-flow-view-headerline-enablebooleantShow clickable controls in the panel’s header-line.
test-flow-headerline-controls-orderlist of symbols/:gap(run run-failed :gap watch :gap copy clear :gap detect goto :gap sessions dashboard :gap logging)Order of header-line controls.
test-flow-controls-registryalist (advanced)see codeDeclarative controls (labels/icons/commands).

Icon settings (if you use all-the-icons)

VariableTypeDefaultDescription
test-flow-controls-use-graphic-iconsbooleantPrefer all-the-icons when available.
test-flow-controls-icon-heightnumber0.9Uniform icon height in header-line.
test-flow-controls-icon-raisenumber0.11Vertical raise via ‘display’ property (fine-tunes alignment).
test-flow-controls-icon-mapalistmappingControl-key → (provider . name) or per-state map.
test-flow-controls-icon-face-mapalistmappingOptional face overrides for non-toggle icons.
test-flow-controls-toggle-on-faceface/plistgray85Face for toggle icons when ON.
test-flow-controls-toggle-off-faceface/plistgray60Face for toggle icons when OFF.

Copy failures and reporting

VariableTypeDefaultDescription
test-flow-copy-formatchoice: plain/org/markdownplainFormat of copied failure report.
test-flow-copy-backtrace-limitint or nilnilTruncate each details/backtrace to this many chars.
test-flow-copy-include-stdoutbooleannilInclude raw stdout tail (capped by the same limit).
test-flow-copy-include-stderrbooleannilInclude captured stderr tail (capped by the same limit).

Session quality of life

VariableTypeDefaultDescription
test-flow-run-on-enablebooleannilIf non-nil, run once when test-flow-mode is enabled.
test-flow-auto-detect-on-openbooleantTry to auto-detect external command when opening the panel.
test-flow-run-on-openbooleantFirst open triggers a run when feasible.
test-flow-log-enabledbooleannilPrint lightweight logs to Messages (toggled via command).
test-flow-session-naming-functionfunctiondefault(fn root) → name for “*test-flow: NAME/” buffer.

Example configurations

Minimal external command

  • (setq test-flow-external-command ‘(“emacs” “-Q” “–batch” “-l” “tests/run-tests.el”))

Per-project .dir-locals (session-level settings)

((lisp-mode
  (test-flow-runner . external-command)
  (test-flow-external-command . ("emacs" "-Q" "--batch" "-l" "tests/run-tests.el"))
  (test-flow-parser . auto)
  (test-flow-watch-mode . after-save)
  (test-flow-debounce-seconds . 0.5)
  (test-flow-file-notify-max-depth . 2)))

Run only failed externally (example adapter)

(setq test-flow-external-failed-args-function
          (lambda (names)
            (when names
              (list "--" "--tests" (mapconcat #'identity names ",")))))

JSON output (recommended schema)

Top-level object

  • summary: {total, passed, failed, error, skipped, duration_ms?, time?}
  • tests: array of {name, status, message?, details?, file?, line?, tags?}

Example

{
    "summary": {"total": 12, "passed": 10, "failed": 1, "error": 1, "duration_ms": 8342},
    "tests": [
      {"name":"ns/test-1","status":"pass"},
      {"name":"ns/test-2","status":"fail","message":"expected X","details":"..."}
    ]
  }

Notes

  • status is case-insensitive and accepts pass/ok, fail/failed, error, skip/skipped, xfail.
  • If duration_ms is missing, test-flow computes elapsed time when possible.

Using the panel effectively

Start with Status

  • Counters, duration, active/queued processes, project, runner, mode, watch state, parser.

Groups (suites)

  • Fold green-all-pass groups (auto-initialized); expand for failures/errors.
  • Click a test to see details; press o to jump to its definition (if loaded).

Header-line controls

  • Mouse-1 on icons: run, run failed, toggle watch, detect, copy, clear, goto, sessions, dashboard, logging.
  • Tooltips explain each control. If icons aren’t available, text labels are used.

Runner detection (external)

  • M-x test-flow-detect-runner tries:
    • tests/run-tests.el or test/run-tests.el → emacs -Q –batch -l <path>
    • flake.nix → nix run .#tests
    • Cask → cask exec ert-runner
  • If multiple entrypoints are found, you’ll be prompted to pick one.

Tips and tricks

  • Prefer in-emacs-ert to quickly jump to failures while iterating on a test file, switch to external for big suites.
  • Set a small debounce (0.3–0.7s) to keep the flow without running on every keystroke-save combo.
  • Use filters (P/F/E/S, / regexp, T tags) to focus on what matters right now.
  • Copy failures in org format for issue trackers that love org’s structured blocks. Your future self (and coworkers) will thank you.

Troubleshooting

  • Icons look plain
    • That’s okay! Unicode mode is intentional. Install all-the-icons for fancier looks. If your fonts and ligatures behave, Emacs will too (most of the time).
  • in-emacs-ert freezes Emacs
    • It’s synchronous by design. For long suites, pick external-command. Coffee is optional but recommended.
  • “Run failed” still runs everything
    • Ensure test-flow-external-command is a list (argv), not a shell string, and set test-flow-external-failed-args-function.
  • Nothing happens on save
    • Check test-flow-watch-mode, include/exclude regexps, and whether your file is under the project root (project.el).
  • JSON parser fails mysteriously
    • Keep batch fallback via ‘auto’. If your runner prints banners around JSON, test-flow tries to snip “{…}” out; when in doubt, emit a clean JSON blob.

Faces (customize for your theme)

  • Result faces
    • test-flow-face-pass, test-flow-face-fail, test-flow-face-error, test-flow-face-skip
  • Toolbar/header-line faces
    • test-flow-headerline
    • Icon faces: test-flow-controls-icon-on/off, or overrides via the icon face map.
  • Toolbar button faces (legacy in-buffer toolbar is superseded by header-line controls, but faces remain available)

Developer notes (optional)

  • Header-line controls are declared in test-flow-view-controls.el; icons live in test-flow-controls-icons.el; the renderer and cache are in test-flow-headerline.el.
  • External runs use make-process with stderr captured separately; sentinel selects stdout vs stderr for parsing, trims buffers according to test-flow-max-raw-output-bytes.
  • In-Emacs runs enrich results directly from ERT objects: file/line, tags, and backtrace pretty-printing.

Contributing

  • Issues and PRs are welcome. Please include:
    • Emacs version, OS, and how you run tests (external vs in-Emacs).
    • A snippet of stdout/stderr or JSON (trimmed is fine) when parsing is the issue.
    • A screenshot of the panel if a UI quirk is suspected (optional but delightful).

Tests

  • You can run package tests in batch:
    • emacs -Q –batch -L lisp -l test-flow.el -l tests/test-flow-tests.el -f ert-run-tests-batch-and-exit
  • Or via your project’s tests/run-tests.el.

License

  • MIT. Share, remix, and don’t blame us if your tests discover new truths about your code.

Roadmap

  • In-Emacs reporter
    • Capture precise file/line/tags/duration without text parsing; unify with in-emacs-ert path.
  • Dashboard++
    • Filterable, sortable multi-session view; quick actions; persistent layout.
  • Parsers
    • TAP and pluggable custom parsers; richer JSON schema (attachments, artifacts).
  • UX
    • Status/search in panel; better folding persistence; richer filters (by tag/status/duration).
  • Adaptive ergonomics
    • Dynamic panel width (golden ratio option); auto-switch runner based on suite size/duration.
  • Packaging
    • MELPA recipe; more examples for JSON emitters; improved Nix story and templates.
  • Documentation
    • More “recipes” for common project setups; troubleshooting playbook with patterns.

About

TDD workflow in Emacs

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors