Skip to content

test(repo): improve test coverage from 77% to 93%#142

Merged
zrosenbauer merged 3 commits intomainfrom
test/coverage-improvements
Apr 1, 2026
Merged

test(repo): improve test coverage from 77% to 93%#142
zrosenbauer merged 3 commits intomainfrom
test/coverage-improvements

Conversation

@zrosenbauer
Copy link
Copy Markdown
Member

Summary

  • Add ~25 new test files across all packages (screen output, context prompts/status, stories check, middleware report, config serialize, crash handler, and more)
  • Exclude untestable files from coverage with documented reasons (React/Ink components, Bun subprocess entry points, dynamic module loaders, integration-tested CLI handlers)
  • Raise coverage thresholds from 60% to 87-95%
  • Fill branch gaps in existing test files (oauth-server, icons/install, figures, screen, cli, compose, register)

Coverage

Metric Before After
Statements 76.9% 93.4%
Branches 74.1% 87.2%
Functions 76.0% 95.4%
Lines 76.7% 93.4%

Test plan

  • pnpm test — all 17 tasks pass
  • pnpm vitest run --coverage — all thresholds met
  • No source code changes, only test files and vitest config

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 1, 2026

🦋 Changeset detected

Latest commit: 241c9dd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
oss-kidd Ignored Ignored Preview Apr 1, 2026 3:33pm

Request Review

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Apr 1, 2026

Merging this PR will not alter performance

✅ 2 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing test/coverage-improvements (241c9dd) with main (97beb1e)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0b7f1697-c79b-494e-af54-583b34105014

📥 Commits

Reviewing files that changed from the base of the PR and between c3f3e27 and 241c9dd.

📒 Files selected for processing (2)
  • packages/core/src/middleware/auth/oauth-server.test.ts
  • packages/core/src/middleware/icons/list-system-fonts.test.ts

📝 Walkthrough

Walkthrough

