Skip to content

Proposal: Testing framework for Bubble Tea applications (charm-test) #1654

@junhinhow

Description

@junhinhow

Problem

There is no standard way to test Bubble Tea applications. Developers either:

  • Test manually (slow, not CI-friendly)
  • Call Update() manually and inspect model internals (brittle, verbose)
  • Skip testing TUI logic entirely

Other UI frameworks have dedicated testing tools (React Testing Library, Flutter widget tests), but Bubble Tea has none.

Proposed Solution

charm-test — a testing framework that simulates the Bubble Tea runtime without a real terminal.

func TestLoginForm(t *testing.T) {
    sim := charmtest.New(NewLoginModel())

    sim.Type("user@email.com")
    sim.SendKey("tab")
    sim.Type("password123")
    sim.SendKey("enter")

    charmtest.RequireViewContains(t, sim, "Welcome")
    charmtest.RequireSnapshot(t, sim)  // golden file comparison
}

Features

  • Simulator — drives Model synchronously through Init/Update/View (no goroutines, deterministic)
  • Input simulationSendKey("enter"), Type("hello"), Resize(80, 24)
  • AssertionsRequireView(), RequireViewContains(), RequireViewLines() with automatic ANSI stripping
  • Snapshot testing — golden file comparison with CHARM_TEST_UPDATE=1 to refresh
  • DebuggingDumpView(), DumpMessages() for test failure diagnosis

Design Principles

  • Deterministic: same input → same output, always
  • Fast: microseconds per test, not seconds
  • Simple: one import, one constructor
  • ANSI-aware: all comparisons strip escape sequences

Working POC

https://github.com/junhinhow/charm-test

Includes a complete counter example with 5 test cases. Bilingual docs (EN/PT-BR).

Questions

  1. Would this fit as an official package (e.g. charm.land/bubbletea/v2/test)?
  2. Or better as a standalone community package?
  3. Should the Simulator also handle async commands (timers, HTTP) via a mock clock?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions