Skip to content

test(thinking-effort): stub the settings read with a spy, not a module mock - #753

Merged
sirmalloc merged 1 commit into
sirmalloc:mainfrom
eric-engberg:test/thinking-effort-settings-spy
Oct 29, 2026
Merged

sirmalloc merged 1 commit into
sirmalloc:mainfrom
eric-engberg:test/thinking-effort-settings-spy

Conversation

@eric-engberg

Copy link
Copy Markdown
Contributor

What

ThinkingEffort.test.ts stubs loadClaudeSettingsSync with vi.spyOn on the claude-settings module, restored after each test, instead of replacing the whole module with vi.mock. Test-only; nothing in the built CLI changes.

Why

Under Bun's test runner, a factory-based vi.mock isn't scoped to the file that declares it. Test files that run later in the same bun test process import the mocked claude-settings too, and its loadClaudeSettingsSync is the stub's vi.fn(), which the ThinkingEffort tests left returning {}.

When claude-settings.test.ts runs after ThinkingEffort.test.ts, three of its tests fail:

(fail) loadClaudeSettingsSync > should parse the settings file
(fail) loadClaudeSettingsSync > should log and throw when the settings file is invalid JSON
(fail) loadClaudeSettingsSync > should throw without logging when logErrors is false

should parse the settings file gets {} instead of the statusLine it wrote, and the invalid-JSON tests get {} instead of a SyntaxError. Whether they fail depends only on the order the runner picks for the files. A CI run on Ubuntu hit it, and running just the two files reproduces it on main:

bun test ./src/widgets/__tests__/ThinkingEffort.test.ts ./src/utils/__tests__/claude-settings.test.ts
 152 pass
 3 fail

terminal.test.ts already notes the same leak for terminal-width-cache and spies on the module namespace for that reason.

How

beforeEach spies on claudeSettings.loadClaudeSettingsSync with mockReturnValue({}) and afterEach calls vi.restoreAllMocks(), as VoiceStatus.test.ts does for getVoiceConfig. The render() helper and the settings-failure test use the spy as they used the vi.fn(), so every test checks the same thing as before. vi.clearAllMocks() goes, since each test now gets a fresh spy.

Demo

None: nothing visible changes.

