test: dedupe fixtures and test harness setup

This commit is contained in:
Peter Steinberger
2026-02-23 05:43:30 +00:00
parent 8af19ddc5b
commit 1c753ea786
75 changed files with 1886 additions and 2136 deletions

View File

@@ -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 () => {

View File

@@ -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": {},

View File

@@ -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);
}

View File

@@ -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");

View File

@@ -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({

View File

@@ -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) {