返回 oh-my-ppt
page-canvas-font-scale.test.ts
根目录 / tests / unit / tools / page-canvas-font-scale.test.ts
1 // @vitest-environment happy-dom
2
3 import { describe, expect, it, vi } from 'vitest'
4
5 vi.mock('electron', () => ({
6 app: { getPath: () => '/tmp' },
7 BrowserWindow: class BrowserWindow {},
8 ipcMain: {},
9 session: {}
10 }))
11
12 vi.mock('@electron-toolkit/utils', () => ({ is: { dev: false } }))
13
14 import { buildBasePageStyleTag, buildFitScript } from '../../../src/main/presentation/html/page-writer-core'
15 import { requireSlideSizePreset, resolveSlideSize } from '../../../src/shared/slide-size'
16
17 describe('canvas-aware font floors', () => {
18 // Root font-size is NOT scaled — we keep the browser 16px default so rem-based
19 // Tailwind utilities (gap-4, p-8, ...) don't blow up layout on tall canvases.
20 // Instead, the fit-script font floors scale with canvas height, and the layout
21 // skills / design contract prompt tell the model to write larger explicit px
22 // font-sizes on taller canvases.
23
24 it('keeps the root and content font-size at the 16px baseline on every canvas', () => {
25 const portrait = resolveSlideSize({ id: 'vertical-9-16' }) // 900x1600
26 const css = buildBasePageStyleTag(portrait)
27
28 // No canvas-height-aware calc on root; .ppt-page-content stays at 16px so
29 // rem-based Tailwind spacing utilities are not side-effect-amplified.
30 expect(css).not.toMatch(/font-size:\s*calc\(16px \* var\(--ppt-slide-height\)/)
31 expect(css).toMatch(/\.ppt-page-content\s*{[^}]*font-size:\s*16px/)
32 expect(css).toMatch(/\[data-ppt-readable-fonts="1"\]\s*{[^}]*font-size:\s*18px/)
33 })
34
35 it('scales fit-script font floors with canvas height (1600h portrait)', () => {
36 const portrait = resolveSlideSize({ id: 'vertical-9-16' }) // height 1600 -> scale ~1.778
37 const script = buildFitScript(portrait)
38
39 // 1600/900 = 1.777...; Math.round(18 * 1.777) = 32
40 expect(script).toContain('const BODY_MIN_FONT = 32;')
41 // Math.round(24 * 1.777) = 43
42 expect(script).toContain('const HEADING_MIN_FONT = 43;')
43 // Math.round(12 * 1.777) = 21
44 expect(script).toContain('const AUXILIARY_MIN_FONT = 21;')
45 // Math.round(14 * 1.777) = 25
46 expect(script).toContain('const LEGACY_MIN_FONT = 25;')
47 })
48
49 it('keeps the original 18/24/12/14 floors on the 900h reference canvas', () => {
50 const wide = requireSlideSizePreset('wide-16-9') // height 900 -> scale 1
51 const script = buildFitScript(wide)
52
53 expect(script).toContain('const BODY_MIN_FONT = 18;')
54 expect(script).toContain('const HEADING_MIN_FONT = 24;')
55 expect(script).toContain('const AUXILIARY_MIN_FONT = 12;')
56 expect(script).toContain('const LEGACY_MIN_FONT = 14;')
57 })
58
59 it('uses an intermediate scale for 1200h canvases (4:3 / 1:1)', () => {
60 const square = resolveSlideSize({ id: 'square-1-1' }) // 1200x1200
61 const script = buildFitScript(square)
62
63 // 1200/900 = 1.333; Math.round(18 * 1.333) = 24, Math.round(24 * 1.333) = 32
64 expect(script).toContain('const BODY_MIN_FONT = 24;')
65 expect(script).toContain('const HEADING_MIN_FONT = 32;')
66 expect(script).toContain('const AUXILIARY_MIN_FONT = 16;')
67 expect(script).toContain('const LEGACY_MIN_FONT = 19;')
68 })
69
70 it('uses the largest scale for 1660h xiaohongshu canvas', () => {
71 const note = resolveSlideSize({ id: 'xiaohongshu-note' }) // 1242x1660
72 const script = buildFitScript(note)
73
74 // 1660/900 = 1.844; Math.round(18 * 1.844) = 33, Math.round(24 * 1.844) = 44
75 expect(script).toContain('const BODY_MIN_FONT = 33;')
76 expect(script).toContain('const HEADING_MIN_FONT = 44;')
77 expect(script).toContain('const AUXILIARY_MIN_FONT = 22;')
78 expect(script).toContain('const LEGACY_MIN_FONT = 26;')
79 })
80 })
81
81 lines TYPESCRIPT