Testing

  • The two files together, three runs: 155 pass, 0 fail each (main: 152 pass, 3 fail).
  • The 123 test files from the CI run that failed, together: 2410 pass, 0 fail (main: 3 fail, the tests above).
  • bun test: 3168 pass, 0 fail across 178 files.
  • bun run lint: clean.
  • Vitest under Node 26.10.0: ThinkingEffort.test.ts 44/44 as on main; claude-settings.test.ts unchanged from main (its 11 failures there come from spying on Node built-ins, which Node doesn't allow).

…e mock

ThinkingEffort.test.ts replaced ../../utils/claude-settings with a
vi.mock factory that exports only a vi.fn() loadClaudeSettingsSync.
Under Bun's test runner that mock isn't scoped to the file: test files
that run later in the same `bun test` process import the mocked module
too. When claude-settings.test.ts runs after it, its
loadClaudeSettingsSync tests get the stub's {} instead of the settings
file they wrote, and "should parse the settings file" and both
invalid-JSON tests fail. Whether they run in that order depends only on
the order the runner picks for the files: a CI run on Ubuntu hit it, and
running just these two files reproduces it on main.

The stub is now vi.spyOn on the module namespace, set in beforeEach and
restored in afterEach, the way VoiceStatus.test.ts stubs getVoiceConfig
and terminal.test.ts explains for terminal-width-cache. The tests check
the same things as before.
@sirmalloc
sirmalloc merged commit 14367e0 into sirmalloc:main Oct 29, 2026
3 checks passed
axisrow added a commit to axisrow/ccstatusline that referenced this pull request Oct 29, 2026
sirmalloc#755 live picker preview, sirmalloc#754 fast mode widget, sirmalloc#753 thinking-effort test stub, sirmalloc#752 transcript block fallback fixes, sirmalloc#751 editor keys no longer pause on global install lookup, sirmalloc#750 git cache TTL starts after the run, sirmalloc#749 npx cache skip, sirmalloc#747 Block Usage hides at 100% and swaps with Block Reset Timer)

Conflict policy: upstream infra wins, fork features ported on top. Joins:
sirmalloc#750 stamps the git cache after the run while keeping the fork's execGit
hardening/env snapshot and daemon prefetch bookkeeping; sirmalloc#752's
isApiErrorMessage guard lands in the fork's shared collectTimestampFromLine
(sync + async twins), upstream's duplicate getActivityTimestamp dropped;
sirmalloc#747 adds SESSION_AT_LIMIT alongside the fork's zero hide state
(BlockResetTimer keeps zero + under-limit via isAtSessionLimit, SessionUsage
is no-data/zero/at-limit); sirmalloc#755 replaces the fork's picker window + "Showing
X-Y of N" note with upstream's renderWindowedList/getPickerMaxVisible and
live preview (markers ↑/↓ N more cover the counts); sirmalloc#751's installationState
useMemo replaces the fork's inline lookups, the fork's mainMenuIndex helper
is kept.

Co-Authored-By: Claude Code <[email protected]>
pcvelz added a commit to pcvelz/ccstatusline-usage that referenced this pull request Oct 29, 2026
Upstream: Extra Usage Limit widget (sirmalloc#756), live widget preview while picking (sirmalloc#755), Fast Mode widget (sirmalloc#754), transcript block fallback fixes (sirmalloc#752), editor keys on a global install (sirmalloc#751), git cache TTL (sirmalloc#750), npx cached copy skip (sirmalloc#749), Block Usage hide at 100% (sirmalloc#747), Block Reset Timer hide until 100% (sirmalloc#697), fish-style branch abbreviation (sirmalloc#614), jj detached HEAD (sirmalloc#705), hooks save warning (sirmalloc#703), dev reload (sirmalloc#700), merge ends at a hidden widget (sirmalloc#698), Block Forecast and Block Limit Timer widgets (sirmalloc#699), contributor guide (sirmalloc#706), POSIX path case fix (sirmalloc#707), whitespace-distinct conflict filenames (sirmalloc#709), Quick Start reorder (sirmalloc#715), bunx launch guidance (sirmalloc#714), jj diff summary counts (sirmalloc#711), powerline manual separators (sirmalloc#713), keychain credential by account (sirmalloc#532), Keychain probe timeout (sirmalloc#760), usage cache scoped per CLAUDE_CONFIG_DIR (sirmalloc#266), test isolation (sirmalloc#717, sirmalloc#753), dev-dependency bumps (sirmalloc#745)

Conflicts resolved per the standard-resolution table; fork deletions re-applied.

Hand edits outside conflicts:
- src/utils/global-command-resolution.ts: fork-rename (ccstatusline@ -> ccstatusline-usage@ in upstream's new bunx pattern)
- src/utils/__tests__/global-package-manager.test.ts: fork-rename (package dir ccstatusline-usage in upstream's new tests)
- src/utils/usage-fetch.ts: compat fix - cacheUsageData gained a fetchedAtMs arg (upstream sirmalloc#266); adapted the fork-only fetchFreshUsageData call site
- src/utils/__tests__/usage-fetch.test.ts: compat fixes - cache/lock now hashed per CLAUDE_CONFIG_DIR (usageFilePath helper) in four fork tests; upstream fableUsage renamed to fork's weeklyFableUsage; seedUsageCache takes TokenHome
- src/utils/__tests__/usage-prefetch.test.ts: compat fix - mockFetchUsageData renamed to upstream's mockFetchUsage in cleanly-merged tests
- README.md: took upstream's Quick Start move (sirmalloc#715) and dropped the fork's old copy; fork-rename of its ccstatusline@ specifiers; links to fork-deleted docs (docs/USAGE.md, docs/WINDOWS.md) replaced with the fork's inline text
- CONTRIBUTING.md: links to the fork-deleted docs/DEVELOPMENT.md pointed at the README Development section
- docs/test-retirements.md: ledger entries for the 12 upstream test renames (sirmalloc#697, sirmalloc#698, sirmalloc#700, sirmalloc#705, sirmalloc#713, sirmalloc#760)
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