本文へ移動
cccskills
無料GitHub で公開

tui-snapshot-tester

Snapshot testing for terminal UI apps (TUIs) - captures rendered terminal frames as deterministic SVG / text snapshots, diffs them on every run, surfaces a reviewable HTML report on failure, and supports `--snapshot-update` to accept changes intentionally. Wraps `pytest-textual-snapshot` for Python Textual apps; provides equivalent recipes for Ratatui (Rust) `insta` snapshots, Charm Bracelet (Go) `teatest` golden files, and Ink (Node) `ink-testing-library`. Use for any TUI where layout regressions otherwise reach users via `screenshot looks wrong in terminal`.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qaスター 13(GitHub 13 + cccskills 0)

実行スコア 未検証

インストール方法を見る

含まれるファイル(2)

  • SKILL.md8.4 KB
  • .tessl-plugin/plugin.json701 B

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

tui-snapshot-tester

Overview

Per textual-testing:

"Snapshot testing is the process of recording the output of a test, and comparing it against the output from previous runs." Textual's pytest-textual-snapshot plugin does this by saving an SVG screenshot of the running app to disk.

A TUI snapshot test:

  1. Renders the TUI to a deterministic frame (SVG / text).
  2. Compares the new frame to a stored baseline.
  3. Fails on diff; produces an HTML diff report so the human reviews the change.
  4. Updates the baseline only when the human says so.

This catches layout regressions (clipped text, wrong column widths, broken borders) that exit-code / output assertions miss.

When to use

  • The unit-under-test is a TUI (Textual / Ratatui / Bubble Tea / Ink / curses).
  • The TUI's value is its visual layout - assertions on individual cells are brittle and miss "the box border now looks broken."
  • The team needs PR-time review of layout changes (vs catching them in user feedback).

For headless CLIs that emit text only, prefer bats-testing + cli-output-conventions; TUI snapshots are only needed for layout-rich UIs.

Step 1 - Install (Python / Textual)

Per txt:

pip install pytest-textual-snapshot

This pulls Textual + the snap_compare pytest fixture.

Step 2 - First snapshot test

Per txt (verbatim):

def test_calculator(snap_compare):
    assert snap_compare("path/to/calculator.py")

First run fails (no baseline). Per txt:

"Only ever run pytest with --snapshot-update if you're happy with how the output looks on the left hand side of the snapshot report."

Workflow:

  1. Run pytest. It fails; emits an HTML report at snapshot_report.html.
  2. Open the report. The "left hand side" shows the new render; the "right hand side" shows the saved baseline.
  3. If the new render is correct, run pytest --snapshot-update to accept it.
  4. Commit the updated __snapshots__/ directory.

Step 3 - Drive interactions before capture

Per txt:

# Press keys before snapshotting
assert snap_compare("path/to/calculator.py", press=["1", "2", "3"])

# Custom terminal dimensions
assert snap_compare("path/to/calculator.py", terminal_size=(50, 100))

# Run setup code (mouse hover, etc.)
async def run_before(pilot) -> None:
    await pilot.hover("#number-5")

assert snap_compare("path/to/calculator.py", run_before=run_before)

The Pilot API per txt:

async def test_keys():
    app = RGBApp()
    async with app.run_test() as pilot:
        await pilot.press("r")
        assert app.screen.styles.background == Color.parse("red")

pilot.press() / pilot.click() / pilot.pause() simulate user input.

Step 4 - CI integration (Textual)

Per txt:

"work well in CI on all supported operating systems, and the snapshot report is just an HTML file which can be exported as a build artifact."

jobs:
  tui-snapshot:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-python@v5
        with: { python-version: '3.13' }
      - run: pip install pytest-textual-snapshot
      - name: Run snapshot tests
        run: pytest tests/ui/
      - uses: actions/upload-artifact@v4
        if: failure()
        with: { name: snapshot-report, path: snapshot_report.html }

