test: tighten model and migration assertions

This commit is contained in:
Peter Steinberger
2026-05-10 01:05:27 +01:00
parent 2e3fa8c086
commit 5f83f4644e
4 changed files with 48 additions and 57 deletions

View File

@@ -23,7 +23,7 @@ function expectMigrationChangesToIncludeFragments(changes: string[], fragments:
const unmatchedFragments = fragments.filter((fragment) =>
changes.every((change) => !change.includes(fragment)),
);
expect({ changes, unmatchedFragments }).toMatchObject({ unmatchedFragments: [] });
expect(unmatchedFragments).toStrictEqual([]);
}
describe("legacy session maintenance migrate", () => {
@@ -226,16 +226,17 @@ describe("legacy migrate mention routing", () => {
historyLimit: 12,
mentionPatterns: ["@openclaw"],
});
expect(res.changes).toEqual(
expect.arrayContaining([
"Moved routing.allowFrom → channels.whatsapp.allowFrom.",
'Moved routing.groupChat.requireMention → channels.whatsapp.groups."*".requireMention.',
'Removed routing.groupChat.requireMention (channels.telegram.groups."*" already set).',
'Moved routing.groupChat.requireMention → channels.imessage.groups."*".requireMention.',
"Moved routing.groupChat.historyLimit → messages.groupChat.historyLimit.",
"Moved routing.groupChat.mentionPatterns → messages.groupChat.mentionPatterns.",
]),
);
expect(res.changes).toHaveLength(6);
for (const change of [
"Moved routing.allowFrom → channels.whatsapp.allowFrom.",
'Moved routing.groupChat.requireMention → channels.whatsapp.groups."*".requireMention.',
'Removed routing.groupChat.requireMention (channels.telegram.groups."*" already set).',
'Moved routing.groupChat.requireMention → channels.imessage.groups."*".requireMention.',
"Moved routing.groupChat.historyLimit → messages.groupChat.historyLimit.",
"Moved routing.groupChat.mentionPatterns → messages.groupChat.mentionPatterns.",
]) {
expect(res.changes).toContain(change);
}
});
it("removes legacy routing requireMention when no compatible channel exists", () => {
@@ -344,13 +345,14 @@ describe("legacy migrate sandbox scope aliases", () => {
},
});
expect(res.changes).toEqual(
expect.arrayContaining([
"Removed agents.defaults.embeddedHarness; runtime is now provider/model scoped.",
"Removed agents.list.0.embeddedHarness; runtime is now provider/model scoped.",
"Removed agents.list.0.agentRuntime; runtime is now provider/model scoped.",
]),
);
expect(res.changes).toHaveLength(3);
for (const change of [
"Removed agents.defaults.embeddedHarness; runtime is now provider/model scoped.",
"Removed agents.list.0.embeddedHarness; runtime is now provider/model scoped.",
"Removed agents.list.0.agentRuntime; runtime is now provider/model scoped.",
]) {
expect(res.changes).toContain(change);
}
expect(res.config?.agents?.defaults).toStrictEqual({});
expect(res.config?.agents?.list?.[0]).toEqual({
id: "reviewer",

View File

@@ -493,12 +493,10 @@ describe("models list/status", () => {
}
const payload = parseJsonLog(runtime);
expect(payload.models).toEqual([
expect.objectContaining({
key: "workspace-cloud/model-a",
available: true,
}),
]);
expect(payload.models).toHaveLength(1);
const model = payload.models[0];
expect(model.key).toBe("workspace-cloud/model-a");
expect(model.available).toBe(true);
});
it("models list all includes unauthenticated provider catalog rows", async () => {
@@ -514,14 +512,12 @@ describe("models list/status", () => {
const payload = parseJsonLog(runtime);
expect(loadModelCatalog).not.toHaveBeenCalled();
expect(payload.models).toEqual([
expect.objectContaining({
key: "moonshot/kimi-k2.6",
name: "Kimi K2.6",
available: false,
missing: false,
}),
]);
expect(payload.models).toHaveLength(1);
const model = payload.models[0];
expect(model.key).toBe("moonshot/kimi-k2.6");
expect(model.name).toBe("Kimi K2.6");
expect(model.available).toBe(false);
expect(model.missing).toBe(false);
});
it("models list rejects provider display labels", async () => {
@@ -682,13 +678,11 @@ describe("models list/status", () => {
await modelsListCommand({ all: true, json: true }, runtime);
const payload = parseJsonLog(runtime);
expect(payload.models).toEqual([
expect.objectContaining({
key: "custom-proxy/custom-model",
name: "Custom Model",
missing: false,
}),
]);
expect(payload.models).toHaveLength(1);
const model = payload.models[0];
expect(model.key).toBe("custom-proxy/custom-model");
expect(model.name).toBe("Custom Model");
expect(model.missing).toBe(false);
});
it("toModelRow marks unavailable when cfg/authStore and availability are undefined", () => {

View File

@@ -72,9 +72,8 @@ describe("models scan command", () => {
expect(mocks.loadModelsConfig).not.toHaveBeenCalled();
expect(mocks.resolveApiKeyForProvider).not.toHaveBeenCalled();
expect(mocks.scanOpenRouterModels).toHaveBeenCalledWith(
expect.objectContaining({ probe: false }),
);
expect(mocks.scanOpenRouterModels).toHaveBeenCalledTimes(1);
expect(mocks.scanOpenRouterModels.mock.calls[0]?.[0]?.probe).toBe(false);
expect(runtime.lines.join("\n")).toContain("metadata only");
expect(runtime.lines.join("\n")).toContain("Tool");
expect(runtime.lines.join("\n")).toContain("skip");
@@ -94,9 +93,8 @@ describe("models scan command", () => {
provider: "openrouter",
cfg: {},
});
expect(mocks.scanOpenRouterModels).toHaveBeenCalledWith(
expect.objectContaining({ probe: false }),
);
expect(mocks.scanOpenRouterModels).toHaveBeenCalledTimes(1);
expect(mocks.scanOpenRouterModels.mock.calls[0]?.[0]?.probe).toBe(false);
expect(runtime.lines.join("\n")).toContain("still require OPENROUTER_API_KEY");
});
@@ -113,12 +111,10 @@ describe("models scan command", () => {
expect(mocks.loadModelsConfig).not.toHaveBeenCalled();
expect(mocks.resolveApiKeyForProvider).not.toHaveBeenCalled();
expect(mocks.scanOpenRouterModels).toHaveBeenCalledWith(
expect.objectContaining({
apiKey: "sk-or-test",
probe: true,
}),
);
expect(mocks.scanOpenRouterModels).toHaveBeenCalledTimes(1);
const scanRequest = mocks.scanOpenRouterModels.mock.calls[0]?.[0];
expect(scanRequest?.apiKey).toBe("sk-or-test");
expect(scanRequest?.probe).toBe(true);
});
it("rejects applying metadata-only scan results", async () => {

View File

@@ -54,7 +54,7 @@ it("uses expanded max_tokens for openai verification probes", () => {
modelId: "detected-model",
});
expect(request.body).toMatchObject({ max_tokens: 16 });
expect(request.body.max_tokens).toBe(16);
});
it("uses azure responses-specific headers and body for openai verification probes", () => {
const request = buildOpenAiVerificationProbeRequest({
@@ -100,7 +100,7 @@ it("uses expanded max_tokens for anthropic verification probes", () => {
});
expect(request.endpoint).toBe("https://example.com/v1/messages");
expect(request.body).toMatchObject({ max_tokens: 1 });
expect(request.body.max_tokens).toBe(1);
});
describe("applyCustomApiConfig", () => {
@@ -291,10 +291,9 @@ describe("applyCustomApiConfig", () => {
"custom",
"custom-2",
]);
expect(result.config.models?.providers?.["custom-2"]).toMatchObject({
baseUrl: "http://localhost:11434/v1",
models: [{ id: "llama3" }],
});
const provider = result.config.models?.providers?.["custom-2"];
expect(provider?.baseUrl).toBe("http://localhost:11434/v1");
expect(provider?.models?.[0]?.id).toBe("llama3");
});
it("does not add azure fields for non-azure URLs", () => {