






















@@ -0,0 +1,115 @@
1+import { beforeEach, describe, expect, it, vi } from "vitest";
2+3+const mocks = vi.hoisted(() => ({
4+loadStaticManifestCatalogRowsForList: vi.fn(),
5+loadProviderIndexCatalogRowsForList: vi.fn(),
6+hasProviderStaticCatalogForFilter: vi.fn(),
7+}));
8+9+vi.mock("./list.manifest-catalog.js", () => ({
10+loadStaticManifestCatalogRowsForList: mocks.loadStaticManifestCatalogRowsForList,
11+}));
12+13+vi.mock("./list.provider-index-catalog.js", () => ({
14+loadProviderIndexCatalogRowsForList: mocks.loadProviderIndexCatalogRowsForList,
15+}));
16+17+vi.mock("./list.provider-catalog.js", () => ({
18+hasProviderStaticCatalogForFilter: mocks.hasProviderStaticCatalogForFilter,
19+}));
20+21+const catalogRow = {
22+provider: "moonshot",
23+id: "kimi-k2.6",
24+ref: "moonshot/kimi-k2.6",
25+mergeKey: "moonshot::kimi-k2.6",
26+name: "Kimi K2.6",
27+source: "manifest",
28+input: ["text"],
29+reasoning: false,
30+status: "available",
31+} as const;
32+33+describe("planAllModelListSources", () => {
34+beforeEach(() => {
35+vi.clearAllMocks();
36+mocks.loadStaticManifestCatalogRowsForList.mockReturnValue([]);
37+mocks.loadProviderIndexCatalogRowsForList.mockReturnValue([]);
38+mocks.hasProviderStaticCatalogForFilter.mockResolvedValue(false);
39+});
40+41+it("uses installed manifest rows before provider index or runtime catalog sources", async () => {
42+const { planAllModelListSources } = await import("./list.source-plan.js");
43+mocks.loadStaticManifestCatalogRowsForList.mockReturnValueOnce([catalogRow]);
44+45+const plan = await planAllModelListSources({
46+all: true,
47+providerFilter: "moonshot",
48+cfg: {},
49+});
50+51+expect(plan).toMatchObject({
52+kind: "manifest",
53+requiresInitialRegistry: false,
54+skipRuntimeModelSuppression: true,
55+});
56+expect(plan.manifestCatalogRows).toEqual([catalogRow]);
57+expect(mocks.loadProviderIndexCatalogRowsForList).not.toHaveBeenCalled();
58+expect(mocks.hasProviderStaticCatalogForFilter).not.toHaveBeenCalled();
59+});
60+61+it("uses provider index rows only when installed manifest rows are unavailable", async () => {
62+const { planAllModelListSources } = await import("./list.source-plan.js");
63+const providerIndexRow = { ...catalogRow, source: "provider-index" };
64+mocks.loadProviderIndexCatalogRowsForList.mockReturnValueOnce([providerIndexRow]);
65+66+const plan = await planAllModelListSources({
67+all: true,
68+providerFilter: "moonshot",
69+cfg: {},
70+});
71+72+expect(plan).toMatchObject({
73+kind: "provider-index",
74+requiresInitialRegistry: false,
75+skipRuntimeModelSuppression: true,
76+});
77+expect(plan.providerIndexCatalogRows).toEqual([providerIndexRow]);
78+expect(mocks.hasProviderStaticCatalogForFilter).not.toHaveBeenCalled();
79+});
80+81+it("keeps scoped runtime catalog fallback separate from broad registry loading", async () => {
82+const { planAllModelListSources } = await import("./list.source-plan.js");
83+84+await expect(
85+planAllModelListSources({
86+all: true,
87+providerFilter: "openrouter",
88+cfg: {},
89+}),
90+).resolves.toMatchObject({
91+kind: "provider-runtime-scoped",
92+requiresInitialRegistry: false,
93+skipRuntimeModelSuppression: false,
94+fallbackToRegistryWhenEmpty: false,
95+});
96+});
97+98+it("falls back to registry only for provider static fast paths that return no rows", async () => {
99+const { planAllModelListSources } = await import("./list.source-plan.js");
100+mocks.hasProviderStaticCatalogForFilter.mockResolvedValueOnce(true);
101+102+await expect(
103+planAllModelListSources({
104+all: true,
105+providerFilter: "codex",
106+cfg: {},
107+}),
108+).resolves.toMatchObject({
109+kind: "provider-runtime-static",
110+requiresInitialRegistry: false,
111+skipRuntimeModelSuppression: true,
112+fallbackToRegistryWhenEmpty: true,
113+});
114+});
115+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。