





















@@ -93,18 +93,56 @@ function requireFetchCallHeaders(index: number): Headers {
9393return new Headers(init.headers);
9494}
959596+function requireRecord(value: unknown, label: string): Record<string, unknown> {
97+expect(typeof value).toBe("object");
98+expect(value).not.toBeNull();
99+if (typeof value !== "object" || value === null) {
100+throw new Error(`${label} was not an object`);
101+}
102+return value as Record<string, unknown>;
103+}
104+105+function expectRecordFields(record: Record<string, unknown>, fields: Record<string, unknown>) {
106+for (const [key, value] of Object.entries(fields)) {
107+expect(record[key]).toEqual(value);
108+}
109+}
110+96111function expectOpenRouterFetchCall(index: number, url: string, auditContext: string) {
97112const call = fetchWithTimeoutGuardedMock.mock.calls[index];
98113if (!call) {
99114throw new Error(`expected OpenRouter fetch call ${index + 1}`);
100115}
101116const [actualUrl, init, timeoutMs, fetchFn, guardOptions] = call;
102117expect(actualUrl).toBe(url);
103-expect(init).toMatchObject({ method: "GET" });
118+expect(requireRecord(init, "OpenRouter fetch init").method).toBe("GET");
104119expect(Number.isInteger(timeoutMs)).toBe(true);
105120expect(timeoutMs).toBeGreaterThan(0);
106121expect(fetchFn).toBe(fetch);
107-expect(guardOptions).toMatchObject({ auditContext });
122+expect(requireRecord(guardOptions, "OpenRouter fetch guard options").auditContext).toBe(
123+auditContext,
124+);
125+}
126+127+function requirePostJsonParams(index = 0): Record<string, unknown> {
128+const call = postJsonRequestMock.mock.calls[index] as unknown[] | undefined;
129+if (!call) {
130+throw new Error(`expected OpenRouter POST JSON call ${index + 1}`);
131+}
132+return requireRecord(call[0], "OpenRouter POST JSON params");
133+}
134+135+function requireMockCallArg(
136+mockCalls: unknown[][],
137+index: number,
138+argIndex: number,
139+label: string,
140+) {
141+const call = mockCalls[index];
142+if (!call) {
143+throw new Error(`expected ${label} call ${index + 1}`);
144+}
145+return call[argIndex];
108146}
109147110148function requireGeneratedVideo(result: OpenRouterVideoResult, index: number) {
@@ -149,8 +187,8 @@ describe("openrouter video generation provider", () => {
149187expect(generateCapabilities.supportedDurationSeconds).toEqual([4, 6, 8]);
150188expect(generateCapabilities.resolutions).toEqual(["720P", "1080P"]);
151189expect(generateCapabilities.aspectRatios).toEqual(["16:9", "9:16"]);
152-expect(provider.capabilities.imageToVideo).toMatchObject({ enabled: true });
153-expect(provider.capabilities.videoToVideo).toMatchObject({ enabled: false });
190+expect(provider.capabilities.imageToVideo?.enabled).toBe(true);
191+expect(provider.capabilities.videoToVideo?.enabled).toBe(false);
154192});
155193156194it("maps OpenRouter video model discovery into unified catalog rows", async () => {
@@ -199,54 +237,58 @@ describe("openrouter video generation provider", () => {
199237}),
200238});
201239202-expect(resolveProviderHttpRequestConfigMock).toHaveBeenCalledWith(
203-expect.objectContaining({
240+expectRecordFields(
241+requireRecord(resolveProviderHttpRequestConfigMock.mock.calls[0]?.[0], "request config"),
242+{
204243baseUrl: "https://custom.openrouter.test/openrouter/api/v1",
205244defaultBaseUrl: "https://openrouter.ai/api/v1",
206245provider: "openrouter",
207246capability: "video",
208-}),
247+},
209248);
210-expect(fetchWithTimeoutGuardedMock).toHaveBeenCalledWith(
249+expectOpenRouterFetchCall(
250+0,
211251"https://custom.openrouter.test/openrouter/api/v1/videos/models",
212-expect.objectContaining({ method: "GET" }),
213-expect.any(Number),
214-expect.any(Function),
215-expect.objectContaining({ auditContext: "openrouter-video-models" }),
252+"openrouter-video-models",
216253);
217254expect(requireFetchCallHeaders(0).get("authorization")).toBe("Bearer resolved-openrouter-key");
218255expectUnifiedModelCatalogEntries(rows, {
219256provider: "openrouter",
220257kind: "video_generation",
221258});
222-expect(rows).toEqual([
223-expect.objectContaining({
224-kind: "video_generation",
225-provider: "openrouter",
226-model: "google/veo-3.1",
227-label: "Veo 3.1",
228-source: "live",
229-capabilities: expect.objectContaining({
230-canonicalSlug: "google/veo-3.1",
231-description: "Google video generation model",
232-created: 1_700_000_000,
233-pricingSkus: { generate: "0.50" },
234-allowedPassthroughParameters: ["provider"],
235-generate: expect.objectContaining({
236-supportsAudio: true,
237-supportedDurationSeconds: [5, 8],
238-aspectRatios: ["16:9"],
239-resolutions: ["720P"],
240-sizes: ["1280x720"],
241-}),
242-imageToVideo: expect.objectContaining({
243-enabled: true,
244-maxInputImages: 2,
245-}),
246-videoToVideo: { enabled: false },
247-}),
248-}),
249-]);
259+expect(rows).toHaveLength(1);
260+const row = rows[0];
261+expect(row).toBeDefined();
262+if (!row) {
263+throw new Error("expected OpenRouter catalog row");
264+}
265+expectRecordFields(row as unknown as Record<string, unknown>, {
266+kind: "video_generation",
267+provider: "openrouter",
268+model: "google/veo-3.1",
269+label: "Veo 3.1",
270+source: "live",
271+});
272+const capabilities = requireRecord(row.capabilities, "catalog row capabilities");
273+expectRecordFields(capabilities, {
274+canonicalSlug: "google/veo-3.1",
275+description: "Google video generation model",
276+created: 1_700_000_000,
277+pricingSkus: { generate: "0.50" },
278+allowedPassthroughParameters: ["provider"],
279+videoToVideo: { enabled: false },
280+});
281+expectRecordFields(requireRecord(capabilities.generate, "generate capabilities"), {
282+supportsAudio: true,
283+supportedDurationSeconds: [5, 8],
284+aspectRatios: ["16:9"],
285+resolutions: ["720P"],
286+sizes: ["1280x720"],
287+});
288+expectRecordFields(requireRecord(capabilities.imageToVideo, "image-to-video capabilities"), {
289+enabled: true,
290+maxInputImages: 2,
291+});
250292});
251293252294it("skips live OpenRouter video catalog discovery without an API key", async () => {
@@ -293,23 +335,28 @@ describe("openrouter video generation provider", () => {
293335timeoutMs: 12_345,
294336});
295337296-expect(resolveApiKeyForProviderMock).toHaveBeenCalledWith(
297-expect.objectContaining({ provider: "openrouter" }),
298-);
299-expect(fetchWithTimeoutGuardedMock).toHaveBeenCalledWith(
338+expect(
339+requireRecord(
340+requireMockCallArg(resolveApiKeyForProviderMock.mock.calls, 0, 0, "API key request"),
341+"API key request",
342+).provider,
343+).toBe("openrouter");
344+expectOpenRouterFetchCall(
345+0,
300346"https://custom.openrouter.test/openrouter/api/v1/videos/models",
301-expect.objectContaining({ method: "GET" }),
302-12_345,
303-expect.any(Function),
304-expect.objectContaining({ auditContext: "openrouter-video-models" }),
347+"openrouter-video-models",
305348);
306-expect(capabilities).toMatchObject({
307-providerOptions: { seed: "number" },
308-generate: {
309-supportsAudio: false,
310-supportedDurationSeconds: [5],
311-resolutions: ["720P"],
312-},
349+expect(fetchWithTimeoutGuardedMock.mock.calls[0]?.[2]).toBe(12_345);
350+expect(fetchWithTimeoutGuardedMock.mock.calls[0]?.[3]).toBeTypeOf("function");
351+const resolvedCapabilities = requireRecord(capabilities, "resolved capabilities");
352+expect(resolvedCapabilities.providerOptions).toEqual({
353+callback_url: "string",
354+seed: "number",
355+});
356+expectRecordFields(requireRecord(resolvedCapabilities.generate, "generate capabilities"), {
357+supportsAudio: false,
358+supportedDurationSeconds: [5],
359+resolutions: ["720P"],
313360});
314361});
315362@@ -335,13 +382,7 @@ describe("openrouter video generation provider", () => {
335382cfg: {} as never,
336383});
337384338-expect(postJsonRequestMock).toHaveBeenCalledWith(
339-expect.objectContaining({
340-body: expect.objectContaining({
341-duration: 8,
342-}),
343-}),
344-);
385+expect(requireRecord(requirePostJsonParams().body, "OpenRouter request body").duration).toBe(8);
345386});
346387347388it("preserves runtime-normalized live catalog durations in request bodies", async () => {
@@ -369,13 +410,7 @@ describe("openrouter video generation provider", () => {
369410[SUPPORTED_DURATIONS_HINT]: readonly number[];
370411});
371412372-expect(postJsonRequestMock).toHaveBeenCalledWith(
373-expect.objectContaining({
374-body: expect.objectContaining({
375-duration: 5,
376-}),
377-}),
378-);
413+expect(requireRecord(requirePostJsonParams().body, "OpenRouter request body").duration).toBe(5);
379414});
380415381416it("submits OpenRouter video jobs, polls completion, and downloads the result", async () => {
@@ -438,57 +473,58 @@ describe("openrouter video generation provider", () => {
438473} as never,
439474});
440475441-expect(resolveApiKeyForProviderMock).toHaveBeenCalledWith(
442-expect.objectContaining({ provider: "openrouter" }),
443-);
444-expect(resolveProviderHttpRequestConfigMock).toHaveBeenCalledWith(
445-expect.objectContaining({
476+expect(
477+requireRecord(
478+requireMockCallArg(resolveApiKeyForProviderMock.mock.calls, 0, 0, "API key request"),
479+"API key request",
480+).provider,
481+).toBe("openrouter");
482+expectRecordFields(
483+requireRecord(resolveProviderHttpRequestConfigMock.mock.calls[0]?.[0], "request config"),
484+{
446485provider: "openrouter",
447486capability: "video",
448487baseUrl: "https://custom.openrouter.test/api/v1",
449488request: requestOverrides,
450-}),
489+},
451490);
452-expect(postJsonRequestMock).toHaveBeenCalledWith(
453-expect.objectContaining({
454-url: "https://custom.openrouter.test/api/v1/videos",
455-body: {
456-model: "google/veo-3.1",
457-prompt: "A chrome sphere glides across a quiet moonlit beach",
458-duration: 6,
459-resolution: "720p",
460-aspect_ratio: "16:9",
461-size: "1280x720",
462-generate_audio: false,
463-frame_images: [
464-{
465-type: "image_url",
466-image_url: {
467-url: `data:image/png;base64,${Buffer.from("first-frame").toString("base64")}`,
468-},
469-frame_type: "first_frame",
470-},
471-{
472-type: "image_url",
473-image_url: {
474-url: `data:image/png;base64,${Buffer.from("last-frame").toString("base64")}`,
475-},
476-frame_type: "last_frame",
477-},
478-],
479-input_references: [
480-{
481-type: "image_url",
482-image_url: {
483-url: `data:image/webp;base64,${Buffer.from("style-reference").toString("base64")}`,
484-},
485-},
486-],
487-callback_url: "https://example.com/openrouter-video-hook",
488-seed: 42,
491+const postParams = requirePostJsonParams();
492+expect(postParams.url).toBe("https://custom.openrouter.test/api/v1/videos");
493+expect(postParams.body).toEqual({
494+model: "google/veo-3.1",
495+prompt: "A chrome sphere glides across a quiet moonlit beach",
496+duration: 6,
497+resolution: "720p",
498+aspect_ratio: "16:9",
499+size: "1280x720",
500+generate_audio: false,
501+frame_images: [
502+{
503+type: "image_url",
504+image_url: {
505+url: `data:image/png;base64,${Buffer.from("first-frame").toString("base64")}`,
506+},
507+frame_type: "first_frame",
489508},
490-}),
491-);
509+{
510+type: "image_url",
511+image_url: {
512+url: `data:image/png;base64,${Buffer.from("last-frame").toString("base64")}`,
513+},
514+frame_type: "last_frame",
515+},
516+],
517+input_references: [
518+{
519+type: "image_url",
520+image_url: {
521+url: `data:image/webp;base64,${Buffer.from("style-reference").toString("base64")}`,
522+},
523+},
524+],
525+callback_url: "https://example.com/openrouter-video-hook",
526+seed: 42,
527+});
492528expectOpenRouterFetchCall(
4935290,
494530"https://custom.openrouter.test/api/v1/videos/job-123",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。