aiPptSlideDesignSelfTest.mjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. import { createServer } from 'vite'
  2. import assert from 'node:assert/strict'
  3. import { writeFileSync } from 'node:fs'
  4. import { slideDesignFixture } from './fixtures/aiPptSlideDesign.mjs'
  5. const vite = await createServer({ server: { middlewareMode: true }, appType: 'custom', logLevel: 'error' })
  6. try {
  7. const { aiCoursewareToSlides } = await vite.ssrLoadModule('/src/utils/aiCoursewareToSlides.ts')
  8. const { modelSlideDesignIssues } = await vite.ssrLoadModule('/src/utils/aiPptModelSlideDesign.ts')
  9. const { getAiPptImageAspectRatios, buildAiPptSlidePreviews } = await vite.ssrLoadModule('/src/utils/aiPptTemplateEngine.ts')
  10. const fixture = slideDesignFixture(), before = structuredClone(fixture)
  11. const result = aiCoursewareToSlides(fixture)
  12. assert.deepEqual(fixture, before, '渲染不得改写输入内容')
  13. assert.equal(result.slides[1].elements.find(e => e.name === '模型教学色块').left, 130 * 1.2)
  14. assert.equal(result.slides[1].elements.find(e => e.name === '模型教学色块').fill, '#FCE4CE')
  15. assert(result.slides[0].elements.find(e => e.type === 'text').content.includes('67.2px'), '模型字号按画布比例转换,不由前端重新选择')
  16. assert(result.slides.every(s => s.background.color === '#FFFDF5'))
  17. assert.equal(getAiPptImageAspectRatios('blank').model_design_v7, 1)
  18. for (const [name, mutate, reason] of [
  19. ['overflow', p => p.pageDesign.elements[3].height = 10, /实际高度|投屏安全区/],
  20. ['missing', p => p.pageDesign.elements.pop(), /遗漏/],
  21. ['contrast', p => p.pageDesign.elements[3].color = '#D9EDF3', /对比度/],
  22. ['unknown reference', p => p.pageDesign.elements[3].textRef = 'interaction.answer', /引用/],
  23. ['required image', p => p.visualPlan.visualMode = 'reference_image', /槽位/],
  24. ['unknown element', p => p.pageDesign.elements[0].kind = 'script', /无效/]
  25. ]) {
  26. const broken = structuredClone(fixture); mutate(broken.pages[0])
  27. assert.throws(() => aiCoursewareToSlides(broken), reason, name)
  28. const previews = buildAiPptSlidePreviews(broken)
  29. assert(previews[0].error && previews[1].slide, `${name}不能清空其他页`)
  30. }
  31. assert.deepEqual(modelSlideDesignIssues(fixture.pages[0]), [])
  32. const textOnly = structuredClone(fixture)
  33. textOnly.pages.forEach(page => { page.pageDesign.elements = page.pageDesign.elements.filter(e => e.kind === 'text') })
  34. const textOnlySlides = aiCoursewareToSlides(textOnly).slides
  35. assert(textOnlySlides.every(slide => slide.elements.every(element => element.type === 'text')), '纯文字设计可通过,不得自动添加色块或分隔线')
  36. writeFileSync('artifacts/ai-ppt-tests/model-slide-design-fixture.json', JSON.stringify(fixture, null, 2))
  37. writeFileSync('artifacts/ai-ppt-tests/model-slide-design-render.json', JSON.stringify(result, null, 2))
  38. console.log('PASS: 模型坐标/颜色/字号忠实执行;内容不变;溢出、遗漏、低对比、未知引用、缺图片槽位和未知元素均阻断;单页错误保留其他预览。此测试使用协议夹具。')
  39. } finally { await vite.close() }