返回 oh-my-ppt
edit-history-store.test.ts
根目录 / tests / unit / editor / edit-history-store.test.ts
1 import { beforeEach, describe, expect, it } from 'vitest'
2
3 import {
4 editTargetMatchesDeletedSelector,
5 useEditHistoryStore
6 } from '../../../src/renderer/src/store/editHistoryStore'
7
8 describe('editHistoryStore delete merging', () => {
9 beforeEach(() => {
10 useEditHistoryStore.getState().clear()
11 })
12
13 it('cancels a pending added element when that element is deleted before saving', () => {
14 const store = useEditHistoryStore.getState()
15 store.addElement({
16 pageId: 'page-1',
17 htmlPath: '/tmp/page.html',
18 parentSelector: 'body[data-page-id="page-1"] [data-ppt-guard-root="1"]',
19 htmlFragment: '<img data-block-id="select-arcsin1-added" src="./images/a.png">',
20 assignedBlockId: 'select-arcsin1-added',
21 insertIndex: -1
22 })
23
24 useEditHistoryStore.getState().addDelete({
25 pageId: 'page-1',
26 htmlPath: '/tmp/page.html',
27 selector: 'body[data-page-id="page-1"] [data-block-id="select-arcsin1-added"]'
28 })
29
30 const snapshot = useEditHistoryStore.getState().getSnapshotForPage('page-1')
31 expect(snapshot.addElements).toHaveLength(0)
32 expect(snapshot.deletes).toHaveLength(0)
33 expect(useEditHistoryStore.getState().canUndo('page-1')).toBe(true)
34 })
35
36 it('removes pending edits that target the same added block when deleting the added element', () => {
37 const store = useEditHistoryStore.getState()
38 store.addElement({
39 pageId: 'page-1',
40 htmlPath: '/tmp/page.html',
41 parentSelector: 'body[data-page-id="page-1"] [data-ppt-guard-root="1"]',
42 htmlFragment: '<p data-block-id="select-arcsin1-added"><span>文字</span></p>',
43 assignedBlockId: 'select-arcsin1-added',
44 insertIndex: -1
45 })
46 useEditHistoryStore.getState().upsertPropertyEdit({
47 pageId: 'page-1',
48 htmlPath: '/tmp/page.html',
49 selector: 'body[data-page-id="page-1"] [data-block-id="select-arcsin1-added"] span',
50 blockId: 'select-arcsin1-added',
51 patch: { style: { color: '#ff0000' } }
52 })
53
54 useEditHistoryStore.getState().addDelete({
55 pageId: 'page-1',
56 htmlPath: '/tmp/page.html',
57 selector: 'body[data-page-id="page-1"] [data-block-id="select-arcsin1-added"]'
58 })
59
60 const snapshot = useEditHistoryStore.getState().getSnapshotForPage('page-1')
61 expect(snapshot.addElements).toHaveLength(0)
62 expect(snapshot.propertyEdits).toHaveLength(0)
63 expect(snapshot.deletes).toHaveLength(0)
64 })
65
66 it('dedupes repeated deletes for the same existing element', () => {
67 const deleteItem = {
68 pageId: 'page-1',
69 htmlPath: '/tmp/page.html',
70 selector: 'body[data-page-id="page-1"] [data-block-id="existing"]'
71 }
72
73 useEditHistoryStore.getState().addDelete(deleteItem)
74 useEditHistoryStore.getState().addDelete(deleteItem)
75
76 const snapshot = useEditHistoryStore.getState().getSnapshotForPage('page-1')
77 expect(snapshot.deletes).toHaveLength(1)
78 })
79
80 it('keeps only the latest pending generated background replacement', () => {
81 const deletes = [
82 {
83 pageId: 'page-1',
84 htmlPath: '/tmp/page.html',
85 selector: '[data-ppt-generated-background="1"]'
86 },
87 {
88 pageId: 'page-1',
89 htmlPath: '/tmp/page.html',
90 selector: '[data-ppt-generated-background-style="1"]'
91 }
92 ]
93
94 useEditHistoryStore.getState().addElementWithDeletes(
95 {
96 pageId: 'page-1',
97 htmlPath: '/tmp/page.html',
98 parentSelector: 'body[data-page-id="page-1"] [data-ppt-guard-root="1"]',
99 htmlFragment: '<img data-block-id="bg-1" data-ppt-generated-background="1">',
100 assignedBlockId: 'bg-1',
101 insertIndex: -1
102 },
103 deletes
104 )
105 useEditHistoryStore.getState().addElementWithDeletes(
106 {
107 pageId: 'page-1',
108 htmlPath: '/tmp/page.html',
109 parentSelector: 'body[data-page-id="page-1"] [data-ppt-guard-root="1"]',
110 htmlFragment: '<img data-block-id="bg-2" data-ppt-generated-background="1">',
111 assignedBlockId: 'bg-2',
112 insertIndex: -1
113 },
114 deletes
115 )
116
117 const snapshot = useEditHistoryStore.getState().getSnapshotForPage('page-1')
118 expect(snapshot.addElements).toHaveLength(1)
119 expect(snapshot.addElements[0].assignedBlockId).toBe('bg-2')
120 expect(snapshot.deletes).toHaveLength(2)
121 })
122 })
123
124 describe('edit history selector matching', () => {
125 it('matches selectors that target the same data-block-id', () => {
126 expect(
127 editTargetMatchesDeletedSelector(
128 'body[data-page-id="page-1"] [data-block-id="block-1"] span',
129 'body[data-page-id="page-1"] [data-block-id="block-1"]'
130 )
131 ).toBe(true)
132 })
133
134 it('can match by edit block id when selector text differs', () => {
135 expect(
136 editTargetMatchesDeletedSelector(
137 'body[data-page-id="page-1"] .generated-title',
138 'body[data-page-id="page-1"] [data-block-id="block-1"]',
139 'block-1'
140 )
141 ).toBe(true)
142 })
143 })
144
144 lines TYPESCRIPT