返回 oh-my-ppt
index-transition.test.ts
根目录 / tests / unit / session / index-transition.test.ts
1 import { describe, expect, it } from 'vitest'
2 import {
3 DEFAULT_INDEX_TRANSITION_CONFIG,
4 carryIndexTransitionConfig,
5 ensureIndexAnimeScript,
6 ensureIndexPresentBackgroundStyle,
7 parseIndexTransitionConfig,
8 patchIndexTransitionConfig,
9 validateIndexShellHtml
10 } from '../../../src/main/session/index-transition'
11
12 const baseIndexHtml = `<!doctype html>
13 <html lang="zh-CN">
14 <head>
15 <meta charset="UTF-8" />
16 <title>Deck</title>
17 </head>
18 <body>
19 <div id="frameViewport"><iframe class="ppt-preview-frame"></iframe></div>
20 <div class="ppt-controls"></div>
21 <script type="application/json" id="pages-data">[]</script>
22 <script src="./assets/index-runtime.js"></script>
23 </body>
24 </html>`
25
26 describe('index transition config patching', () => {
27 it('inserts anime before index-runtime and writes normalized config', () => {
28 const next = patchIndexTransitionConfig(baseIndexHtml, {
29 type: 'flip',
30 durationMs: 520
31 })
32
33 expect(next).toContain('<script id="ppt-index-transition-config" type="application/json">{"type":"flip","durationMs":520}</script>')
34 expect(next.indexOf('./assets/anime.v4.js')).toBeLessThan(
35 next.indexOf('./assets/index-runtime.js')
36 )
37 expect(validateIndexShellHtml(next)).toEqual([])
38 })
39
40 it('removes old CSS transition style and old config', () => {
41 const oldHtml = baseIndexHtml.replace(
42 '<script src="./assets/index-runtime.js"></script>',
43 `<style id="ppt-index-transition-style">.ppt-preview-frame{transition:opacity 420ms}</style>
44 <script id="ppt-index-transition-config" type="application/json">{"type":"zoom","durationMs":420}</script>
45 <script src="./assets/index-runtime.js"></script>`
46 )
47 const next = patchIndexTransitionConfig(oldHtml, {
48 type: 'stack',
49 durationMs: 480
50 })
51
52 expect(next).not.toContain('ppt-index-transition-style')
53 expect(next.match(/ppt-index-transition-config/g)).toHaveLength(1)
54 expect(parseIndexTransitionConfig(next)).toEqual({ type: 'stack', durationMs: 480 })
55 })
56
57 it('keeps none at 0ms instead of clamping to the minimum duration', () => {
58 const next = patchIndexTransitionConfig(baseIndexHtml, {
59 type: 'none',
60 durationMs: 999
61 })
62
63 expect(parseIndexTransitionConfig(next)).toEqual({ type: 'none', durationMs: 0 })
64 })
65
66 it('writes distinctive transition types such as center reveal', () => {
67 const next = patchIndexTransitionConfig(baseIndexHtml, {
68 type: 'center-reveal',
69 durationMs: 580
70 })
71
72 expect(parseIndexTransitionConfig(next)).toEqual({ type: 'center-reveal', durationMs: 580 })
73 })
74
75 it('does not duplicate anime script', () => {
76 const withAnime = ensureIndexAnimeScript(baseIndexHtml)
77 const next = ensureIndexAnimeScript(withAnime)
78
79 expect(next.match(/anime\.v4\.js/g)).toHaveLength(1)
80 })
81
82 it('adds present-mode black background styles without duplication', () => {
83 const withPresentBackground = ensureIndexPresentBackgroundStyle(baseIndexHtml)
84 const next = ensureIndexPresentBackgroundStyle(withPresentBackground)
85
86 expect(next.match(/ppt-present-background-style/g)).toHaveLength(1)
87 expect(next).toContain('body.present { background: #000000 !important; }')
88 expect(next).toContain('body.present .ppt-preview-viewport')
89 expect(next.indexOf('ppt-present-background-style')).toBeLessThan(next.indexOf('</head>'))
90 })
91
92 it('falls back to default config when JSON is missing or invalid', () => {
93 expect(parseIndexTransitionConfig(baseIndexHtml)).toEqual(DEFAULT_INDEX_TRANSITION_CONFIG)
94 expect(
95 parseIndexTransitionConfig(
96 baseIndexHtml.replace(
97 '<script src="./assets/index-runtime.js"></script>',
98 '<script id="ppt-index-transition-config" type="application/json">{bad}</script><script src="./assets/index-runtime.js"></script>'
99 )
100 )
101 ).toEqual(DEFAULT_INDEX_TRANSITION_CONFIG)
102 })
103
104 it('carries old transition config into rebuilt index html', () => {
105 const previous = patchIndexTransitionConfig(baseIndexHtml, {
106 type: 'slide-up',
107 durationMs: 420
108 })
109 const rebuilt = baseIndexHtml.replace('Deck', 'Renamed Deck')
110 const next = carryIndexTransitionConfig(previous, rebuilt)
111
112 expect(next).toContain('Renamed Deck')
113 expect(parseIndexTransitionConfig(next)).toEqual({ type: 'slide-up', durationMs: 420 })
114 })
115 })
116
116 lines TYPESCRIPT