mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 22:34:32 +00:00
test: migrate suites to e2e coverage layout
This commit is contained in:
249
src/commands/models/list.status.e2e.test.ts
Normal file
249
src/commands/models/list.status.e2e.test.ts
Normal file
@@ -0,0 +1,249 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mocks = vi.hoisted(() => {
|
||||
const store = {
|
||||
version: 1,
|
||||
profiles: {
|
||||
"anthropic:default": {
|
||||
type: "oauth",
|
||||
provider: "anthropic",
|
||||
access: "sk-ant-oat01-ACCESS-TOKEN-1234567890",
|
||||
refresh: "sk-ant-ort01-REFRESH-TOKEN-1234567890",
|
||||
expires: Date.now() + 60_000,
|
||||
email: "peter@example.com",
|
||||
},
|
||||
"anthropic:work": {
|
||||
type: "api_key",
|
||||
provider: "anthropic",
|
||||
key: "sk-ant-api-0123456789abcdefghijklmnopqrstuvwxyz",
|
||||
},
|
||||
"openai-codex:default": {
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
access: "eyJhbGciOi-ACCESS",
|
||||
refresh: "oai-refresh-1234567890",
|
||||
expires: Date.now() + 60_000,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
store,
|
||||
resolveOpenClawAgentDir: vi.fn().mockReturnValue("/tmp/openclaw-agent"),
|
||||
resolveAgentDir: vi.fn().mockReturnValue("/tmp/openclaw-agent"),
|
||||
resolveAgentModelPrimary: vi.fn().mockReturnValue(undefined),
|
||||
resolveAgentModelFallbacksOverride: vi.fn().mockReturnValue(undefined),
|
||||
listAgentIds: vi.fn().mockReturnValue(["main", "jeremiah"]),
|
||||
ensureAuthProfileStore: vi.fn().mockReturnValue(store),
|
||||
listProfilesForProvider: vi.fn((s: typeof store, provider: string) => {
|
||||
return Object.entries(s.profiles)
|
||||
.filter(([, cred]) => cred.provider === provider)
|
||||
.map(([id]) => id);
|
||||
}),
|
||||
resolveAuthProfileDisplayLabel: vi.fn(({ profileId }: { profileId: string }) => profileId),
|
||||
resolveAuthStorePathForDisplay: vi
|
||||
.fn()
|
||||
.mockReturnValue("/tmp/openclaw-agent/auth-profiles.json"),
|
||||
resolveEnvApiKey: vi.fn((provider: string) => {
|
||||
if (provider === "openai") {
|
||||
return {
|
||||
apiKey: "sk-openai-0123456789abcdefghijklmnopqrstuvwxyz",
|
||||
source: "shell env: OPENAI_API_KEY",
|
||||
};
|
||||
}
|
||||
if (provider === "anthropic") {
|
||||
return {
|
||||
apiKey: "sk-ant-oat01-ACCESS-TOKEN-1234567890",
|
||||
source: "env: ANTHROPIC_OAUTH_TOKEN",
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
getCustomProviderApiKey: vi.fn().mockReturnValue(undefined),
|
||||
getShellEnvAppliedKeys: vi.fn().mockReturnValue(["OPENAI_API_KEY", "ANTHROPIC_OAUTH_TOKEN"]),
|
||||
shouldEnableShellEnvFallback: vi.fn().mockReturnValue(true),
|
||||
loadConfig: vi.fn().mockReturnValue({
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "anthropic/claude-opus-4-5", fallbacks: [] },
|
||||
models: { "anthropic/claude-opus-4-5": { alias: "Opus" } },
|
||||
},
|
||||
},
|
||||
models: { providers: {} },
|
||||
env: { shellEnv: { enabled: true } },
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../agents/agent-paths.js", () => ({
|
||||
resolveOpenClawAgentDir: mocks.resolveOpenClawAgentDir,
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/agent-scope.js", () => ({
|
||||
resolveAgentDir: mocks.resolveAgentDir,
|
||||
resolveAgentModelPrimary: mocks.resolveAgentModelPrimary,
|
||||
resolveAgentModelFallbacksOverride: mocks.resolveAgentModelFallbacksOverride,
|
||||
listAgentIds: mocks.listAgentIds,
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/auth-profiles.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../../agents/auth-profiles.js")>();
|
||||
return {
|
||||
...actual,
|
||||
ensureAuthProfileStore: mocks.ensureAuthProfileStore,
|
||||
listProfilesForProvider: mocks.listProfilesForProvider,
|
||||
resolveAuthProfileDisplayLabel: mocks.resolveAuthProfileDisplayLabel,
|
||||
resolveAuthStorePathForDisplay: mocks.resolveAuthStorePathForDisplay,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../../agents/model-auth.js", () => ({
|
||||
resolveEnvApiKey: mocks.resolveEnvApiKey,
|
||||
getCustomProviderApiKey: mocks.getCustomProviderApiKey,
|
||||
}));
|
||||
|
||||
vi.mock("../../infra/shell-env.js", () => ({
|
||||
getShellEnvAppliedKeys: mocks.getShellEnvAppliedKeys,
|
||||
shouldEnableShellEnvFallback: mocks.shouldEnableShellEnvFallback,
|
||||
}));
|
||||
|
||||
vi.mock("../../config/config.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../../config/config.js")>();
|
||||
return {
|
||||
...actual,
|
||||
loadConfig: mocks.loadConfig,
|
||||
};
|
||||
});
|
||||
|
||||
import { modelsStatusCommand } from "./list.js";
|
||||
|
||||
const runtime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
|
||||
describe("modelsStatusCommand auth overview", () => {
|
||||
it("includes masked auth sources in JSON output", async () => {
|
||||
await modelsStatusCommand({ json: true }, runtime as never);
|
||||
const payload = JSON.parse(String((runtime.log as vi.Mock).mock.calls[0][0]));
|
||||
|
||||
expect(mocks.resolveOpenClawAgentDir).toHaveBeenCalled();
|
||||
expect(payload.defaultModel).toBe("anthropic/claude-opus-4-5");
|
||||
expect(payload.auth.storePath).toBe("/tmp/openclaw-agent/auth-profiles.json");
|
||||
expect(payload.auth.shellEnvFallback.enabled).toBe(true);
|
||||
expect(payload.auth.shellEnvFallback.appliedKeys).toContain("OPENAI_API_KEY");
|
||||
expect(payload.auth.missingProvidersInUse).toEqual([]);
|
||||
expect(payload.auth.oauth.warnAfterMs).toBeGreaterThan(0);
|
||||
expect(payload.auth.oauth.profiles.length).toBeGreaterThan(0);
|
||||
|
||||
const providers = payload.auth.providers as Array<{
|
||||
provider: string;
|
||||
profiles: { labels: string[] };
|
||||
env?: { value: string; source: string };
|
||||
}>;
|
||||
const anthropic = providers.find((p) => p.provider === "anthropic");
|
||||
expect(anthropic).toBeTruthy();
|
||||
expect(anthropic?.profiles.labels.join(" ")).toContain("OAuth");
|
||||
expect(anthropic?.profiles.labels.join(" ")).toContain("...");
|
||||
|
||||
const openai = providers.find((p) => p.provider === "openai");
|
||||
expect(openai?.env?.source).toContain("OPENAI_API_KEY");
|
||||
expect(openai?.env?.value).toContain("...");
|
||||
|
||||
expect(
|
||||
(payload.auth.providersWithOAuth as string[]).some((e) => e.startsWith("anthropic")),
|
||||
).toBe(true);
|
||||
expect(
|
||||
(payload.auth.providersWithOAuth as string[]).some((e) => e.startsWith("openai-codex")),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("uses agent overrides and reports sources", async () => {
|
||||
const localRuntime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
const originalPrimary = mocks.resolveAgentModelPrimary.getMockImplementation();
|
||||
const originalFallbacks = mocks.resolveAgentModelFallbacksOverride.getMockImplementation();
|
||||
const originalAgentDir = mocks.resolveAgentDir.getMockImplementation();
|
||||
|
||||
mocks.resolveAgentModelPrimary.mockReturnValue("openai/gpt-4");
|
||||
mocks.resolveAgentModelFallbacksOverride.mockReturnValue(["openai/gpt-3.5"]);
|
||||
mocks.resolveAgentDir.mockReturnValue("/tmp/openclaw-agent-custom");
|
||||
|
||||
try {
|
||||
await modelsStatusCommand({ json: true, agent: "Jeremiah" }, localRuntime as never);
|
||||
expect(mocks.resolveAgentDir).toHaveBeenCalledWith(expect.anything(), "jeremiah");
|
||||
const payload = JSON.parse(String((localRuntime.log as vi.Mock).mock.calls[0][0]));
|
||||
expect(payload.agentId).toBe("jeremiah");
|
||||
expect(payload.agentDir).toBe("/tmp/openclaw-agent-custom");
|
||||
expect(payload.defaultModel).toBe("openai/gpt-4");
|
||||
expect(payload.fallbacks).toEqual(["openai/gpt-3.5"]);
|
||||
expect(payload.modelConfig).toEqual({
|
||||
defaultSource: "agent",
|
||||
fallbacksSource: "agent",
|
||||
});
|
||||
} finally {
|
||||
mocks.resolveAgentModelPrimary.mockImplementation(originalPrimary);
|
||||
mocks.resolveAgentModelFallbacksOverride.mockImplementation(originalFallbacks);
|
||||
mocks.resolveAgentDir.mockImplementation(originalAgentDir);
|
||||
}
|
||||
});
|
||||
|
||||
it("labels defaults when --agent has no overrides", async () => {
|
||||
const localRuntime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
const originalPrimary = mocks.resolveAgentModelPrimary.getMockImplementation();
|
||||
const originalFallbacks = mocks.resolveAgentModelFallbacksOverride.getMockImplementation();
|
||||
|
||||
mocks.resolveAgentModelPrimary.mockReturnValue(undefined);
|
||||
mocks.resolveAgentModelFallbacksOverride.mockReturnValue(undefined);
|
||||
|
||||
try {
|
||||
await modelsStatusCommand({ agent: "main" }, localRuntime as never);
|
||||
const output = (localRuntime.log as vi.Mock).mock.calls
|
||||
.map((call) => String(call[0]))
|
||||
.join("\n");
|
||||
expect(output).toContain("Default (defaults)");
|
||||
expect(output).toContain("Fallbacks (0) (defaults)");
|
||||
} finally {
|
||||
mocks.resolveAgentModelPrimary.mockImplementation(originalPrimary);
|
||||
mocks.resolveAgentModelFallbacksOverride.mockImplementation(originalFallbacks);
|
||||
}
|
||||
});
|
||||
|
||||
it("throws when agent id is unknown", async () => {
|
||||
const localRuntime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
await expect(modelsStatusCommand({ agent: "unknown" }, localRuntime as never)).rejects.toThrow(
|
||||
'Unknown agent id "unknown".',
|
||||
);
|
||||
});
|
||||
it("exits non-zero when auth is missing", async () => {
|
||||
const originalProfiles = { ...mocks.store.profiles };
|
||||
mocks.store.profiles = {};
|
||||
const localRuntime = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn(),
|
||||
};
|
||||
const originalEnvImpl = mocks.resolveEnvApiKey.getMockImplementation();
|
||||
mocks.resolveEnvApiKey.mockImplementation(() => null);
|
||||
|
||||
try {
|
||||
await modelsStatusCommand({ check: true, plain: true }, localRuntime as never);
|
||||
expect(localRuntime.exit).toHaveBeenCalledWith(1);
|
||||
} finally {
|
||||
mocks.store.profiles = originalProfiles;
|
||||
mocks.resolveEnvApiKey.mockImplementation(originalEnvImpl);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user