Reviewer downloads snapshot_report.html from the failed CI artifact, opens it locally, and decides accept / reject.

Step 5 - Equivalent for Rust / Ratatui

Use insta for snapshot testing:

# Cargo.toml
[dev-dependencies]
insta = "1"
ratatui = { version = "0.29", features = ["test-buffer"] }
#[test]
fn renders_main_view() {
    let mut terminal = Terminal::new(TestBackend::new(80, 24)).unwrap();
    terminal.draw(|f| draw_main(f, &app_state())).unwrap();
    insta::assert_snapshot!(terminal.backend().to_string());
}

Update with cargo insta accept (or cargo insta review for interactive triage). Snapshots stored in tests/snapshots/.

Step 6 - Equivalent for Go / Bubble Tea

Use teatest:

func TestApp(t *testing.T) {
    tm := teatest.NewTestModel(t, NewModel(), teatest.WithInitialTermSize(80, 24))
    tm.Send(tea.KeyMsg{Type: tea.KeyEnter})

    teatest.RequireEqualOutput(t, tm.FinalOutput(t,
        teatest.WithFinalTimeout(2*time.Second)))
}

teatest.RequireEqualOutput writes / compares against testdata/<test-name>.golden. Update with -update:

go test -update ./...

Step 7 - Equivalent for Node / Ink

Use ink-testing-library:

import { render } from 'ink-testing-library';
import App from './app';

test('renders welcome screen', () => {
  const { lastFrame } = render(<App />);
  expect(lastFrame()).toMatchSnapshot();
});

Jest's built-in toMatchSnapshot writes to __snapshots__/. Update with jest -u.

Step 8 - Determinism

Snapshots fail randomly if any of these vary:

  • Date / time in output. Mock the clock (Textual: freezegun; Ratatui: pass now as state; Ink: use vi.useFakeTimers()).
  • Random IDs. Seed PRNGs deterministically.
  • OS-specific glyphs / fonts. Pin OS in CI; warn on cross-OS diffs.
  • Locale. LC_ALL=C in CI.

Without determinism, snapshot tests become noise → team disables.

Step 9 - Snapshot review discipline

Treat snapshot diffs like test diffs in code review:

  • Every snapshot change must be reviewed in PR.
  • The HTML report is the artifact reviewers consult.
  • Auto-update in CI (e.g., bot pushes --snapshot-update commit on diff) defeats the purpose.

The same review discipline applies to browser screenshots (covered by the qa-visual-regression sister plugin).

Anti-patterns

Anti-patternWhy it failsFix
--snapshot-update in CI by defaultDefeats regression detection; baselines drift silently.Updates only on developer machine + reviewed in PR (Step 2).
Snapshots with timestamps / random IDsRandom failures; team disables tests.Mock clock + seed PRNG (Step 8).
One giant snapshot per appAny change forces full baseline review; reviewer skips.Per-screen / per-state snapshots.
Skipping Step 8 (determinism)Cross-OS / cross-machine diffs.LC_ALL=C + pin OS in CI.
No HTML report artifactReviewer can't see the diff; rejects blindly or rubber-stamps.Upload snapshot_report.html artifact (Step 4).

Limitations

  • Brittle to font / terminal width changes. Pin terminal size in tests (Step 3 terminal_size=).
  • Binary diff is harder to review. Per-pixel SVG diffs require the HTML report; raw text diff is unreadable.
  • Slow on large UIs. Each snapshot renders the full UI.
  • Platform divergence. Cross-OS snapshots may diverge by font rendering; restrict CI to one OS for golden files.

References

  • txt - pytest-textual-snapshot, snap_compare, --snapshot-update, Pilot.press / Pilot.click / Pilot.pause, HTML report, CI workflow.
  • insta (Rust): https://insta.rs/.
  • teatest (Go Bubble Tea): https://github.com/charmbracelet/x/tree/main/exp/teatest.
  • ink-testing-library (Node Ink): https://github.com/vadimdemedes/ink-testing-library.
  • bats-testing - exit-code + text output testing (text CLIs); pair with TUI snapshots for layout regression.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

