Skip to content

fix(ci): disable vitest console intercept to eliminate teardown race - #14

Merged
seeones merged 1 commit into
mainfrom
fix/vitest-console-teardown-race
Sep 22, 2026
Merged

seeones merged 1 commit into
mainfrom
fix/vitest-console-teardown-race

Conversation

@seeones

@seeones seeones commented Sep 22, 2026

Copy link
Copy Markdown
Owner

背景

PR #12 合并后 main 上的 Code QA 在 ubuntu/windows 随机失败:

EnvironmentTeardownError: [vitest-worker]: Closing rpc while "onUserConsoleLog" was pending

根因(源码级确认)

vitest 4.1.11 在 worker 侧无条件替换 globalThis.console(setupConsoleLogSpy),每次 console 输出经 microtask → state().rpc.onUserConsoleLog(...) 转发到主进程。测试文件的异步 console 输出在 worker teardown 时在途,RPC 关闭与之竞争即报错。

origin 是随机的:windows 落在 ClineProvider.flicker-free-cancel.spec.ts,ubuntu 落在 Task.throttle.test.ts——系统性 flake,不是单文件问题。

修复

  1. src/vitest.config.ts:启用 disableConsoleIntercept: true,console 保持原生直接写进程流,完全绕开 onUserConsoleLog RPC。
  2. ClineProvider.flicker-free-cancel.spec.ts:补 SkillsManager mock(唯一真实构造 ClineProvider 的测试),消除最常触发的 console.error 来源。

验证

  • 本地全量测试:363 files / 5233 tests 全绿
  • lint / check-types 通过

vitest 4.1.11 unconditionally replaces globalThis.console in the worker
(setupConsoleLogSpy) and forwards every log via state().rpc.onUserConsoleLog.
When a test leaves async console output in flight during worker teardown, the
RPC close races with the pending onUserConsoleLog call and vitest fails with:
EnvironmentTeardownError: [vitest-worker]: Closing rpc while onUserConsoleLog
was pending.

The origin is random (ClineProvider.flicker-free-cancel.spec.ts on windows,
Task.throttle.test.ts on ubuntu), so it is a systemic flake, not a single
file issue. Enabling disableConsoleIntercept keeps the native console, which
writes straight to the process streams and completely bypasses the RPC.

Also mock SkillsManager in ClineProvider.flicker-free-cancel.spec.ts (the
only test that constructs ClineProvider directly). It was missing that mock,
so the real SkillsManager.initialize() ran directory scans and emitted
console.error, which was the most common trigger. Use a regular function for
the constructor mock because arrow functions lack [[Construct]] and break
new SkillsManager(this).
@seeones
seeones merged commit 4193bf8 into main Sep 22, 2026
7 checks passed
@seeones
seeones deleted the fix/vitest-console-teardown-race branch September 22, 2026 15:51
seeones added a commit that referenced this pull request Sep 23, 2026
…14)

vitest 4.1.11 unconditionally replaces globalThis.console in the worker
(setupConsoleLogSpy) and forwards every log via state().rpc.onUserConsoleLog.
When a test leaves async console output in flight during worker teardown, the
RPC close races with the pending onUserConsoleLog call and vitest fails with:
EnvironmentTeardownError: [vitest-worker]: Closing rpc while onUserConsoleLog
was pending.

The origin is random (ClineProvider.flicker-free-cancel.spec.ts on windows,
Task.throttle.test.ts on ubuntu), so it is a systemic flake, not a single
file issue. Enabling disableConsoleIntercept keeps the native console, which
writes straight to the process streams and completely bypasses the RPC.

Also mock SkillsManager in ClineProvider.flicker-free-cancel.spec.ts (the
only test that constructs ClineProvider directly). It was missing that mock,
so the real SkillsManager.initialize() ran directory scans and emitted
console.error, which was the most common trigger. Use a regular function for
the constructor mock because arrow functions lack [[Construct]] and break
new SkillsManager(this).

Co-authored-by: seeones <seeones@163.com>
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