charmbracelet / charmbracelet/bubbletea

TestViewModel is flaky under the Taskfile's test flags

Open
#1,746 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
44.9k
Forks
1.3k
PR merge metrics
No merged PRs in 30d

Description

`task test` fails most of the time on `main` for me, currently `fc707bb`. Over 15 consecutive runs of `go test -race -count 4 -cpu 1,4 ./...` I get 13 failures. It's always `TestViewModel`, but a different subset of subtests each run, and the race detector doesn't report a data race.

Smallest reproducer I found, which fails consistently:

```
go test -race -cpu 1 -run TestViewModel ./...
```

Both flags matter. `-race` alone passes and `-cpu 1` alone passes; it needs the two together, presumably because `-race` slows things down enough and `GOMAXPROCS=1` removes the parallelism that was hiding the ordering.

A representative diff, from `mouse_allmotion`:

```
-\x1b[?25l\x1b[?2004h\x1b[?1003h\x1b[?1006h\x1b[>4;2m\x1b[=1;1u\r\x1b[Jsuccess...
+\x1b[?25l\x1b[?2004h\x1b[>4;2m\x1b[=1;1u\x1b[?u\r\x1b[Jsuccess\x1b[?1003h\x1b[?1006h...
```

As far as I can tell the renderer's flush ticker in `startRenderer` runs at the program's FPS, so an intermediate `flush(false)` can land before `Quit` is handled. When that happens the output picks up the `\x1b[?u` keyboard enhancements request, which `cursed_renderer.go` only writes when `closing` is false, and the mouse mode sequences move into a later frame. The golden files record the ordering where no intermediate flush happened.

This doesn't look like a recent regression: it reproduces the same way at c60f0c5, where the `-race`/`-count`/`-cpu` flags were added in #1691.

Setting `WithFPS(1)` in the test keeps the ticker from firing while these tests run, which fixes it for me at 15/15 with the golden files unchanged. Happy to send that as a PR if it's the direction you'd want, though you may prefer something that removes the timing dependency outright rather than widening the window.

Contributor guide

Open the contributing guide

Research direction

Start by running `go test -race -cpu 1 -run TestViewModel ./...` and locate `TestViewModel`. Read `startRenderer` and `cursed_renderer.go`, focusing on the flush ticker, `Quit`, and the `closing`-dependent output ordering. Done means the test no longer depends on ticker timing and passes with the existing golden files under the reproducer flags.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli, testing
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.