Skip to content

Commit a240c7d

Browse files
authored
fix(sender-e2e): stabilize template delete e2e case (#317)
1 parent 0b6ba74 commit a240c7d

3 files changed

Lines changed: 96 additions & 25 deletions

File tree

packages/test/src/sender/helpers/template-helper.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ import { SENDER_SELECTORS } from '../selectors'
66
*/
77
export function createTemplateTestHelper(page: Page) {
88
const selectors = SENDER_SELECTORS
9+
const normalizeEditorText = async () => {
10+
const text = await page.evaluate(() => {
11+
const editor = document.querySelector('[data-testid="test-sender"] .ProseMirror')
12+
return editor?.textContent || ''
13+
})
14+
15+
return text
16+
.replace(/\u200b/g, '')
17+
.replace(/\u00a0/g, ' ')
18+
.replace(/\s+/g, ' ')
19+
.trim()
20+
}
921

1022
return {
1123
selectors,
@@ -110,6 +122,17 @@ export function createTemplateTestHelper(page: Page) {
110122
await block.click()
111123
},
112124

125+
/**
126+
* 从模板块左侧触发 Delete,避免依赖外层键盘时序
127+
*/
128+
async pressDeleteBeforeTemplate(index: number) {
129+
const handled = await page.evaluate((templateIndex) => {
130+
return window.__senderTestApi?.pressDeleteBeforeTemplate(templateIndex) ?? false
131+
}, index)
132+
133+
expect(handled).toBe(true)
134+
},
135+
113136
/**
114137
* 聚焦到模板块内容末尾
115138
*/
@@ -206,6 +229,13 @@ export function createTemplateTestHelper(page: Page) {
206229
await expect(this.getEditor()).toContainText(text)
207230
},
208231

232+
/**
233+
* 验证去除零宽字符后的编辑器文本完全匹配
234+
*/
235+
async expectNormalizedEditorText(text: string) {
236+
await expect.poll(async () => normalizeEditorText()).toBe(text)
237+
},
238+
209239
/**
210240
* 等待一段时间
211241
*/

packages/test/src/sender/index.vue

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
<script setup lang="ts">
2-
import { computed, ref } from 'vue'
2+
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
33
import { TinySwitch } from '@opentiny/vue'
44
import { Sender } from '@opentiny/tiny-robot'
55
import type { MentionItem, TemplateItem, SenderSuggestionItem } from '@opentiny/tiny-robot'
66
7+
declare global {
8+
interface Window {
9+
__senderTestApi?: {
10+
moveCursorBeforeTemplate: (index: number) => boolean
11+
pressDeleteBeforeTemplate: (index: number) => boolean
12+
}
13+
}
14+
}
15+
716
const senderRef = ref()
817
const content = ref('')
918
const result = ref('')
@@ -157,6 +166,58 @@ const extensions = computed(() => {
157166
}
158167
return exts
159168
})
169+
170+
const moveCursorBeforeTemplate = (index: number) => {
171+
const exposedEditor = senderRef.value?.editor
172+
const editor = exposedEditor?.value ?? exposedEditor
173+
if (!editor) return false
174+
175+
let currentIndex = 0
176+
let templatePosition: number | null = null
177+
178+
editor.state.doc.descendants((node: { type: { name: string } }, pos: number) => {
179+
if (node.type.name === 'templateBlock') {
180+
if (currentIndex === index) {
181+
templatePosition = pos
182+
return false
183+
}
184+
currentIndex += 1
185+
}
186+
return true
187+
})
188+
189+
if (templatePosition === null) return false
190+
191+
editor.commands.setTextSelection(templatePosition)
192+
editor.commands.focus(templatePosition)
193+
194+
return editor.state.selection.$from.nodeAfter?.type?.name === 'templateBlock'
195+
}
196+
197+
const pressDeleteBeforeTemplate = (index: number) => {
198+
const exposedEditor = senderRef.value?.editor
199+
const editor = exposedEditor?.value ?? exposedEditor
200+
if (!editor || !moveCursorBeforeTemplate(index)) return false
201+
202+
const deleteEvent = new KeyboardEvent('keydown', {
203+
key: 'Delete',
204+
bubbles: true,
205+
cancelable: true,
206+
})
207+
208+
return editor.view.dom.dispatchEvent(deleteEvent) === false
209+
}
210+
211+
onMounted(() => {
212+
window.__senderTestApi = {
213+
moveCursorBeforeTemplate,
214+
pressDeleteBeforeTemplate,
215+
}
216+
})
217+
218+
onBeforeUnmount(() => {
219+
delete window.__senderTestApi
220+
})
160221
</script>
161222

162223
<template>

packages/test/src/sender/specs/template/delete.spec.ts

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -66,38 +66,18 @@ test.describe('Template Block - Delete 删除逻辑', () => {
6666

6767
test('TC-DL-05: 从模板块左侧按 Delete 应该进入模板块', async () => {
6868
await templateHelper!.setSimpleTemplate()
69-
await helper!.getEditor().click()
70-
await templateHelper!.wait(100)
71-
await helper!.getEditor().press('Home')
72-
await templateHelper!.pressArrowRight(2)
73-
await templateHelper!.pressDelete()
69+
await templateHelper!.pressDeleteBeforeTemplate(0)
7470

7571
await templateHelper!.expectTemplateCount(1)
7672
await templateHelper!.expectTemplateText(0, '张三')
7773
})
7874

79-
test('TC-DL-06: 从左侧删除空模板块需要多次操作', async () => {
75+
test('TC-DL-06: 从左侧按 Delete 应稳定删除空模板块', async () => {
8076
await templateHelper!.setEmptyTemplate()
81-
await helper!.getEditor().click()
82-
await helper!.getEditor().press('Home')
83-
await templateHelper!.pressArrowRight(2)
84-
85-
for (let i = 0; i < 4; i++) {
86-
if ((await templateHelper!.getTemplateCount()) === 0) {
87-
break
88-
}
89-
await templateHelper!.pressDelete()
90-
await templateHelper!.wait(100)
91-
}
92-
93-
if ((await templateHelper!.getTemplateCount()) > 0) {
94-
await templateHelper!.pressArrowLeft(1)
95-
await templateHelper!.pressBackspace()
96-
await templateHelper!.wait(100)
97-
}
77+
await templateHelper!.pressDeleteBeforeTemplate(0)
9878

9979
await templateHelper!.expectTemplateCount(0)
100-
await templateHelper!.expectEditorToContainText(',来自')
80+
await templateHelper!.expectNormalizedEditorText('我是,来自')
10181
})
10282

10383
test('TC-DL-07: 选区删除应该包含模板块', async () => {

0 commit comments

Comments
 (0)