@lobehub/chat 0.104.0 → 0.105.1
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/CHANGELOG.md +50 -0
- package/README.md +14 -14
- package/README.zh-CN.md +8 -8
- package/package.json +1 -1
- package/src/app/api/config.test.ts +4 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/Iframe.tsx +13 -5
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/iframeOnReady.test.ts +75 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/iframeOnReady.ts +2 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/listenToPlugin.test.ts +104 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginSettings.test.ts +53 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginState.test.ts +43 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/postMessage.test.ts +64 -0
- package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/postMessage.ts +13 -2
- package/src/app/market/(desktop)/features/AgentDetail.tsx +1 -0
- package/src/layout/GlobalLayout/index.tsx +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.105.1](https://github.com/lobehub/lobe-chat/compare/v0.105.0...v0.105.1)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-11-27**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Fix agent market detail scroll error.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Fix agent market detail scroll error, closes [#503](https://github.com/lobehub/lobe-chat/issues/503) ([8900ad0](https://github.com/lobehub/lobe-chat/commit/8900ad0))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## [Version 0.105.0](https://github.com/lobehub/lobe-chat/compare/v0.104.0...v0.105.0)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2023-11-22**</sup>
|
|
33
|
+
|
|
34
|
+
#### ✨ Features
|
|
35
|
+
|
|
36
|
+
- **misc**: Standalone pluginn can get more arguments on init.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's improved
|
|
44
|
+
|
|
45
|
+
- **misc**: Standalone pluginn can get more arguments on init, closes [#498](https://github.com/lobehub/lobe-chat/issues/498) ([a7624f5](https://github.com/lobehub/lobe-chat/commit/a7624f5))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 0.104.0](https://github.com/lobehub/lobe-chat/compare/v0.103.1...v0.104.0)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2023-11-21**</sup>
|
package/README.md
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
<a name="readme-top"></a>
|
|
2
|
-
|
|
3
|
-
<div align="center">
|
|
1
|
+
<a name="readme-top"></a><div align="center">
|
|
4
2
|
|
|
5
3
|
<img height="120" src="https://registry.npmmirror.com/@lobehub/assets-logo/1.0.0/files/assets/logo-3d.webp">
|
|
6
4
|
<img height="120" src="https://gw.alipayobjects.com/zos/kitchen/qJ3l3EPsdW/split.svg">
|
|
7
5
|
<img height="120" src="https://registry.npmmirror.com/@lobehub/assets-emoji-anim/1.0.0/files/assets/robot.webp">
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
# Lobe Chat
|
|
10
8
|
|
|
11
9
|
LobeChat is an open-source, high-performance chatbot framework<br/>that supports speech synthesis, multimodal, and extensible ([Function Call][fc-link]) plugin system. <br/>
|
|
12
10
|
Supports one-click free deployment of your private ChatGPT/LLM web application.
|
|
@@ -81,7 +79,8 @@ Please be aware that LobeChat is currently under active development, and feedbac
|
|
|
81
79
|
|
|
82
80
|

|
|
83
81
|
|
|
84
|
-
<details
|
|
82
|
+
<details>
|
|
83
|
+
<summary><kbd>Star History</kbd></summary>
|
|
85
84
|
<picture>
|
|
86
85
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=lobehub%2Flobe-chat&theme=dark&type=Date">
|
|
87
86
|
<img width="100%" src="https://api.star-history.com/svg?repos=lobehub%2Flobe-chat&type=Date">
|
|
@@ -153,8 +152,9 @@ Users can choose the voice that suits their personal preferences or specific sce
|
|
|
153
152
|
> As a result, we invested a lot of effort, including data conversion, audio progress management, and speech visualization, among other tasks.
|
|
154
153
|
|
|
155
154
|
> \[!IMPORTANT]
|
|
155
|
+
>
|
|
156
156
|
> Therefore, we decided to refine our implementation and make it open source, hoping to assist developers who wish to implement TTS.
|
|
157
|
-
> [@lobehub/tts][lobe-tts-
|
|
157
|
+
> [@lobehub/tts][lobe-tts-github] is a high-quality TTS toolkit developed in TypeScript, which supports usage both on the server-side and in the browser.
|
|
158
158
|
>
|
|
159
159
|
> - **Server-side:** With just 15 lines of code, you can achieve high-quality voice generation capabilities comparable to OpenAI's TTS service. It currently supports EdgeSpeechTTS, MicrosoftTTS, OpenAITTS, and OpenAISTT.
|
|
160
160
|
> - **Browser-side:** It provides high-quality React Hooks and visual audio components, supporting common functions such as loading, playing, pausing, and dragging the timeline. Additionally, it offers a very rich set of capabilities for adjusting the audio track styles.
|
|
@@ -186,7 +186,7 @@ e-commerce platform data access, and various third-party services.
|
|
|
186
186
|
> We welcome developers to use these resources to unleash their creativity and write feature-rich, user-friendly plugins.
|
|
187
187
|
> With collective efforts, we can continuously expand the boundaries of chat applications and explore a more intelligent and efficient creativity platform.
|
|
188
188
|
|
|
189
|
-
<https://github.com/lobehub/lobe-chat/assets/28616219/f29475a3-f346-4196-a435-41a6373ab9e2>
|
|
189
|
+
<video controls src="https://github.com/lobehub/lobe-chat/assets/28616219/f29475a3-f346-4196-a435-41a6373ab9e2" muted="false"></video>
|
|
190
190
|
|
|
191
191
|
<!-- PLUGIN LIST -->
|
|
192
192
|
|
|
@@ -229,14 +229,14 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
229
229
|
|
|
230
230
|
<!-- AGENT LIST -->
|
|
231
231
|
|
|
232
|
-
| Recent Submits
|
|
233
|
-
|
|
|
234
|
-
| [
|
|
235
|
-
| [
|
|
236
|
-
| [
|
|
237
|
-
| [
|
|
232
|
+
| Recent Submits | Description |
|
|
233
|
+
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
234
|
+
| [JS Code Quality Optimization](https://chat-preview.lobehub.com/market?agent=js-code-quality)<br/><sup>By **[canisminor1990](https://github.com/canisminor1990)** on **2023-11-22**</sup> | Dedicated to clean and elegant code refactoring<br/>`refactoring` `code-optimization` `code-quality` |
|
|
235
|
+
| [LobeChat Test Engineer](https://chat-preview.lobehub.com/market?agent=lobe-chat-unit-test-dev)<br/><sup>By **[arvinxx](https://github.com/arvinxx)** on **2023-11-22**</sup> | Proficient in writing frontend automation tests, especially comprehensive test coverage for TypeScript applications. Skilled in using the Vitest testing framework with a deep understanding of testing principles and strategies.<br/>`automation-testing` `testing` `lobe-chat` `frontend` |
|
|
236
|
+
| [Q\&A Document Conversion Expert](https://chat-preview.lobehub.com/market?agent=q-a-helper)<br/><sup>By **[barryWang12138](https://github.com/barryWang12138)** on **2023-11-22**</sup> | Please provide your document content, and I will segment and clean it according to your requirements, and provide answers in a standardized format.<br/>`q-a` `document` |
|
|
237
|
+
| [True Friend](https://chat-preview.lobehub.com/market?agent=ai-0x0-old-friends)<br/><sup>By **[mushan0x0](https://github.com/mushan0x0)** on **2023-11-21**</sup> | You can talk to me about anything. I can give you some thoughts and advice as a friend. Relax.<br/>`friendship` `humor` `authentic` `simulation` |
|
|
238
238
|
|
|
239
|
-
> 📊 Total agents: [<kbd>**
|
|
239
|
+
> 📊 Total agents: [<kbd>**52**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
240
240
|
|
|
241
241
|
<!-- AGENT LIST -->
|
|
242
242
|
|
package/README.zh-CN.md
CHANGED
|
@@ -208,14 +208,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
208
208
|
|
|
209
209
|
<!-- AGENT LIST -->
|
|
210
210
|
|
|
211
|
-
| 最近新增
|
|
212
|
-
|
|
|
213
|
-
| [
|
|
214
|
-
| [
|
|
215
|
-
| [
|
|
216
|
-
| [
|
|
217
|
-
|
|
218
|
-
> 📊 Total agents: [<kbd>**
|
|
211
|
+
| 最近新增 | 助手说明 |
|
|
212
|
+
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
213
|
+
| [JS 代码质量优化](https://chat-preview.lobehub.com/market?agent=js-code-quality)<br/><sup>By **[canisminor1990](https://github.com/canisminor1990)** on **2023-11-22**</sup> | 致力于干净和优雅的代码重构<br/>`重构` `代码优化` `代码质量` |
|
|
214
|
+
| [LobeChat 测试工程师](https://chat-preview.lobehub.com/market?agent=lobe-chat-unit-test-dev)<br/><sup>By **[arvinxx](https://github.com/arvinxx)** on **2023-11-22**</sup> | 擅长编写前端自动化测试,特别是 TypeScript 应用的全面测试覆盖。熟练使用 Vitest 测试框架,具备深入的测试原理和策略理解。<br/>`自动化测试` `测试` `lobe-chat` `前端` |
|
|
215
|
+
| [问答文档转换专家](https://chat-preview.lobehub.com/market?agent=q-a-helper)<br/><sup>By **[barryWang12138](https://github.com/barryWang12138)** on **2023-11-22**</sup> | 请提供您的文档内容,我将根据您的要求进行分段和清洗,并按照规范的格式回答。<br/>`q-a` `文档` |
|
|
216
|
+
| [真实的老友](https://chat-preview.lobehub.com/market?agent=ai-0x0-old-friends)<br/><sup>By **[mushan0x0](https://github.com/mushan0x0)** on **2023-11-21**</sup> | 可以跟我谈论一切,我可以给你作为老友的一些想法和建议,放轻松<br/>`友情` `幽默` `真实` `模拟` |
|
|
217
|
+
|
|
218
|
+
> 📊 Total agents: [<kbd>**52**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
219
219
|
|
|
220
220
|
<!-- AGENT LIST -->
|
|
221
221
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.105.1",
|
|
4
4
|
"description": "An open-source, extensible (Function Calling), high-performance chatbot framework. It supports one-click free deployment of your private ChatGPT/LLM web application",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatbot",
|
|
@@ -16,12 +16,16 @@ describe('getPreferredRegion', () => {
|
|
|
16
16
|
|
|
17
17
|
it('returns default value when get config error', () => {
|
|
18
18
|
const originalProcess = global.process;
|
|
19
|
+
const originalError = console.error;
|
|
19
20
|
// @ts-ignore
|
|
20
21
|
global.process = undefined;
|
|
22
|
+
console.error = () => {};
|
|
23
|
+
|
|
21
24
|
const preferredRegion = getPreferredRegion();
|
|
22
25
|
expect(preferredRegion).toBe('auto');
|
|
23
26
|
|
|
24
27
|
global.process = originalProcess;
|
|
28
|
+
console.error = originalError;
|
|
25
29
|
});
|
|
26
30
|
|
|
27
31
|
it('return default value when preferredRegion is empty', () => {
|
package/src/app/chat/features/Conversation/ChatList/Plugins/Render/StandaloneType/Iframe.tsx
CHANGED
|
@@ -23,6 +23,11 @@ import {
|
|
|
23
23
|
sendPluginStateToPlugin,
|
|
24
24
|
} from '../utils/postMessage';
|
|
25
25
|
|
|
26
|
+
// just to simplify code a little, don't use this pattern everywhere
|
|
27
|
+
const getSettings = (identifier: string) =>
|
|
28
|
+
pluginSelectors.getPluginSettingsById(identifier)(usePluginStore.getState());
|
|
29
|
+
const getMessage = (id: string) => chatSelectors.getMessageById(id)(useSessionStore.getState());
|
|
30
|
+
|
|
26
31
|
interface IFrameRenderProps {
|
|
27
32
|
height?: number;
|
|
28
33
|
id: string;
|
|
@@ -39,8 +44,13 @@ const IFrameRender = memo<IFrameRenderProps>(({ url, id, payload, width = 600, h
|
|
|
39
44
|
// when payload change,send content to plugin
|
|
40
45
|
useOnPluginReadyForInteraction(() => {
|
|
41
46
|
const iframeWin = iframeRef.current?.contentWindow;
|
|
47
|
+
|
|
42
48
|
if (iframeWin && payload) {
|
|
43
|
-
|
|
49
|
+
const settings = getSettings(payload.identifier);
|
|
50
|
+
const message = getMessage(id);
|
|
51
|
+
const state = message?.pluginState;
|
|
52
|
+
|
|
53
|
+
sendPayloadToPlugin(iframeWin, { payload, settings, state });
|
|
44
54
|
}
|
|
45
55
|
}, [payload]);
|
|
46
56
|
|
|
@@ -74,7 +84,7 @@ const IFrameRender = memo<IFrameRenderProps>(({ url, id, payload, width = 600, h
|
|
|
74
84
|
const iframeWin = iframeRef.current?.contentWindow;
|
|
75
85
|
|
|
76
86
|
if (iframeWin) {
|
|
77
|
-
const message =
|
|
87
|
+
const message = getMessage(id);
|
|
78
88
|
if (!message) return;
|
|
79
89
|
|
|
80
90
|
sendPluginStateToPlugin(iframeWin, key, message.pluginState?.[key]);
|
|
@@ -94,9 +104,7 @@ const IFrameRender = memo<IFrameRenderProps>(({ url, id, payload, width = 600, h
|
|
|
94
104
|
if (iframeWin) {
|
|
95
105
|
if (!payload?.identifier) return;
|
|
96
106
|
|
|
97
|
-
const settings =
|
|
98
|
-
usePluginStore.getState(),
|
|
99
|
-
);
|
|
107
|
+
const settings = getSettings(payload.identifier);
|
|
100
108
|
|
|
101
109
|
sendPluginSettingsToPlugin(iframeWin, settings);
|
|
102
110
|
}
|
package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/iframeOnReady.test.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { act, renderHook } from '@testing-library/react';
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { useOnPluginReadyForInteraction } from './iframeOnReady';
|
|
6
|
+
|
|
7
|
+
describe('useOnPluginReadyForInteraction', () => {
|
|
8
|
+
const mockOnReady = vi.fn();
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
mockOnReady.mockReset();
|
|
12
|
+
window.removeEventListener('message', expect.any(Function));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('sets readyForRender to true when a PluginChannel.pluginReadyForRender message is received', async () => {
|
|
16
|
+
const { result } = renderHook(() => useOnPluginReadyForInteraction(mockOnReady));
|
|
17
|
+
|
|
18
|
+
expect(result.current).toBe(false); // Initially, readyForRender should be false
|
|
19
|
+
|
|
20
|
+
const event = new MessageEvent('message', {
|
|
21
|
+
data: { type: PluginChannel.pluginReadyForRender },
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
act(() => {
|
|
25
|
+
window.dispatchEvent(event);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(result.current).toBe(true); // After the event, readyForRender should be true
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('sets readyForRender to true when a PluginChannel.pluginReadyForRender message is received', async () => {
|
|
32
|
+
const { result } = renderHook(() => useOnPluginReadyForInteraction(mockOnReady));
|
|
33
|
+
|
|
34
|
+
expect(result.current).toBe(false); // Initially, readyForRender should be false
|
|
35
|
+
|
|
36
|
+
const event = new MessageEvent('message', {
|
|
37
|
+
data: { type: PluginChannel.pluginReadyForRender },
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
act(() => {
|
|
41
|
+
window.dispatchEvent(event);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(result.current).toBe(true); // After the event, readyForRender should be true
|
|
45
|
+
expect(mockOnReady).toHaveBeenCalledTimes(1); // onReady should have been called once
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('does not call onReady for non-pluginReadyForRender messages', async () => {
|
|
49
|
+
renderHook(() => useOnPluginReadyForInteraction(mockOnReady));
|
|
50
|
+
|
|
51
|
+
const event = new MessageEvent('message', {
|
|
52
|
+
data: { type: 'nonPluginReadyMessage' },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
act(() => {
|
|
56
|
+
window.dispatchEvent(event);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
expect(mockOnReady).not.toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('cleans up message event listener on unmount', () => {
|
|
63
|
+
const { unmount } = renderHook(() => useOnPluginReadyForInteraction(mockOnReady));
|
|
64
|
+
|
|
65
|
+
unmount();
|
|
66
|
+
|
|
67
|
+
const event = new MessageEvent('message', {
|
|
68
|
+
data: { type: PluginChannel.pluginReadyForRender },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
window.dispatchEvent(event);
|
|
72
|
+
|
|
73
|
+
expect(mockOnReady).not.toHaveBeenCalled();
|
|
74
|
+
});
|
|
75
|
+
});
|
package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/listenToPlugin.test.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { renderHook } from '@testing-library/react';
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
useOnPluginFetchMessage,
|
|
7
|
+
useOnPluginFetchPluginSettings,
|
|
8
|
+
useOnPluginFetchPluginState,
|
|
9
|
+
useOnPluginFillContent,
|
|
10
|
+
} from './listenToPlugin';
|
|
11
|
+
|
|
12
|
+
afterEach(() => {
|
|
13
|
+
vi.restoreAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('useOnPluginFetchMessage', () => {
|
|
17
|
+
it('calls onRequest when a fetchPluginMessage is received', () => {
|
|
18
|
+
const mockOnRequest = vi.fn();
|
|
19
|
+
renderHook(() => useOnPluginFetchMessage(mockOnRequest));
|
|
20
|
+
|
|
21
|
+
const testData = { key: 'testData', type: PluginChannel.fetchPluginMessage };
|
|
22
|
+
const event = new MessageEvent('message', {
|
|
23
|
+
data: testData,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
window.dispatchEvent(event);
|
|
27
|
+
|
|
28
|
+
expect(mockOnRequest).toHaveBeenCalledWith(testData);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('does not call onRequest for other message types', () => {
|
|
32
|
+
const mockOnRequest = vi.fn();
|
|
33
|
+
renderHook(() => useOnPluginFetchMessage(mockOnRequest));
|
|
34
|
+
|
|
35
|
+
const event = new MessageEvent('message', {
|
|
36
|
+
data: { type: 'otherMessageType' },
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
window.dispatchEvent(event);
|
|
40
|
+
|
|
41
|
+
expect(mockOnRequest).not.toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('useOnPluginFetchPluginState', () => {
|
|
46
|
+
it('calls onRequest with the key when a fetchPluginState message is received', () => {
|
|
47
|
+
const mockOnRequest = vi.fn();
|
|
48
|
+
renderHook(() => useOnPluginFetchPluginState(mockOnRequest));
|
|
49
|
+
|
|
50
|
+
const testKey = 'testKey';
|
|
51
|
+
const event = new MessageEvent('message', {
|
|
52
|
+
data: { type: PluginChannel.fetchPluginState, key: testKey },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
window.dispatchEvent(event);
|
|
56
|
+
|
|
57
|
+
expect(mockOnRequest).toHaveBeenCalledWith(testKey);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('useOnPluginFillContent', () => {
|
|
62
|
+
it('calls callback with content when a fillStandalonePluginContent message is received', () => {
|
|
63
|
+
const mockCallback = vi.fn();
|
|
64
|
+
renderHook(() => useOnPluginFillContent(mockCallback));
|
|
65
|
+
|
|
66
|
+
const testContent = 'testContent';
|
|
67
|
+
const event = new MessageEvent('message', {
|
|
68
|
+
data: { type: PluginChannel.fillStandalonePluginContent, content: testContent },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
window.dispatchEvent(event);
|
|
72
|
+
|
|
73
|
+
expect(mockCallback).toHaveBeenCalledWith(testContent);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('calls callback with JSON stringified content if content is not a string', () => {
|
|
77
|
+
const mockCallback = vi.fn();
|
|
78
|
+
renderHook(() => useOnPluginFillContent(mockCallback));
|
|
79
|
+
|
|
80
|
+
const testContent = { some: 'data' };
|
|
81
|
+
const event = new MessageEvent('message', {
|
|
82
|
+
data: { type: PluginChannel.fillStandalonePluginContent, content: testContent },
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
window.dispatchEvent(event);
|
|
86
|
+
|
|
87
|
+
expect(mockCallback).toHaveBeenCalledWith(JSON.stringify(testContent));
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('useOnPluginFetchPluginSettings', () => {
|
|
92
|
+
it('calls onRequest when a fetchPluginSettings message is received', () => {
|
|
93
|
+
const mockOnRequest = vi.fn();
|
|
94
|
+
renderHook(() => useOnPluginFetchPluginSettings(mockOnRequest));
|
|
95
|
+
|
|
96
|
+
const event = new MessageEvent('message', {
|
|
97
|
+
data: { type: PluginChannel.fetchPluginSettings },
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
window.dispatchEvent(event);
|
|
101
|
+
|
|
102
|
+
expect(mockOnRequest).toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
});
|
package/src/app/chat/features/Conversation/ChatList/Plugins/Render/utils/pluginSettings.test.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { renderHook } from '@testing-library/react';
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { useOnPluginSettingsUpdate } from './pluginSettings';
|
|
6
|
+
|
|
7
|
+
describe('useOnPluginSettingsUpdate', () => {
|
|
8
|
+
const mockCallback = vi.fn();
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
mockCallback.mockReset();
|
|
12
|
+
window.removeEventListener('message', expect.any(Function));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('calls the callback when a PluginChannel updatePluginSettings message is received', () => {
|
|
16
|
+
renderHook(() => useOnPluginSettingsUpdate(mockCallback));
|
|
17
|
+
|
|
18
|
+
const testSettings = { theme: 'dark', notifications: true };
|
|
19
|
+
const event = new MessageEvent('message', {
|
|
20
|
+
data: { type: PluginChannel.updatePluginSettings, value: testSettings },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
window.dispatchEvent(event);
|
|
24
|
+
|
|
25
|
+
expect(mockCallback).toHaveBeenCalledWith(testSettings);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('does not call the callback for non-updatePluginSettings messages', () => {
|
|
29
|
+
renderHook(() => useOnPluginSettingsUpdate(mockCallback));
|
|
30
|
+
|
|
31
|
+
const event = new MessageEvent('message', {
|
|
32
|
+
data: { type: 'nonPluginSettingsUpdate', value: { irrelevant: true } },
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
window.dispatchEvent(event);
|
|
36
|
+
|
|
37
|
+
expect(mockCallback).not.toHaveBeenCalled();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('cleans up message event listener on unmount', () => {
|
|
41
|
+
const { unmount } = renderHook(() => useOnPluginSettingsUpdate(mockCallback));
|
|
42
|
+
|
|
43
|
+
unmount();
|
|
44
|
+
|
|
45
|
+
const event = new MessageEvent('message', {
|
|
46
|
+
data: { type: PluginChannel.updatePluginSettings, value: {} },
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
window.dispatchEvent(event);
|
|
50
|
+
|
|
51
|
+
expect(mockCallback).not.toHaveBeenCalled();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { renderHook } from '@testing-library/react';
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { useOnPluginStateUpdate } from './pluginState';
|
|
6
|
+
|
|
7
|
+
describe('useOnPluginStateUpdate', () => {
|
|
8
|
+
// Mock for the callback function to be used in tests
|
|
9
|
+
const mockCallback = vi.fn();
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
// Reset the mock callback after each test
|
|
13
|
+
mockCallback.mockReset();
|
|
14
|
+
// Ensure no event listeners are left hanging after each test
|
|
15
|
+
window.removeEventListener('message', expect.any(Function));
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('calls the callback when a PluginChannel update message is received', () => {
|
|
19
|
+
renderHook(() => useOnPluginStateUpdate(mockCallback));
|
|
20
|
+
|
|
21
|
+
const testKey = 'testKey';
|
|
22
|
+
const testValue = 'testValue';
|
|
23
|
+
const event = new MessageEvent('message', {
|
|
24
|
+
data: { type: PluginChannel.updatePluginState, key: testKey, value: testValue },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
window.dispatchEvent(event);
|
|
28
|
+
|
|
29
|
+
expect(mockCallback).toHaveBeenCalledWith(testKey, testValue);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('does not call the callback for non-PluginChannel messages', () => {
|
|
33
|
+
renderHook(() => useOnPluginStateUpdate(mockCallback));
|
|
34
|
+
|
|
35
|
+
const event = new MessageEvent('message', {
|
|
36
|
+
data: { type: 'nonPluginMessage', key: 'key', value: 'value' },
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
window.dispatchEvent(event);
|
|
40
|
+
|
|
41
|
+
expect(mockCallback).not.toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { PluginChannel } from '@lobehub/chat-plugin-sdk/client';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
sendMessageContentToPlugin,
|
|
6
|
+
sendPayloadToPlugin,
|
|
7
|
+
sendPluginSettingsToPlugin,
|
|
8
|
+
sendPluginStateToPlugin,
|
|
9
|
+
} from './postMessage';
|
|
10
|
+
|
|
11
|
+
// Mock window object with a postMessage spy
|
|
12
|
+
const mockWindow = {
|
|
13
|
+
postMessage: vi.fn(),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
describe('plugin communication functions', () => {
|
|
17
|
+
it('sendMessageContentToPlugin should call window.postMessage with correct arguments', () => {
|
|
18
|
+
const props = { some: 'data' };
|
|
19
|
+
sendMessageContentToPlugin(mockWindow as unknown as Window, props);
|
|
20
|
+
expect(mockWindow.postMessage).toHaveBeenCalledWith(
|
|
21
|
+
{ props, type: PluginChannel.renderPlugin },
|
|
22
|
+
'*',
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('sendPayloadToPlugin should call window.postMessage with correct arguments', () => {
|
|
27
|
+
const props = { payload: 'payload', settings: 'settings', state: 'state' };
|
|
28
|
+
sendPayloadToPlugin(mockWindow as unknown as Window, props);
|
|
29
|
+
expect(mockWindow.postMessage).toHaveBeenCalledWith(
|
|
30
|
+
{
|
|
31
|
+
type: PluginChannel.initStandalonePlugin,
|
|
32
|
+
payload: props.payload,
|
|
33
|
+
settings: props.settings,
|
|
34
|
+
state: props.state,
|
|
35
|
+
props: props.payload, // Note: This is due to the TODO in your code
|
|
36
|
+
},
|
|
37
|
+
'*',
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('sendPluginStateToPlugin should call window.postMessage with correct arguments', () => {
|
|
42
|
+
const key = 'key';
|
|
43
|
+
const value = 'value';
|
|
44
|
+
sendPluginStateToPlugin(mockWindow as unknown as Window, key, value);
|
|
45
|
+
expect(mockWindow.postMessage).toHaveBeenCalledWith(
|
|
46
|
+
{ key, type: PluginChannel.renderPluginState, value },
|
|
47
|
+
'*',
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('sendPluginSettingsToPlugin should call window.postMessage with correct arguments', () => {
|
|
52
|
+
const settings = { setting1: 'value1' };
|
|
53
|
+
sendPluginSettingsToPlugin(mockWindow as unknown as Window, settings);
|
|
54
|
+
expect(mockWindow.postMessage).toHaveBeenCalledWith(
|
|
55
|
+
{ type: PluginChannel.renderPluginSettings, value: settings },
|
|
56
|
+
'*',
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Reset the mock after each test
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
vi.resetAllMocks();
|
|
64
|
+
});
|
|
@@ -4,8 +4,19 @@ export const sendMessageContentToPlugin = (window: Window, props: any) => {
|
|
|
4
4
|
window.postMessage({ props, type: PluginChannel.renderPlugin }, '*');
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
export const sendPayloadToPlugin = (
|
|
8
|
-
window
|
|
7
|
+
export const sendPayloadToPlugin = (
|
|
8
|
+
window: Window,
|
|
9
|
+
props: { payload: any; settings: any; state?: any },
|
|
10
|
+
) => {
|
|
11
|
+
window.postMessage(
|
|
12
|
+
{
|
|
13
|
+
type: PluginChannel.initStandalonePlugin,
|
|
14
|
+
...props,
|
|
15
|
+
// TODO: props need to deprecated
|
|
16
|
+
props: props.payload,
|
|
17
|
+
},
|
|
18
|
+
'*',
|
|
19
|
+
);
|
|
9
20
|
};
|
|
10
21
|
|
|
11
22
|
export const sendPluginStateToPlugin = (window: Window, key: string, value: any) => {
|