mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 13:20:42 +00:00
206 lines
6.8 KiB
TypeScript
206 lines
6.8 KiB
TypeScript
import { Command } from "commander";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { runRegisteredCli } from "../test-utils/command-runner.js";
|
|
import { registerModelsCli } from "./models-cli.js";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
modelsStatusCommand: vi.fn().mockResolvedValue(undefined),
|
|
modelsSetCommand: vi.fn().mockResolvedValue(undefined),
|
|
modelsSetImageCommand: vi.fn().mockResolvedValue(undefined),
|
|
noopAsync: vi.fn(async () => undefined),
|
|
modelsAuthAddCommand: vi.fn().mockResolvedValue(undefined),
|
|
modelsAuthLoginCommand: vi.fn().mockResolvedValue(undefined),
|
|
modelsAuthPasteTokenCommand: vi.fn().mockResolvedValue(undefined),
|
|
modelsAuthSetupTokenCommand: vi.fn().mockResolvedValue(undefined),
|
|
}));
|
|
|
|
const {
|
|
modelsAuthAddCommand,
|
|
modelsAuthLoginCommand,
|
|
modelsAuthPasteTokenCommand,
|
|
modelsAuthSetupTokenCommand,
|
|
modelsSetCommand,
|
|
modelsSetImageCommand,
|
|
modelsStatusCommand,
|
|
} = mocks;
|
|
|
|
vi.mock("../commands/models/list.list-command.js", () => ({
|
|
modelsListCommand: mocks.noopAsync,
|
|
}));
|
|
vi.mock("../commands/models/list.status-command.js", () => ({
|
|
modelsStatusCommand: mocks.modelsStatusCommand,
|
|
}));
|
|
vi.mock("../commands/models/auth.js", () => ({
|
|
modelsAuthAddCommand: mocks.modelsAuthAddCommand,
|
|
modelsAuthLoginCommand: mocks.modelsAuthLoginCommand,
|
|
modelsAuthPasteTokenCommand: mocks.modelsAuthPasteTokenCommand,
|
|
modelsAuthSetupTokenCommand: mocks.modelsAuthSetupTokenCommand,
|
|
}));
|
|
vi.mock("../commands/models/auth-order.js", () => ({
|
|
modelsAuthOrderClearCommand: mocks.noopAsync,
|
|
modelsAuthOrderGetCommand: mocks.noopAsync,
|
|
modelsAuthOrderSetCommand: mocks.noopAsync,
|
|
}));
|
|
vi.mock("../commands/models/aliases.js", () => ({
|
|
modelsAliasesAddCommand: mocks.noopAsync,
|
|
modelsAliasesListCommand: mocks.noopAsync,
|
|
modelsAliasesRemoveCommand: mocks.noopAsync,
|
|
}));
|
|
vi.mock("../commands/models/fallbacks.js", () => ({
|
|
modelsFallbacksAddCommand: mocks.noopAsync,
|
|
modelsFallbacksClearCommand: mocks.noopAsync,
|
|
modelsFallbacksListCommand: mocks.noopAsync,
|
|
modelsFallbacksRemoveCommand: mocks.noopAsync,
|
|
}));
|
|
vi.mock("../commands/models/image-fallbacks.js", () => ({
|
|
modelsImageFallbacksAddCommand: mocks.noopAsync,
|
|
modelsImageFallbacksClearCommand: mocks.noopAsync,
|
|
modelsImageFallbacksListCommand: mocks.noopAsync,
|
|
modelsImageFallbacksRemoveCommand: mocks.noopAsync,
|
|
}));
|
|
vi.mock("../commands/models/scan.js", () => ({
|
|
modelsScanCommand: mocks.noopAsync,
|
|
}));
|
|
vi.mock("../commands/models/set.js", () => ({
|
|
modelsSetCommand: mocks.modelsSetCommand,
|
|
}));
|
|
vi.mock("../commands/models/set-image.js", () => ({
|
|
modelsSetImageCommand: mocks.modelsSetImageCommand,
|
|
}));
|
|
|
|
describe("models cli", () => {
|
|
beforeEach(() => {
|
|
modelsAuthAddCommand.mockClear();
|
|
modelsAuthLoginCommand.mockClear();
|
|
modelsAuthPasteTokenCommand.mockClear();
|
|
modelsAuthSetupTokenCommand.mockClear();
|
|
modelsSetCommand.mockClear();
|
|
modelsSetImageCommand.mockClear();
|
|
modelsStatusCommand.mockClear();
|
|
});
|
|
|
|
function createProgram() {
|
|
const program = new Command();
|
|
registerModelsCli(program);
|
|
return program;
|
|
}
|
|
|
|
async function runModelsCommand(args: string[]) {
|
|
await runRegisteredCli({
|
|
register: registerModelsCli as (program: Command) => void,
|
|
argv: args,
|
|
});
|
|
}
|
|
|
|
it("registers github-copilot login command", async () => {
|
|
const program = createProgram();
|
|
const models = program.commands.find((cmd) => cmd.name() === "models");
|
|
expect(models).toBeTruthy();
|
|
|
|
const auth = models?.commands.find((cmd) => cmd.name() === "auth");
|
|
expect(auth).toBeTruthy();
|
|
|
|
const login = auth?.commands.find((cmd) => cmd.name() === "login-github-copilot");
|
|
expect(login).toBeTruthy();
|
|
|
|
await program.parseAsync(
|
|
["models", "auth", "--agent", "poe", "login-github-copilot", "--yes"],
|
|
{ from: "user" },
|
|
);
|
|
|
|
expect(modelsAuthLoginCommand).toHaveBeenCalledTimes(1);
|
|
expect(modelsAuthLoginCommand).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
provider: "github-copilot",
|
|
method: "device",
|
|
yes: true,
|
|
agent: "poe",
|
|
}),
|
|
expect.any(Object),
|
|
);
|
|
});
|
|
|
|
it.each([
|
|
{ label: "status flag", args: ["models", "status", "--agent", "poe"] },
|
|
{ label: "parent flag", args: ["models", "--agent", "poe", "status"] },
|
|
])("passes --agent to models status ($label)", async ({ args }) => {
|
|
await runModelsCommand(args);
|
|
expect(modelsStatusCommand).toHaveBeenCalledWith(
|
|
expect.objectContaining({ agent: "poe" }),
|
|
expect.any(Object),
|
|
);
|
|
});
|
|
|
|
it.each([
|
|
{
|
|
label: "add",
|
|
args: ["models", "auth", "--agent", "poe", "add"],
|
|
command: modelsAuthAddCommand,
|
|
expected: { agent: "poe" },
|
|
},
|
|
{
|
|
label: "login",
|
|
args: ["models", "auth", "--agent", "poe", "login", "--provider", "openai-codex"],
|
|
command: modelsAuthLoginCommand,
|
|
expected: { agent: "poe", provider: "openai-codex" },
|
|
},
|
|
{
|
|
label: "setup-token",
|
|
args: ["models", "auth", "--agent", "poe", "setup-token", "--provider", "anthropic"],
|
|
command: modelsAuthSetupTokenCommand,
|
|
expected: { agent: "poe", provider: "anthropic" },
|
|
},
|
|
{
|
|
label: "paste-token",
|
|
args: ["models", "auth", "--agent", "poe", "paste-token", "--provider", "anthropic"],
|
|
command: modelsAuthPasteTokenCommand,
|
|
expected: { agent: "poe", provider: "anthropic" },
|
|
},
|
|
{
|
|
label: "login-github-copilot",
|
|
args: ["models", "auth", "--agent", "poe", "login-github-copilot", "--yes"],
|
|
command: modelsAuthLoginCommand,
|
|
expected: { agent: "poe", provider: "github-copilot", method: "device", yes: true },
|
|
},
|
|
])("passes parent --agent to models auth $label", async ({ args, command, expected }) => {
|
|
await runModelsCommand(args);
|
|
|
|
expect(command).toHaveBeenCalledWith(expect.objectContaining(expected), expect.any(Object));
|
|
});
|
|
|
|
it.each([
|
|
{
|
|
label: "set",
|
|
args: ["models", "--agent", "poe", "set", "anthropic/claude-sonnet-4-6"],
|
|
command: modelsSetCommand,
|
|
},
|
|
{
|
|
label: "set-image",
|
|
args: ["models", "--agent", "poe", "set-image", "openai/gpt-image-1"],
|
|
command: modelsSetImageCommand,
|
|
},
|
|
])("rejects parent --agent for models $label", async ({ args, command }) => {
|
|
await expect(runModelsCommand(args)).rejects.toThrow("does not support `--agent`");
|
|
|
|
expect(command).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("shows help for models auth without error exit", async () => {
|
|
const program = new Command();
|
|
program.exitOverride();
|
|
program.configureOutput({
|
|
writeOut: () => {},
|
|
writeErr: () => {},
|
|
});
|
|
registerModelsCli(program);
|
|
|
|
try {
|
|
await program.parseAsync(["models", "auth"], { from: "user" });
|
|
expect.fail("expected help to exit");
|
|
} catch (err) {
|
|
const error = err as { exitCode?: number };
|
|
expect(error.exitCode).toBe(0);
|
|
}
|
|
});
|
|
});
|