test: cover default models list registry narrowing

This commit is contained in:
Shakker
2026-04-24 02:59:56 +01:00
committed by Shakker
parent a6a2516cd8
commit c93f053f80
2 changed files with 62 additions and 9 deletions

View File

@@ -27,6 +27,7 @@ const modelRegistryState = {
available: [] as Array<Record<string, unknown>>,
getAllError: undefined as unknown,
getAvailableError: undefined as unknown,
findError: undefined as unknown,
};
let previousExitCode: typeof process.exitCode;
@@ -46,6 +47,9 @@ vi.mock("./models/load-config.js", () => ({
vi.mock("./models/list.runtime.js", () => {
class MockModelRegistry {
find(provider: string, id: string) {
if (modelRegistryState.findError !== undefined) {
throw modelRegistryState.findError;
}
return (
modelRegistryState.models.find((model) => model.provider === provider && model.id === id) ??
null
@@ -65,6 +69,12 @@ vi.mock("./models/list.runtime.js", () => {
}
return modelRegistryState.available;
}
hasConfiguredAuth(model: { provider: string; id: string }) {
return modelRegistryState.available.some(
(available) => available.provider === model.provider && available.id === model.id,
);
}
}
return {
@@ -133,6 +143,7 @@ beforeEach(() => {
process.exitCode = undefined;
modelRegistryState.getAllError = undefined;
modelRegistryState.getAvailableError = undefined;
modelRegistryState.findError = undefined;
getRuntimeConfig.mockReset();
getRuntimeConfig.mockReturnValue({});
listProfilesForProvider.mockReturnValue([]);
@@ -390,22 +401,27 @@ describe("models list/status", () => {
expect(loadProviderCatalogModelsForList).not.toHaveBeenCalled();
});
it("models list does not treat availability-unavailable code as discovery fallback", async () => {
it("models list default does not enumerate all registry models", async () => {
configureGoogleAntigravityModel("claude-opus-4-6-thinking");
modelRegistryState.models = [
makeGoogleAntigravityTemplate("claude-opus-4-6-thinking", "Claude Opus 4.6 Thinking"),
];
modelRegistryState.available = modelRegistryState.models;
modelRegistryState.getAllError = Object.assign(new Error("model discovery failed"), {
code: "MODEL_AVAILABILITY_UNAVAILABLE",
});
const runtime = makeRuntime();
await modelsListCommand({ json: true }, runtime);
expectModelRegistryUnavailable(runtime, "model discovery failed");
expect(runtime.error.mock.calls[0]?.[0]).not.toContain("configured models may appear missing");
expect(runtime.error).not.toHaveBeenCalled();
const payload = parseJsonLog(runtime);
expect(payload.models[0]?.key).toBe("google-antigravity/claude-opus-4-6-thinking");
});
it("models list fails fast when registry model discovery is unavailable", async () => {
it("models list fails fast when configured registry lookup is unavailable", async () => {
configureGoogleAntigravityModel("claude-opus-4-6-thinking");
enableGoogleAntigravityAuthProfile();
modelRegistryState.getAllError = Object.assign(new Error("model discovery unavailable"), {
modelRegistryState.findError = Object.assign(new Error("model discovery unavailable"), {
code: "MODEL_DISCOVERY_UNAVAILABLE",
});
const runtime = makeRuntime();

View File

@@ -141,6 +141,43 @@ function installModelsListCommandForwardCompatMocks() {
printModelTable: mocks.printModelTable,
}));
vi.doMock("./list.registry-load.js", () => ({
loadListModelRegistry: async (
cfg: unknown,
opts?: { providerFilter?: string },
): Promise<{
models: Array<{ provider: string; id: string }>;
availableKeys?: Set<string>;
registry?: unknown;
discoveredKeys: Set<string>;
}> => {
const loaded = await mocks.loadModelRegistry(cfg, opts);
return {
...loaded,
discoveredKeys: new Set(
loaded.models.map(
(model: { provider: string; id: string }) => `${model.provider}/${model.id}`,
),
),
};
},
loadConfiguredListModelRegistry: (
_cfg: unknown,
_entries: unknown,
opts?: { providerFilter?: string },
) => {
mocks.loadModelRegistry(mocks.resolvedConfig, opts);
return {
registry: {
find: () => undefined,
hasConfiguredAuth: () => false,
},
discoveredKeys: new Set(),
availableKeys: new Set(),
};
},
}));
vi.doMock("./list.runtime.js", () => ({
ensureOpenClawModelsJson: mocks.ensureOpenClawModelsJson,
ensureAuthProfileStore: mocks.ensureAuthProfileStore,
@@ -363,7 +400,7 @@ describe("modelsListCommand forward-compat", () => {
);
});
it("exits with an error when configured-mode listing has no model registry", async () => {
it("does not require the all-model registry result for configured-mode listing", async () => {
const previousExitCode = process.exitCode;
process.exitCode = undefined;
mocks.loadModelRegistry.mockResolvedValueOnce({
@@ -381,9 +418,9 @@ describe("modelsListCommand forward-compat", () => {
process.exitCode = previousExitCode;
}
expect(runtime.error).toHaveBeenCalledWith("Model registry unavailable.");
expect(observedExitCode).toBe(1);
expect(mocks.printModelTable).not.toHaveBeenCalled();
expect(runtime.error).not.toHaveBeenCalled();
expect(observedExitCode).toBeUndefined();
expect(mocks.printModelTable).toHaveBeenCalled();
});
});