Files
thu-maic--openmaic/tests/edit/content-validation.test.ts
wehub-resource-sync c48612c494
CI / E2E Tests (push) Has been cancelled
CI / Lint, Typecheck & Unit Tests (push) Has been cancelled
Docs Build / Build docs site (push) Has been cancelled
Publish @openmaic packages / Build, validate & publish (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:03:23 +08:00

96 lines
3.3 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import {
validateScene,
sceneHasIssues,
validateOutline,
outlinesHaveBlockingIssues,
countBlockingOutlines,
} from '@/lib/edit/content-validation';
import type { Action } from '@/lib/types/action';
import type { Scene } from '@/lib/types/stage';
import type { SceneOutline } from '@/lib/types/generation';
const scene = (actions: Action[]): Scene =>
({
id: 's',
stageId: 'stage',
type: 'slide',
title: 'T',
order: 1,
content: { type: 'slide', canvas: {} },
actions,
}) as unknown as Scene;
const speech = (id: string, text: string): Action => ({ id, type: 'speech', text }) as Action;
const spotlight = (id: string, elementId: string): Action =>
({ id, type: 'spotlight', elementId }) as Action;
const discussion = (id: string, topic: string): Action =>
({ id, type: 'discussion', topic }) as unknown as Action;
const outline = (over: Partial<SceneOutline>): SceneOutline =>
({
id: 'o',
order: 1,
type: 'slide',
title: 'X',
description: '',
keyPoints: [],
...over,
}) as SceneOutline;
describe('validateScene', () => {
test('a fully-filled scene has no issues', () => {
expect(validateScene(scene([speech('a', 'hi'), spotlight('b', 'el_1')]))).toEqual([]);
expect(sceneHasIssues(scene([speech('a', 'hi')]))).toBe(false);
});
test('empty action list → emptyActions', () => {
expect(validateScene(scene([]))).toEqual([{ kind: 'emptyActions' }]);
expect(sceneHasIssues(scene([]))).toBe(true);
});
test('blank / whitespace-only speech text → emptySpeech with the action id', () => {
expect(validateScene(scene([speech('a', '')]))).toEqual([
{ kind: 'emptySpeech', actionId: 'a' },
]);
expect(validateScene(scene([speech('a', ' ')]))).toEqual([
{ kind: 'emptySpeech', actionId: 'a' },
]);
});
test('element-bound cue with no elementId → unboundCue', () => {
expect(validateScene(scene([speech('a', 'hi'), spotlight('b', '')]))).toEqual([
{ kind: 'unboundCue', actionId: 'b' },
]);
});
test('discussion with blank topic → emptyDiscussion', () => {
expect(validateScene(scene([speech('a', 'hi'), discussion('d', ' ')]))).toEqual([
{ kind: 'emptyDiscussion', actionId: 'd' },
]);
});
test('reports one issue per offending action, in order', () => {
expect(validateScene(scene([speech('a', ''), spotlight('b', '')]))).toEqual([
{ kind: 'emptySpeech', actionId: 'a' },
{ kind: 'unboundCue', actionId: 'b' },
]);
});
});
describe('validateOutline / blocking helpers', () => {
test('blank title → emptyTitle; filled title → no issue', () => {
expect(validateOutline(outline({ title: '' }))).toEqual([{ kind: 'emptyTitle' }]);
expect(validateOutline(outline({ title: ' ' }))).toEqual([{ kind: 'emptyTitle' }]);
expect(validateOutline(outline({ title: 'Intro' }))).toEqual([]);
});
test('outlinesHaveBlockingIssues / countBlockingOutlines count blank titles', () => {
const os = [outline({ title: 'A' }), outline({ title: '' }), outline({ title: ' ' })];
expect(outlinesHaveBlockingIssues(os)).toBe(true);
expect(countBlockingOutlines(os)).toBe(2);
expect(outlinesHaveBlockingIssues([outline({ title: 'A' })])).toBe(false);
expect(countBlockingOutlines([outline({ title: 'A' })])).toBe(0);
});
});