Adds a large suite of Vitest unit tests across multiple packages: bundler (build/bun-config), CLI (add command handlers and config helpers), and core (context prompts/status, compose, crash, log, middleware for auth/figures/icons, screen/output store/report/spinner/log, config serialization, runtime registration, stories validation). Tests mock external APIs, assert edge cases, and verify observable behaviors. Updates vitest.config.ts to include **/*.tsx, expand coverage exclusions, and raise coverage thresholds. No production source or exported/public API declarations were changed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and accurately describes the main changeset: adding ~25 test files to improve coverage from 77% to 93%.
Description check ✅ Passed The description is directly relevant to the changeset, detailing test additions, coverage exclusions, threshold increases, and coverage metrics.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/coverage-improvements

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/lib/crash.test.ts`:
- Around line 21-25: The module-level spy exitSpy on process.exit leaks beyond
this test file because it's never restored; change the setup so the spy is
created and torn down within the test lifecycle: either move vi.spyOn(process,
'exit') into a beforeEach (or beforeAll) and call exitSpy.mockRestore() in
afterEach (or afterAll), or keep the module-level exitSpy but add an afterAll
that calls exitSpy.mockRestore(); ensure vi.clearAllMocks() remains to clear
call history but does not replace the restore call for exitSpy.

In `@packages/core/src/lib/log.test.ts`:
- Around line 205-213: The test for resolveOutput doesn’t actually assert stderr
fallback; update the test in log.test.ts (the describe 'resolveOutput' case that
uses createLog() and log.newline()) to spy/mock process.stderr.write and assert
that it was called when no output stream is provided instead of checking
clack.log.error; ensure you restore the original write after the test. Use the
createLog and log.newline() calls to trigger output and replace the unrelated
expect(clack.log.error).not.toHaveBeenCalled() with an assertion that
process.stderr.write was invoked.

In `@packages/core/src/middleware/auth/oauth-server.test.ts`:
- Around line 286-311: The test title and assertions are wrong: instead of
asserting a positive port it should exercise the string-address branch in
oauth-server.ts (the typeof addr === 'string' path) by mocking
handle.server.address() to return a string and then asserting handle.port
resolves to null; to fix, after the server emits 'listening' override
handle.server.address = () => "/tmp/socket" (or other string), then await
handle.port and expect(port).toBeNull(), and finally call
destroyServer(handle.server, handle.sockets); alternatively, remove or rename
the test if string (Unix socket) addresses are not a supported case.

In `@packages/core/src/middleware/icons/install.test.ts`:
- Around line 272-277: The test overrides for process.platform using
Object.defineProperty in the beforeEach/afterEach blocks should include
configurable: true so the property can be redefined in afterEach; update the
Object.defineProperty calls that set process.platform (e.g., the ones in the
Windows override and the later Darwin override) to pass { value: 'win32',
configurable: true } / { value: 'darwin', configurable: true } respectively,
matching the pattern used in list-system-fonts.test.ts and ensuring teardown can
restore originalPlatform.

In `@packages/core/src/middleware/icons/list-system-fonts.test.ts`:
- Around line 184-226: The tests claiming to exercise Promise-level
rejection/wrapping don't actually trigger a top-level rejection because
safeLstat swallows lstat errors; update the two failing tests so Promise.all
truly rejects instead of only causing safeLstat to return null: change the
readdir mock (used by listSystemFonts) to reject for at least one expected
directory (or throw) so Promise.all rejects, and for the second test supply a
non-Error rejection value (e.g., reject('string error') from readdir) to verify
the listSystemFonts top-level catch wraps non-Error throws; target the mocked
readdir and lstat/safeLstat behavior used by listSystemFonts to ensure the code
path being asserted is actually hit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f7a3ada3-c3a6-40c2-bc8e-dfb903641af9

📥 Commits

Reviewing files that changed from the base of the PR and between 97beb1e and 0d0c55b.

⛔ Files ignored due to path filters (1)
  • .changeset/fuzzy-bugs-sleep.md is excluded by !.changeset/**
📒 Files selected for processing (26)
  • packages/bundler/src/build/bun-config.test.ts
  • packages/cli/src/commands/add/config.test.ts
  • packages/cli/src/commands/add/middleware.test.ts
  • packages/cli/src/lib/config-helpers.test.ts
  • packages/core/src/cli.test.ts
  • packages/core/src/compose.test.ts
  • packages/core/src/context/prompts.test.ts
  • packages/core/src/context/resolve-defaults.test.ts
  • packages/core/src/context/status.test.ts
  • packages/core/src/lib/config/serialize.test.ts
  • packages/core/src/lib/crash.test.ts
  • packages/core/src/lib/log.test.ts
  • packages/core/src/middleware/auth/oauth-server.test.ts
  • packages/core/src/middleware/figures/figures.test.ts
  • packages/core/src/middleware/icons/install.test.ts
  • packages/core/src/middleware/icons/list-system-fonts.test.ts
  • packages/core/src/middleware/report/report.test.ts
  • packages/core/src/runtime/register.test.ts
  • packages/core/src/screen/output/screen-log.test.ts
  • packages/core/src/screen/output/screen-report.test.ts
  • packages/core/src/screen/output/screen-spinner.test.ts
  • packages/core/src/screen/output/store-key.test.ts
  • packages/core/src/screen/output/store.test.ts
  • packages/core/src/screen/screen.test.ts
  • packages/core/src/stories/check.test.ts
  • vitest.config.ts

Add ~25 new test files across all packages covering:
- Screen output store, log, report, and spinner adapters
- Context prompts, status, and resolve-defaults
- Stories check validation
- Middleware report
- Config serialization
- Crash handler

Exclude untestable files from coverage (React/Ink components,
Bun subprocess entry points, dynamic module loaders, and
integration-tested CLI command handlers).

Raise coverage thresholds from 60% to 87-95%.

Co-Authored-By: Claude <noreply@anthropic.com>
@zrosenbauer zrosenbauer force-pushed the test/coverage-improvements branch from 0d0c55b to b47c2da Compare April 1, 2026 04:05
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (5)
packages/core/src/middleware/auth/oauth-server.test.ts (1)

286-311: ⚠️ Potential issue | 🟠 Major

Test name contradicts its actual behavior — this doesn't exercise the string-address code path.

The test claims to verify "port as null when server address returns a string" but:

  1. The server starts and resolves handle.port before the override can take effect
  2. Asserts expect(port).toBeGreaterThan(0) instead of toBeNull()
  3. Never exercises the typeof addr === 'string' branch at oauth-server.ts:239-242

This effectively duplicates the first startLocalServer test. Either remove it or fix it to actually mock server.address() to return a string before the listening callback fires.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/middleware/auth/oauth-server.test.ts` around lines 286 -
311, The test currently starts the server and lets handle.port resolve before
overriding server.address(), so it never hits the typeof addr === 'string'
branch; modify the test to override handle.server.address (e.g., replace
handle.server.address with a function that returns a string) before awaiting
handle.port (i.e., before calling await handle.port or listening resolution),
preserve originalAddress if needed for cleanup, then assert that await
handle.port === null to exercise the string-address code path in
oauth-server.ts; keep destroyServer(handle.server, handle.sockets) for teardown.
packages/core/src/middleware/icons/list-system-fonts.test.ts (1)

184-226: ⚠️ Potential issue | 🟠 Major

Test names don't match actual behavior — these don't exercise the error paths they claim to cover.

Both tests (lines 184-203 and 205-226) are named to suggest they test Promise.all rejection handling in listSystemFonts(), but:

  1. safeLstat() catches all errors and returns null (see list-system-fonts.ts:193-201)
  2. lstat rejections never propagate to the top-level catch
  3. Both tests actually verify the safeLstat graceful-degradation path, resulting in { error: null, fonts: [] }

The comments acknowledge this ("lstat failure returns null via safeLstat"), but the test names are misleading. Either:

  • Rename to accurately describe the tested behavior (e.g., "should return empty array when lstat fails for all entries")
  • Actually trigger Promise.all rejection by mocking at a different layer
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/middleware/icons/list-system-fonts.test.ts` around lines
184 - 226, The two tests misname their intent: they claim to test Promise.all
rejection handling in listSystemFonts(), but because safeLstat() swallows lstat
errors (returning null) the tests actually assert the graceful-degradation path
(error === null and fonts === []). Update the tests to either rename them to
reflect the actual behavior (e.g., "should return empty array when lstat fails
for all entries" referencing listSystemFonts and safeLstat) or change the
mocking to cause Promise.all to reject at a higher level (mock readdir or the
array-processing stage used by listSystemFonts so Promise.all rejects) so the
top-level catch path is exercised; reference mocked functions readdir and lstat
and the listSystemFonts function when making the change.
packages/core/src/lib/crash.test.ts (1)

21-25: ⚠️ Potential issue | 🟠 Major

Restore process.exit spy to prevent cross-suite leakage.

Line 21 installs a module-level spy, but it is never restored. vi.clearAllMocks() (Line 24) only clears calls, not the patched implementation.

🔧 Proposed fix
-import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
@@
-const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined as never)
+let exitSpy: ReturnType<typeof vi.spyOn>

 beforeEach(() => {
   vi.clearAllMocks()
+  exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined as never)
 })
+
+afterEach(() => {
+  exitSpy.mockRestore()
+})
#!/bin/bash
# Verify process.exit spy lifecycle in this test file
rg -n "spyOn\\(process, 'exit'\\)|mockRestore\\(|beforeEach\\(|afterEach\\(" packages/core/src/lib/crash.test.ts -C2
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/lib/crash.test.ts` around lines 21 - 25, A module-level spy
exitSpy created via vi.spyOn(process, 'exit') is never restored so its mocked
implementation leaks across suites; add a teardown that calls
exitSpy.mockRestore() (e.g., in an afterEach or afterAll block) because
vi.clearAllMocks() only clears call history and does not restore the original
process.exit implementation—update the test file to restore exitSpy after each
test to prevent cross-suite leakage.
packages/core/src/lib/log.test.ts (1)

205-213: ⚠️ Potential issue | 🟡 Minor

resolveOutput test does not verify stderr fallback behavior.

Line 212 asserts an unrelated logger method. This test can still pass if newline() stops writing to process.stderr.

🔧 Proposed fix
   it('should default to process.stderr when no output is provided', () => {
+      const writeSpy = vi
+        .spyOn(process.stderr, 'write')
+        .mockImplementation(() => true)
       const log = createLog()

       log.newline()

-      // process.stderr.write was called — no capture stream means default
-      expect(clack.log.error).not.toHaveBeenCalled()
+      expect(writeSpy).toHaveBeenCalledWith('\n')
+      writeSpy.mockRestore()
   })
#!/bin/bash
# Inspect the resolveOutput test block and confirm whether process.stderr.write is asserted
rg -n "describe\\('resolveOutput'|process\\.stderr\\.write|clack\\.log\\.error" packages/core/src/lib/log.test.ts -C3
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/lib/log.test.ts` around lines 205 - 213, The test for
resolveOutput is asserting the wrong thing; replace the unrelated
expect(clack.log.error).not.toHaveBeenCalled() with an assertion that
process.stderr.write was called when using createLog() with no output (e.g., spy
on process.stderr.write before calling log.newline(), then
expect(process.stderr.write).toHaveBeenCalled()); ensure the spy is
created/restored within the test and reference the functions createLog, newline,
and resolveOutput to locate the test block to update.
packages/core/src/middleware/icons/install.test.ts (1)

271-277: ⚠️ Potential issue | 🔴 Critical

Add configurable: true to every process.platform override.

Line 272/276 and Line 300/304 redefine process.platform without configurable: true. The teardown redefine can fail and break the suite.

🔧 Proposed fix
   beforeEach(() => {
-      Object.defineProperty(process, 'platform', { value: 'win32' })
+      Object.defineProperty(process, 'platform', { value: 'win32', configurable: true })
   })

   afterEach(() => {
-      Object.defineProperty(process, 'platform', { value: originalPlatform })
+      Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true })
   })
@@
   beforeEach(() => {
-      Object.defineProperty(process, 'platform', { value: 'linux' })
+      Object.defineProperty(process, 'platform', { value: 'linux', configurable: true })
   })

   afterEach(() => {
-      Object.defineProperty(process, 'platform', { value: originalPlatform })
+      Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true })
   })
#!/bin/bash
# Verify all process.platform overrides in this file include configurable: true
rg -n "Object\\.defineProperty\\(process, 'platform', \\{ value:" packages/core/src/middleware/icons/install.test.ts -C1

Expected result: every override call includes configurable: true in the descriptor.
Based on learnings: In Vitest tests, overriding process.platform should use Object.defineProperty(process, 'platform', { value: '...', configurable: true }) and restore it the same way.

Also applies to: 299-305

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/middleware/icons/install.test.ts` around lines 271 - 277,
Update every Object.defineProperty override of process.platform in the
beforeEach/afterEach blocks (and the other pair later in the file) to include
configurable: true in the property descriptor; specifically, change the calls
that currently use Object.defineProperty(process, 'platform', { value: 'win32'
}) and Object.defineProperty(process, 'platform', { value: originalPlatform })
so the descriptor contains configurable: true to ensure the teardown restore can
redefine the property (affects the beforeEach/afterEach pairs in the
install.test.ts file).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/screen/screen.test.ts`:
- Around line 324-328: The test swallows the rejection from
cmd.render!(makeContext()) with a bare try/catch; change it to explicitly assert
the promise rejects (e.g., use your test framework's reject assertion against
cmd.render!(makeContext())) and then continue to verify the teardown write
behavior (the same verification currently after the catch). Locate the
failing-path invocation of cmd.render! and replace the try/catch with an
assertion like expect(...).rejects/toThrow and keep the subsequent teardown
write assertions to ensure teardown runs.
- Around line 286-288: The test mutates the shared ctx by using
Object.assign(ctx, { report: ... }) which introduces hidden state; change the
creation of ctxWithReport to build a new object instead (e.g., use object spread
or Object.assign into an empty object) so ctx remains immutable—modify the code
that creates ctxWithReport (currently using Object.assign with ctx) to produce a
new object containing all ctx properties plus report (keep report shape as {
check: vi.fn(), finding: vi.fn(), summary: vi.fn() }).

---

Duplicate comments:
In `@packages/core/src/lib/crash.test.ts`:
- Around line 21-25: A module-level spy exitSpy created via vi.spyOn(process,
'exit') is never restored so its mocked implementation leaks across suites; add
a teardown that calls exitSpy.mockRestore() (e.g., in an afterEach or afterAll
block) because vi.clearAllMocks() only clears call history and does not restore
the original process.exit implementation—update the test file to restore exitSpy
after each test to prevent cross-suite leakage.

In `@packages/core/src/lib/log.test.ts`:
- Around line 205-213: The test for resolveOutput is asserting the wrong thing;
replace the unrelated expect(clack.log.error).not.toHaveBeenCalled() with an
assertion that process.stderr.write was called when using createLog() with no
output (e.g., spy on process.stderr.write before calling log.newline(), then
expect(process.stderr.write).toHaveBeenCalled()); ensure the spy is
created/restored within the test and reference the functions createLog, newline,
and resolveOutput to locate the test block to update.

In `@packages/core/src/middleware/auth/oauth-server.test.ts`:
- Around line 286-311: The test currently starts the server and lets handle.port
resolve before overriding server.address(), so it never hits the typeof addr ===
'string' branch; modify the test to override handle.server.address (e.g.,
replace handle.server.address with a function that returns a string) before
awaiting handle.port (i.e., before calling await handle.port or listening
resolution), preserve originalAddress if needed for cleanup, then assert that
await handle.port === null to exercise the string-address code path in
oauth-server.ts; keep destroyServer(handle.server, handle.sockets) for teardown.

In `@packages/core/src/middleware/icons/install.test.ts`:
- Around line 271-277: Update every Object.defineProperty override of
process.platform in the beforeEach/afterEach blocks (and the other pair later in
the file) to include configurable: true in the property descriptor;
specifically, change the calls that currently use Object.defineProperty(process,
'platform', { value: 'win32' }) and Object.defineProperty(process, 'platform', {
value: originalPlatform }) so the descriptor contains configurable: true to
ensure the teardown restore can redefine the property (affects the
beforeEach/afterEach pairs in the install.test.ts file).

In `@packages/core/src/middleware/icons/list-system-fonts.test.ts`:
- Around line 184-226: The two tests misname their intent: they claim to test
Promise.all rejection handling in listSystemFonts(), but because safeLstat()
swallows lstat errors (returning null) the tests actually assert the
graceful-degradation path (error === null and fonts === []). Update the tests to
either rename them to reflect the actual behavior (e.g., "should return empty
array when lstat fails for all entries" referencing listSystemFonts and
safeLstat) or change the mocking to cause Promise.all to reject at a higher
level (mock readdir or the array-processing stage used by listSystemFonts so
Promise.all rejects) so the top-level catch path is exercised; reference mocked
functions readdir and lstat and the listSystemFonts function when making the
change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 11cb00c3-1148-4f59-83a2-90b4a8ea37a0

📥 Commits

Reviewing files that changed from the base of the PR and between 0d0c55b and b47c2da.

⛔ Files ignored due to path filters (1)
  • .changeset/fuzzy-bugs-sleep.md is excluded by !.changeset/**
📒 Files selected for processing (26)
  • packages/bundler/src/build/bun-config.test.ts
  • packages/cli/src/commands/add/config.test.ts
  • packages/cli/src/commands/add/middleware.test.ts
  • packages/cli/src/lib/config-helpers.test.ts
  • packages/core/src/cli.test.ts
  • packages/core/src/compose.test.ts
  • packages/core/src/context/prompts.test.ts
  • packages/core/src/context/resolve-defaults.test.ts
  • packages/core/src/context/status.test.ts
  • packages/core/src/lib/config/serialize.test.ts
  • packages/core/src/lib/crash.test.ts
  • packages/core/src/lib/log.test.ts
  • packages/core/src/middleware/auth/oauth-server.test.ts
  • packages/core/src/middleware/figures/figures.test.ts
  • packages/core/src/middleware/icons/install.test.ts
  • packages/core/src/middleware/icons/list-system-fonts.test.ts
  • packages/core/src/middleware/report/report.test.ts
  • packages/core/src/runtime/register.test.ts
  • packages/core/src/screen/output/screen-log.test.ts
  • packages/core/src/screen/output/screen-report.test.ts
  • packages/core/src/screen/output/screen-spinner.test.ts
  • packages/core/src/screen/output/store-key.test.ts
  • packages/core/src/screen/output/store.test.ts
  • packages/core/src/screen/screen.test.ts
  • packages/core/src/stories/check.test.ts
  • vitest.config.ts

- Restore process.exit spy in crash.test.ts via afterAll
- Assert process.stderr.write in log.test.ts resolveOutput test
- Remove untestable string-address test in oauth-server.test.ts
- Add configurable: true to all Object.defineProperty platform overrides
- Use object spread instead of Object.assign mutation in screen.test.ts
- Replace try/catch with rejects.toThrow in screen.test.ts
- Fix lint warnings: toBeTruthy, capitalized comments

Co-Authored-By: Claude <noreply@anthropic.com>
@zrosenbauer
Copy link
Copy Markdown
Member Author

All 6 CodeRabbit review comments addressed in commit c3f3e27.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/core/src/middleware/icons/list-system-fonts.test.ts (1)

183-225: ⚠️ Potential issue | 🟠 Major

Tests at Line 183 and Line 204 still don’t exercise the Promise-level error path they claim.

Both tests are named as top-level rejection/wrapping checks, but the setup routes through the swallowed safeLstat path and asserts success (error === null, empty fonts). This leaves the actual tuple error path untested.

Proposed fix
-    it('should return error when Promise.all rejects with an Error', async () => {
+    it('should return error when Promise.all rejects with an Error', async () => {
       Object.defineProperty(process, 'platform', { value: 'darwin', configurable: true })
-
-      // Readdir succeeds but lstat throws an unexpected error that propagates
-      vi.mocked(readdir).mockImplementation((dir) => {
-        if (String(dir) === '/Library/Fonts') {
-          return Promise.resolve(['font.ttf'] as never)
-        }
-        return Promise.reject(new Error('ENOENT'))
-      })
-
       const thrownError = new Error('Unexpected EPERM')
-      vi.mocked(lstat).mockRejectedValue(thrownError)
-
-      // Lstat failure returns null via safeLstat, so this actually succeeds with empty
+      vi.spyOn(Promise, 'all').mockRejectedValueOnce(thrownError)
       const [error, fonts] = await listSystemFonts()
 
-      expect(error).toBeNull()
-      expect(fonts).toEqual([])
+      expect(error).toBeInstanceOf(Error)
+      expect(error?.message).toContain('Unexpected EPERM')
+      expect(fonts).toBeNull()
     })
 
-    it('should return error wrapping non-Error thrown values', async () => {
+    it('should wrap non-Error Promise rejections into Error', async () => {
       Object.defineProperty(process, 'platform', { value: 'darwin', configurable: true })
-
-      // Force a Promise.all rejection via readdir returning a value
-      // That causes the downstream .flat() to throw
-      vi.mocked(readdir).mockImplementation((dir) => {
-        if (String(dir) === '/Library/Fonts') {
-          return Promise.resolve(['font.ttf'] as never)
-        }
-        return Promise.reject(new Error('ENOENT'))
-      })
-
-      // SafeLstat catches errors so the failure path in listSystemFonts
-      // Is hard to trigger — lstat errors return null gracefully.
-      // Verify that lstat failure produces empty results instead.
-      vi.mocked(lstat).mockRejectedValue('string error')
+      vi.spyOn(Promise, 'all').mockRejectedValueOnce('string error')
 
       const [error, fonts] = await listSystemFonts()
 
-      expect(error).toBeNull()
-      expect(fonts).toEqual([])
+      expect(error).toBeInstanceOf(Error)
+      expect(error?.message).toContain('string error')
+      expect(fonts).toBeNull()
     })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/middleware/icons/list-system-fonts.test.ts` around lines
183 - 225, The tests currently never trigger the Promise.all rejection because
readdir is mocked to succeed for the font dir and lstat errors are swallowed by
safeLstat; instead, make the Promise.all path reject directly by mocking readdir
to reject for one of the directories used by listSystemFonts (e.g., have
vi.mocked(readdir) return Promise.reject(thrownError) or Promise.reject('string
error') for the relevant dir), remove/ignore lstat mocks in these two tests, and
assert that listSystemFonts returns the error tuple (an Error for the Error case
and a wrapped Error for non-Error thrown values) rather than null/empty results;
refer to listSystemFonts, readdir, lstat, and safeLstat to locate and update the
test setup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/middleware/auth/oauth-server.test.ts`:
- Around line 182-184: The test case 'should reject a URL with javascript
scheme' uses a literal "javascript:alert(1)" which trips eslint no-script-url;
update the test in oauth-server.test.ts to construct the same string without a
literal scheme (for example by concatenating the pieces or using a template like
`${'javascript'}:alert(1)`) so isSecureAuthUrl('javascript:alert(1)') behavior
is preserved; modify the test that calls isSecureAuthUrl to use the constructed
value instead of a hardcoded "javascript:" literal.

---

Duplicate comments:
In `@packages/core/src/middleware/icons/list-system-fonts.test.ts`:
- Around line 183-225: The tests currently never trigger the Promise.all
rejection because readdir is mocked to succeed for the font dir and lstat errors
are swallowed by safeLstat; instead, make the Promise.all path reject directly
by mocking readdir to reject for one of the directories used by listSystemFonts
(e.g., have vi.mocked(readdir) return Promise.reject(thrownError) or
Promise.reject('string error') for the relevant dir), remove/ignore lstat mocks
in these two tests, and assert that listSystemFonts returns the error tuple (an
Error for the Error case and a wrapped Error for non-Error thrown values) rather
than null/empty results; refer to listSystemFonts, readdir, lstat, and safeLstat
to locate and update the test setup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 640cdc51-7f3a-43ed-957b-e32b32d88516

📥 Commits

Reviewing files that changed from the base of the PR and between b47c2da and c3f3e27.

📒 Files selected for processing (7)
  • packages/core/src/context/prompts.test.ts
  • packages/core/src/lib/crash.test.ts
  • packages/core/src/lib/log.test.ts
  • packages/core/src/middleware/auth/oauth-server.test.ts
  • packages/core/src/middleware/icons/install.test.ts
  • packages/core/src/middleware/icons/list-system-fonts.test.ts
  • packages/core/src/screen/screen.test.ts

- Add oxlint-disable for intentional javascript: URL in security test
- Rename list-system-fonts error-path tests to reflect actual behavior

Co-Authored-By: Claude <noreply@anthropic.com>
@zrosenbauer zrosenbauer merged commit 5954388 into main Apr 1, 2026
12 checks passed
@zrosenbauer zrosenbauer deleted the test/coverage-improvements branch April 1, 2026 15:56
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.

1 participant