studio-api-keyframes-209.test.ts
Rama main · réplica de lectura del repositorio original.
// slate#209: `!api film-submit` on a keyframes-only brief must go to the keyframes-only door.
//
// POST /api/render/film has no keyframes-only mode and never read `keyframes_only`, so this action used
// to start, and pay for, a full film. The studio now refuses a field a door does not read
// (vivijure-cf#896), so the same request would also fail. Both cases drive the real action with a
// stubbed fetch and read the request it actually sent.
import { afterEach, describe, expect, it, vi } from 'vitest';
import { STUDIO_ACTIONS } from './studio-api.mjs';
type Sent = { url: string; body: Record<string, unknown> };
function ctx(keyframesOnly: boolean) {
return {
cfg: { vivijureUrl: 'https://studio.example', headers: {} },
brief: {
scenes: [{ id: 'shot_01', prompt: 'a cat on a roof', target_seconds: 4 }],
clip_seconds: 5,
cast_bindings: { hero: 'cast-public-id' },
render_settings: {
quality_tier: 'standard', motion_backend: 'seedance', keyframes_only: keyframesOnly,
module_overrides: { config: {} }, subtitles: false, audio_key: null,
},
},
emptyRenderSettings: () => ({}),
fetchRegistry: async () => null,
getSubtitleModule: async () => null,
fetchCastCatalog: async () => [],
};
}
function stubFetch(): Sent[] {
const sent: Sent[] = [];
vi.stubGlobal('fetch', async (url: string, init: { body?: string }) => {
sent.push({ url: String(url), body: init?.body ? JSON.parse(init.body) : {} });
return new Response(JSON.stringify({ jobId: 'film-1', film_id: 'film-1' }), {
status: 201, headers: { 'content-type': 'application/json' },
});
});
return sent;
}
afterEach(() => { vi.unstubAllGlobals(); });
describe('film-submit and keyframes-only (slate#209)', () => {
it('a keyframes-only brief goes to /api/storyboard/render with keyframesOnly, never to the film door', async () => {
const sent = stubFetch();
await STUDIO_ACTIONS['film-submit'].run(ctx(true), { bundleKey: 'bundles/b.tar.gz' });
expect(sent).toHaveLength(1);
expect(new URL(sent[0].url).pathname).toBe('/api/storyboard/render');
expect(sent[0].body).toEqual({
bundleKey: 'bundles/b.tar.gz',
scenes: [{ shot_id: 'shot_01', prompt: 'a cat on a roof', seconds: 4 }],
qualityTier: 'standard',
castLoras: { hero: 'cast-public-id' },
keyframesOnly: true,
});
});
it('a full brief still goes to /api/render/film, and carries no keyframes_only field', async () => {
const sent = stubFetch();
await STUDIO_ACTIONS['film-submit'].run(ctx(false), { bundleKey: 'bundles/b.tar.gz' });
expect(sent).toHaveLength(1);
expect(new URL(sent[0].url).pathname).toBe('/api/render/film');
expect(sent[0].body.bundle_key).toBe('bundles/b.tar.gz');
expect(sent[0].body).not.toHaveProperty('keyframes_only');
});
});