@lobehub/chat 1.141.6 → 1.141.8
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/.github/PULL_REQUEST_TEMPLATE.md +26 -0
- package/.github/workflows/e2e.yml +6 -6
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/docs/usage/features/{group-chat.mdx → agent-team.mdx} +14 -14
- package/docs/usage/features/agent-team.zh-CN.mdx +52 -0
- package/e2e/README.md +143 -0
- package/e2e/cucumber.config.js +20 -0
- package/e2e/package.json +24 -0
- package/e2e/src/features/discover/smoke.feature +11 -0
- package/e2e/src/features/routes/core-routes.feature +43 -0
- package/e2e/src/steps/common/navigation.steps.ts +36 -0
- package/e2e/src/steps/discover/smoke.steps.ts +34 -0
- package/e2e/src/steps/hooks.ts +69 -0
- package/e2e/src/steps/routes/routes.steps.ts +41 -0
- package/e2e/src/support/webServer.ts +96 -0
- package/e2e/src/support/world.ts +76 -0
- package/e2e/tsconfig.json +19 -0
- package/locales/ar/chat.json +17 -17
- package/locales/ar/setting.json +15 -19
- package/locales/ar/welcome.json +1 -1
- package/locales/bg-BG/chat.json +17 -17
- package/locales/bg-BG/setting.json +15 -19
- package/locales/de-DE/chat.json +17 -17
- package/locales/de-DE/setting.json +15 -19
- package/locales/de-DE/welcome.json +1 -1
- package/locales/en-US/chat.json +17 -17
- package/locales/en-US/setting.json +15 -19
- package/locales/en-US/welcome.json +1 -1
- package/locales/es-ES/chat.json +17 -17
- package/locales/es-ES/setting.json +15 -19
- package/locales/es-ES/welcome.json +1 -1
- package/locales/fa-IR/chat.json +17 -17
- package/locales/fa-IR/setting.json +15 -19
- package/locales/fa-IR/welcome.json +1 -1
- package/locales/fr-FR/chat.json +16 -16
- package/locales/fr-FR/setting.json +15 -19
- package/locales/fr-FR/welcome.json +1 -1
- package/locales/it-IT/chat.json +17 -17
- package/locales/it-IT/setting.json +15 -19
- package/locales/it-IT/welcome.json +1 -1
- package/locales/ja-JP/chat.json +17 -17
- package/locales/ja-JP/setting.json +15 -19
- package/locales/ja-JP/welcome.json +1 -1
- package/locales/ko-KR/chat.json +17 -17
- package/locales/ko-KR/setting.json +15 -19
- package/locales/ko-KR/welcome.json +1 -1
- package/locales/nl-NL/chat.json +17 -17
- package/locales/nl-NL/setting.json +15 -19
- package/locales/nl-NL/welcome.json +1 -1
- package/locales/pl-PL/chat.json +17 -17
- package/locales/pl-PL/setting.json +15 -19
- package/locales/pt-BR/chat.json +17 -17
- package/locales/pt-BR/setting.json +15 -19
- package/locales/pt-BR/welcome.json +1 -1
- package/locales/ru-RU/chat.json +17 -17
- package/locales/ru-RU/setting.json +15 -19
- package/locales/ru-RU/welcome.json +1 -1
- package/locales/tr-TR/chat.json +17 -17
- package/locales/tr-TR/setting.json +15 -19
- package/locales/vi-VN/chat.json +15 -15
- package/locales/vi-VN/setting.json +15 -19
- package/locales/zh-CN/chat.json +17 -17
- package/locales/zh-CN/setting.json +15 -19
- package/locales/zh-CN/welcome.json +1 -1
- package/locales/zh-TW/chat.json +17 -17
- package/locales/zh-TW/setting.json +15 -19
- package/locales/zh-TW/welcome.json +1 -1
- package/package.json +6 -3
- package/packages/const/src/layoutTokens.ts +1 -1
- package/packages/const/src/settings/systemAgent.ts +0 -1
- package/packages/database/src/models/__tests__/session.test.ts +108 -0
- package/packages/database/src/models/session.ts +41 -1
- package/packages/model-bank/src/aiModels/groq.ts +0 -17
- package/packages/model-bank/src/aiModels/novita.ts +2 -60
- package/packages/model-bank/src/aiModels/siliconcloud.ts +116 -17
- package/packages/types/src/user/settings/systemAgent.ts +0 -1
- package/pnpm-workspace.yaml +1 -0
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/OrchestratorThinking.tsx +2 -3
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/ChatItem/index.tsx +2 -2
- package/src/app/[variants]/(main)/chat/(workspace)/@topic/features/GroupConfig/GroupMember.tsx +34 -2
- package/src/app/[variants]/(main)/chat/(workspace)/_layout/Desktop/ChatHeader/Main.tsx +1 -1
- package/src/app/[variants]/(main)/chat/(workspace)/features/{GroupChatSettings → AgentTeamSettings}/index.tsx +4 -5
- package/src/app/[variants]/(main)/chat/(workspace)/features/SettingButton.tsx +2 -2
- package/src/app/[variants]/(main)/chat/@session/_layout/Desktop/SessionHeader.tsx +2 -0
- package/src/app/[variants]/(main)/chat/@session/features/SessionListContent/CollapseGroup/Actions.tsx +18 -1
- package/src/app/[variants]/(main)/discover/(list)/assistant/features/List/Item.tsx +1 -0
- package/src/app/[variants]/(main)/discover/DiscoverRouter.tsx +12 -10
- package/src/app/[variants]/(main)/discover/[[...path]]/page.tsx +7 -6
- package/src/app/[variants]/(main)/discover/features/Search.tsx +1 -0
- package/src/components/ChatGroupWizard/ChatGroupWizard.tsx +33 -5
- package/src/components/Loading/index.ts +1 -0
- package/src/components/MemberSelectionModal/MemberSelectionModal.tsx +170 -26
- package/src/features/AgentSetting/AgentModal/index.tsx +262 -35
- package/src/features/ChatInput/ActionBar/Params/Controls.tsx +261 -50
- package/src/features/Conversation/Messages/Assistant/Actions/index.tsx +7 -2
- package/src/features/Conversation/Messages/User/Actions.tsx +8 -2
- package/src/features/GroupChatSettings/{ChatGroupSettings.tsx → AgentTeamChatSettings.tsx} +6 -5
- package/src/features/GroupChatSettings/{GroupMembers.tsx → AgentTeamMembersSettings.tsx} +64 -19
- package/src/features/GroupChatSettings/{ChatGroupMeta.tsx → AgentTeamMetaSettings.tsx} +2 -2
- package/src/features/GroupChatSettings/AgentTeamSettings.tsx +54 -0
- package/src/features/GroupChatSettings/index.ts +4 -5
- package/src/features/ModelParamsControl/FrequencyPenalty.tsx +8 -3
- package/src/features/ModelParamsControl/PresencePenalty.tsx +8 -3
- package/src/features/ModelParamsControl/Temperature.tsx +8 -5
- package/src/features/ModelParamsControl/TopP.tsx +8 -3
- package/src/locales/default/chat.ts +17 -17
- package/src/locales/default/setting.ts +15 -19
- package/src/locales/default/welcome.ts +1 -1
- package/src/services/chat/index.ts +6 -0
- package/src/store/chat/slices/aiChat/actions/generateAIGroupChat.ts +2 -1
- package/src/store/chatGroup/action.ts +36 -1
- package/src/store/user/slices/settings/selectors/__snapshots__/settings.test.ts.snap +0 -4
- package/src/store/user/slices/settings/selectors/systemAgent.ts +0 -2
- package/docs/usage/features/group-chat.zh-CN.mdx +0 -52
- package/e2e/routes.spec.ts +0 -73
- package/playwright.config.ts +0 -35
- package/src/features/GroupChatSettings/GroupSettings.tsx +0 -30
- package/src/features/GroupChatSettings/GroupSettingsContent.tsx +0 -24
|
@@ -12,10 +12,36 @@
|
|
|
12
12
|
- [ ] 📝 docs
|
|
13
13
|
- [ ] 🔨 chore
|
|
14
14
|
|
|
15
|
+
#### 🔗 Related Issue
|
|
16
|
+
|
|
17
|
+
<!-- Link to the issue that is fixed by this PR -->
|
|
18
|
+
|
|
19
|
+
<!-- Example: Fixes #123, Closes #456, Related to #789 -->
|
|
20
|
+
|
|
15
21
|
#### 🔀 Description of Change
|
|
16
22
|
|
|
17
23
|
<!-- Thank you for your Pull Request. Please provide a description above. -->
|
|
18
24
|
|
|
25
|
+
#### 🧪 How to Test
|
|
26
|
+
|
|
27
|
+
<!-- Please describe how you tested your changes -->
|
|
28
|
+
|
|
29
|
+
<!-- For AI features, please include test prompts or scenarios -->
|
|
30
|
+
|
|
31
|
+
- [ ] Tested locally
|
|
32
|
+
- [ ] Added/updated tests
|
|
33
|
+
- [ ] No tests needed
|
|
34
|
+
|
|
35
|
+
#### 📸 Screenshots / Videos
|
|
36
|
+
|
|
37
|
+
<!-- If this PR includes UI changes, please provide screenshots or videos -->
|
|
38
|
+
|
|
39
|
+
| Before | After |
|
|
40
|
+
| ------ | ----- |
|
|
41
|
+
| ... | ... |
|
|
42
|
+
|
|
19
43
|
#### 📝 Additional Information
|
|
20
44
|
|
|
21
45
|
<!-- Add any other context about the Pull Request here. -->
|
|
46
|
+
|
|
47
|
+
<!-- Breaking changes? Migration guide? Performance impact? -->
|
|
@@ -35,18 +35,18 @@ jobs:
|
|
|
35
35
|
PORT: 3010
|
|
36
36
|
run: bun run e2e
|
|
37
37
|
|
|
38
|
-
- name: Upload
|
|
38
|
+
- name: Upload Cucumber HTML report (on failure)
|
|
39
39
|
if: failure()
|
|
40
40
|
uses: actions/upload-artifact@v4
|
|
41
41
|
with:
|
|
42
|
-
name:
|
|
43
|
-
path:
|
|
42
|
+
name: cucumber-report
|
|
43
|
+
path: e2e/reports
|
|
44
44
|
if-no-files-found: ignore
|
|
45
45
|
|
|
46
|
-
- name: Upload
|
|
46
|
+
- name: Upload screenshots (on failure)
|
|
47
47
|
if: failure()
|
|
48
48
|
uses: actions/upload-artifact@v4
|
|
49
49
|
with:
|
|
50
|
-
name: test-
|
|
51
|
-
path:
|
|
50
|
+
name: test-screenshots
|
|
51
|
+
path: e2e/screenshots
|
|
52
52
|
if-no-files-found: ignore
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 1.141.8](https://github.com/lobehub/lobe-chat/compare/v1.141.7...v1.141.8)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-10-23**</sup>
|
|
8
|
+
|
|
9
|
+
#### 💄 Styles
|
|
10
|
+
|
|
11
|
+
- **misc**: Improvement for Agent Team After Alpha Launch \[LOB-517].
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Styles
|
|
19
|
+
|
|
20
|
+
- **misc**: Improvement for Agent Team After Alpha Launch \[LOB-517], closes [#9748](https://github.com/lobehub/lobe-chat/issues/9748) ([28245be](https://github.com/lobehub/lobe-chat/commit/28245be))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 1.141.7](https://github.com/lobehub/lobe-chat/compare/v1.141.6...v1.141.7)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2025-10-23**</sup>
|
|
33
|
+
|
|
34
|
+
#### 💄 Styles
|
|
35
|
+
|
|
36
|
+
- **misc**: Allow removal of `top_p` and similar request parameters.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Styles
|
|
44
|
+
|
|
45
|
+
- **misc**: Allow removal of `top_p` and similar request parameters, closes [#9498](https://github.com/lobehub/lobe-chat/issues/9498) ([4c313ce](https://github.com/lobehub/lobe-chat/commit/4c313ce))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 1.141.6](https://github.com/lobehub/lobe-chat/compare/v1.141.5...v1.141.6)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2025-10-22**</sup>
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"improvements": [
|
|
5
|
+
"Improvement for Agent Team After Alpha Launch [LOB-517]."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2025-10-23",
|
|
9
|
+
"version": "1.141.8"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {
|
|
13
|
+
"improvements": [
|
|
14
|
+
"Allow removal of top_p and similar request parameters."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"date": "2025-10-23",
|
|
18
|
+
"version": "1.141.7"
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"children": {},
|
|
4
22
|
"date": "2025-10-22",
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: Agent Team
|
|
3
3
|
description: Turn any conversation into a team effort. Multiple AI agents collaborate naturally to give you richer, more insightful responses.
|
|
4
4
|
tags:
|
|
5
|
-
-
|
|
5
|
+
- Agent Team
|
|
6
6
|
- Multi-Agent
|
|
7
7
|
- AI Orchestration
|
|
8
8
|
- Agent Coordination
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
#
|
|
11
|
+
# Agent Team
|
|
12
12
|
|
|
13
|
-
<Image alt={'
|
|
13
|
+
<Image alt={'Agent Team'} cover src={'https://github.com/user-attachments/assets/6e5599f6-1e39-4b14-a218-4f5ffa2c306a'} />
|
|
14
14
|
|
|
15
|
-
Sometimes one perspective isn't enough.
|
|
15
|
+
Sometimes one perspective isn't enough. Agent Team brings together multiple AI agents, each with their own expertise, to collaborate on your conversations. Richer discussions, diverse viewpoints, and solutions you wouldn't get from any single agent.
|
|
16
16
|
|
|
17
17
|
## Highlights
|
|
18
18
|
|
|
19
19
|
- Multiple assistants with specialized knowledge work together, each contributing their strengths
|
|
20
|
-
- A built-in host ensures the
|
|
20
|
+
- A built-in host ensures the agent team conversation runs smoothly and organized
|
|
21
21
|
- Private messaging allows seamless coordination between assistants
|
|
22
22
|
- You get comprehensive answers from multiple perspectives
|
|
23
|
-
- Ready to use with your own assistants or rich
|
|
23
|
+
- Ready to use with your own assistants or rich agent team templates
|
|
24
24
|
|
|
25
25
|
## Use Cases
|
|
26
26
|
|
|
@@ -30,23 +30,23 @@ Sometimes one perspective isn't enough. Group Chat brings together multiple AI a
|
|
|
30
30
|
|
|
31
31
|
**Brainstorming**: Diverse perspectives spark better ideas.
|
|
32
32
|
|
|
33
|
-
**Problem Solving**: Benefit from insights across different professional fields, with different tools and MCPs,
|
|
33
|
+
**Problem Solving**: Benefit from insights across different professional fields, with different tools and MCPs, agent team allows you to have the perfect AI team.
|
|
34
34
|
|
|
35
35
|
## Quick Start
|
|
36
36
|
|
|
37
|
-
Click the "Create
|
|
37
|
+
Click the "Create Agent Team" button, you can choose to create directly from preset agent team templates, or select your own assistants to form an agent team.
|
|
38
38
|
|
|
39
|
-
You can use @ to mention a
|
|
39
|
+
You can use @ to mention a team member in the agent team, or click their avatar to send them a private message. Everything works just like in a real chat room.
|
|
40
40
|
|
|
41
|
-
### Interrupt and Resume
|
|
41
|
+
### Interrupt and Resume Agent Team
|
|
42
42
|
|
|
43
|
-
You can interrupt the host's thinking at any time, and the
|
|
43
|
+
You can interrupt the host's thinking at any time, and the agent team will "pause" after interruption. You can start the moderator at any time, and the agent team will continue.
|
|
44
44
|
|
|
45
45
|
Of course, conversations may also stop naturally.
|
|
46
46
|
|
|
47
47
|
### Advanced Options
|
|
48
48
|
|
|
49
|
-
-
|
|
49
|
+
- Agent Team Speed: Customize the response speed of the agent team
|
|
50
50
|
- Custom Moderator: Guide the moderator's behavior according to specific needs
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Agent Team transforms how you interact with AI. Instead of getting one answer, you participate in a conversation—complete with different viewpoints, collaborative problem-solving, and profound insights that emerge when AI agents work together.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Agent 团队
|
|
3
|
+
description: 让对话变成团队协作。多个 AI 智能体自然配合,为你提供更丰富、更有洞察力的回答。
|
|
4
|
+
tags:
|
|
5
|
+
- 群组对话
|
|
6
|
+
- 多智能体
|
|
7
|
+
- AI 编排
|
|
8
|
+
- 智能体协调
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Agent 团队
|
|
12
|
+
|
|
13
|
+
<Image alt={'Agent 团队'} cover src={'https://github.com/user-attachments/assets/6e5599f6-1e39-4b14-a218-4f5ffa2c306a'} />
|
|
14
|
+
|
|
15
|
+
有时候,一个视角远远不够。Agent 团队功能让多个拥有不同知识和技能的 AI 智能体聚在一起,协作参与你的对话。更丰富的讨论、多元的观点,以及任何单一智能体都无法提供的解决方案。
|
|
16
|
+
|
|
17
|
+
## 亮点
|
|
18
|
+
|
|
19
|
+
- 多个具有专业知识的助手协同工作,各取所长
|
|
20
|
+
- 团队内置的主持人将确保整个团队聊天有条不紊的进行
|
|
21
|
+
- 私信功能让助手间无缝协调配合
|
|
22
|
+
- 你将从多个视角获得全面的答案
|
|
23
|
+
- 开箱即用,由你自己的助手组成,或者使用丰富的团队模版
|
|
24
|
+
|
|
25
|
+
## 适用场景
|
|
26
|
+
|
|
27
|
+
**学习研究**:不同的助手通过不同的工具收集不同的资料,汇聚一处并自发讨论。
|
|
28
|
+
|
|
29
|
+
**娱乐**:狼人杀、模拟联合国、海龟汤等多人语聊游戏。
|
|
30
|
+
|
|
31
|
+
**头脑风暴**:多元观点激发更好的想法。
|
|
32
|
+
|
|
33
|
+
**问题解决**:受益于不同专业领域的见解,以及不同的工具和 MCP,Agent 团队允许你拥有完美的 AI 团队。
|
|
34
|
+
|
|
35
|
+
## 快速开始
|
|
36
|
+
|
|
37
|
+
点击「创建 Agent 团队」按钮,你可以选择直接从预设的团队模版创建,或选择你自己的助手组成团队。
|
|
38
|
+
|
|
39
|
+
你可以在团队聊天中输入 @ 来提及某个成员,或者点击他们的头像对其私聊。一切就像是在真实的聊天室中一样。
|
|
40
|
+
|
|
41
|
+
### 中断与继续团队聊天
|
|
42
|
+
|
|
43
|
+
你可以随时打断主持人的思考,打断后团队聊天将会「暂停」。你可以随时开启主持人,团队聊天便会继续。
|
|
44
|
+
|
|
45
|
+
当然,对话也有可能自然地停止。
|
|
46
|
+
|
|
47
|
+
### 高级选项
|
|
48
|
+
|
|
49
|
+
- 团队速度:自定义团队的回答速度
|
|
50
|
+
- 自定义主持人:根据特定需要指导主持人的行为
|
|
51
|
+
|
|
52
|
+
Agent 团队改变了你与 AI 的互动方式。不再是获得一个答案,而是参与一场对话 —— 包含不同观点、协作解决问题,以及 AI 智能体协同工作时产生的深刻洞察。
|
package/e2e/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# E2E Tests for LobeChat
|
|
2
|
+
|
|
3
|
+
This directory contains end-to-end (E2E) tests for LobeChat using Cucumber (BDD) and Playwright.
|
|
4
|
+
|
|
5
|
+
## Directory Structure
|
|
6
|
+
|
|
7
|
+
````
|
|
8
|
+
e2e/
|
|
9
|
+
├── src/ # Source files
|
|
10
|
+
│ ├── features/ # Gherkin feature files
|
|
11
|
+
│ │ └── discover/ # Discover page tests
|
|
12
|
+
│ ├── steps/ # Step definitions
|
|
13
|
+
│ │ ├── common/ # Reusable step definitions
|
|
14
|
+
│ │ └── discover/ # Discover-specific steps
|
|
15
|
+
│ └── support/ # Test support files
|
|
16
|
+
│ └── world.ts # Custom World context
|
|
17
|
+
├── reports/ # Test reports (generated)
|
|
18
|
+
├── cucumber.config.js # Cucumber configuration
|
|
19
|
+
├── tsconfig.json # TypeScript configuration
|
|
20
|
+
└── package.json # Dependencies and scripts
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
- Node.js 20, 22, or >=24
|
|
25
|
+
- Dev server running on `http://localhost:3010` (or set `BASE_URL` env var)
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Install dependencies:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cd e2e
|
|
33
|
+
pnpm install
|
|
34
|
+
````
|
|
35
|
+
|
|
36
|
+
Install Playwright browsers:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npx playwright install chromium
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Running Tests
|
|
43
|
+
|
|
44
|
+
Run all tests:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm test
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Run tests in headed mode (see browser):
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm run test:headed
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Run only smoke tests:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm run test:smoke
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Run discover tests:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm run test:discover
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Environment Variables
|
|
69
|
+
|
|
70
|
+
- `BASE_URL`: Base URL for the application (default: `http://localhost:3010`)
|
|
71
|
+
- `PORT`: Port number (default: `3010`)
|
|
72
|
+
- `HEADLESS`: Run browser in headless mode (default: `true`, set to `false` to see browser)
|
|
73
|
+
|
|
74
|
+
Example:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
HEADLESS=false BASE_URL=http://localhost:3000 npm run test:smoke
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Writing Tests
|
|
81
|
+
|
|
82
|
+
### Feature Files
|
|
83
|
+
|
|
84
|
+
Feature files are written in Gherkin syntax and placed in the `src/features/` directory:
|
|
85
|
+
|
|
86
|
+
```gherkin
|
|
87
|
+
@discover @smoke
|
|
88
|
+
Feature: Discover Smoke Tests
|
|
89
|
+
Critical path tests to ensure the discover module is functional
|
|
90
|
+
|
|
91
|
+
@DISCOVER-SMOKE-001 @P0
|
|
92
|
+
Scenario: Load discover assistant list page
|
|
93
|
+
Given I navigate to "/discover/assistant"
|
|
94
|
+
Then the page should load without errors
|
|
95
|
+
And I should see the page body
|
|
96
|
+
And I should see the search bar
|
|
97
|
+
And I should see assistant cards
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Step Definitions
|
|
101
|
+
|
|
102
|
+
Step definitions are TypeScript files in the `src/steps/` directory that implement the steps from feature files:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { Given, Then } from '@cucumber/cucumber';
|
|
106
|
+
import { expect } from '@playwright/test';
|
|
107
|
+
|
|
108
|
+
import { CustomWorld } from '../../support/world';
|
|
109
|
+
|
|
110
|
+
Given('I navigate to {string}', async function (this: CustomWorld, path: string) {
|
|
111
|
+
await this.page.goto(path);
|
|
112
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Test Reports
|
|
117
|
+
|
|
118
|
+
After running tests, HTML and JSON reports are generated in the `reports/` directory:
|
|
119
|
+
|
|
120
|
+
- `reports/cucumber-report.html` - Human-readable HTML report
|
|
121
|
+
- `reports/cucumber-report.json` - Machine-readable JSON report
|
|
122
|
+
|
|
123
|
+
## Troubleshooting
|
|
124
|
+
|
|
125
|
+
### Browser not found
|
|
126
|
+
|
|
127
|
+
If you see errors about missing browser executables:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx playwright install chromium
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Port already in use
|
|
134
|
+
|
|
135
|
+
Make sure the dev server is running on the expected port (3010 by default), or set `PORT` or `BASE_URL` environment variable.
|
|
136
|
+
|
|
137
|
+
### Test timeout
|
|
138
|
+
|
|
139
|
+
Increase timeout in `cucumber.config.js` or `src/steps/hooks.ts`:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
setDefaultTimeout(120000); // 2 minutes
|
|
143
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @type {import('@cucumber/cucumber').IConfiguration}
|
|
3
|
+
*/
|
|
4
|
+
export default {
|
|
5
|
+
format: [
|
|
6
|
+
'progress-bar',
|
|
7
|
+
'html:reports/cucumber-report.html',
|
|
8
|
+
'json:reports/cucumber-report.json',
|
|
9
|
+
],
|
|
10
|
+
formatOptions: {
|
|
11
|
+
snippetInterface: 'async-await',
|
|
12
|
+
},
|
|
13
|
+
parallel: process.env.CI ? 1 : 4,
|
|
14
|
+
paths: ['src/features/**/*.feature'],
|
|
15
|
+
publishQuiet: true,
|
|
16
|
+
require: ['src/steps/**/*.ts', 'src/support/**/*.ts'],
|
|
17
|
+
requireModule: ['tsx/cjs'],
|
|
18
|
+
retry: 0,
|
|
19
|
+
timeout: 120_000,
|
|
20
|
+
};
|
package/e2e/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lobechat/e2e-tests",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "E2E tests for LobeChat using Cucumber and Playwright",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "cucumber-js --config cucumber.config.js",
|
|
8
|
+
"test:discover": "cucumber-js --config cucumber.config.js src/features/discover/",
|
|
9
|
+
"test:headed": "HEADLESS=false cucumber-js --config cucumber.config.js",
|
|
10
|
+
"test:routes": "cucumber-js --config cucumber.config.js --tags '@routes'",
|
|
11
|
+
"test:routes:ci": "cucumber-js --config cucumber.config.js --tags '@routes and not @ci-skip'",
|
|
12
|
+
"test:smoke": "cucumber-js --config cucumber.config.js --tags '@smoke'"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@cucumber/cucumber": "^12.2.0",
|
|
16
|
+
"@playwright/test": "^1.56.1",
|
|
17
|
+
"playwright": "^1.56.1"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^22.10.5",
|
|
21
|
+
"tsx": "^4.20.6",
|
|
22
|
+
"typescript": "^5.7.3"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
@discover @smoke
|
|
2
|
+
Feature: Discover Smoke Tests
|
|
3
|
+
Critical path tests to ensure the discover module is functional
|
|
4
|
+
|
|
5
|
+
@DISCOVER-SMOKE-001 @P0
|
|
6
|
+
Scenario: Load discover assistant list page
|
|
7
|
+
Given I navigate to "/discover/assistant"
|
|
8
|
+
Then the page should load without errors
|
|
9
|
+
And I should see the page body
|
|
10
|
+
And I should see the search bar
|
|
11
|
+
And I should see assistant cards
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
@routes @smoke
|
|
2
|
+
Feature: Core Routes Accessibility
|
|
3
|
+
As a user
|
|
4
|
+
I want all core application routes to be accessible
|
|
5
|
+
So that I can navigate the application without errors
|
|
6
|
+
|
|
7
|
+
Background:
|
|
8
|
+
Given the application is running
|
|
9
|
+
|
|
10
|
+
@ROUTES-001 @P0
|
|
11
|
+
Scenario Outline: Access core routes without errors
|
|
12
|
+
When I navigate to "<route>"
|
|
13
|
+
Then the response status should be less than 400
|
|
14
|
+
And the page should load without errors
|
|
15
|
+
And I should see the page body
|
|
16
|
+
And the page title should not contain "error" or "not found"
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
| route |
|
|
20
|
+
| / |
|
|
21
|
+
| /chat |
|
|
22
|
+
| /discover |
|
|
23
|
+
| /files |
|
|
24
|
+
| /repos |
|
|
25
|
+
|
|
26
|
+
@ROUTES-002 @P0
|
|
27
|
+
Scenario Outline: Access settings routes without errors
|
|
28
|
+
When I navigate to "/settings?active=<tab>"
|
|
29
|
+
Then the response status should be less than 400
|
|
30
|
+
And the page should load without errors
|
|
31
|
+
And I should see the page body
|
|
32
|
+
And the page title should not contain "error" or "not found"
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
| tab |
|
|
36
|
+
| about |
|
|
37
|
+
| agent |
|
|
38
|
+
| hotkey |
|
|
39
|
+
| provider |
|
|
40
|
+
| proxy |
|
|
41
|
+
| storage |
|
|
42
|
+
| system-agent |
|
|
43
|
+
| tts |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Given, Then } from '@cucumber/cucumber';
|
|
2
|
+
import { expect } from '@playwright/test';
|
|
3
|
+
|
|
4
|
+
import { CustomWorld } from '../../support/world';
|
|
5
|
+
|
|
6
|
+
// ============================================
|
|
7
|
+
// Given Steps (Preconditions)
|
|
8
|
+
// ============================================
|
|
9
|
+
|
|
10
|
+
Given('I navigate to {string}', async function (this: CustomWorld, path: string) {
|
|
11
|
+
const response = await this.page.goto(path, { waitUntil: 'commit' });
|
|
12
|
+
this.testContext.lastResponse = response;
|
|
13
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// ============================================
|
|
17
|
+
// Then Steps (Assertions)
|
|
18
|
+
// ============================================
|
|
19
|
+
|
|
20
|
+
Then('the page should load without errors', async function (this: CustomWorld) {
|
|
21
|
+
// Check for no JavaScript errors
|
|
22
|
+
expect(this.testContext.jsErrors).toHaveLength(0);
|
|
23
|
+
|
|
24
|
+
// Check page didn't navigate to error page
|
|
25
|
+
const url = this.page.url();
|
|
26
|
+
expect(url).not.toMatch(/\/404|\/error|not-found/i);
|
|
27
|
+
|
|
28
|
+
// Check no error title
|
|
29
|
+
const title = await this.page.title();
|
|
30
|
+
expect(title).not.toMatch(/not found|error/i);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
Then('I should see the page body', async function (this: CustomWorld) {
|
|
34
|
+
const body = this.page.locator('body');
|
|
35
|
+
await expect(body).toBeVisible();
|
|
36
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Then } from '@cucumber/cucumber';
|
|
2
|
+
import { expect } from '@playwright/test';
|
|
3
|
+
|
|
4
|
+
import { CustomWorld } from '../../support/world';
|
|
5
|
+
|
|
6
|
+
// ============================================
|
|
7
|
+
// Then Steps (Assertions)
|
|
8
|
+
// ============================================
|
|
9
|
+
|
|
10
|
+
Then('I should see the search bar', async function (this: CustomWorld) {
|
|
11
|
+
// Wait for network to be idle to ensure Suspense components are loaded
|
|
12
|
+
await this.page.waitForLoadState('networkidle', { timeout: 120_000 });
|
|
13
|
+
|
|
14
|
+
// The SearchBar component from @lobehub/ui may not pass through data-testid
|
|
15
|
+
// Try to find the input element within the search component
|
|
16
|
+
const searchBar = this.page.locator('input[type="text"]').first();
|
|
17
|
+
await expect(searchBar).toBeVisible({ timeout: 120_000 });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
Then('I should see assistant cards', async function (this: CustomWorld) {
|
|
21
|
+
// Wait for content to load
|
|
22
|
+
await this.page.waitForLoadState('networkidle', { timeout: 120_000 });
|
|
23
|
+
|
|
24
|
+
// After migrating to SPA (react-router), links use relative paths like /assistant/:id
|
|
25
|
+
// Look for assistant items by data-testid instead of href
|
|
26
|
+
const assistantItems = this.page.locator('[data-testid="assistant-item"]');
|
|
27
|
+
|
|
28
|
+
// Wait for at least one item to be visible
|
|
29
|
+
await expect(assistantItems.first()).toBeVisible({ timeout: 120_000 });
|
|
30
|
+
|
|
31
|
+
// Check we have multiple items
|
|
32
|
+
const count = await assistantItems.count();
|
|
33
|
+
expect(count).toBeGreaterThan(0);
|
|
34
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { After, AfterAll, Before, BeforeAll, Status, setDefaultTimeout } from '@cucumber/cucumber';
|
|
2
|
+
|
|
3
|
+
import { startWebServer, stopWebServer } from '../support/webServer';
|
|
4
|
+
import { CustomWorld } from '../support/world';
|
|
5
|
+
|
|
6
|
+
// Set default timeout for all steps to 120 seconds
|
|
7
|
+
setDefaultTimeout(120_000);
|
|
8
|
+
|
|
9
|
+
BeforeAll({ timeout: 120_000 }, async function () {
|
|
10
|
+
console.log('🚀 Starting E2E test suite...');
|
|
11
|
+
|
|
12
|
+
const PORT = process.env.PORT ? Number(process.env.PORT) : 3010;
|
|
13
|
+
const BASE_URL = process.env.BASE_URL || `http://localhost:${PORT}`;
|
|
14
|
+
|
|
15
|
+
console.log(`Base URL: ${BASE_URL}`);
|
|
16
|
+
|
|
17
|
+
// Start web server if not using external BASE_URL
|
|
18
|
+
if (!process.env.BASE_URL) {
|
|
19
|
+
await startWebServer({
|
|
20
|
+
command: 'npm run dev',
|
|
21
|
+
port: PORT,
|
|
22
|
+
reuseExistingServer: !process.env.CI,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
Before(async function (this: CustomWorld, { pickle }) {
|
|
28
|
+
await this.init();
|
|
29
|
+
|
|
30
|
+
const testId = pickle.tags.find((tag) => tag.name.startsWith('@DISCOVER-'));
|
|
31
|
+
console.log(`\n📝 Running: ${pickle.name}${testId ? ` (${testId.name.replace('@', '')})` : ''}`);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
After(async function (this: CustomWorld, { pickle, result }) {
|
|
35
|
+
const testId = pickle.tags
|
|
36
|
+
.find((tag) => tag.name.startsWith('@DISCOVER-'))
|
|
37
|
+
?.name.replace('@', '');
|
|
38
|
+
|
|
39
|
+
if (result?.status === Status.FAILED) {
|
|
40
|
+
const screenshot = await this.takeScreenshot(`${testId || 'failure'}-${Date.now()}`);
|
|
41
|
+
this.attach(screenshot, 'image/png');
|
|
42
|
+
|
|
43
|
+
const html = await this.page.content();
|
|
44
|
+
this.attach(html, 'text/html');
|
|
45
|
+
|
|
46
|
+
if (this.testContext.jsErrors.length > 0) {
|
|
47
|
+
const errors = this.testContext.jsErrors.map((e) => e.message).join('\n');
|
|
48
|
+
this.attach(`JavaScript Errors:\n${errors}`, 'text/plain');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log(`❌ Failed: ${pickle.name}`);
|
|
52
|
+
if (result.message) {
|
|
53
|
+
console.log(` Error: ${result.message}`);
|
|
54
|
+
}
|
|
55
|
+
} else if (result?.status === Status.PASSED) {
|
|
56
|
+
console.log(`✅ Passed: ${pickle.name}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await this.cleanup();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
AfterAll(async function () {
|
|
63
|
+
console.log('\n🏁 Test suite completed');
|
|
64
|
+
|
|
65
|
+
// Stop web server if we started it
|
|
66
|
+
if (!process.env.BASE_URL && process.env.CI) {
|
|
67
|
+
await stopWebServer();
|
|
68
|
+
}
|
|
69
|
+
});
|