fix(ci): simplify test runner to plain bun test by fixing mock.module() leakage

- Add afterAll(() => { mock.restore() }) to 52 test files missing cleanup
- Rewrite create-tool-guard-hooks.test.ts to use spyOn instead of barrel mock
- Fix skill-mcp-manager OAuth tests with missing mockTokens/mockLogin definitions
- Fix start-work hook: show worktree active block on resume with existing worktree_path
- Extract createWorktreeActiveBlock to worktree-block.ts to avoid circular import
- Replace 80-line isolated test runner CI config with single `bun test` command
This commit is contained in:
YeonGyu-Kim
2026-04-03 23:06:35 +09:00
parent 06180e09f8
commit 53eeac3f31
55 changed files with 219 additions and 190 deletions
+3 -1
View File
@@ -1,11 +1,13 @@
declare const require: (name: string) => any
const { afterEach, describe, expect, mock, test } = require("bun:test")
const { afterEach, afterAll, describe, expect, mock, test } = require("bun:test")
mock.module("../shared/connected-providers-cache", () => ({
readConnectedProvidersCache: () => null,
readProviderModelsCache: () => null,
}))
afterAll(() => { mock.restore() })
import { createEventHandler } from "./event"
import { createChatMessageHandler } from "./chat-message"
import { _resetForTesting, setMainSession } from "../features/claude-code-session-state"
@@ -1,5 +1,5 @@
declare const require: (name: string) => any
const { afterEach, describe, expect, mock, test } = require("bun:test")
const { afterEach, afterAll, describe, expect, mock, test } = require("bun:test")
const PROVIDER_ID = "cliproxyapi"
@@ -10,6 +10,8 @@ mock.module("../shared/connected-providers-cache", () => ({
}),
}))
afterAll(() => { mock.restore() })
import { createEventHandler } from "./event"
import { createChatMessageHandler } from "./chat-message"
import { createModelFallbackHook } from "../hooks/model-fallback/hook"
@@ -1,7 +1,8 @@
import { beforeEach, describe, expect, it, mock } from "bun:test"
import { beforeEach, describe, expect, it, spyOn } from "bun:test"
import type { OhMyOpenCodeConfig } from "../../config"
import type { ModelCacheState } from "../../plugin-state"
import type { PluginContext } from "../types"
import * as hooks from "../../hooks"
const mockContext = {
directory: "/tmp",
@@ -9,58 +10,41 @@ const mockContext = {
const mockModelCacheState = {
anthropicContext1MEnabled: false,
modelContextLimitsCache: new Map(),
} satisfies ModelCacheState
let capturedRulesInjectorOptions: { skipClaudeUserRules?: boolean } | undefined
mock.module("../../hooks", () => ({
createCommentCheckerHooks: () => ({ name: "comment-checker" }),
createToolOutputTruncatorHook: () => ({ name: "tool-output-truncator" }),
createDirectoryAgentsInjectorHook: () => ({ name: "directory-agents-injector" }),
createDirectoryReadmeInjectorHook: () => ({ name: "directory-readme-injector" }),
createEmptyTaskResponseDetectorHook: () => ({ name: "empty-task-response-detector" }),
createRulesInjectorHook: (
_ctx: PluginContext,
_modelCacheState: ModelCacheState,
options?: { skipClaudeUserRules?: boolean },
) => {
capturedRulesInjectorOptions = options
return { name: "rules-injector" }
},
createTasksTodowriteDisablerHook: () => ({ name: "tasks-todowrite-disabler" }),
createWriteExistingFileGuardHook: () => ({ name: "write-existing-file-guard" }),
createBashFileReadGuardHook: () => ({ name: "bash-file-read-guard" }),
createHashlineReadEnhancerHook: () => ({ name: "hashline-read-enhancer" }),
createReadImageResizerHook: () => ({ name: "read-image-resizer" }),
createJsonErrorRecoveryHook: () => ({ name: "json-error-recovery" }),
createTodoDescriptionOverrideHook: () => ({ name: "todo-description-override" }),
createWebFetchRedirectGuardHook: () => ({ name: "webfetch-redirect-guard" }),
}))
describe("createToolGuardHooks", () => {
let capturedOptions: { skipClaudeUserRules?: boolean } | undefined
beforeEach(() => {
capturedRulesInjectorOptions = undefined
capturedOptions = undefined
spyOn(hooks, "createRulesInjectorHook").mockImplementation(
(_ctx: unknown, _state: unknown, options?: { skipClaudeUserRules?: boolean }) => {
capturedOptions = options
return { name: "rules-injector" } as never
},
)
})
it("skips Claude user rules when claude_code.hooks is false", async () => {
it("skips Claude user rules when claude_code.hooks is false", () => {
// given
const pluginConfig = {
claude_code: {
hooks: false,
},
} as OhMyOpenCodeConfig
const { createToolGuardHooks } = await import("./create-tool-guard-hooks")
const { createToolGuardHooks } = require("./create-tool-guard-hooks")
// when
createToolGuardHooks({
ctx: mockContext,
pluginConfig,
modelCacheState: mockModelCacheState,
isHookEnabled: (hookName) => hookName === "rules-injector",
isHookEnabled: (hookName: string) => hookName === "rules-injector",
safeHookEnabled: true,
})
// then
expect(capturedRulesInjectorOptions).toEqual({ skipClaudeUserRules: true })
expect(capturedOptions).toEqual({ skipClaudeUserRules: true })
})
})