@lobehub/lobehub 2.0.0-next.267 → 2.0.0-next.268
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/microcopy-cn.mdc +75 -63
- package/.cursor/rules/microcopy-en.mdc +4 -8
- package/CHANGELOG.md +25 -0
- package/README.md +8 -8
- package/README.zh-CN.md +8 -8
- package/apps/desktop/src/main/locales/default/common.ts +2 -2
- package/changelog/v1.json +5 -0
- package/docs/development/database-schema.dbml +4 -0
- package/e2e/CLAUDE.md +9 -8
- package/e2e/cucumber.config.js +1 -0
- package/e2e/src/features/page/README.md +118 -0
- package/e2e/src/features/page/crud.feature +62 -0
- package/e2e/src/features/page/editor-content.feature +93 -0
- package/e2e/src/features/page/editor-meta.feature +60 -0
- package/e2e/src/steps/agent/conversation.steps.ts +4 -4
- package/e2e/src/steps/home/sidebarAgent.steps.ts +91 -94
- package/e2e/src/steps/home/sidebarGroup.steps.ts +4 -4
- package/e2e/src/steps/hooks.ts +2 -0
- package/e2e/src/steps/page/editor-content.steps.ts +344 -0
- package/e2e/src/steps/page/editor-meta.steps.ts +410 -0
- package/e2e/src/steps/page/page-crud.steps.ts +363 -0
- package/e2e/src/support/world.ts +12 -0
- package/locales/ar/file.json +2 -0
- package/locales/bg-BG/file.json +2 -0
- package/locales/de-DE/file.json +2 -0
- package/locales/en-US/auth.json +1 -1
- package/locales/en-US/file.json +2 -0
- package/locales/en-US/metadata.json +2 -2
- package/locales/es-ES/file.json +2 -0
- package/locales/fa-IR/file.json +2 -0
- package/locales/fr-FR/file.json +2 -0
- package/locales/it-IT/file.json +2 -0
- package/locales/ja-JP/file.json +2 -0
- package/locales/ko-KR/file.json +2 -0
- package/locales/nl-NL/file.json +2 -0
- package/locales/pl-PL/file.json +2 -0
- package/locales/pt-BR/file.json +2 -0
- package/locales/ru-RU/file.json +2 -0
- package/locales/tr-TR/file.json +2 -0
- package/locales/vi-VN/file.json +2 -0
- package/locales/zh-CN/file.json +2 -0
- package/locales/zh-TW/file.json +2 -0
- package/package.json +1 -1
- package/packages/builtin-agents/src/agents/agent-builder/index.ts +1 -1
- package/packages/builtin-agents/src/agents/group-agent-builder/index.ts +1 -1
- package/packages/builtin-agents/src/agents/page-agent/index.ts +1 -1
- package/packages/const/src/settings/group.ts +0 -10
- package/packages/database/migrations/0068_update_group_data.sql +4 -0
- package/packages/database/migrations/meta/0068_snapshot.json +9588 -0
- package/packages/database/migrations/meta/_journal.json +7 -0
- package/packages/database/src/models/__tests__/chatGroup.test.ts +5 -7
- package/packages/database/src/models/__tests__/knowledgeBase.test.ts +185 -0
- package/packages/database/src/models/knowledgeBase.ts +67 -3
- package/packages/database/src/repositories/agentGroup/index.test.ts +23 -29
- package/packages/database/src/repositories/agentGroup/index.ts +4 -9
- package/packages/database/src/repositories/knowledge/index.ts +3 -3
- package/packages/database/src/schemas/chatGroup.ts +4 -3
- package/packages/database/src/types/chatGroup.ts +0 -7
- package/packages/types/src/agentGroup/index.ts +30 -9
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/ModalProvider.tsx +9 -32
- package/src/app/[variants]/(main)/home/_layout/hooks/useCreateMenuItems.tsx +3 -37
- package/src/app/[variants]/(main)/home/_layout/hooks/useSessionGroupMenuItems.tsx +7 -53
- package/src/app/[variants]/(main)/home/features/RecentPage/List.tsx +2 -1
- package/src/app/[variants]/(main)/resource/features/DndContextWrapper.tsx +1 -1
- package/src/app/[variants]/(main)/resource/library/_layout/Sidebar.tsx +2 -2
- package/src/app/[variants]/(main)/resource/library/features/LibraryMenu.tsx +2 -2
- package/src/app/[variants]/(mobile)/chat/settings/features/SettingButton.tsx +2 -12
- package/src/components/ChatGroupWizard/ChatGroupWizard.tsx +5 -27
- package/src/components/DragUpload/index.tsx +24 -27
- package/src/components/MemberSelectionModal/MemberSelectionModal.tsx +2 -11
- package/src/features/CommandMenu/useCommandMenu.ts +4 -14
- package/src/features/ResourceManager/components/Editor/index.tsx +2 -3
- package/src/features/ResourceManager/components/Explorer/Header/index.tsx +13 -17
- package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +1 -1
- package/src/features/ResourceManager/components/Explorer/ListView/ListItem/TruncatedFileName.tsx +130 -0
- package/src/features/ResourceManager/components/Explorer/ListView/ListItem/index.tsx +36 -4
- package/src/features/ResourceManager/components/Explorer/ListView/Skeleton.tsx +4 -3
- package/src/features/ResourceManager/components/Explorer/ListView/index.tsx +58 -2
- package/src/features/ResourceManager/components/Explorer/MasonryView/index.tsx +58 -6
- package/src/features/ResourceManager/components/Explorer/MoveToFolderModal.tsx +2 -5
- package/src/features/ResourceManager/components/Explorer/ToolBar/BatchActionsDropdown.tsx +9 -5
- package/src/features/ResourceManager/components/Explorer/index.tsx +11 -56
- package/src/features/ResourceManager/components/Header/AddButton.tsx +5 -6
- package/src/features/ResourceManager/components/LibraryHierarchy/HierarchyNode.tsx +382 -0
- package/src/features/ResourceManager/components/LibraryHierarchy/index.tsx +396 -0
- package/src/features/ResourceManager/components/LibraryHierarchy/styles.ts +19 -0
- package/src/features/ResourceManager/components/LibraryHierarchy/treeState.ts +178 -0
- package/src/features/ResourceManager/components/LibraryHierarchy/types.ts +10 -0
- package/src/features/ResourceManager/index.tsx +3 -0
- package/src/layout/GlobalProvider/GroupWizardProvider.tsx +6 -29
- package/src/locales/default/auth.ts +1 -1
- package/src/locales/default/file.ts +2 -0
- package/src/locales/default/metadata.ts +2 -2
- package/src/server/modules/AgentRuntime/AgentRuntimeCoordinator.ts +30 -30
- package/src/server/modules/AgentRuntime/AgentStateManager.ts +23 -23
- package/src/server/modules/AgentRuntime/InMemoryAgentStateManager.ts +16 -16
- package/src/server/modules/AgentRuntime/InMemoryStreamEventManager.ts +13 -13
- package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +2 -2
- package/src/server/modules/AgentRuntime/StreamEventManager.ts +18 -18
- package/src/server/modules/AgentRuntime/types.ts +21 -21
- package/src/server/routers/lambda/__tests__/agentGroup.test.ts +8 -8
- package/src/server/routers/lambda/agentGroup.ts +10 -12
- package/src/server/services/document/index.ts +1 -0
- package/src/store/agentGroup/slices/curd.test.ts +4 -4
- package/src/store/file/slices/fileManager/action.ts +12 -4
- package/src/store/home/slices/homeInput/action.ts +0 -3
- package/src/store/session/slices/session/action.ts +5 -9
- package/src/app/[variants]/(mobile)/chat/settings/features/AgentTeamSettings/index.tsx +0 -95
- package/src/features/GroupChatSettings/AgentCard.tsx +0 -154
- package/src/features/GroupChatSettings/AgentTeamChatSettings.tsx +0 -179
- package/src/features/GroupChatSettings/AgentTeamMembersSettings.tsx +0 -244
- package/src/features/GroupChatSettings/AgentTeamMetaSettings.tsx +0 -94
- package/src/features/GroupChatSettings/AgentTeamSettings.tsx +0 -54
- package/src/features/GroupChatSettings/GroupCategory/index.tsx +0 -30
- package/src/features/GroupChatSettings/GroupCategory/useGroupCategory.tsx +0 -42
- package/src/features/GroupChatSettings/GroupChatSettingsProvider.tsx +0 -19
- package/src/features/GroupChatSettings/HostMemberCard.tsx +0 -113
- package/src/features/GroupChatSettings/StoreUpdater.tsx +0 -34
- package/src/features/GroupChatSettings/hooks/useGroupChatSettings.ts +0 -25
- package/src/features/GroupChatSettings/index.ts +0 -16
- package/src/features/GroupChatSettings/store/action.ts +0 -105
- package/src/features/GroupChatSettings/store/index.ts +0 -18
- package/src/features/GroupChatSettings/store/initialState.ts +0 -23
- package/src/features/GroupChatSettings/store/selectors.ts +0 -13
- package/src/features/ResourceManager/components/Tree/index.tsx +0 -883
- /package/src/features/ResourceManager/components/{Tree → LibraryHierarchy}/TreeSkeleton.tsx +0 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page Editor Content Steps
|
|
3
|
+
*
|
|
4
|
+
* Step definitions for Page editor rich text editing E2E tests
|
|
5
|
+
*/
|
|
6
|
+
import { Then, When } from '@cucumber/cucumber';
|
|
7
|
+
import { expect } from '@playwright/test';
|
|
8
|
+
|
|
9
|
+
import { CustomWorld } from '../../support/world';
|
|
10
|
+
|
|
11
|
+
// ============================================
|
|
12
|
+
// Helper Functions
|
|
13
|
+
// ============================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get the contenteditable editor element
|
|
17
|
+
*/
|
|
18
|
+
async function getEditor(world: CustomWorld) {
|
|
19
|
+
const editor = world.page.locator('[contenteditable="true"]').first();
|
|
20
|
+
await expect(editor).toBeVisible({ timeout: 5000 });
|
|
21
|
+
return editor;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ============================================
|
|
25
|
+
// When Steps - Basic Text
|
|
26
|
+
// ============================================
|
|
27
|
+
|
|
28
|
+
When('用户点击编辑器内容区域', async function (this: CustomWorld) {
|
|
29
|
+
console.log(' 📍 Step: 点击编辑器内容区域...');
|
|
30
|
+
|
|
31
|
+
const editorContent = this.page.locator('[contenteditable="true"]').first();
|
|
32
|
+
if ((await editorContent.count()) > 0) {
|
|
33
|
+
await editorContent.click();
|
|
34
|
+
} else {
|
|
35
|
+
// Fallback: click somewhere else
|
|
36
|
+
await this.page.click('body', { position: { x: 400, y: 400 } });
|
|
37
|
+
}
|
|
38
|
+
await this.page.waitForTimeout(500);
|
|
39
|
+
|
|
40
|
+
console.log(' ✅ 已点击编辑器内容区域');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
When('用户按下 Enter 键', async function (this: CustomWorld) {
|
|
44
|
+
console.log(' 📍 Step: 按下 Enter 键...');
|
|
45
|
+
|
|
46
|
+
await this.page.keyboard.press('Enter');
|
|
47
|
+
// Wait for debounce save (1000ms) + buffer
|
|
48
|
+
await this.page.waitForTimeout(1500);
|
|
49
|
+
|
|
50
|
+
console.log(' ✅ 已按下 Enter 键');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
When('用户输入文本 {string}', async function (this: CustomWorld, text: string) {
|
|
54
|
+
console.log(` 📍 Step: 输入文本 "${text}"...`);
|
|
55
|
+
|
|
56
|
+
await this.page.keyboard.type(text, { delay: 30 });
|
|
57
|
+
await this.page.waitForTimeout(300);
|
|
58
|
+
|
|
59
|
+
// Store for later verification
|
|
60
|
+
this.testContext.inputText = text;
|
|
61
|
+
|
|
62
|
+
console.log(` ✅ 已输入文本 "${text}"`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
When('用户在编辑器中输入内容 {string}', async function (this: CustomWorld, content: string) {
|
|
66
|
+
console.log(` 📍 Step: 在编辑器中输入内容 "${content}"...`);
|
|
67
|
+
|
|
68
|
+
const editor = await getEditor(this);
|
|
69
|
+
await editor.click();
|
|
70
|
+
await this.page.waitForTimeout(300);
|
|
71
|
+
await this.page.keyboard.type(content, { delay: 30 });
|
|
72
|
+
await this.page.waitForTimeout(300);
|
|
73
|
+
|
|
74
|
+
this.testContext.inputText = content;
|
|
75
|
+
|
|
76
|
+
console.log(` ✅ 已输入内容 "${content}"`);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
When('用户选中所有内容', async function (this: CustomWorld) {
|
|
80
|
+
console.log(' 📍 Step: 选中所有内容...');
|
|
81
|
+
|
|
82
|
+
await this.page.keyboard.press(`${this.modKey}+A`);
|
|
83
|
+
await this.page.waitForTimeout(300);
|
|
84
|
+
|
|
85
|
+
console.log(' ✅ 已选中所有内容');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// ============================================
|
|
89
|
+
// When Steps - Slash Commands
|
|
90
|
+
// ============================================
|
|
91
|
+
|
|
92
|
+
When('用户输入斜杠 {string}', async function (this: CustomWorld, slash: string) {
|
|
93
|
+
console.log(` 📍 Step: 输入斜杠 "${slash}"...`);
|
|
94
|
+
|
|
95
|
+
await this.page.keyboard.type(slash, { delay: 50 });
|
|
96
|
+
// Wait for slash menu to appear
|
|
97
|
+
await this.page.waitForTimeout(500);
|
|
98
|
+
|
|
99
|
+
console.log(` ✅ 已输入斜杠 "${slash}"`);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
When('用户输入斜杠命令 {string}', async function (this: CustomWorld, command: string) {
|
|
103
|
+
console.log(` 📍 Step: 输入斜杠命令 "${command}"...`);
|
|
104
|
+
|
|
105
|
+
// The command format is "/shortcut" (e.g., "/h1", "/codeblock")
|
|
106
|
+
// First type the slash and wait for menu
|
|
107
|
+
await this.page.keyboard.type('/', { delay: 100 });
|
|
108
|
+
await this.page.waitForTimeout(800); // Wait for slash menu to appear
|
|
109
|
+
|
|
110
|
+
// Then type the rest of the command (without the leading /)
|
|
111
|
+
const shortcut = command.startsWith('/') ? command.slice(1) : command;
|
|
112
|
+
await this.page.keyboard.type(shortcut, { delay: 80 });
|
|
113
|
+
await this.page.waitForTimeout(500); // Wait for menu to filter
|
|
114
|
+
|
|
115
|
+
console.log(` ✅ 已输入斜杠命令 "${command}"`);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// ============================================
|
|
119
|
+
// When Steps - Formatting
|
|
120
|
+
// ============================================
|
|
121
|
+
|
|
122
|
+
When('用户按下快捷键 {string}', async function (this: CustomWorld, shortcut: string) {
|
|
123
|
+
console.log(` 📍 Step: 按下快捷键 "${shortcut}"...`);
|
|
124
|
+
|
|
125
|
+
// Convert Meta to platform-specific modifier key for cross-platform support
|
|
126
|
+
const platformShortcut = shortcut.replaceAll('Meta', this.modKey);
|
|
127
|
+
await this.page.keyboard.press(platformShortcut);
|
|
128
|
+
await this.page.waitForTimeout(300);
|
|
129
|
+
|
|
130
|
+
console.log(` ✅ 已按下快捷键 "${platformShortcut}"`);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// ============================================
|
|
134
|
+
// Then Steps - Basic Text
|
|
135
|
+
// ============================================
|
|
136
|
+
|
|
137
|
+
Then('编辑器应该显示输入的文本', async function (this: CustomWorld) {
|
|
138
|
+
console.log(' 📍 Step: 验证编辑器显示输入的文本...');
|
|
139
|
+
|
|
140
|
+
const editor = await getEditor(this);
|
|
141
|
+
const text = this.testContext.inputText;
|
|
142
|
+
|
|
143
|
+
// Check if the text is visible in the editor
|
|
144
|
+
const editorText = await editor.textContent();
|
|
145
|
+
expect(editorText).toContain(text);
|
|
146
|
+
|
|
147
|
+
console.log(` ✅ 编辑器显示文本: "${text}"`);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
Then('编辑器应该显示 {string}', async function (this: CustomWorld, expectedText: string) {
|
|
151
|
+
console.log(` 📍 Step: 验证编辑器显示 "${expectedText}"...`);
|
|
152
|
+
|
|
153
|
+
const editor = await getEditor(this);
|
|
154
|
+
const editorText = await editor.textContent();
|
|
155
|
+
expect(editorText).toContain(expectedText);
|
|
156
|
+
|
|
157
|
+
console.log(` ✅ 编辑器显示 "${expectedText}"`);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// ============================================
|
|
161
|
+
// Then Steps - Slash Commands
|
|
162
|
+
// ============================================
|
|
163
|
+
|
|
164
|
+
Then('应该显示斜杠命令菜单', async function (this: CustomWorld) {
|
|
165
|
+
console.log(' 📍 Step: 验证显示斜杠命令菜单...');
|
|
166
|
+
|
|
167
|
+
// The slash menu should be visible
|
|
168
|
+
// Look for menu with heading options, list options, etc.
|
|
169
|
+
const menuSelectors = ['[role="menu"]', '[role="listbox"]', '.slash-menu', '[data-slash-menu]'];
|
|
170
|
+
|
|
171
|
+
let menuFound = false;
|
|
172
|
+
for (const selector of menuSelectors) {
|
|
173
|
+
const menu = this.page.locator(selector);
|
|
174
|
+
if ((await menu.count()) > 0 && (await menu.isVisible())) {
|
|
175
|
+
menuFound = true;
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Alternative: look for menu items by text
|
|
181
|
+
if (!menuFound) {
|
|
182
|
+
const headingOption = this.page.getByText(/heading|标题/i).first();
|
|
183
|
+
const listOption = this.page.getByText(/list|列表/i).first();
|
|
184
|
+
|
|
185
|
+
menuFound =
|
|
186
|
+
((await headingOption.count()) > 0 && (await headingOption.isVisible())) ||
|
|
187
|
+
((await listOption.count()) > 0 && (await listOption.isVisible()));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
expect(menuFound).toBe(true);
|
|
191
|
+
|
|
192
|
+
console.log(' ✅ 斜杠命令菜单已显示');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
Then('编辑器应该包含一级标题', async function (this: CustomWorld) {
|
|
196
|
+
console.log(' 📍 Step: 验证编辑器包含一级标题...');
|
|
197
|
+
|
|
198
|
+
// Check for h1 element in the editor
|
|
199
|
+
const editor = await getEditor(this);
|
|
200
|
+
const h1 = editor.locator('h1');
|
|
201
|
+
|
|
202
|
+
await expect(h1).toBeVisible({ timeout: 5000 });
|
|
203
|
+
|
|
204
|
+
console.log(' ✅ 编辑器包含一级标题');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
Then('编辑器应该包含无序列表', async function (this: CustomWorld) {
|
|
208
|
+
console.log(' 📍 Step: 验证编辑器包含无序列表...');
|
|
209
|
+
|
|
210
|
+
const editor = await getEditor(this);
|
|
211
|
+
const ul = editor.locator('ul');
|
|
212
|
+
|
|
213
|
+
await expect(ul).toBeVisible({ timeout: 5000 });
|
|
214
|
+
|
|
215
|
+
console.log(' ✅ 编辑器包含无序列表');
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
Then('编辑器应该包含任务列表', async function (this: CustomWorld) {
|
|
219
|
+
console.log(' 📍 Step: 验证编辑器包含任务列表...');
|
|
220
|
+
|
|
221
|
+
const editor = await getEditor(this);
|
|
222
|
+
|
|
223
|
+
// Task list usually has checkbox elements
|
|
224
|
+
const checkboxSelectors = [
|
|
225
|
+
'input[type="checkbox"]',
|
|
226
|
+
'[role="checkbox"]',
|
|
227
|
+
'[data-lexical-check-list]',
|
|
228
|
+
'li[role="listitem"] input',
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
let found = false;
|
|
232
|
+
for (const selector of checkboxSelectors) {
|
|
233
|
+
const checkbox = editor.locator(selector);
|
|
234
|
+
if ((await checkbox.count()) > 0) {
|
|
235
|
+
found = true;
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Alternative: check for specific class or structure
|
|
241
|
+
if (!found) {
|
|
242
|
+
const listItem = editor.locator('li');
|
|
243
|
+
found = (await listItem.count()) > 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
expect(found).toBe(true);
|
|
247
|
+
|
|
248
|
+
console.log(' ✅ 编辑器包含任务列表');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
Then('编辑器应该包含代码块', async function (this: CustomWorld) {
|
|
252
|
+
console.log(' 📍 Step: 验证编辑器包含代码块...');
|
|
253
|
+
|
|
254
|
+
// Code block might be rendered inside the editor OR as a sibling element
|
|
255
|
+
// CodeMirror renders its own container
|
|
256
|
+
|
|
257
|
+
// First check inside the editor
|
|
258
|
+
const editor = await getEditor(this);
|
|
259
|
+
const codeBlockSelectors = [
|
|
260
|
+
'pre',
|
|
261
|
+
'code',
|
|
262
|
+
'.cm-editor', // CodeMirror
|
|
263
|
+
'[data-language]',
|
|
264
|
+
'.code-block',
|
|
265
|
+
];
|
|
266
|
+
|
|
267
|
+
let found = false;
|
|
268
|
+
for (const selector of codeBlockSelectors) {
|
|
269
|
+
const codeBlock = editor.locator(selector);
|
|
270
|
+
if ((await codeBlock.count()) > 0) {
|
|
271
|
+
found = true;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// If not found inside editor, check the whole page
|
|
277
|
+
// CodeMirror might render outside the contenteditable
|
|
278
|
+
if (!found) {
|
|
279
|
+
for (const selector of codeBlockSelectors) {
|
|
280
|
+
const codeBlock = this.page.locator(selector);
|
|
281
|
+
if ((await codeBlock.count()) > 0 && (await codeBlock.isVisible())) {
|
|
282
|
+
found = true;
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
expect(found).toBe(true);
|
|
289
|
+
|
|
290
|
+
console.log(' ✅ 编辑器包含代码块');
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// ============================================
|
|
294
|
+
// Then Steps - Formatting
|
|
295
|
+
// ============================================
|
|
296
|
+
|
|
297
|
+
Then('选中的文本应该被加粗', async function (this: CustomWorld) {
|
|
298
|
+
console.log(' 📍 Step: 验证文本已加粗...');
|
|
299
|
+
|
|
300
|
+
const editor = await getEditor(this);
|
|
301
|
+
|
|
302
|
+
// Check for bold element (strong or b tag, or font-weight style)
|
|
303
|
+
const boldSelectors = [
|
|
304
|
+
'strong',
|
|
305
|
+
'b',
|
|
306
|
+
'[style*="font-weight: bold"]',
|
|
307
|
+
'[style*="font-weight: 700"]',
|
|
308
|
+
];
|
|
309
|
+
|
|
310
|
+
let found = false;
|
|
311
|
+
for (const selector of boldSelectors) {
|
|
312
|
+
const boldElement = editor.locator(selector);
|
|
313
|
+
if ((await boldElement.count()) > 0) {
|
|
314
|
+
found = true;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
expect(found).toBe(true);
|
|
320
|
+
|
|
321
|
+
console.log(' ✅ 文本已加粗');
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
Then('选中的文本应该变为斜体', async function (this: CustomWorld) {
|
|
325
|
+
console.log(' 📍 Step: 验证文本已斜体...');
|
|
326
|
+
|
|
327
|
+
const editor = await getEditor(this);
|
|
328
|
+
|
|
329
|
+
// Check for italic element (em or i tag, or font-style style)
|
|
330
|
+
const italicSelectors = ['em', 'i', '[style*="font-style: italic"]'];
|
|
331
|
+
|
|
332
|
+
let found = false;
|
|
333
|
+
for (const selector of italicSelectors) {
|
|
334
|
+
const italicElement = editor.locator(selector);
|
|
335
|
+
if ((await italicElement.count()) > 0) {
|
|
336
|
+
found = true;
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
expect(found).toBe(true);
|
|
342
|
+
|
|
343
|
+
console.log(' ✅ 文本已斜体');
|
|
344
|
+
});
|