Skip to content

test: cover renderer separators, ANSI edge cases and settings errors - #660

Merged
sirmalloc merged 1 commit into
sirmalloc:mainfrom
eric-engberg:test/renderer-ansi-settings-coverage
Oct 6, 2026
Merged

sirmalloc merged 1 commit into
sirmalloc:mainfrom
eric-engberg:test/renderer-ansi-settings-coverage

Conversation

@eric-engberg

Copy link
Copy Markdown
Contributor

What

Adds 65 tests for three core utilities. Test files only; no production code changes.

  • src/utils/renderer.ts
    • Powerline: separator (arrow) colors for every background combination (different, same, only the left widget, only the right widget, none), in normal and inverted mode; start, flex-boundary and end caps on widgets without a background; bold reset before a flex gap and after an end cap; bold kept through the separator after a bold, dimmed widget; widgets that keep their own colors (preserveColors); auto-align padding for merged groups, and merges across or into widgets that rendered empty.
    • Standard mode: separator widgets and the automatic defaultSeparator taking the previous widget's colors with inheritSeparatorColors (including its default color), the background override on separators, , and - separator spacing, padding colored with the widget background on each padding side, the preview width in full-minus-40, and widget types this version doesn't know.
  • src/utils/ansi.ts (new ansi.test.ts): 8-bit C1 CSI/OSC sequences, non-hyperlink OSC (window titles), unterminated CSI/OSC, two-character ESC x escapes, flags, ZWJ emoji sequences, stray combining marks, and truncation that never splits a flag or ZWJ sequence and closes hyperlinks correctly.
  • src/utils/claude-settings.ts: loadClaudeSettingsSync, getRefreshInterval / setRefreshInterval against unreadable settings, a failed .orig backup during install, invalid or malformed ccstatusline configs during install, and getRemoteControlStatus.

Why

  • Powerline separator coloring had tests for two of its ten branches (normal mode, different backgrounds or none). The rest pick the arrow color whenever neighbors share a background, only one has a background, or the separator is inverted. A mistake there shows up as an invisible arrow or a hole in the color band.
  • The bold and dim resets at flex gaps and end caps keep bold from leaking into the next segment, or past the end of the line into Claude Code's UI.
  • inheritSeparatorColors (for separator widgets and the automatic defaultSeparator) and the background override on separators and padding had no tests. If they break, a configured color band breaks at every separator and padding space.
  • The ANSI parser measures custom-command output, which can contain anything a script prints: C1 controls, cursor save/restore, hyperlinks, emoji. A width error there misplaces flex separators and truncates at the wrong column.
  • getRemoteControlStatus, behind the Remote Control widget, had no direct tests (the widget's tests mock it). How it handles a missing sessions directory, non-manifest files, malformed manifests and other sessions was unverified.
  • installStatusLine must still install when the .orig backup can't be written, and must not sync hooks from a ccstatusline config that fails validation or isn't valid JSON.

How

  • Three new focused files: ansi.test.ts, renderer-powerline-separators.test.ts and renderer-separator-colors.test.ts. Everything else extends the existing test file for that topic (renderer-dim, renderer-flex-width, renderer-padding-side, renderer-separator-collapse, claude-settings).
  • Expected strings are hand-written literals. Colors are hex: values, which produce raw truecolor codes whatever chalk detects about the terminal. The one place that needs a widget's named default color pins chalk.level and restores it afterwards, as renderer-config-warning.test.ts already does.
  • Renderer tests pass terminalWidth explicitly (0 for "width unknown"), so nothing depends on the terminal running the tests.
  • File-system tests use real temp directories under CLAUDE_CONFIG_DIR, like the rest of claude-settings.test.ts. A failed backup write and an unreadable session manifest both come from a directory sitting where the file should be. Nothing spies on fs, child_process or os.
  • The "no manifest matches" test puts every kind of skipped entry in one directory without a match, so each skip branch runs whatever order readdir returns.

Left uncovered on purpose:

  • claude-settings.ts: isNpmAvailable, isNpxAvailable, isBunAvailable, isBunxAvailable and getPackageCommandAvailability, which run which / where in a child process; and the Windows (cmd.exe) branch of the --config path quoting, which needs process.platform mocked to win32.
  • renderer.ts: the fallback for an unknown flexMode (settings are validated against the three modes on load), the catch around widget rendering (nothing inside throws for a registered widget), and the default-separator branch for an element without a widget (every element has one).
  • ansi.ts: the fallback for runtimes without Unicode property escapes, guards for indices that can't be out of range, and truncation's "nothing was cut" return, which needs an escape sequence inside a single emoji cluster.

Demo

No demo: test-only, nothing visible changes.

Testing

  • Line coverage, full suite with bun test --coverage:
    • src/utils/renderer.ts: 90.41% → 99.35%
    • src/utils/ansi.ts: 84.54% → 98.31%
    • src/utils/claude-settings.ts: 81.90% → 95.81%
  • bun test: 2423 pass, 0 fail, 151 files (main: 2358 pass, 148 files), so 65 new tests.
  • bun run lint: clean.
  • Each of the 8 touched test files run 15 times in a row under Bun (120 runs): all passed.
  • Node 26.10.0, node node_modules/vitest/vitest.mjs run on the 8 touched files: 230 tests, 219 pass, and all 65 new tests pass. The 11 failures are the existing execSync spies in claude-settings.test.ts, which fail the same way on main.
  • Mutation spot checks, each reverted afterwards: disabling flag pairing, ZWJ joining or C1 string-terminator parsing in ansi.ts; using the wrong text color for the inverted same-background arrow, dropping the bold reset before a flex gap, or dropping the 22;1 bold restore in renderer.ts; ignoring the previous widget's background on inherited separators; dropping the placeholder for unknown widget types; and removing the empty-session-id guard, the .json filter or the schema check before hook sync in claude-settings.ts. Each one made at least one new test fail.

Powerline separator colors (same, single and missing backgrounds, both
normal and inverted), caps on widgets without a background, bold resets
at flex gaps and end caps, preserved command colors, and auto-align
padding for merged groups had no tests, and neither did inherited and
override colors on standard-mode separators and padding. These paths
decide whether a status line keeps a continuous color band or shows
gaps, wrong arrow colors and leaked bold.

The ANSI parser gets direct tests for 8-bit C1 CSI/OSC, unterminated
sequences, two-character escapes, flags, ZWJ emoji sequences and
hyperlink closing on truncation, so widths and truncation stay right
for custom command output.

Claude settings gain tests for loadClaudeSettingsSync, refresh-interval
reads and writes against unreadable settings, a failed .orig backup not
blocking install, invalid ccstatusline configs not syncing hooks, and
the getRemoteControlStatus manifest lookup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants