test: localize stop hook command mocks
This commit is contained in:
@@ -1,26 +1,14 @@
|
|||||||
import { describe, it, expect, mock, beforeEach, afterAll } from "bun:test"
|
import { describe, it, expect, mock, beforeEach, afterEach, spyOn } from "bun:test"
|
||||||
import type { ClaudeHooksConfig } from "./types"
|
import type { ClaudeHooksConfig } from "./types"
|
||||||
import type { StopContext } from "./stop"
|
import type { StopContext } from "./stop"
|
||||||
|
import * as dispatchHookModule from "./dispatch-hook"
|
||||||
|
import * as logger from "../../shared/logger"
|
||||||
|
import { executeStopHooks } from "./stop"
|
||||||
|
|
||||||
const mockExecuteHookCommand = mock(() =>
|
const mockDispatchHook = mock(() =>
|
||||||
Promise.resolve({ exitCode: 0, stdout: "", stderr: "" })
|
Promise.resolve({ exitCode: 0, stdout: "", stderr: "" })
|
||||||
)
|
)
|
||||||
|
|
||||||
mock.module("../../shared/command-executor", () => ({
|
|
||||||
executeHookCommand: mockExecuteHookCommand,
|
|
||||||
executeCommand: mock(),
|
|
||||||
resolveCommandsInText: mock(),
|
|
||||||
}))
|
|
||||||
|
|
||||||
mock.module("../../shared/logger", () => ({
|
|
||||||
log: () => {},
|
|
||||||
getLogFilePath: () => "/tmp/test.log",
|
|
||||||
}))
|
|
||||||
|
|
||||||
afterAll(() => { mock.restore() })
|
|
||||||
|
|
||||||
const { executeStopHooks } = await import("./stop")
|
|
||||||
|
|
||||||
function createStopContext(overrides?: Partial<StopContext>): StopContext {
|
function createStopContext(overrides?: Partial<StopContext>): StopContext {
|
||||||
return {
|
return {
|
||||||
sessionId: "test-session",
|
sessionId: "test-session",
|
||||||
@@ -35,10 +23,19 @@ function createConfig(stopHooks: ClaudeHooksConfig["Stop"]): ClaudeHooksConfig {
|
|||||||
|
|
||||||
describe("executeStopHooks", () => {
|
describe("executeStopHooks", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockExecuteHookCommand.mockReset()
|
mockDispatchHook.mockReset()
|
||||||
mockExecuteHookCommand.mockImplementation(() =>
|
mockDispatchHook.mockImplementation(() =>
|
||||||
Promise.resolve({ exitCode: 0, stdout: "", stderr: "" })
|
Promise.resolve({ exitCode: 0, stdout: "", stderr: "" })
|
||||||
)
|
)
|
||||||
|
|
||||||
|
spyOn(dispatchHookModule, "dispatchHook").mockImplementation(
|
||||||
|
async (_hook, _stdinJson, _cwd) => await mockDispatchHook()
|
||||||
|
)
|
||||||
|
spyOn(logger, "log").mockImplementation(() => {})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
mock.restore()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("#given parent session #when stop hooks called #then skips execution", async () => {
|
it("#given parent session #when stop hooks called #then skips execution", async () => {
|
||||||
@@ -50,7 +47,7 @@ describe("executeStopHooks", () => {
|
|||||||
const result = await executeStopHooks(ctx, config)
|
const result = await executeStopHooks(ctx, config)
|
||||||
|
|
||||||
expect(result.block).toBe(false)
|
expect(result.block).toBe(false)
|
||||||
expect(mockExecuteHookCommand).not.toHaveBeenCalled()
|
expect(mockDispatchHook).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("#given null config #when stop hooks called #then returns non-blocking", async () => {
|
it("#given null config #when stop hooks called #then returns non-blocking", async () => {
|
||||||
@@ -59,7 +56,7 @@ describe("executeStopHooks", () => {
|
|||||||
const result = await executeStopHooks(ctx, null)
|
const result = await executeStopHooks(ctx, null)
|
||||||
|
|
||||||
expect(result.block).toBe(false)
|
expect(result.block).toBe(false)
|
||||||
expect(mockExecuteHookCommand).not.toHaveBeenCalled()
|
expect(mockDispatchHook).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("#given empty stop hooks #when stop hooks called #then returns non-blocking", async () => {
|
it("#given empty stop hooks #when stop hooks called #then returns non-blocking", async () => {
|
||||||
@@ -76,7 +73,7 @@ describe("executeStopHooks", () => {
|
|||||||
const config = createConfig([
|
const config = createConfig([
|
||||||
{ matcher: "*", hooks: [{ type: "command", command: "exit 2" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "exit 2" }] },
|
||||||
])
|
])
|
||||||
mockExecuteHookCommand.mockResolvedValueOnce({
|
mockDispatchHook.mockResolvedValueOnce({
|
||||||
exitCode: 2,
|
exitCode: 2,
|
||||||
stdout: "",
|
stdout: "",
|
||||||
stderr: "blocked reason",
|
stderr: "blocked reason",
|
||||||
@@ -93,7 +90,7 @@ describe("executeStopHooks", () => {
|
|||||||
const config = createConfig([
|
const config = createConfig([
|
||||||
{ matcher: "*", hooks: [{ type: "command", command: "blocker" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "blocker" }] },
|
||||||
])
|
])
|
||||||
mockExecuteHookCommand.mockResolvedValueOnce({
|
mockDispatchHook.mockResolvedValueOnce({
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
stdout: JSON.stringify({ decision: "block", reason: "must fix" }),
|
stdout: JSON.stringify({ decision: "block", reason: "must fix" }),
|
||||||
stderr: "",
|
stderr: "",
|
||||||
@@ -111,7 +108,7 @@ describe("executeStopHooks", () => {
|
|||||||
{ matcher: "*", hooks: [{ type: "command", command: "hook-a" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "hook-a" }] },
|
||||||
{ matcher: "*", hooks: [{ type: "command", command: "hook-b" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "hook-b" }] },
|
||||||
])
|
])
|
||||||
mockExecuteHookCommand
|
mockDispatchHook
|
||||||
.mockResolvedValueOnce({
|
.mockResolvedValueOnce({
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
stdout: JSON.stringify({ suppressOutput: true }),
|
stdout: JSON.stringify({ suppressOutput: true }),
|
||||||
@@ -126,7 +123,7 @@ describe("executeStopHooks", () => {
|
|||||||
const result = await executeStopHooks(ctx, config)
|
const result = await executeStopHooks(ctx, config)
|
||||||
|
|
||||||
expect(result.block).toBe(false)
|
expect(result.block).toBe(false)
|
||||||
expect(mockExecuteHookCommand).toHaveBeenCalledTimes(2)
|
expect(mockDispatchHook).toHaveBeenCalledTimes(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("#given first hook returns stdin passthrough JSON #when multiple hooks #then executes all hooks", async () => {
|
it("#given first hook returns stdin passthrough JSON #when multiple hooks #then executes all hooks", async () => {
|
||||||
@@ -140,7 +137,7 @@ describe("executeStopHooks", () => {
|
|||||||
{ matcher: "*", hooks: [{ type: "command", command: "check-console-log" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "check-console-log" }] },
|
||||||
{ matcher: "*", hooks: [{ type: "command", command: "task-complete-notify" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "task-complete-notify" }] },
|
||||||
])
|
])
|
||||||
mockExecuteHookCommand
|
mockDispatchHook
|
||||||
.mockResolvedValueOnce({
|
.mockResolvedValueOnce({
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
stdout: JSON.stringify(stdinPassthrough),
|
stdout: JSON.stringify(stdinPassthrough),
|
||||||
@@ -155,7 +152,7 @@ describe("executeStopHooks", () => {
|
|||||||
const result = await executeStopHooks(ctx, config)
|
const result = await executeStopHooks(ctx, config)
|
||||||
|
|
||||||
expect(result.block).toBe(false)
|
expect(result.block).toBe(false)
|
||||||
expect(mockExecuteHookCommand).toHaveBeenCalledTimes(2)
|
expect(mockDispatchHook).toHaveBeenCalledTimes(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("#given first hook blocks #when multiple hooks #then stops at blocking hook", async () => {
|
it("#given first hook blocks #when multiple hooks #then stops at blocking hook", async () => {
|
||||||
@@ -164,7 +161,7 @@ describe("executeStopHooks", () => {
|
|||||||
{ matcher: "*", hooks: [{ type: "command", command: "blocker" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "blocker" }] },
|
||||||
{ matcher: "*", hooks: [{ type: "command", command: "notifier" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "notifier" }] },
|
||||||
])
|
])
|
||||||
mockExecuteHookCommand.mockResolvedValueOnce({
|
mockDispatchHook.mockResolvedValueOnce({
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
stdout: JSON.stringify({ decision: "block", reason: "fix first" }),
|
stdout: JSON.stringify({ decision: "block", reason: "fix first" }),
|
||||||
stderr: "",
|
stderr: "",
|
||||||
@@ -173,7 +170,7 @@ describe("executeStopHooks", () => {
|
|||||||
const result = await executeStopHooks(ctx, config)
|
const result = await executeStopHooks(ctx, config)
|
||||||
|
|
||||||
expect(result.block).toBe(true)
|
expect(result.block).toBe(true)
|
||||||
expect(mockExecuteHookCommand).toHaveBeenCalledTimes(1)
|
expect(mockDispatchHook).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("#given hook with non-JSON stdout #when stop hooks called #then continues to next hook", async () => {
|
it("#given hook with non-JSON stdout #when stop hooks called #then continues to next hook", async () => {
|
||||||
@@ -182,7 +179,7 @@ describe("executeStopHooks", () => {
|
|||||||
{ matcher: "*", hooks: [{ type: "command", command: "hook-a" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "hook-a" }] },
|
||||||
{ matcher: "*", hooks: [{ type: "command", command: "hook-b" }] },
|
{ matcher: "*", hooks: [{ type: "command", command: "hook-b" }] },
|
||||||
])
|
])
|
||||||
mockExecuteHookCommand
|
mockDispatchHook
|
||||||
.mockResolvedValueOnce({
|
.mockResolvedValueOnce({
|
||||||
exitCode: 0,
|
exitCode: 0,
|
||||||
stdout: "not json",
|
stdout: "not json",
|
||||||
@@ -197,6 +194,6 @@ describe("executeStopHooks", () => {
|
|||||||
const result = await executeStopHooks(ctx, config)
|
const result = await executeStopHooks(ctx, config)
|
||||||
|
|
||||||
expect(result.block).toBe(false)
|
expect(result.block).toBe(false)
|
||||||
expect(mockExecuteHookCommand).toHaveBeenCalledTimes(2)
|
expect(mockDispatchHook).toHaveBeenCalledTimes(2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user