返回 oh-my-ppt
presentation-editor-runtime-bridge.test.ts
根目录 / tests / unit / preview / presentation-editor-runtime-bridge.test.ts
1 import { Window } from 'happy-dom'
2 import { describe, expect, it } from 'vitest'
3 import { buildEditModeInjectScript } from '@arcsin1/presentation-editor-runtime'
4
5 type EditorWindow = Window & {
6 __pptEditModeInspectElement: (selector: string) => {
7 attributes: Record<string, string>
8 inlineStyle: Record<string, { value: string; priority: string }>
9 computedStyle: Record<string, string>
10 } | null
11 __pptEditModeApplyOperations: (
12 selector: string,
13 operations: unknown[]
14 ) => Array<{ ok: boolean; errorCode?: string }>
15 __pptEditModeRestoreSelection: (selector: string) => boolean
16 __pptEditModeClearSelection: () => void
17 }
18
19 describe('presentation editor runtime bridge', () => {
20 it('keeps legacy edit-mode selection while exposing full inspection and controlled generic edits', () => {
21 const window = new Window({ url: 'http://localhost/page.html' }) as EditorWindow & {
22 ResizeObserver: typeof ResizeObserver
23 eval: (code: string) => void
24 }
25 const { document } = window
26 document.body.setAttribute('data-page-id', 'page')
27 document.body.innerHTML = `
28 <main class="ppt-page-root" data-ppt-guard-root="1" data-ppt-width="1000" data-ppt-height="600">
29 <main data-block-id="content" data-role="content">
30 <p id="title" data-block-id="title" aria-label="Original" style="letter-spacing: 0.02em">Hello</p>
31 </main>
32 </main>
33 `
34 const title = document.querySelector('#title') as HTMLElement
35 window.HTMLElement.prototype.getBoundingClientRect = function () {
36 return this === title
37 ? ({ left: 20, top: 30, width: 240, height: 60, right: 260, bottom: 90 } as DOMRect)
38 : ({ left: 0, top: 0, width: 1000, height: 600, right: 1000, bottom: 600 } as DOMRect)
39 }
40 window.HTMLElement.prototype.getClientRects = function () {
41 return [this.getBoundingClientRect()]
42 }
43 window.ResizeObserver = class {
44 observe() {}
45 disconnect() {}
46 } as unknown as typeof ResizeObserver
47
48 window.eval(buildEditModeInjectScript())
49 const selector = 'body[data-page-id="page"] [data-block-id="title"]'
50
51 const inspector = window.__pptEditModeInspectElement(selector)
52 expect(inspector?.attributes).toMatchObject({
53 id: 'title',
54 'data-block-id': 'title',
55 'aria-label': 'Original'
56 })
57 expect(inspector?.inlineStyle['letter-spacing']).toEqual({ value: '0.02em', priority: '' })
58 expect(inspector?.computedStyle.display).toBeTruthy()
59
60 expect(
61 window.__pptEditModeApplyOperations(selector, [
62 { type: 'set-attribute', name: 'data-theme', value: 'dark' },
63 { type: 'set-style', property: 'letter-spacing', value: '0.08em', priority: 'important' },
64 { type: 'set-attribute', name: 'onclick', value: 'alert(1)' }
65 ])
66 ).toMatchObject([
67 { ok: true },
68 { ok: true },
69 { ok: false, errorCode: 'PROTECTED_ATTRIBUTE' }
70 ])
71 expect(title.getAttribute('data-theme')).toBe('dark')
72 expect(title.style.getPropertyValue('letter-spacing')).toBe('0.08em')
73 expect(title.style.getPropertyPriority('letter-spacing')).toBe('important')
74
75 expect(window.__pptEditModeRestoreSelection(selector)).toBe(true)
76 expect(title.classList.contains('arcsin1-presentation-editor-selected')).toBe(true)
77 expect(title.getAttribute('data-arcsin1-presentation-editor-selected')).toBe('true')
78
79 window.__pptEditModeClearSelection()
80 expect(title.hasAttribute('data-arcsin1-presentation-editor-selected')).toBe(false)
81 })
82 })
83
83 lines TYPESCRIPT