Builds a CI gate that fails the build on **new** WCAG / a11y violations introduced by a PR while grandfathering pre-existing violations on a per-rule / per-page baseline. Aggregates verdicts from axe-core / pa11y / Lighthouse a11y / WAVE / IBM Equal Access scans. Use when a project has accumulated a11y debt and a strict "zero violations" gate would block every PR - the ratchet pattern lets the team ship while preventing regressions.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Workflow skill that builds an A/B-test validity checklist from an experiment proposal, walking the canonical design-correctness gates - pre-registered OEC/power/guardrails, randomization unit + SRM check, assignment integrity, telemetry, peeking discipline, novelty/primacy, post-experiment SRM re-check - into a per-experiment checklist + sign-off form. Use when launching, auditing, or governing an experiment. For pitfall mechanics (guardrails, peeking) see experiment-results-interpreter's references; to read an already-valid result use experiment-results-interpreter; for per-SDK harness tests use experiment-sdk-testing - this gates DESIGN, not SDK code.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

The single install-flow skill: the reference contract for the PWA install flow (installability gate fields, `beforeinstallprompt` handshake, per-platform paths - Android WebAPK / iOS Share menu / Firefox no-op - and the `display-mode` post-install signal, in references/install-flow-reference.md) plus the build-an-X workflow that emits the Add-to-Home-Screen suite. Walks the four-stage timeline, emitting one test per gate cell per [web.dev/articles/install-criteria][install-criteria], the deferred-prompt → `prompt()` → `userChoice` chain per [web.dev/articles/customize-install][customize-install], the iOS Safari manual-metadata branch (`apple-touch-icon`) per [web.dev/learn/pwa/installation][learn-pwa], and the post-install `(display-mode: standalone)` MQ assertion. Output: a Playwright spec with per-stage cells plus a coverage matrix. Use when a PWA's manifest, icons, or install handler change, when install conversion drops at an unknown stage, or when triaging a flaky install assertion.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Build-an-X workflow that uses an LLM to map existing tests to spec sections - given a spec doc + the test suite, the LLM identifies which tests cover which sections, surfaces uncovered sections (gap), and recommends specific tests to add. Output is a coverage matrix per spec ID. Scope is mapping tests that already exist and naming the gaps, not authoring tests for new acceptance criteria. Use when a spec doc and a test suite both exist but nobody can say which requirements are actually covered - before a release sign-off, an audit, or a decision about where to spend the next round of test effort.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Generates tests from natural-language specs (acceptance criteria, user stories, requirements) using an LLM, with confidence scoring per test case (LLM self-assessment plus heuristics: assertion quality, naming, completeness), batching uncertain cases for human review, and integration with the team's existing test framework. Use when the user asks to generate unit tests from acceptance criteria, convert user stories to test cases, automate test creation from requirements, or augment a spec-driven test suite with AI-generated stubs that are then curated before merge.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

Configures Allure Report (test-runner adapter install, `allure-results` directory wiring, `categories.json` for failure classification, `history-trend.json` retention via the copy-history-between-runs pattern), runs the Allure CLI to convert `allure-results` to a static HTML site, and uploads the report as a CI artifact. Use when the team needs richer test reporting than JUnit XML - step-level attachments, per-test history, retry tracking, and severity / epic / feature labeling across framework-agnostic adapters (pytest, Jest, JUnit, TestNG, NUnit, Mocha). As a rich static HTML report generator, it is the open-source alternative to the sunset ExtentReports (JVM/.NET per-test HTML narrative); for hosted cross-run flakiness analytics rather than a static per-run report use currents-integration.

日本語の概要は準備中です。原文の説明を表示しています。

testland/qa132026年10月20日 更新

testland のスキルをすべて見る

このスキルの問題を報告する