refactor(test): share internal hook and npm pack assertions

This commit is contained in:
Peter Steinberger
2026-02-18 16:59:38 +00:00
parent 72a4d83334
commit f05395ae00
6 changed files with 57 additions and 48 deletions

View File

@@ -1,5 +1,6 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
import { createInternalHookEventPayload } from "../../test-utils/internal-hook-event-payload.js";
import type { MsgContext } from "../templating.js";
import type { GetReplyOptions, ReplyPayload } from "../types.js";
import type { ReplyDispatcher } from "./reply-dispatcher.js";
@@ -26,16 +27,7 @@ const hookMocks = vi.hoisted(() => ({
},
}));
const internalHookMocks = vi.hoisted(() => ({
createInternalHookEvent: vi.fn(
(type: string, action: string, sessionKey: string, context: Record<string, unknown>) => ({
type,
action,
sessionKey,
context,
timestamp: new Date(),
messages: [],
}),
),
createInternalHookEvent: vi.fn(),
triggerInternalHook: vi.fn(async () => {}),
}));
@@ -121,7 +113,8 @@ describe("dispatchReplyFromConfig", () => {
hookMocks.runner.hasHooks.mockReset();
hookMocks.runner.hasHooks.mockReturnValue(false);
hookMocks.runner.runMessageReceived.mockReset();
internalHookMocks.createInternalHookEvent.mockClear();
internalHookMocks.createInternalHookEvent.mockReset();
internalHookMocks.createInternalHookEvent.mockImplementation(createInternalHookEventPayload);
internalHookMocks.triggerInternalHook.mockClear();
});
it("does not route when Provider matches OriginatingChannel (even if Surface is missing)", async () => {

View File

@@ -3,7 +3,10 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
import { expectSingleNpmInstallIgnoreScriptsCall } from "../test-utils/exec-assertions.js";
import {
expectSingleNpmInstallIgnoreScriptsCall,
expectSingleNpmPackIgnoreScriptsCall,
} from "../test-utils/exec-assertions.js";
import { isAddressInUseError } from "./gmail-watcher.js";
const fixtureRoot = path.join(os.tmpdir(), `openclaw-hook-install-${randomUUID()}`);
@@ -273,18 +276,10 @@ describe("installHooksFromNpmSpec", () => {
expect(result.hookPackId).toBe("test-hooks");
expect(fs.existsSync(path.join(result.targetDir, "hooks", "one-hook", "HOOK.md"))).toBe(true);
const packCalls = run.mock.calls.filter(
(c) => Array.isArray(c[0]) && c[0][0] === "npm" && c[0][1] === "pack",
);
expect(packCalls.length).toBe(1);
const packCall = packCalls[0];
if (!packCall) {
throw new Error("expected npm pack call");
}
const [argv, options] = packCall;
expect(argv).toEqual(["npm", "pack", "@openclaw/test-hooks@0.0.1", "--ignore-scripts"]);
const commandOptions = typeof options === "number" ? undefined : options;
expect(commandOptions?.env).toMatchObject({ NPM_CONFIG_IGNORE_SCRIPTS: "true" });
expectSingleNpmPackIgnoreScriptsCall({
calls: run.mock.calls,
expectedSpec: "@openclaw/test-hooks@0.0.1",
});
expect(packTmpDir).not.toBe("");
expect(fs.existsSync(packTmpDir)).toBe(false);

View File

@@ -9,6 +9,7 @@ import { setActivePluginRegistry } from "../../plugins/runtime.js";
import { markdownToSignalTextChunks } from "../../signal/format.js";
import { createOutboundTestPlugin, createTestRegistry } from "../../test-utils/channel-plugins.js";
import { createIMessageTestPlugin } from "../../test-utils/imessage-test-plugin.js";
import { createInternalHookEventPayload } from "../../test-utils/internal-hook-event-payload.js";
const mocks = vi.hoisted(() => ({
appendAssistantMessageToSessionTranscript: vi.fn(async () => ({ ok: true, sessionFile: "x" })),
@@ -20,16 +21,7 @@ const hookMocks = vi.hoisted(() => ({
},
}));
const internalHookMocks = vi.hoisted(() => ({
createInternalHookEvent: vi.fn(
(type: string, action: string, sessionKey: string, context: Record<string, unknown>) => ({
type,
action,
sessionKey,
context,
timestamp: new Date(),
messages: [],
}),
),
createInternalHookEvent: vi.fn(),
triggerInternalHook: vi.fn(async () => {}),
}));
const queueMocks = vi.hoisted(() => ({
@@ -93,7 +85,8 @@ describe("deliverOutboundPayloads", () => {
hookMocks.runner.hasHooks.mockReturnValue(false);
hookMocks.runner.runMessageSent.mockReset();
hookMocks.runner.runMessageSent.mockResolvedValue(undefined);
internalHookMocks.createInternalHookEvent.mockClear();
internalHookMocks.createInternalHookEvent.mockReset();
internalHookMocks.createInternalHookEvent.mockImplementation(createInternalHookEventPayload);
internalHookMocks.triggerInternalHook.mockClear();
queueMocks.enqueueDelivery.mockReset();
queueMocks.enqueueDelivery.mockResolvedValue("mock-queue-id");

View File

@@ -6,7 +6,10 @@ import JSZip from "jszip";
import * as tar from "tar";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import * as skillScanner from "../security/skill-scanner.js";
import { expectSingleNpmInstallIgnoreScriptsCall } from "../test-utils/exec-assertions.js";
import {
expectSingleNpmInstallIgnoreScriptsCall,
expectSingleNpmPackIgnoreScriptsCall,
} from "../test-utils/exec-assertions.js";
vi.mock("../process/exec.js", () => ({
runCommandWithTimeout: vi.fn(),
@@ -506,18 +509,10 @@ describe("installPluginFromNpmSpec", () => {
});
expect(result.ok).toBe(true);
const packCalls = run.mock.calls.filter(
(c) => Array.isArray(c[0]) && c[0][0] === "npm" && c[0][1] === "pack",
);
expect(packCalls.length).toBe(1);
const packCall = packCalls[0];
if (!packCall) {
throw new Error("expected npm pack call");
}
const [argv, options] = packCall;
expect(argv).toEqual(["npm", "pack", "@openclaw/voice-call@0.0.1", "--ignore-scripts"]);
const commandOptions = typeof options === "number" ? undefined : options;
expect(commandOptions?.env).toMatchObject({ NPM_CONFIG_IGNORE_SCRIPTS: "true" });
expectSingleNpmPackIgnoreScriptsCall({
calls: run.mock.calls,
expectedSpec: "@openclaw/voice-call@0.0.1",
});
expect(packTmpDir).not.toBe("");
expect(fs.existsSync(packTmpDir)).toBe(false);

View File

@@ -14,3 +14,21 @@ export function expectSingleNpmInstallIgnoreScriptsCall(params: {
expect(argv).toEqual(["npm", "install", "--omit=dev", "--silent", "--ignore-scripts"]);
expect(opts?.cwd).toBe(params.expectedCwd);
}
export function expectSingleNpmPackIgnoreScriptsCall(params: {
calls: Array<[unknown, unknown]>;
expectedSpec: string;
}) {
const packCalls = params.calls.filter(
(call) => Array.isArray(call[0]) && call[0][0] === "npm" && call[0][1] === "pack",
);
expect(packCalls.length).toBe(1);
const packCall = packCalls[0];
if (!packCall) {
throw new Error("expected npm pack call");
}
const [argv, options] = packCall;
expect(argv).toEqual(["npm", "pack", params.expectedSpec, "--ignore-scripts"]);
const commandOptions = typeof options === "number" ? undefined : options;
expect(commandOptions).toMatchObject({ env: { NPM_CONFIG_IGNORE_SCRIPTS: "true" } });
}

View File

@@ -0,0 +1,15 @@
export function createInternalHookEventPayload(
type: string,
action: string,
sessionKey: string,
context: Record<string, unknown>,
) {
return {
type,
action,
sessionKey,
context,
timestamp: new Date(),
messages: [],
};
}