Skip to Content
ContributingSnapshot blessing

Snapshot Blessing

Every rendering change you make to FrankenTUI will eventually touch a snapshot baseline. This page is the contributor-side protocol for blessing, reviewing, and committing snapshot changes without introducing drift.

This page is paired with the user-side snapshot testing page. That one explains what insta is and how the tooling works. This one is about the discipline: when to bless, what to look at in the diff, how to commit, and what mistakes to avoid.

If you touched widgets, styles, layout, the presenter, the text engine, or anything in ftui-extras, you will almost certainly need to re-bless. Read this page before running BLESS=1 for the first time on a change.

When to bless

ScenarioAction
You intentionally changed rendering and all visible diffs match your expectationBless, then commit
You changed non-rendering code and snapshots still matchDon’t bless — nothing to do
Snapshots diverge but you didn’t change renderingStop — that’s a regression, not a re-bless
You added a new screenBless to create its baseline, then review carefully
Snapshots flake run-to-runStop — that’s a determinism bug, not a flake

The key distinction: blessing is for intended changes. If a snapshot diff appeared that you didn’t expect, blessing it without understanding why hides a real bug.

Mental model

The protocol

Run the full workspace tests first

cargo test --workspace

This catches issues unrelated to your change. Do this before touching the snapshot workflow so you know your baseline is green.

Run the showcase snapshot tests

cargo test -p ftui-demo-showcase

If it’s green, you have nothing to bless. Move on.

If it’s red, read the failure messages. For each divergent snapshot, insta tells you the screen and the diff location.

Triage the diffs

For every diff, ask: did I expect this?

  • “I changed the table theme and now the table screens look different” — expected.
  • “I added a feature to Input and now command_palette_lab diverged” — unexpected; trace it.
  • “I fixed a bug in the presenter and now every screen changed by one cell” — expected (but review to confirm the change is correct).
  • “I only changed docs and snapshots diverged” — unexpected; there is a hidden coupling.

If any diff is unexpected, fix the regression first. Don’t bless around it.

Run cargo insta review

cargo insta review

This is an interactive TUI. For each change you see:

  • The test name (maps to a screen and tick point).
  • A side-by-side diff: current baseline on one side, new render on the other.
  • Key controls: a accept, r reject, s skip, q quit.

Accept changes you intended. Reject changes you didn’t. If you skip, remember to come back.

Re-run tests to confirm green

cargo test -p ftui-demo-showcase

After accepting your changes, this should pass. If it doesn’t, you either skipped something or there’s a second-order divergence (an accepted change propagated to another screen). Repeat.

Commit baseline + code together

commit
git add crates/ftui-demo-showcase/src/snapshots/ git add <your code changes> git commit -m "widgets: Table hover transition reset"

One commit per logical change. Never commit a code change without its snapshot update, and never commit a snapshot update without the code change that caused it.

Using BLESS=1 directly

BLESS=1 cargo test -p ftui-demo-showcase bypasses the interactive review and writes every baseline update unconditionally. Use it when:

  • You added a new screen. Its baseline doesn’t exist yet; you’ve run the showcase binary to confirm the screen looks right.
  • You made a workspace-wide cosmetic update (font metric change, consistent border style swap) where every diff is identical in shape.
  • You’re scripting a CI regen job on a dedicated branch.

Do not use BLESS=1 when:

  • You haven’t looked at what’s changing.
  • You have unrelated snapshot diffs from a merge or rebase.
  • You’re in a hurry. Hurry is how regressions land.

Reviewing someone else’s snapshot commit

If you’re reading code (or your own commit from last week) and a snapshot diff looks wrong, the commit itself is the audit trail. You can see:

  • What the code change was.
  • What the rendered output changed to.
  • Whether the two are consistent.

If a snapshot update doesn’t match its code change — e.g. a commit labeled “fix Input cursor” but the snapshot update is in the Table screen — that’s worth questioning. Most of the time it means the change had a broader impact than the commit message says, and the message should be updated (or the change scoped down).

New screens

When you add a new screen to the showcase:

  1. Add the module to crates/ftui-demo-showcase/src/screens/.
  2. Wire it into the screen registry (see mod.rs).
  3. Add a snapshot test entry.
  4. Run the binary first — manually verify it looks right.
  5. BLESS=1 cargo test -p ftui-demo-showcase to create the baseline.
  6. Commit the code and baselines together.

Step 4 is the one contributors skip. Don’t. Baselines freeze what the snapshot-test machine sees, not what a human thinks looks right — if the screen has a visual bug at bless time, you will ship the bug.

Pitfalls

Don’t bless around unexpected diffs. If a snapshot diff surprised you, investigate before blessing. Blessing hides the regression and commits it to the baseline — then every future contributor sees the broken render as “correct.”

Don’t commit .snap.new files. Those are insta’s pending-review artifacts. Only .snap files are baselines. Always run cargo insta review or BLESS=1 before committing.

Don’t split code changes and snapshot updates across multiple commits. They belong together. If you commit the code first and the baseline second, everyone between those two commits sees a red CI.

Don’t bless on a dirty working tree. If you have unrelated changes in your working tree, BLESS=1 will pick up any rendering side effects from those too. Stash or commit them first, then bless on a clean working tree.

Don’t “fix” a flaky snapshot by re-blessing. If a baseline diverges run-to-run, that’s a determinism bug. Fix the non-determinism source (usually a clock read, a PRNG without a seed, or HashMap iteration order), not the baseline.

Where next