tui-testing
Skill2.7k starsChanged 42 days agoMITView on GitHub
Testing Gloomberb at every level: CLI commands for fast data/integration checks, OpenTUI's built-in test harness for component tests, and tmux for full end-to-end terminal TUI testing. Use this skill when you need to verify terminal TUI features, write OpenTUI regression tests, or smoke-test the terminal app. Do not use it for Electrobun/desktop-web-only visual or window chrome work unless tmux/OpenTUI coverage is explicitly needed.
- Deletes or force-pushes
7 other projects use a version of this.
Trending
Steady talk.thin dataabout the whole repository
Most recently taken up by
- dominikmartn/harptheir own version, first seen Oct 20, 2026
- vincelwt/gloomberbword for word, first seen Oct 8, 2026
- warpdotdev/Warptheir own version, first seen Oct 8, 2026
- warpdotdev/warptheir own version, first seen Oct 8, 2026
- black12-ag/wefttheir own version, first seen Aug 19, 2026
- masonhuemmer/dopstheir own version, first seen Mar 24, 2026
Who's talking about gloom-sh/gloomberb
- chenrui333/homebrew-tap“gloomberb 0.20.7”GitHub · Nov 8, 2026 · 1 reactions
- @matsuu.bsky.social“オープンソースな投資情報ターミナルアプリ。おそらくBloomberg Terminalをもじった名前と思われる。”Bluesky · Sep 21, 2026 · 1 likes
- gloom-sh/gloom-byok-ai“Say what unlocks the provider walls and point to Ask Gloom”GitHub · Oct 17, 2026
- SylEleuth/gruvbox-plus-icon-pack“Missing icon: gloomberb”GitHub · Sep 6, 2026
- Elmata2/LaVega“Vendor Gloomberb's Yahoo Finance client (trimmed)”GitHub · Aug 18, 2026
The biggest 5 of 8 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 8
Talked about on GitHub and Bluesky (8 times).
On GitHub · 7
- Nov 8, 2026gloomberb 0.20.7 — chenrui333/homebrew-tap1 reaction · 1 comment
- Oct 17, 2026Say what unlocks the provider walls and point to Ask Gloom — gloom-sh/gloom-byok-ai0 reactions
- Sep 6, 2026Missing icon: gloomberb — SylEleuth/gruvbox-plus-icon-pack0 reactions · 1 comment
- Aug 18, 2026Vendor Gloomberb's Yahoo Finance client (trimmed) — Elmata2/LaVega0 reactions · 1 comment
- Aug 18, 2026Vendor Gloomberb's IBKR Flex Web Service client — Elmata2/LaVega0 reactions · 2 comments
2 more on GitHub
- Aug 18, 2026Enforce core/ import boundaries with a test — Elmata2/LaVega0 reactions · 1 comment
- Aug 18, 2026Third-party code adoption policy (vendoring) — Elmata2/LaVega0 reactions · 1 comment
On Bluesky · 1
- Sep 21, 2026オープンソースな投資情報ターミナルアプリ。おそらくBloomberg Terminalをもじった名前と思われる。 — @matsuu.bsky.social1 likes and repost
Used with
Projects with it also use classify-changelog-pr, cross-platform-cloud-verification and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
black12-agSkillclassify-changelog-pr
Reference guidance for classifying whether an unmarked PR should appear in the changelog and under which category. Used inline by the changelog-draft skill — not dispatched as a separate agent.
Also in 4 projects that use this
black12-agSkillcross-platform-cloud-verification
Orchestrates cost-conscious cloud verification across available operating-system and architecture runners after cheaper checks pass. Use whenever a code change, bug fix, build, packaging flow, native dependency, UI behavior, filesystem behavior, or test has material cross-platform implications, even if the user only asks to verify or test the change. Consult domain verification skills for what to test; use this skill to choose and access the smallest relevant set of platforms.
Also in 4 projects that use this
- +10 more from black12-ag
Other versions7 projects use a version of this.
Word for word · 1
- vincelwt/gloomberb★ 2.7k100% same
Edited · 0
None found.
Wrote their own version · 6
- warpdotdev/Warp★ 66ksame name
- warpdotdev/warp★ 66ksame name
- dominikmartn/harp★ 698same name
- masonhuemmer/dops★ 3same name
- rundops/dops★ 3same name
- black12-ag/weft★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository3 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- pane-conventionsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
23 rules. 0 are common, 8 are distinctive, and 15 are very specific to this project.
0
Common
Most of the 6 edited versions we read keep these.
8
Distinctive
This author's own choices. Worth a look.
15
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 20
Never touch the real
~/.gloomberb: Every tmux smoke, and any CLI command that writes (plugins, config, notes, alerts, portfolios), runs … - Very specific: line 37
Prefer named tmux sessions and end them with tmux kill-session -t <name>.
- Very specific: line 38
If you start a background process without tmux, capture its PID and terminate it explicitly with kill <pid> or the matching shutdown …
- Distinctive: line 39
Do not leave test helpers running across iterations unless the workflow explicitly requires it and you clean them up before handoff.
- Distinctive: line 49
Finish with a leak sweep: Before you report a test as done, confirm nothing you started is still alive:
- Very specific: line 81
Use bun start <command> for one-shot checks.
- Very specific: line 96
Verifying data layer changes: after modifying config, ticker storage, or persistence, run portfolio or ticker to confirm data loads …
- Very specific: line 97
Checking new data fields: if you add a new field (e.g.
- Distinctive: line 116
Fast: no real terminal, network, or app startup.
- Very specific: line 143
Use mockInput and React's act() to simulate user input:
- Very specific: line 201
Test files live next to source: foo.tsx → foo.test.tsx
- Very specific: line 202
Create the renderer with createOpenTuiTestHarness so it is destroyed after every test.
- Very specific: line 203
Always call renderOnce() before captureCharFrame()
- Distinctive: line 204
Use consistent dimensions for snapshot stability (80×24 default)
- Distinctive: line 210
Run the actual app in a tmux session, send keystrokes, and capture the rendered screen.
- Distinctive: line 212
When tmux is used for React/OpenTUI changes, always treat runtime health as part of the smoke.
- Very specific: line 224
Create the throwaway $SMOKE_HOME profile from Critical Rules first.
- Very specific: line 243
If you need to run the app without tmux, keep the process handle so you can shut it down:
- Very specific: line 280
Important: Always use -l for text input.
- Very specific: line 284
Always add sleep 0.5 to sleep 1 after sending input to let the UI re-render.
- Distinctive: line 356
When a bug mentions a specific saved layout, pane type, or focus path, launch directly into that layout or use the remote-control endpoint …
- Distinctive: line 367
Timing: If captures look incomplete, increase sleep duration.
- Very specific: line 369
Cleanup: Always kill the tmux session or any other background process you started when done, then rm -rf "${SMOKE_HOME:?}".
“Common” is measured: kept by at least 6 in 10 of the 6 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Testing Gloomberb
Three testing approaches. Start with the simplest level that covers your change and escalate only when needed.
This skill is for terminal TUI and OpenTUI test workflows. For Electrobun/desktop-web-only fixes, use focused desktop builds/tests instead unless the task explicitly asks for tmux or terminal rendering coverage.
Critical Rules
Never touch the real ~/.gloomberb. Every tmux smoke, and any CLI command that writes (plugins, config, notes, alerts, portfolios), runs against a throwaway profile: point GLOOMBERB_HOME at a temp dir whose config.json sets "onboardingComplete": true.
SMOKE_HOME=$HOME/.cache/gloom-smoke/my-change # a literal path, unique to this task, on disk
mkdir -p "$SMOKE_HOME"
printf '{ "dataDir": "%s", "onboardingComplete": true }\n' "$SMOKE_HOME" > "$SMOKE_HOME/config.json"
grep '"dataDir"' "$SMOKE_HOME/config.json" # must name $SMOKE_HOME, never ~/.gloomberbKeep the profile on disk, not under /tmp: on many Linux machines /tmp is RAM-backed with a fixed inode limit, and one profile is about 29,000 files once the first launch has installed the plugins, so a handful of leftover profiles can fill it and make every shell command fail.
An empty GLOOMBERB_HOME falls back to the real profile: ~/.gloomberb, or the XDG folders (~/.config/gloomberb, ~/.local/share/gloomberb) on a Linux machine without one. Shell variables do not carry over between separate shells, so set SMOKE_HOME again in every shell that launches the app, and write it as ${SMOKE_HOME:?} in launch commands so an unset value aborts instead of opening the real profile.
If you start from a copy of a real config instead, rewrite its dataDir into the temp dir and confirm with the same grep before launching: the app reads and writes wherever dataDir points, so a copied config that still names ~/.gloomberb edits the real profile. The first launch on a new profile reinstalls the plugins that moved out of this repo into $SMOKE_HOME/plugins, which needs network and takes a few seconds.
Cleanup is part of testing. If you start tmux, a dev server, a watcher, or any other background process while testing, stop it before you finish the task, even if the test fails.
- Prefer named
tmuxsessions and end them withtmux kill-session -t <name>. - If you start a background process without
tmux, capture its PID and terminate it explicitly withkill <pid>or the matching shutdown command. - Do not leave test helpers running across iterations unless the workflow explicitly requires it and you clean them up before handoff.
Never open the TV pane in a live app. macro-tv (shortcut TV) spawns an external media player such as mpv, plus yt-dlp/ffmpeg. Those processes outlive the tmux session that started them, keep playing audio, and burn CPU on the developer's machine until they are killed by hand. Verify TV changes by reading the code and with unit tests. The same rule applies to any pane or feature that shells out to a media player.
Never run an unbounded or streaming log scan. A tail -c 4000000 <log> | strings | grep ... | head -20 health scan once pinned a core at 100% for over five hours. Scan a bounded slice of a file that is no longer being written, and never involve strings:
head -c 200000 /tmp/gloomberb-test.log | grep -aE "<pattern>" | head -20Finish with a leak sweep. Before you report a test as done, confirm nothing you started is still alive:
ps -Ao pid,%cpu,etime,command \
| grep -iE "mpv|yt-dlp|ffmpeg|ffplay|tail -c|strings|bun run dev|bun src/cli/entry.ts" \
| grep -v grep
tmux ls 2>&1Kill anything of yours that shows up and re-run until the sweep is clean.
What are you testing?
├─ Data flow, config, business logic, or integration with external sources
│ ├─ CLI command exists for it → Run the CLI command (fastest)
│ └─ No CLI command, but it makes sense as one → Add it, then use it
├─ A component's rendering, interaction, or visual regression
│ └─ OpenTUI test harness (.test.tsx file)
├─ Pure logic with no UI or data layer
│ └─ Unit test (bun:test, no renderer needed)
└─ Full app behavior across multiple views
└─ tmux (last resort)1. CLI Commands (fastest feedback loop)
Gloomberb doubles as a CLI tool. CLI commands are the fastest way to verify data flow, config state, and business logic: no renderer, no harness setup, just run and check output.
Running commands
Use bun start <command> for one-shot checks. It runs src/cli/entry.ts once, like the installed gloomberb; bun run dev adds --watch and is for working on the interactive app.
bun start help # Every command, grouped
bun start help ticker # Usage, options, and examples for one command
bun start portfolio # Portfolios and watchlists
bun start ticker AAPL # Quote, fundamentals, positions
bun start ticker AAPL --json # The same report as JSON
bun start plugins # Plugins installed from GitHubbun start help is the source of truth for what exists; do not rely on a list copied into docs.
When to use CLI testing
- Verifying data layer changes: after modifying config, ticker storage, or persistence, run
portfolioortickerto confirm data loads correctly. - Checking new data fields: if you add a new field (e.g. earnings date), first expose it via the
tickerCLI command and verify the output, before wiring it into the TUI. - Smoke-testing integrations:
ticker AAPLexercises the market data providers, quote formatting, and fundamentals parsing in one command. - Testing plugin management:
install,remove,update, andpluginscommands verify the plugin lifecycle. Run them under a tempGLOOMBERB_HOME(see Critical Rules).
Adding new CLI commands
If you're building a feature and need to verify data that isn't exposed via CLI yet, consider adding a CLI command first when it makes sense (e.g. listing watchlists, showing config values, checking broker sync status). This gives you a fast feedback loop before building the TUI component.
Commands are CliCommandDef objects. Core commands are listed in createCoreCliCommands() in src/cli/index.ts, most of them defined in src/cli/commands/*. A plugin contributes its own through cliCommands (see src/plugins/builtin/portfolio-list/cli/portfolio-command.ts). src/cli/registry.ts merges both into one lookup, rejects duplicate names and aliases, and drops commands from disabled plugins. Give it a help block (group, usage, examples) so bun start help files it under the right heading.
2. OpenTUI Test Harness (component & snapshot tests)
Headless, deterministic component and integration tests using Bun's test runner and OpenTUI's built-in test renderer. Use this for UI component tests and visual regressions.
Why use this
- Deterministic:
renderOnce()guarantees the frame is complete before capture. No timing guesswork. - Fast: no real terminal, network, or app startup.
- Isolated: each test gets its own headless renderer, and the harness destroys it after the test.
- Composable: render individual components with controlled props/state.
- Snapshotable: built-in
toMatchSnapshot()for visual regression testing.
Quick start
import { test, expect } from "bun:test";
import { createOpenTuiTestHarness } from "../../renderers/opentui/test-utils"; // relative to your test file
// One renderer per test, destroyed after every test even when an assertion fails.
const tui = createOpenTuiTestHarness({ width: 80, height: 24 });
test("renders my component", async () => {
await tui.render(<MyComponent someProp="value" />);
// Polls until the text renders and throws with the last frame if it never does.
const frame = await tui.waitForFrameToContain("expected text");
// or: expect(frame).toMatchSnapshot();
});Import the harness from src/renderers/opentui/test-utils (plugins in their own repositories use gloomberb/test-support), not testRender straight from @opentui/react/test-utils: the wrapper mounts the UI host, input, toast, and dialog providers that the shared kit needs. Besides render and setup() (the current renderer), the harness has frame(), emitKeypress, renderFrames, waitForFrameToContain, waitForFrameToExclude, clickFrameText and destroy(). Prefer waitForFrameToContain over a fixed number of frames when a test waits for something to render: fixed frame counts flake on a loaded CI runner. A suite that must configure the renderer before anything mounts (kitty capabilities, pixel resolution) uses tui.createRoot() instead of render.
Interaction testing
Use mockInput and React's act() to simulate user input:
import { act } from "react";
test("arrow keys navigate the list", async () => {
await tui.render(<MyList items={items} />);
await tui.renderFrames(1);
await act(async () => {
tui.setup().mockInput.pressArrow("down");
await tui.setup().renderOnce();
});
expect(tui.frame()).toContain("▸ Second Item");
});Testing components that need app context
The harness already provides the dialog host. Components that read app state also need AppContext:
import { AppContext, createInitialState } from "../../state/app/context";
import { createDefaultConfig } from "../../types/config";
const state = createInitialState(createDefaultConfig("/tmp/gloomberb-my-test"));
await tui.render(
<AppContext value={{ state, dispatch: () => {} }}>
<MyComponent />
</AppContext>,
);src/components/layout/header.test.tsx is a short example that also records dispatched actions and clicks with mockMouse; src/components/ui/ui.test.tsx covers the shared kit (lists, tables, tabs, fields, dialogs).
tui.setup() return object
| Property | Type | Description |
renderer | Renderer | The headless renderer instance |
renderOnce | () => Promise<void> | Trigger a single render cycle |
captureCharFrame | () => string | Capture current output as text |
resize | (w, h) => void | Resize the virtual terminal |
mockInput | MockInput | Simulate keyboard input (e.g. pressArrow("down"), typeText("AAPL")) |
mockMouse | MockMouse | Simulate mouse input (e.g. click(x, y), scroll(x, y, "down")) |
Running tests
bun test # Run all tests
bun test src/components/ui/ui.test.tsx # Run a specific file
bun test -t "command bar" # Only tests whose name matches
bun test --update-snapshots # Update snapshot filesConventions
- Test files live next to source:
foo.tsx→foo.test.tsx - Create the renderer with
createOpenTuiTestHarnessso it is destroyed after every test; keep only suite-specific resets in your ownafterEach - Always call
renderOnce()beforecaptureCharFrame() - Use consistent dimensions for snapshot stability (80×24 default)
3. tmux (full end-to-end TUI testing)
Run the actual app in a tmux session, send keystrokes, and capture the rendered screen. Use this as a last resort, for verifying full-app behavior that can't be tested with the harness or CLI.
When tmux is used for React/OpenTUI changes, always treat runtime health as part of the smoke. Do not stop at "it rendered"; scan for React hook/update-depth failures, listener leak warnings, and obvious memory runaway.
When to use tmux
- Verifying layout and pane arrangement with real data
- Testing keyboard navigation flows across multiple views
- Smoke-testing after major refactors
- Debugging rendering issues that only appear with the full app
- Checking for real-app React warnings, listener leaks, update loops, or memory growth after layout/pane/chart/subscription changes
Setup
Create the throwaway $SMOKE_HOME profile from Critical Rules first.
# Kill any existing test session first
tmux kill-session -t test 2>/dev/null
# Start the app with a fixed terminal size for consistent captures
tmux new-session -d -s test -x 120 -y 40 "GLOOMBERB_HOME=${SMOKE_HOME:?} bun start 2>&1"
# Wait for the app to render (2-3 seconds for initial load)
sleep 3For warning/error scans, pipe the pane output to a log before interacting:
tmux pipe-pane -o -t test 'cat > /tmp/gloomberb-test.log'If you need to run the app without tmux, keep the process handle so you can shut it down:
GLOOMBERB_HOME="${SMOKE_HOME:?}" bun start > /tmp/gloomberb-test.log 2>&1 &
app_pid=$!
# ... test whatever you need ...
kill "$app_pid"
wait "$app_pid" 2>/dev/nullCapturing the screen
tmux capture-pane -t test -pReturns the full rendered text grid including box-drawing characters. Does NOT capture colors or styling.
Sending input
# Special keys
tmux send-keys -t test C-p # Ctrl+P: open command bar
tmux send-keys -t test Escape # Escape: close dialogs
tmux send-keys -t test Enter # Enter: select/confirm
tmux send-keys -t test Tab # Tab: focus the next pane
tmux send-keys -t test Up # Arrow keys
tmux send-keys -t test Down
tmux send-keys -t test j # j/k: navigate lists
tmux send-keys -t test k
# Typing text (always use -l flag for literal strings)
tmux send-keys -t test -l 'AAPL'Important: Always use -l for text input. Without it, each character is interpreted as a key name.
Typical test flow
Always add sleep 0.5 to sleep 1 after sending input to let the UI re-render.
# 1. Start the app on the throwaway profile
tmux kill-session -t test 2>/dev/null
tmux new-session -d -s test -x 120 -y 40 "GLOOMBERB_HOME=${SMOKE_HOME:?} bun start 2>&1"
sleep 3
# 2. Capture initial state
tmux capture-pane -t test -p
# 3. Open command bar and search
tmux send-keys -t test C-p
sleep 0.5
tmux send-keys -t test -l 'AAPL'
sleep 0.5
tmux capture-pane -t test -p
# 4. Select and verify
tmux send-keys -t test Enter
sleep 1
tmux capture-pane -t test -p
# 5. Always clean up
tmux kill-session -t testRuntime health checks
For real-app smokes, especially after touching React hooks, subscriptions, chart rendering, pane settings, market-data events, layout switching, or plugin runtime code, perform these checks before finishing:
- Capture a log and final screen.
- Scan both for React/runtime warnings.
- Sample RSS before and after interactions if the test runs long enough to compare.
- Explicitly report any remaining uncertainty, such as a short smoke not proving long-horizon leak absence.
Suggested scan:
LOG=/tmp/gloomberb-test.log
CAP=/tmp/gloomberb-test.capture
tmux capture-pane -t test -p > "$CAP"
rg -n \
"Possible EventTarget|MaxListeners|Maximum update depth|Invalid hook|Rendered more hooks|Rendered fewer hooks|React has detected|\\[ERROR\\]|Error:" \
"$LOG" "$CAP" || trueSuggested RSS sampling:
pane_pid=$(tmux display-message -p -t test '#{pane_pid}')
child_pids=$(pgrep -P "$pane_pid" || true)
grandchild_pids=""
for pid in $child_pids; do
grandchild_pids="$grandchild_pids $(pgrep -P "$pid" || true)"
done
app_pids=$(printf '%s\n' $child_pids $grandchild_pids | awk 'NF' | sort -u)
for pid in $app_pids; do
ps -o pid=,rss=,command= -p "$pid" || true
doneInterpret memory samples conservatively:
- A short smoke can catch obvious runaway growth, but it cannot prove there is no long-horizon leak.
- Startup, first data load, chart bitmap allocation, and layout switching can legitimately increase RSS.
- Suspicious signs are repeated warning logs, unbounded growth across repeated identical interactions, or jumps paired with update-depth/listener warnings.
Layout and pane smoke coverage
When a bug mentions a specific saved layout, pane type, or focus path, launch directly into that layout or use the remote-control endpoint to switch layouts rather than relying only on keyboard shortcuts. Keyboard encoding in tmux can be terminal-dependent.
Recommended coverage for layout/pane regressions:
- Launch the affected layout directly from the throwaway profile, or from a copied app config whose
dataDiryou rewrote into it. - Exercise the affected pane's own interactions, such as chart period changes, refresh, tab changes, pane settings, or legend toggles.
- Switch between the affected layout and another layout at least a few times when the bug involved layout activation or pane unmount/remount behavior.
- Re-run the warning scan after interactions and after layout switches.
Tips
- Timing: If captures look incomplete, increase sleep duration. Network-dependent views take longer.
- Terminal size:
-x 120 -y 40gives consistent layout. Smaller sizes may cause wrapping. - Cleanup: Always kill the
tmuxsession or any other background process you started when done, thenrm -rf "${SMOKE_HOME:?}". - Debugging crashes: stderr is captured via
2>&1so crash output is visible.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

