mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-07 23:01:24 +00:00
test: dedupe fixtures and test harness setup
This commit is contained in:
@@ -32,53 +32,46 @@ async function runReplyToCurrentCase(home: string, text: string) {
|
||||
return Array.isArray(res) ? res[0] : res;
|
||||
}
|
||||
|
||||
async function expectThinkStatusForReasoningModel(params: {
|
||||
reasoning: boolean;
|
||||
expectedLevel: "low" | "off";
|
||||
}): Promise<void> {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(loadModelCatalog).mockResolvedValueOnce([
|
||||
{
|
||||
id: "claude-opus-4-5",
|
||||
name: "Opus 4.5",
|
||||
provider: "anthropic",
|
||||
reasoning: params.reasoning,
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/think", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
makeWhatsAppDirectiveConfig(home, { model: "anthropic/claude-opus-4-5" }),
|
||||
);
|
||||
|
||||
const text = replyText(res);
|
||||
expect(text).toContain(`Current thinking level: ${params.expectedLevel}`);
|
||||
expect(text).toContain("Options: off, minimal, low, medium, high.");
|
||||
expect(runEmbeddedPiAgent).not.toHaveBeenCalled();
|
||||
});
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("defaults /think to low for reasoning-capable models when no default set", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(loadModelCatalog).mockResolvedValueOnce([
|
||||
{
|
||||
id: "claude-opus-4-5",
|
||||
name: "Opus 4.5",
|
||||
provider: "anthropic",
|
||||
reasoning: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/think", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
makeWhatsAppDirectiveConfig(home, { model: "anthropic/claude-opus-4-5" }),
|
||||
);
|
||||
|
||||
const text = replyText(res);
|
||||
expect(text).toContain("Current thinking level: low");
|
||||
expect(text).toContain("Options: off, minimal, low, medium, high.");
|
||||
expect(runEmbeddedPiAgent).not.toHaveBeenCalled();
|
||||
await expectThinkStatusForReasoningModel({
|
||||
reasoning: true,
|
||||
expectedLevel: "low",
|
||||
});
|
||||
});
|
||||
it("shows off when /think has no argument and model lacks reasoning", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(loadModelCatalog).mockResolvedValueOnce([
|
||||
{
|
||||
id: "claude-opus-4-5",
|
||||
name: "Opus 4.5",
|
||||
provider: "anthropic",
|
||||
reasoning: false,
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: "/think", From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
makeWhatsAppDirectiveConfig(home, { model: "anthropic/claude-opus-4-5" }),
|
||||
);
|
||||
|
||||
const text = replyText(res);
|
||||
expect(text).toContain("Current thinking level: off");
|
||||
expect(text).toContain("Options: off, minimal, low, medium, high.");
|
||||
expect(runEmbeddedPiAgent).not.toHaveBeenCalled();
|
||||
await expectThinkStatusForReasoningModel({
|
||||
reasoning: false,
|
||||
expectedLevel: "off",
|
||||
});
|
||||
});
|
||||
it("persists /reasoning off on discord even when model defaults reasoning on", async () => {
|
||||
|
||||
@@ -5,46 +5,19 @@ import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
loadModelCatalog,
|
||||
makeWhatsAppDirectiveConfig,
|
||||
replyText,
|
||||
runEmbeddedPiAgent,
|
||||
sessionStorePath,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { runModelDirectiveText } from "./reply.directive.directive-behavior.model-directive-test-utils.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
async function runModelDirective(
|
||||
home: string,
|
||||
body: string,
|
||||
options: {
|
||||
defaults?: Record<string, unknown>;
|
||||
extra?: Record<string, unknown>;
|
||||
} = {},
|
||||
): Promise<string | undefined> {
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: body, From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
makeWhatsAppDirectiveConfig(
|
||||
home,
|
||||
{
|
||||
model: { primary: "anthropic/claude-opus-4-5" },
|
||||
models: {
|
||||
"anthropic/claude-opus-4-5": {},
|
||||
"openai/gpt-4.1-mini": {},
|
||||
},
|
||||
...options.defaults,
|
||||
},
|
||||
{ session: { store: sessionStorePath(home) }, ...options.extra },
|
||||
),
|
||||
);
|
||||
return replyText(res);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
it("aliases /model list to /models", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const text = await runModelDirective(home, "/model list");
|
||||
const text = await runModelDirectiveText(home, "/model list");
|
||||
expect(text).toContain("Providers:");
|
||||
expect(text).toContain("- anthropic");
|
||||
expect(text).toContain("- openai");
|
||||
@@ -56,7 +29,7 @@ describe("directive behavior", () => {
|
||||
it("shows current model when catalog is unavailable", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
vi.mocked(loadModelCatalog).mockResolvedValueOnce([]);
|
||||
const text = await runModelDirective(home, "/model");
|
||||
const text = await runModelDirectiveText(home, "/model");
|
||||
expect(text).toContain("Current: anthropic/claude-opus-4-5");
|
||||
expect(text).toContain("Switch: /model <provider/model>");
|
||||
expect(text).toContain("Browse: /models (providers) or /models <provider> (models)");
|
||||
@@ -71,7 +44,7 @@ describe("directive behavior", () => {
|
||||
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", provider: "openai" },
|
||||
{ id: "grok-4", name: "Grok 4", provider: "xai" },
|
||||
]);
|
||||
const text = await runModelDirective(home, "/model list", {
|
||||
const text = await runModelDirectiveText(home, "/model list", {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "anthropic/claude-opus-4-5",
|
||||
@@ -101,7 +74,7 @@ describe("directive behavior", () => {
|
||||
},
|
||||
{ provider: "openai", id: "gpt-4.1-mini", name: "GPT-4.1 mini" },
|
||||
]);
|
||||
const text = await runModelDirective(home, "/models minimax", {
|
||||
const text = await runModelDirectiveText(home, "/models minimax", {
|
||||
defaults: {
|
||||
models: {
|
||||
"anthropic/claude-opus-4-5": {},
|
||||
@@ -129,7 +102,7 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("does not repeat missing auth labels on /model list", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const text = await runModelDirective(home, "/model list", {
|
||||
const text = await runModelDirectiveText(home, "/model list", {
|
||||
defaults: {
|
||||
models: {
|
||||
"anthropic/claude-opus-4-5": {},
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import {
|
||||
makeWhatsAppDirectiveConfig,
|
||||
replyText,
|
||||
sessionStorePath,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
export async function runModelDirectiveText(
|
||||
home: string,
|
||||
body: string,
|
||||
options: {
|
||||
defaults?: Record<string, unknown>;
|
||||
extra?: Record<string, unknown>;
|
||||
includeSessionStore?: boolean;
|
||||
} = {},
|
||||
): Promise<string | undefined> {
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: body, From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
makeWhatsAppDirectiveConfig(
|
||||
home,
|
||||
{
|
||||
model: { primary: "anthropic/claude-opus-4-5" },
|
||||
models: {
|
||||
"anthropic/claude-opus-4-5": {},
|
||||
"openai/gpt-4.1-mini": {},
|
||||
},
|
||||
...options.defaults,
|
||||
},
|
||||
{
|
||||
...(options.includeSessionStore === false
|
||||
? {}
|
||||
: { session: { store: sessionStorePath(home) } }),
|
||||
...options.extra,
|
||||
},
|
||||
),
|
||||
);
|
||||
return replyText(res);
|
||||
}
|
||||
@@ -5,12 +5,12 @@ import {
|
||||
installDirectiveBehaviorE2EHooks,
|
||||
makeEmbeddedTextResult,
|
||||
makeWhatsAppDirectiveConfig,
|
||||
replyText,
|
||||
replyTexts,
|
||||
runEmbeddedPiAgent,
|
||||
sessionStorePath,
|
||||
withTempHome,
|
||||
} from "./reply.directive.directive-behavior.e2e-harness.js";
|
||||
import { runModelDirectiveText } from "./reply.directive.directive-behavior.model-directive-test-utils.js";
|
||||
import { getReplyFromConfig } from "./reply.js";
|
||||
|
||||
function makeRunConfig(home: string, storePath: string) {
|
||||
@@ -69,24 +69,6 @@ async function runInFlightVerboseToggleCase(params: {
|
||||
return { res };
|
||||
}
|
||||
|
||||
async function runModelDirectiveAndGetText(
|
||||
home: string,
|
||||
body: string,
|
||||
): Promise<string | undefined> {
|
||||
const res = await getReplyFromConfig(
|
||||
{ Body: body, From: "+1222", To: "+1222", CommandAuthorized: true },
|
||||
{},
|
||||
makeWhatsAppDirectiveConfig(home, {
|
||||
model: { primary: "anthropic/claude-opus-4-5" },
|
||||
models: {
|
||||
"anthropic/claude-opus-4-5": {},
|
||||
"openai/gpt-4.1-mini": {},
|
||||
},
|
||||
}),
|
||||
);
|
||||
return replyText(res);
|
||||
}
|
||||
|
||||
describe("directive behavior", () => {
|
||||
installDirectiveBehaviorE2EHooks();
|
||||
|
||||
@@ -119,7 +101,7 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("shows summary on /model", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const text = await runModelDirectiveAndGetText(home, "/model");
|
||||
const text = await runModelDirectiveText(home, "/model", { includeSessionStore: false });
|
||||
expect(text).toContain("Current: anthropic/claude-opus-4-5");
|
||||
expect(text).toContain("Switch: /model <provider/model>");
|
||||
expect(text).toContain("Browse: /models (providers) or /models <provider> (models)");
|
||||
@@ -130,7 +112,9 @@ describe("directive behavior", () => {
|
||||
});
|
||||
it("lists allowlisted models on /model status", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const text = await runModelDirectiveAndGetText(home, "/model status");
|
||||
const text = await runModelDirectiveText(home, "/model status", {
|
||||
includeSessionStore: false,
|
||||
});
|
||||
expect(text).toContain("anthropic/claude-opus-4-5");
|
||||
expect(text).toContain("openai/gpt-4.1-mini");
|
||||
expect(text).not.toContain("claude-sonnet-4-1");
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
getRunEmbeddedPiAgentMock,
|
||||
installTriggerHandlingE2eTestHooks,
|
||||
installTriggerHandlingReplyHarness,
|
||||
makeCfg,
|
||||
runGreetingPromptForBareNewOrReset,
|
||||
withTempHome,
|
||||
} from "./reply.triggers.trigger-handling.test-harness.js";
|
||||
|
||||
let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
|
||||
beforeAll(async () => {
|
||||
({ getReplyFromConfig } = await import("./reply.js"));
|
||||
installTriggerHandlingReplyHarness((loader) => {
|
||||
getReplyFromConfig = loader;
|
||||
});
|
||||
|
||||
installTriggerHandlingE2eTestHooks();
|
||||
|
||||
async function expectResetBlockedForNonOwner(params: {
|
||||
home: string;
|
||||
commandAuthorized: boolean;
|
||||
@@ -68,6 +66,7 @@ describe("trigger handling", () => {
|
||||
expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("injects group activation context into the system prompt", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
getRunEmbeddedPiAgentMock().mockResolvedValue({
|
||||
@@ -112,16 +111,19 @@ describe("trigger handling", () => {
|
||||
expect(extra).toContain("Activation: always-on");
|
||||
});
|
||||
});
|
||||
|
||||
it("runs a greeting prompt for a bare /reset", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
await runGreetingPromptForBareNewOrReset({ home, body: "/reset", getReplyFromConfig });
|
||||
});
|
||||
});
|
||||
|
||||
it("runs a greeting prompt for a bare /new", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
await runGreetingPromptForBareNewOrReset({ home, body: "/new", getReplyFromConfig });
|
||||
});
|
||||
});
|
||||
|
||||
it("does not reset for unauthorized /reset", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
await expectResetBlockedForNonOwner({
|
||||
@@ -131,6 +133,7 @@ describe("trigger handling", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("blocks /reset for non-owner senders", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
await expectResetBlockedForNonOwner({
|
||||
|
||||
@@ -222,6 +222,17 @@ export async function loadGetReplyFromConfig() {
|
||||
return (await import("./reply.js")).getReplyFromConfig;
|
||||
}
|
||||
|
||||
export function installTriggerHandlingReplyHarness(
|
||||
setGetReplyFromConfig: (
|
||||
getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig,
|
||||
) => void,
|
||||
): void {
|
||||
beforeAll(async () => {
|
||||
setGetReplyFromConfig(await loadGetReplyFromConfig());
|
||||
});
|
||||
installTriggerHandlingE2eTestHooks();
|
||||
}
|
||||
|
||||
export function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
|
||||
const storePath = cfg.session?.store;
|
||||
if (!storePath) {
|
||||
|
||||
Reference in New Issue
Block a user