test: stabilize plugin contract mocks

This commit is contained in:
Peter Steinberger 2026-03-18 02:44:24 +00:00
parent 6f060d7e6c
commit 44521d6b20
3 changed files with 65 additions and 26 deletions

View File

@ -27,14 +27,6 @@ const resolveNonBundledProviderPluginIdsMock = vi.hoisted(() =>
vi.fn<ResolveNonBundledProviderPluginIds>((_) => [] as string[]),
);
vi.mock("../providers.js", () => ({
resolvePluginProviders: (params: unknown) => resolvePluginProvidersMock(params as never),
resolveOwningPluginIdsForProvider: (params: unknown) =>
resolveOwningPluginIdsForProviderMock(params as never),
resolveNonBundledProviderPluginIds: (params: unknown) =>
resolveNonBundledProviderPluginIdsMock(params as never),
}));
let augmentModelCatalogWithProviderPlugins: typeof import("../provider-runtime.js").augmentModelCatalogWithProviderPlugins;
let buildProviderMissingAuthMessageWithPlugin: typeof import("../provider-runtime.js").buildProviderMissingAuthMessageWithPlugin;
let resetProviderRuntimeHookCacheForTest: typeof import("../provider-runtime.js").resetProviderRuntimeHookCacheForTest;
@ -43,18 +35,12 @@ let resolveProviderBuiltInModelSuppression: typeof import("../provider-runtime.j
describe("provider catalog contract", () => {
beforeEach(async () => {
vi.resetModules();
vi.doUnmock("../providers.js");
({
resolveProviderContractPluginIdsForProvider,
resolveProviderContractProvidersForPluginIds,
uniqueProviderContractProviders,
} = await import("./registry.js"));
({
augmentModelCatalogWithProviderPlugins,
buildProviderMissingAuthMessageWithPlugin,
resetProviderRuntimeHookCacheForTest,
resolveProviderBuiltInModelSuppression,
} = await import("../provider-runtime.js"));
resetProviderRuntimeHookCacheForTest();
resolveOwningPluginIdsForProviderMock.mockReset();
resolveOwningPluginIdsForProviderMock.mockImplementation((params) =>
@ -72,6 +58,22 @@ describe("provider catalog contract", () => {
}
return resolveProviderContractProvidersForPluginIds(onlyPluginIds);
});
vi.doMock("../providers.js", () => ({
resolvePluginProviders: (params: unknown) => resolvePluginProvidersMock(params as never),
resolveOwningPluginIdsForProvider: (params: unknown) =>
resolveOwningPluginIdsForProviderMock(params as never),
resolveNonBundledProviderPluginIds: (params: unknown) =>
resolveNonBundledProviderPluginIdsMock(params as never),
}));
({
augmentModelCatalogWithProviderPlugins,
buildProviderMissingAuthMessageWithPlugin,
resetProviderRuntimeHookCacheForTest,
resolveProviderBuiltInModelSuppression,
} = await import("../provider-runtime.js"));
resetProviderRuntimeHookCacheForTest();
});
it("keeps codex-only missing-auth hints wired through the provider runtime", () => {

View File

@ -2,7 +2,9 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createCapturedPluginRegistration } from "../../test-utils/plugin-registration.js";
import { createProviderUsageFetch, makeResponse } from "../../test-utils/provider-usage-fetch.js";
import type { OpenClawPluginApi, ProviderPlugin } from "../types.js";
import type { ProviderRuntimeModel } from "../types.js";
const getOAuthApiKeyMock = vi.hoisted(() => vi.fn());
@ -16,11 +18,17 @@ vi.mock("@mariozechner/pi-ai/oauth", async () => {
};
});
vi.mock("../../providers/qwen-portal-oauth.js", () => ({
refreshQwenPortalCredentials: refreshQwenPortalCredentialsMock,
}));
vi.mock("openclaw/plugin-sdk/qwen-portal-auth", async () => {
const actual = await vi.importActual<object>("openclaw/plugin-sdk/qwen-portal-auth");
return {
...actual,
refreshQwenPortalCredentials: refreshQwenPortalCredentialsMock,
};
});
let requireProviderContractProvider: typeof import("./registry.js").requireProviderContractProvider;
let requireBundledProviderContractProvider: typeof import("./registry.js").requireProviderContractProvider;
let openAIPlugin: (typeof import("../../../extensions/openai/index.js"))["default"];
let qwenPortalPlugin: (typeof import("../../../extensions/qwen-portal-auth/index.js"))["default"];
function createModel(overrides: Partial<ProviderRuntimeModel> & Pick<ProviderRuntimeModel, "id">) {
return {
@ -37,10 +45,39 @@ function createModel(overrides: Partial<ProviderRuntimeModel> & Pick<ProviderRun
} satisfies ProviderRuntimeModel;
}
function registerProviders(...plugins: Array<{ register(api: OpenClawPluginApi): void }>) {
const captured = createCapturedPluginRegistration();
for (const plugin of plugins) {
plugin.register(captured.api);
}
return captured.providers;
}
function requireProvider(providers: ProviderPlugin[], providerId: string) {
const provider = providers.find((entry) => entry.id === providerId);
if (!provider) {
throw new Error(`provider ${providerId} missing`);
}
return provider;
}
function requireProviderContractProvider(providerId: string): ProviderPlugin {
if (providerId === "openai-codex") {
return requireProvider(registerProviders(openAIPlugin), providerId);
}
if (providerId === "qwen-portal") {
return requireProvider(registerProviders(qwenPortalPlugin), providerId);
}
return requireBundledProviderContractProvider(providerId);
}
describe("provider runtime contract", () => {
beforeEach(async () => {
vi.resetModules();
({ requireProviderContractProvider } = await import("./registry.js"));
({ requireProviderContractProvider: requireBundledProviderContractProvider } =
await import("./registry.js"));
openAIPlugin = (await import("../../../extensions/openai/index.js")).default;
qwenPortalPlugin = (await import("../../../extensions/qwen-portal-auth/index.js")).default;
getOAuthApiKeyMock.mockReset();
refreshQwenPortalCredentialsMock.mockReset();
});

View File

@ -3,10 +3,6 @@ import type { ProviderPlugin } from "../types.js";
const resolvePluginProvidersMock = vi.fn();
vi.mock("../providers.js", () => ({
resolvePluginProviders: (...args: unknown[]) => resolvePluginProvidersMock(...args),
}));
let buildProviderPluginMethodChoice: typeof import("../provider-wizard.js").buildProviderPluginMethodChoice;
let providerContractPluginIds: typeof import("./registry.js").providerContractPluginIds;
let resolveProviderModelPickerEntries: typeof import("../provider-wizard.js").resolveProviderModelPickerEntries;
@ -73,16 +69,20 @@ function resolveExpectedModelPickerValues(providers: ProviderPlugin[]) {
describe("provider wizard contract", () => {
beforeEach(async () => {
vi.resetModules();
vi.doUnmock("../providers.js");
({ providerContractPluginIds, uniqueProviderContractProviders } =
await import("./registry.js"));
resolvePluginProvidersMock.mockReset();
resolvePluginProvidersMock.mockReturnValue(uniqueProviderContractProviders);
vi.doMock("../providers.js", () => ({
resolvePluginProviders: (...args: unknown[]) => resolvePluginProvidersMock(...args),
}));
({
buildProviderPluginMethodChoice,
resolveProviderModelPickerEntries,
resolveProviderPluginChoice,
resolveProviderWizardOptions,
} = await import("../provider-wizard.js"));
resolvePluginProvidersMock.mockReset();
resolvePluginProvidersMock.mockReturnValue(uniqueProviderContractProviders);
});
it("exposes every registered provider setup choice through the shared wizard layer", () => {