66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { normalizeScenes, VideoTimelineCompileError } from '@/lib/video-export';
|
|
import { act, quiz, slide, speech, spotlight } from './helpers';
|
|
|
|
describe('normalizeScenes — ordering', () => {
|
|
it('orders scenes by `order`, tie-broken by input index (stable)', () => {
|
|
const scenes = [
|
|
slide('c', [], { order: 2 }),
|
|
slide('a', [], { order: 1 }),
|
|
slide('b', [], { order: 1 }),
|
|
];
|
|
const { scenes: out } = normalizeScenes(scenes);
|
|
expect(out.map((s) => s.id)).toEqual(['a', 'b', 'c']);
|
|
});
|
|
|
|
it('falls back to input index when `order` is absent, preserving input order', () => {
|
|
const scenes = [
|
|
{ ...slide('x', []), order: undefined },
|
|
{ ...slide('y', []), order: undefined },
|
|
];
|
|
const { scenes: out } = normalizeScenes(scenes as never);
|
|
expect(out.map((s) => s.id)).toEqual(['x', 'y']);
|
|
});
|
|
|
|
it('throws on an empty scene list', () => {
|
|
expect(() => normalizeScenes([])).toThrow(VideoTimelineCompileError);
|
|
});
|
|
});
|
|
|
|
describe('normalizeScenes — action validation', () => {
|
|
it('drops an unknown action type with an unknown-action diagnostic', () => {
|
|
const scenes = [slide('s', [act({ id: 'bad', type: 'teleport' }), speech('ok', 'hi')])];
|
|
const { scenes: out, diagnostics } = normalizeScenes(scenes);
|
|
expect(out[0].actions).toHaveLength(1);
|
|
expect(out[0].actions?.[0].id).toBe('ok');
|
|
expect(diagnostics).toEqual([
|
|
expect.objectContaining({ code: 'unknown-action', sceneId: 's', actionId: 'bad' }),
|
|
]);
|
|
});
|
|
|
|
it('drops an action missing a required field with an invalid-action diagnostic', () => {
|
|
// spotlight without elementId
|
|
const scenes = [slide('s', [act({ id: 'sp', type: 'spotlight' }), spotlight('good', 'e1')])];
|
|
const { scenes: out, diagnostics } = normalizeScenes(scenes);
|
|
expect(out[0].actions?.map((a) => a.id)).toEqual(['good']);
|
|
expect(diagnostics[0]).toMatchObject({ code: 'invalid-action', actionId: 'sp' });
|
|
});
|
|
|
|
it('keeps an empty-text speech (a legal dwell beat)', () => {
|
|
const { scenes: out, diagnostics } = normalizeScenes([slide('s', [speech('e', '')])]);
|
|
expect(out[0].actions).toHaveLength(1);
|
|
expect(diagnostics).toHaveLength(0);
|
|
});
|
|
|
|
it('does not mutate the input scenes', () => {
|
|
const scenes = [slide('b', [], { order: 2 }), slide('a', [], { order: 1 })];
|
|
normalizeScenes(scenes);
|
|
expect(scenes.map((s) => s.id)).toEqual(['b', 'a']);
|
|
});
|
|
|
|
it('validates quiz scene actions too', () => {
|
|
const { diagnostics } = normalizeScenes([quiz('q', [act({ id: 'z', type: 'nope' })])]);
|
|
expect(diagnostics[0].code).toBe('unknown-action');
|
|
});
|
|
});
|