@lmcc-dev/mult-fetch-mcp-server 1.1.0 → 1.2.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/README.md +8 -8
- package/README.zh.md +16 -8
- package/dist/i18n-test-report.json +8 -0
- package/dist/i18n-unused-keys-report.json +8 -0
- package/dist/src/client.js +70 -37
- package/dist/src/index.js +0 -0
- package/dist/src/lib/BrowserFetcher.js +12 -12
- package/dist/src/lib/NodeFetcher.js +22 -22
- package/dist/src/lib/fetch.js +40 -0
- package/dist/src/lib/fetchers/FetcherFactory.js +43 -0
- package/dist/src/lib/fetchers/browser/BrowserFetcher.js +381 -0
- package/dist/src/lib/fetchers/browser/BrowserInstance.js +180 -0
- package/dist/src/lib/fetchers/browser/PageOperations.js +168 -0
- package/dist/src/lib/fetchers/common/types.js +41 -0
- package/dist/src/lib/fetchers/common/utils.js +141 -0
- package/dist/src/lib/fetchers/index.js +62 -0
- package/dist/src/lib/fetchers/node/HttpClient.js +239 -0
- package/dist/src/lib/fetchers/node/NodeFetcher.js +180 -0
- package/dist/src/lib/i18n/index.js +105 -17
- package/dist/src/lib/i18n/keys/base.js +41 -0
- package/dist/src/lib/i18n/keys/browser.js +91 -0
- package/dist/src/lib/i18n/keys/client.js +68 -0
- package/dist/src/lib/i18n/keys/errors.js +49 -0
- package/dist/src/lib/i18n/keys/factory.js +46 -0
- package/dist/src/lib/i18n/keys/fetcher.js +87 -0
- package/dist/src/lib/i18n/keys/index.js +16 -0
- package/dist/src/lib/i18n/keys/node.js +69 -0
- package/dist/src/lib/i18n/keys/prompts.js +79 -0
- package/dist/src/lib/i18n/keys/resources.js +53 -0
- package/dist/src/lib/i18n/keys/server.js +67 -0
- package/dist/src/lib/i18n/keys/tools.js +39 -0
- package/dist/src/lib/i18n/keys.js +488 -119
- package/dist/src/lib/i18n/locales/en/browser.js +67 -57
- package/dist/src/lib/i18n/locales/en/client.js +57 -33
- package/dist/src/lib/i18n/locales/en/errors.js +36 -12
- package/dist/src/lib/i18n/locales/en/factory.js +38 -0
- package/dist/src/lib/i18n/locales/en/fetcher.js +8 -2
- package/dist/src/lib/i18n/locales/en/index.js +10 -8
- package/dist/src/lib/i18n/locales/en/node.js +57 -35
- package/dist/src/lib/i18n/locales/en/prompts.js +42 -65
- package/dist/src/lib/i18n/locales/en/resources.js +52 -55
- package/dist/src/lib/i18n/locales/en/server.js +49 -24
- package/dist/src/lib/i18n/locales/en/tools.js +27 -19
- package/dist/src/lib/i18n/locales/zh/browser.js +71 -62
- package/dist/src/lib/i18n/locales/zh/client.js +57 -32
- package/dist/src/lib/i18n/locales/zh/errors.js +36 -12
- package/dist/src/lib/i18n/locales/zh/factory.js +38 -0
- package/dist/src/lib/i18n/locales/zh/fetcher.js +36 -30
- package/dist/src/lib/i18n/locales/zh/index.js +10 -8
- package/dist/src/lib/i18n/locales/zh/node.js +61 -36
- package/dist/src/lib/i18n/locales/zh/prompts.js +35 -57
- package/dist/src/lib/i18n/locales/zh/resources.js +52 -55
- package/dist/src/lib/i18n/locales/zh/server.js +51 -25
- package/dist/src/lib/i18n/locales/zh/tools.js +27 -19
- package/dist/src/lib/i18n/logger.js +90 -19
- package/dist/src/lib/logger.js +135 -14
- package/dist/src/lib/server/browser.js +42 -10
- package/dist/src/lib/server/fetcher.js +87 -37
- package/dist/src/lib/server/index.js +2 -2
- package/dist/src/lib/server/prompts.js +1 -1
- package/dist/src/lib/server/resources.js +1 -1
- package/dist/src/lib/server/tools.js +46 -10
- package/dist/src/lib/utils/ErrorHandler.js +125 -0
- package/dist/src/mcp-server.js +0 -0
- package/dist/src/test-i18n.js +139 -0
- package/dist/tests/BrowserFetcher.test.js +0 -0
- package/dist/tests/NodeFetcher.test.js +0 -0
- package/dist/tests/client.test.js +42 -81
- package/dist/tests/fetch.test.js +70 -0
- package/dist/tests/fetchers/Fetcher.test.js +108 -0
- package/dist/tests/fetchers/browser/BrowserFetcher.test.js +195 -0
- package/dist/tests/fetchers/browser/BrowserInstance.test.js +163 -0
- package/dist/tests/fetchers/node/NodeFetcher.test.js +211 -0
- package/dist/tests/i18n-missing-keys.js +364 -0
- package/dist/tests/i18n-remove-unused-keys.js +236 -0
- package/dist/tests/i18n-test-report.json +2004 -0
- package/dist/tests/i18n-unused-keys.js +425 -0
- package/dist/tests/i18n.test.js +6 -7
- package/dist/tests/logger.test.js +14 -13
- package/dist/tests/mcp-server.test.js +7 -7
- package/dist/tests/server/browser.test.js +25 -21
- package/dist/tests/server/fetcher.test.js +58 -101
- package/dist/tests/server/index.test.js +30 -30
- package/dist/tests/server/prompts.test.js +36 -33
- package/dist/tests/server/resources.test.js +120 -84
- package/dist/tests/server/tools.test.js +7 -6
- package/dist/tests/setup.js +36 -0
- package/dist/tests/src/lib/i18n/index.js +108 -0
- package/dist/tests/src/lib/i18n/keys/base.js +47 -0
- package/dist/tests/src/lib/i18n/keys/browser.js +93 -0
- package/dist/tests/src/lib/i18n/keys/client.js +70 -0
- package/dist/tests/src/lib/i18n/keys/errors.js +34 -0
- package/dist/tests/src/lib/i18n/keys/fetcher.js +84 -0
- package/dist/tests/src/lib/i18n/keys/index.js +31 -0
- package/dist/tests/src/lib/i18n/keys/node.js +56 -0
- package/dist/tests/src/lib/i18n/keys/prompts.js +82 -0
- package/dist/tests/src/lib/i18n/keys/resources.js +50 -0
- package/dist/tests/src/lib/i18n/keys/server.js +64 -0
- package/dist/tests/src/lib/i18n/keys/tools.js +34 -0
- package/dist/tests/src/lib/i18n/locales/en/browser.js +88 -0
- package/dist/tests/src/lib/i18n/locales/en/client.js +66 -0
- package/dist/tests/src/lib/i18n/locales/en/errors.js +28 -0
- package/dist/tests/src/lib/i18n/locales/en/fetcher.js +71 -0
- package/dist/tests/src/lib/i18n/locales/en/index.js +29 -0
- package/dist/tests/src/lib/i18n/locales/en/node.js +51 -0
- package/dist/tests/src/lib/i18n/locales/en/prompts.js +52 -0
- package/dist/tests/src/lib/i18n/locales/en/resources.js +50 -0
- package/dist/tests/src/lib/i18n/locales/en/server.js +56 -0
- package/dist/tests/src/lib/i18n/locales/en/tools.js +28 -0
- package/dist/tests/src/lib/i18n/locales/zh/browser.js +87 -0
- package/dist/tests/src/lib/i18n/locales/zh/client.js +66 -0
- package/dist/tests/src/lib/i18n/locales/zh/errors.js +28 -0
- package/dist/tests/src/lib/i18n/locales/zh/fetcher.js +71 -0
- package/dist/tests/src/lib/i18n/locales/zh/index.js +29 -0
- package/dist/tests/src/lib/i18n/locales/zh/node.js +51 -0
- package/dist/tests/src/lib/i18n/locales/zh/prompts.js +53 -0
- package/dist/tests/src/lib/i18n/locales/zh/resources.js +50 -0
- package/dist/tests/src/lib/i18n/locales/zh/server.js +57 -0
- package/dist/tests/src/lib/i18n/locales/zh/tools.js +28 -0
- package/dist/tests/src/lib/i18n/logger.js +114 -0
- package/dist/tests/src/lib/logger.js +181 -0
- package/dist/tests/test-direct-client.js +0 -0
- package/dist/tests/test-i18n.js +530 -0
- package/dist/tests/test-mcp-methods.js +1 -1
- package/dist/tests/test-mcp.js +0 -0
- package/dist/tests/test-mini4k.js +0 -0
- package/dist/tests/tests/test-i18n.js +588 -0
- package/dist/tests/types.test.js +1 -1
- package/dist/tests/utils/ErrorHandler.test.js +144 -0
- package/dist/vitest.config.js +29 -0
- package/package.json +31 -27
- package/dist/src/cli-language.js +0 -78
- package/dist/src/client.d.ts +0 -6
- package/dist/src/client.js.map +0 -1
- package/dist/src/index.d.ts +0 -15
- package/dist/src/index.js.map +0 -1
- package/dist/src/lib/BrowserFetcher.d.ts +0 -175
- package/dist/src/lib/BrowserFetcher.js.map +0 -1
- package/dist/src/lib/NodeFetcher.d.ts +0 -92
- package/dist/src/lib/NodeFetcher.js.map +0 -1
- package/dist/src/lib/example.js +0 -93
- package/dist/src/lib/i18n/index.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/browser.d.ts +0 -61
- package/dist/src/lib/i18n/locales/en/browser.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/client.d.ts +0 -39
- package/dist/src/lib/i18n/locales/en/client.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/errors.d.ts +0 -17
- package/dist/src/lib/i18n/locales/en/errors.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/fetcher.d.ts +0 -66
- package/dist/src/lib/i18n/locales/en/fetcher.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/index.d.ts +0 -344
- package/dist/src/lib/i18n/locales/en/index.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/node.d.ts +0 -41
- package/dist/src/lib/i18n/locales/en/node.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/prompts.d.ts +0 -65
- package/dist/src/lib/i18n/locales/en/prompts.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/resources.d.ts +0 -41
- package/dist/src/lib/i18n/locales/en/resources.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/server.d.ts +0 -30
- package/dist/src/lib/i18n/locales/en/server.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/tools.d.ts +0 -24
- package/dist/src/lib/i18n/locales/en/tools.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/browser.d.ts +0 -61
- package/dist/src/lib/i18n/locales/zh/browser.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/client.d.ts +0 -38
- package/dist/src/lib/i18n/locales/zh/client.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/errors.d.ts +0 -17
- package/dist/src/lib/i18n/locales/zh/errors.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/fetcher.d.ts +0 -66
- package/dist/src/lib/i18n/locales/zh/fetcher.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/index.d.ts +0 -343
- package/dist/src/lib/i18n/locales/zh/index.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/node.d.ts +0 -41
- package/dist/src/lib/i18n/locales/zh/node.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/prompts.d.ts +0 -65
- package/dist/src/lib/i18n/locales/zh/prompts.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/resources.d.ts +0 -41
- package/dist/src/lib/i18n/locales/zh/resources.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/server.d.ts +0 -30
- package/dist/src/lib/i18n/locales/zh/server.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/tools.d.ts +0 -24
- package/dist/src/lib/i18n/locales/zh/tools.js.map +0 -1
- package/dist/src/lib/i18n/logger.d.ts +0 -38
- package/dist/src/lib/i18n/logger.js.map +0 -1
- package/dist/src/lib/logger.d.ts +0 -32
- package/dist/src/lib/logger.js.map +0 -1
- package/dist/src/lib/server/browser.d.ts +0 -34
- package/dist/src/lib/server/browser.js.map +0 -1
- package/dist/src/lib/server/fetcher.d.ts +0 -20
- package/dist/src/lib/server/fetcher.js.map +0 -1
- package/dist/src/lib/server/index.d.ts +0 -10
- package/dist/src/lib/server/index.js.map +0 -1
- package/dist/src/lib/server/logger.js +0 -23
- package/dist/src/lib/server/prompts.d.ts +0 -11
- package/dist/src/lib/server/prompts.js.map +0 -1
- package/dist/src/lib/server/resources.d.ts +0 -11
- package/dist/src/lib/server/resources.js.map +0 -1
- package/dist/src/lib/server/tools.d.ts +0 -12
- package/dist/src/lib/server/tools.js.map +0 -1
- package/dist/src/lib/server/types.d.ts +0 -71
- package/dist/src/lib/server/types.js.map +0 -1
- package/dist/src/lib/types.d.ts +0 -119
- package/dist/src/lib/types.js.map +0 -1
- package/dist/src/mcp-server.d.ts +0 -6
- package/dist/src/mcp-server.js.map +0 -1
- package/dist/tests/jest.setup.d.ts +0 -6
- package/dist/tests/jest.setup.js +0 -30
- package/dist/tests/jest.setup.js.map +0 -1
- package/dist/tests/test-direct-client.d.ts +0 -6
- package/dist/tests/test-direct-client.js.map +0 -1
- package/dist/tests/test-mcp-methods.d.ts +0 -6
- package/dist/tests/test-mcp-methods.js.map +0 -1
- package/dist/tests/test-mcp.d.ts +0 -6
- package/dist/tests/test-mcp.js.map +0 -1
- package/dist/tests/test-mini4k.d.ts +0 -6
- package/dist/tests/test-mini4k.js.map +0 -1
|
@@ -3,24 +3,27 @@
|
|
|
3
3
|
* Co-Author: AI Assistant (Claude)
|
|
4
4
|
* Description: This code was collaboratively developed by Martin and AI Assistant.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { BrowserInstance } from '../../src/lib/fetchers/browser/BrowserInstance.js';
|
|
7
|
+
import { vi, describe, test, expect, beforeEach } from 'vitest';
|
|
8
|
+
import * as logger from '../../src/lib/logger.js';
|
|
9
|
+
import * as browserModule from '../../src/lib/server/browser.js';
|
|
7
10
|
// 模拟依赖
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
vi.mock('../../src/lib/fetchers/browser/BrowserInstance.js');
|
|
12
|
+
vi.mock('../../src/lib/logger.js', () => {
|
|
10
13
|
return {
|
|
11
|
-
log:
|
|
14
|
+
log: vi.fn(),
|
|
12
15
|
COMPONENTS: {
|
|
13
16
|
SERVER: 'server'
|
|
14
17
|
}
|
|
15
18
|
};
|
|
16
19
|
});
|
|
17
20
|
// 获取模拟的 log 函数和 COMPONENTS
|
|
18
|
-
const { log, COMPONENTS } =
|
|
21
|
+
const { log, COMPONENTS } = logger;
|
|
19
22
|
// 模拟 browser.js 模块
|
|
20
23
|
let browserInitialized = false;
|
|
21
|
-
|
|
24
|
+
vi.mock('../../src/lib/server/browser.js', () => {
|
|
22
25
|
return {
|
|
23
|
-
initializeBrowser:
|
|
26
|
+
initializeBrowser: vi.fn(async (debug = false) => {
|
|
24
27
|
if (!browserInitialized) {
|
|
25
28
|
if (debug) {
|
|
26
29
|
log('server.initializingBrowser', debug, {}, COMPONENTS.SERVER);
|
|
@@ -28,16 +31,16 @@ jest.mock('../../src/lib/server/browser.js', () => {
|
|
|
28
31
|
browserInitialized = true;
|
|
29
32
|
}
|
|
30
33
|
}),
|
|
31
|
-
closeBrowserInstance:
|
|
34
|
+
closeBrowserInstance: vi.fn(async (debug = false) => {
|
|
32
35
|
if (browserInitialized) {
|
|
33
36
|
if (debug) {
|
|
34
37
|
log('server.closingBrowser', debug, {}, COMPONENTS.SERVER);
|
|
35
38
|
}
|
|
36
|
-
await
|
|
39
|
+
await BrowserInstance.closeBrowser(debug);
|
|
37
40
|
browserInitialized = false;
|
|
38
41
|
}
|
|
39
42
|
}),
|
|
40
|
-
shouldSwitchToBrowser:
|
|
43
|
+
shouldSwitchToBrowser: vi.fn((error) => {
|
|
41
44
|
if (error && error.message) {
|
|
42
45
|
const errorMessage = error.message.toLowerCase();
|
|
43
46
|
return errorMessage.includes('403') ||
|
|
@@ -48,26 +51,27 @@ jest.mock('../../src/lib/server/browser.js', () => {
|
|
|
48
51
|
}
|
|
49
52
|
return false;
|
|
50
53
|
}),
|
|
51
|
-
shouldUseBrowser:
|
|
54
|
+
shouldUseBrowser: vi.fn((response, url) => {
|
|
52
55
|
if (response.isError) {
|
|
53
56
|
const errorText = response.content[0].text.toLowerCase();
|
|
54
57
|
return errorText.includes('403') ||
|
|
55
58
|
errorText.includes('forbidden') ||
|
|
56
59
|
errorText.includes('cloudflare') ||
|
|
57
|
-
errorText.includes('
|
|
60
|
+
errorText.includes('timeout') ||
|
|
61
|
+
errorText.includes('econnrefused');
|
|
58
62
|
}
|
|
59
63
|
return false;
|
|
60
64
|
})
|
|
61
65
|
};
|
|
62
66
|
});
|
|
63
|
-
//
|
|
64
|
-
const { initializeBrowser, closeBrowserInstance, shouldSwitchToBrowser, shouldUseBrowser } =
|
|
67
|
+
// 从模块中获取函数
|
|
68
|
+
const { initializeBrowser, closeBrowserInstance, shouldSwitchToBrowser, shouldUseBrowser } = browserModule;
|
|
65
69
|
describe('浏览器管理函数测试 (Browser Management Functions Tests)', () => {
|
|
66
70
|
beforeEach(() => {
|
|
67
71
|
// 重置所有模拟
|
|
68
|
-
|
|
72
|
+
vi.clearAllMocks();
|
|
69
73
|
// 设置默认返回值
|
|
70
|
-
|
|
74
|
+
BrowserInstance.closeBrowser.mockResolvedValue(undefined);
|
|
71
75
|
// 重置 browserInitialized 变量
|
|
72
76
|
browserInitialized = false;
|
|
73
77
|
});
|
|
@@ -87,7 +91,7 @@ describe('浏览器管理函数测试 (Browser Management Functions Tests)', ()
|
|
|
87
91
|
test('应该只初始化一次浏览器 (Should initialize browser only once)', async () => {
|
|
88
92
|
// 调用被测试的函数两次
|
|
89
93
|
await initializeBrowser(true);
|
|
90
|
-
|
|
94
|
+
vi.clearAllMocks(); // 清除第一次调用的记录
|
|
91
95
|
await initializeBrowser(true);
|
|
92
96
|
// 验证第二次调用时 log 函数没有被调用
|
|
93
97
|
expect(log).not.toHaveBeenCalled();
|
|
@@ -99,8 +103,8 @@ describe('浏览器管理函数测试 (Browser Management Functions Tests)', ()
|
|
|
99
103
|
await initializeBrowser();
|
|
100
104
|
// 调用被测试的函数
|
|
101
105
|
await closeBrowserInstance();
|
|
102
|
-
// 验证
|
|
103
|
-
expect(
|
|
106
|
+
// 验证 BrowserInstance.closeBrowser 被调用
|
|
107
|
+
expect(BrowserInstance.closeBrowser).toHaveBeenCalled();
|
|
104
108
|
});
|
|
105
109
|
test('应该在调试模式下记录日志 (Should log in debug mode)', async () => {
|
|
106
110
|
// 首先初始化浏览器
|
|
@@ -115,8 +119,8 @@ describe('浏览器管理函数测试 (Browser Management Functions Tests)', ()
|
|
|
115
119
|
browserInitialized = false;
|
|
116
120
|
// 调用被测试的函数
|
|
117
121
|
await closeBrowserInstance();
|
|
118
|
-
// 验证
|
|
119
|
-
expect(
|
|
122
|
+
// 验证 BrowserInstance.closeBrowser 没有被调用
|
|
123
|
+
expect(BrowserInstance.closeBrowser).not.toHaveBeenCalled();
|
|
120
124
|
});
|
|
121
125
|
});
|
|
122
126
|
describe('shouldSwitchToBrowser 函数测试 (shouldSwitchToBrowser Function Tests)', () => {
|
|
@@ -4,15 +4,14 @@
|
|
|
4
4
|
* Description: This code was collaboratively developed by Martin and AI Assistant.
|
|
5
5
|
*/
|
|
6
6
|
import { fetchWithAutoDetect } from '../../src/lib/server/fetcher.js';
|
|
7
|
-
import {
|
|
8
|
-
import { NodeFetcher } from '../../src/lib/NodeFetcher.js';
|
|
7
|
+
import { Fetcher } from '../../src/lib/fetch.js';
|
|
9
8
|
import { initializeBrowser, closeBrowserInstance, shouldSwitchToBrowser } from '../../src/lib/server/browser.js';
|
|
9
|
+
import { vi, describe, test, expect, beforeEach } from 'vitest';
|
|
10
10
|
// 模拟依赖
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
log: jest.fn(),
|
|
11
|
+
vi.mock('../../src/lib/fetch.js');
|
|
12
|
+
vi.mock('../../src/lib/server/browser.js');
|
|
13
|
+
vi.mock('../../src/lib/logger.js', () => ({
|
|
14
|
+
log: vi.fn(),
|
|
16
15
|
COMPONENTS: {
|
|
17
16
|
SERVER: 'server'
|
|
18
17
|
}
|
|
@@ -20,153 +19,135 @@ jest.mock('../../src/lib/logger.js', () => ({
|
|
|
20
19
|
describe('fetchWithAutoDetect 函数测试 (fetchWithAutoDetect Function Tests)', () => {
|
|
21
20
|
beforeEach(() => {
|
|
22
21
|
// 重置所有模拟
|
|
23
|
-
|
|
22
|
+
vi.clearAllMocks();
|
|
24
23
|
// 设置默认返回值
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
NodeFetcher.txt.mockResolvedValue({ text: 'Test text' });
|
|
28
|
-
NodeFetcher.markdown.mockResolvedValue({ markdown: '# Test' });
|
|
29
|
-
BrowserFetcher.html.mockResolvedValue({
|
|
30
|
-
content: [{ type: 'text', text: '<html>Browser Test</html>' }],
|
|
24
|
+
Fetcher.html.mockResolvedValue({
|
|
25
|
+
content: [{ type: 'text', text: '<html>Test</html>' }],
|
|
31
26
|
isError: false
|
|
32
27
|
});
|
|
33
|
-
|
|
34
|
-
content: [{ type: 'text', text: '{"test":"
|
|
28
|
+
Fetcher.json.mockResolvedValue({
|
|
29
|
+
content: [{ type: 'text', text: '{"test":"data"}' }],
|
|
35
30
|
isError: false
|
|
36
31
|
});
|
|
37
|
-
|
|
38
|
-
content: [{ type: 'text', text: '
|
|
32
|
+
Fetcher.txt.mockResolvedValue({
|
|
33
|
+
content: [{ type: 'text', text: 'Test text' }],
|
|
39
34
|
isError: false
|
|
40
35
|
});
|
|
41
|
-
|
|
42
|
-
content: [{ type: 'text', text: '#
|
|
36
|
+
Fetcher.markdown.mockResolvedValue({
|
|
37
|
+
content: [{ type: 'text', text: '# Test' }],
|
|
43
38
|
isError: false
|
|
44
39
|
});
|
|
45
40
|
initializeBrowser.mockResolvedValue(undefined);
|
|
46
41
|
closeBrowserInstance.mockResolvedValue(undefined);
|
|
47
42
|
shouldSwitchToBrowser.mockReturnValue(false);
|
|
48
43
|
});
|
|
49
|
-
test('应该使用
|
|
44
|
+
test('应该使用 Fetcher 获取 HTML (Should use Fetcher to fetch HTML)', async () => {
|
|
50
45
|
const params = { url: 'https://example.com' };
|
|
51
46
|
const result = await fetchWithAutoDetect(params, 'html');
|
|
52
|
-
expect(
|
|
53
|
-
expect(BrowserFetcher.html).not.toHaveBeenCalled();
|
|
47
|
+
expect(Fetcher.html).toHaveBeenCalledWith(params);
|
|
54
48
|
expect(result).toEqual({
|
|
55
49
|
content: [{ type: 'text', text: '<html>Test</html>' }],
|
|
56
50
|
isError: false
|
|
57
51
|
});
|
|
58
52
|
});
|
|
59
|
-
test('应该使用
|
|
53
|
+
test('应该使用 Fetcher 获取 JSON (Should use Fetcher to fetch JSON)', async () => {
|
|
60
54
|
const params = { url: 'https://example.com/data.json' };
|
|
61
55
|
const result = await fetchWithAutoDetect(params, 'json');
|
|
62
|
-
expect(
|
|
63
|
-
expect(BrowserFetcher.json).not.toHaveBeenCalled();
|
|
56
|
+
expect(Fetcher.json).toHaveBeenCalledWith(params);
|
|
64
57
|
expect(result).toEqual({
|
|
65
|
-
content: [{ type: 'text', text:
|
|
58
|
+
content: [{ type: 'text', text: '{"test":"data"}' }],
|
|
66
59
|
isError: false
|
|
67
60
|
});
|
|
68
61
|
});
|
|
69
|
-
test('应该使用
|
|
62
|
+
test('应该使用 Fetcher 获取文本 (Should use Fetcher to fetch text)', async () => {
|
|
70
63
|
const params = { url: 'https://example.com/text.txt' };
|
|
71
64
|
const result = await fetchWithAutoDetect(params, 'txt');
|
|
72
|
-
expect(
|
|
73
|
-
expect(BrowserFetcher.txt).not.toHaveBeenCalled();
|
|
65
|
+
expect(Fetcher.txt).toHaveBeenCalledWith(params);
|
|
74
66
|
expect(result).toEqual({
|
|
75
67
|
content: [{ type: 'text', text: 'Test text' }],
|
|
76
68
|
isError: false
|
|
77
69
|
});
|
|
78
70
|
});
|
|
79
|
-
test('应该使用
|
|
71
|
+
test('应该使用 Fetcher 获取 Markdown (Should use Fetcher to fetch Markdown)', async () => {
|
|
80
72
|
const params = { url: 'https://example.com/readme.md' };
|
|
81
73
|
const result = await fetchWithAutoDetect(params, 'markdown');
|
|
82
|
-
expect(
|
|
83
|
-
expect(BrowserFetcher.markdown).not.toHaveBeenCalled();
|
|
74
|
+
expect(Fetcher.markdown).toHaveBeenCalledWith(params);
|
|
84
75
|
expect(result).toEqual({
|
|
85
76
|
content: [{ type: 'text', text: '# Test' }],
|
|
86
77
|
isError: false
|
|
87
78
|
});
|
|
88
79
|
});
|
|
89
|
-
test('
|
|
80
|
+
test('应该在浏览器模式下使用 Fetcher 获取 HTML (Should use Fetcher to fetch HTML in browser mode)', async () => {
|
|
90
81
|
const params = { url: 'https://example.com', useBrowser: true };
|
|
82
|
+
// 设置浏览器模式下的返回值
|
|
83
|
+
Fetcher.html.mockResolvedValue({
|
|
84
|
+
content: [{ type: 'text', text: '<html>Browser Test</html>' }],
|
|
85
|
+
isError: false
|
|
86
|
+
});
|
|
91
87
|
const result = await fetchWithAutoDetect(params, 'html');
|
|
92
88
|
expect(initializeBrowser).toHaveBeenCalled();
|
|
93
|
-
expect(
|
|
94
|
-
expect(BrowserFetcher.html).toHaveBeenCalledWith({ ...params, debug: false });
|
|
89
|
+
expect(Fetcher.html).toHaveBeenCalledWith({ ...params, debug: false });
|
|
95
90
|
expect(result).toEqual({
|
|
96
91
|
content: [{ type: 'text', text: '<html>Browser Test</html>' }],
|
|
97
92
|
isError: false
|
|
98
93
|
});
|
|
99
94
|
});
|
|
100
|
-
test('
|
|
95
|
+
test('应该在浏览器模式下使用 Fetcher 获取 JSON (Should use Fetcher to fetch JSON in browser mode)', async () => {
|
|
101
96
|
const params = { url: 'https://example.com/data.json', useBrowser: true };
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
expect(NodeFetcher.json).not.toHaveBeenCalled();
|
|
105
|
-
expect(BrowserFetcher.json).toHaveBeenCalledWith({ ...params, debug: false });
|
|
106
|
-
expect(result).toEqual({
|
|
97
|
+
// 设置浏览器模式下的返回值
|
|
98
|
+
Fetcher.json.mockResolvedValue({
|
|
107
99
|
content: [{ type: 'text', text: '{"test":"browser data"}' }],
|
|
108
100
|
isError: false
|
|
109
101
|
});
|
|
110
|
-
|
|
111
|
-
test('应该使用 BrowserFetcher 获取文本 (Should use BrowserFetcher to fetch text)', async () => {
|
|
112
|
-
const params = { url: 'https://example.com/text.txt', useBrowser: true };
|
|
113
|
-
const result = await fetchWithAutoDetect(params, 'txt');
|
|
102
|
+
const result = await fetchWithAutoDetect(params, 'json');
|
|
114
103
|
expect(initializeBrowser).toHaveBeenCalled();
|
|
115
|
-
expect(
|
|
116
|
-
expect(BrowserFetcher.txt).toHaveBeenCalledWith({ ...params, debug: false });
|
|
104
|
+
expect(Fetcher.json).toHaveBeenCalledWith({ ...params, debug: false });
|
|
117
105
|
expect(result).toEqual({
|
|
118
|
-
content: [{ type: 'text', text: '
|
|
106
|
+
content: [{ type: 'text', text: '{"test":"browser data"}' }],
|
|
119
107
|
isError: false
|
|
120
108
|
});
|
|
121
109
|
});
|
|
122
|
-
test('
|
|
123
|
-
const params = { url: 'https://example.com
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
content: [{ type: 'text', text: '# Browser Test' }],
|
|
110
|
+
test('应该在 Fetcher 失败时自动切换到浏览器模式 (Should automatically switch to browser mode when Fetcher fails)', async () => {
|
|
111
|
+
const params = { url: 'https://example.com' };
|
|
112
|
+
// 设置 Fetcher 第一次调用抛出错误,第二次调用成功
|
|
113
|
+
Fetcher.html
|
|
114
|
+
.mockRejectedValueOnce(new Error('Fetch failed'))
|
|
115
|
+
.mockResolvedValueOnce({
|
|
116
|
+
content: [{ type: 'text', text: '<html>Browser Test</html>' }],
|
|
130
117
|
isError: false
|
|
131
118
|
});
|
|
132
|
-
});
|
|
133
|
-
test('应该在 NodeFetcher 失败时自动切换到 BrowserFetcher (Should automatically switch to BrowserFetcher when NodeFetcher fails)', async () => {
|
|
134
|
-
const params = { url: 'https://example.com' };
|
|
135
|
-
// 设置 NodeFetcher 抛出错误
|
|
136
|
-
NodeFetcher.html.mockRejectedValue(new Error('Fetch failed'));
|
|
137
119
|
// 设置 shouldSwitchToBrowser 返回 true
|
|
138
120
|
shouldSwitchToBrowser.mockReturnValue(true);
|
|
139
121
|
const result = await fetchWithAutoDetect(params, 'html');
|
|
140
|
-
expect(
|
|
122
|
+
expect(Fetcher.html).toHaveBeenCalledTimes(2);
|
|
123
|
+
expect(Fetcher.html).toHaveBeenNthCalledWith(1, params);
|
|
124
|
+
expect(Fetcher.html).toHaveBeenNthCalledWith(2, { ...params, useBrowser: true, debug: false });
|
|
141
125
|
expect(shouldSwitchToBrowser).toHaveBeenCalled();
|
|
142
126
|
expect(initializeBrowser).toHaveBeenCalled();
|
|
143
|
-
expect(BrowserFetcher.html).toHaveBeenCalledWith({ ...params, useBrowser: true, debug: false });
|
|
144
127
|
expect(result).toEqual({
|
|
145
128
|
content: [{ type: 'text', text: '<html>Browser Test</html>' }],
|
|
146
129
|
isError: false
|
|
147
130
|
});
|
|
148
131
|
});
|
|
149
|
-
test('应该在
|
|
132
|
+
test('应该在 Fetcher 失败且不需要切换时抛出原始错误 (Should throw original error when Fetcher fails and no switch is needed)', async () => {
|
|
150
133
|
const params = { url: 'https://example.com' };
|
|
151
|
-
// 设置
|
|
134
|
+
// 设置 Fetcher 抛出错误
|
|
152
135
|
const originalError = new Error('Fetch failed');
|
|
153
|
-
|
|
136
|
+
Fetcher.html.mockRejectedValue(originalError);
|
|
154
137
|
// 设置 shouldSwitchToBrowser 返回 false
|
|
155
138
|
shouldSwitchToBrowser.mockReturnValue(false);
|
|
156
139
|
await expect(fetchWithAutoDetect(params, 'html')).rejects.toThrow(originalError);
|
|
157
|
-
expect(
|
|
140
|
+
expect(Fetcher.html).toHaveBeenCalledWith(params);
|
|
158
141
|
expect(shouldSwitchToBrowser).toHaveBeenCalled();
|
|
159
|
-
expect(BrowserFetcher.html).not.toHaveBeenCalled();
|
|
160
142
|
});
|
|
161
143
|
test('应该在 autoDetectMode 为 false 时不自动切换 (Should not automatically switch when autoDetectMode is false)', async () => {
|
|
162
144
|
const params = { url: 'https://example.com', autoDetectMode: false };
|
|
163
|
-
// 设置
|
|
145
|
+
// 设置 Fetcher 抛出错误
|
|
164
146
|
const originalError = new Error('Fetch failed');
|
|
165
|
-
|
|
147
|
+
Fetcher.html.mockRejectedValue(originalError);
|
|
166
148
|
await expect(fetchWithAutoDetect(params, 'html')).rejects.toThrow(originalError);
|
|
167
|
-
expect(
|
|
149
|
+
expect(Fetcher.html).toHaveBeenCalledWith(params);
|
|
168
150
|
expect(shouldSwitchToBrowser).not.toHaveBeenCalled();
|
|
169
|
-
expect(BrowserFetcher.html).not.toHaveBeenCalled();
|
|
170
151
|
});
|
|
171
152
|
test('应该在 closeBrowser 为 true 时关闭浏览器 (Should close browser when closeBrowser is true)', async () => {
|
|
172
153
|
const params = { url: 'https://example.com', useBrowser: true, closeBrowser: true };
|
|
@@ -176,41 +157,17 @@ describe('fetchWithAutoDetect 函数测试 (fetchWithAutoDetect Function Tests)'
|
|
|
176
157
|
// 手动调用 closeBrowserInstance 函数,模拟外部调用
|
|
177
158
|
await closeBrowserInstance(false);
|
|
178
159
|
expect(initializeBrowser).toHaveBeenCalled();
|
|
179
|
-
expect(
|
|
160
|
+
expect(Fetcher.html).toHaveBeenCalled();
|
|
180
161
|
expect(closeBrowserInstance).toHaveBeenCalled();
|
|
181
162
|
});
|
|
182
163
|
test('应该在出错且 closeBrowser 为 true 时关闭浏览器 (Should close browser when error occurs and closeBrowser is true)', async () => {
|
|
183
164
|
const params = { url: 'https://example.com', useBrowser: true, closeBrowser: true };
|
|
184
|
-
// 设置
|
|
165
|
+
// 设置 Fetcher 抛出错误
|
|
185
166
|
const originalError = new Error('Browser fetch failed');
|
|
186
|
-
|
|
167
|
+
Fetcher.html.mockRejectedValue(originalError);
|
|
187
168
|
await expect(fetchWithAutoDetect(params, 'html')).rejects.toThrow(originalError);
|
|
188
169
|
expect(initializeBrowser).toHaveBeenCalled();
|
|
189
|
-
expect(
|
|
170
|
+
expect(Fetcher.html).toHaveBeenCalled();
|
|
190
171
|
expect(closeBrowserInstance).toHaveBeenCalled();
|
|
191
172
|
});
|
|
192
|
-
test('应该处理 JSON 对象和字符串 (Should handle JSON objects and strings)', async () => {
|
|
193
|
-
// 测试 JSON 对象
|
|
194
|
-
NodeFetcher.json.mockResolvedValue({ json: { test: 'data' } });
|
|
195
|
-
let result = await fetchWithAutoDetect({ url: 'https://example.com/data.json' }, 'json');
|
|
196
|
-
expect(result).toEqual({
|
|
197
|
-
content: [{ type: 'text', text: JSON.stringify({ test: 'data' }, null, 2) }],
|
|
198
|
-
isError: false
|
|
199
|
-
});
|
|
200
|
-
// 测试 JSON 字符串
|
|
201
|
-
NodeFetcher.json.mockResolvedValue({ json: '{"test":"string data"}' });
|
|
202
|
-
result = await fetchWithAutoDetect({ url: 'https://example.com/data.json' }, 'json');
|
|
203
|
-
expect(result).toEqual({
|
|
204
|
-
content: [{ type: 'text', text: '{"test":"string data"}' }],
|
|
205
|
-
isError: false
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
test('应该返回不支持的内容类型错误 (Should return unsupported content type error)', async () => {
|
|
209
|
-
// @ts-ignore - 故意传入不支持的类型
|
|
210
|
-
const result = await fetchWithAutoDetect({ url: 'https://example.com' }, 'unsupported');
|
|
211
|
-
expect(result).toEqual({
|
|
212
|
-
content: [{ type: 'text', text: 'Unsupported content type: unsupported' }],
|
|
213
|
-
isError: true
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
173
|
});
|
|
@@ -3,32 +3,33 @@
|
|
|
3
3
|
* Co-Author: AI Assistant (Claude)
|
|
4
4
|
* Description: This code was collaboratively developed by Martin and AI Assistant.
|
|
5
5
|
*/
|
|
6
|
+
import { vi, describe, test, expect, beforeEach, afterEach } from 'vitest';
|
|
6
7
|
// 模拟依赖
|
|
7
|
-
|
|
8
|
-
Server:
|
|
9
|
-
connect:
|
|
10
|
-
registerTool:
|
|
11
|
-
registerResource:
|
|
12
|
-
registerPrompt:
|
|
8
|
+
vi.mock('@modelcontextprotocol/sdk/server/index.js', () => ({
|
|
9
|
+
Server: vi.fn().mockImplementation(() => ({
|
|
10
|
+
connect: vi.fn().mockResolvedValue(undefined),
|
|
11
|
+
registerTool: vi.fn(),
|
|
12
|
+
registerResource: vi.fn(),
|
|
13
|
+
registerPrompt: vi.fn()
|
|
13
14
|
}))
|
|
14
15
|
}));
|
|
15
|
-
|
|
16
|
-
StdioServerTransport:
|
|
16
|
+
vi.mock('@modelcontextprotocol/sdk/server/stdio.js', () => ({
|
|
17
|
+
StdioServerTransport: vi.fn().mockImplementation(() => ({}))
|
|
17
18
|
}));
|
|
18
|
-
|
|
19
|
-
registerTools:
|
|
19
|
+
vi.mock('../../src/lib/server/tools.js', () => ({
|
|
20
|
+
registerTools: vi.fn()
|
|
20
21
|
}));
|
|
21
|
-
|
|
22
|
-
registerResources:
|
|
22
|
+
vi.mock('../../src/lib/server/resources.js', () => ({
|
|
23
|
+
registerResources: vi.fn()
|
|
23
24
|
}));
|
|
24
|
-
|
|
25
|
-
registerPrompts:
|
|
25
|
+
vi.mock('../../src/lib/server/prompts.js', () => ({
|
|
26
|
+
registerPrompts: vi.fn()
|
|
26
27
|
}));
|
|
27
|
-
|
|
28
|
-
closeBrowserInstance:
|
|
28
|
+
vi.mock('../../src/lib/server/browser.js', () => ({
|
|
29
|
+
closeBrowserInstance: vi.fn().mockResolvedValue(undefined)
|
|
29
30
|
}));
|
|
30
|
-
|
|
31
|
-
log:
|
|
31
|
+
vi.mock('../../src/lib/logger.js', () => ({
|
|
32
|
+
log: vi.fn(),
|
|
32
33
|
COMPONENTS: {
|
|
33
34
|
SERVER: 'SERVER'
|
|
34
35
|
}
|
|
@@ -42,15 +43,15 @@ describe('MCP服务器信号处理测试 (MCP Server Signal Handling Tests)', ()
|
|
|
42
43
|
const originalProcessOn = process.on;
|
|
43
44
|
const originalProcessExit = process.exit;
|
|
44
45
|
// 存储信号处理函数
|
|
45
|
-
let exitHandler;
|
|
46
|
-
let sigintHandler;
|
|
47
|
-
let sigtermHandler;
|
|
48
|
-
let uncaughtExceptionHandler;
|
|
49
|
-
beforeEach(() => {
|
|
46
|
+
let exitHandler = null;
|
|
47
|
+
let sigintHandler = null;
|
|
48
|
+
let sigtermHandler = null;
|
|
49
|
+
let uncaughtExceptionHandler = null;
|
|
50
|
+
beforeEach(async () => {
|
|
50
51
|
// 重置所有模拟
|
|
51
|
-
|
|
52
|
+
vi.clearAllMocks();
|
|
52
53
|
// 模拟process.on
|
|
53
|
-
process.on =
|
|
54
|
+
process.on = vi.fn().mockImplementation((event, handler) => {
|
|
54
55
|
// 存储处理函数以便测试
|
|
55
56
|
if (event === 'exit') {
|
|
56
57
|
exitHandler = handler;
|
|
@@ -67,12 +68,11 @@ describe('MCP服务器信号处理测试 (MCP Server Signal Handling Tests)', ()
|
|
|
67
68
|
return process;
|
|
68
69
|
});
|
|
69
70
|
// 模拟process.exit
|
|
70
|
-
process.exit =
|
|
71
|
+
process.exit = vi.fn();
|
|
71
72
|
// 导入startServer函数
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
73
|
+
// 使用动态导入而不是isolateModules
|
|
74
|
+
const serverModule = await import('../../src/lib/server/index.js');
|
|
75
|
+
serverModule.startServer();
|
|
76
76
|
});
|
|
77
77
|
afterEach(() => {
|
|
78
78
|
// 恢复原始的process.on和process.exit
|
|
@@ -4,9 +4,11 @@
|
|
|
4
4
|
* Description: This code was collaboratively developed by Martin and AI Assistant.
|
|
5
5
|
*/
|
|
6
6
|
import { registerPrompts } from "../../src/lib/server/prompts.js";
|
|
7
|
-
import { ListPromptsRequestSchema, GetPromptRequestSchema } from
|
|
7
|
+
import { ListPromptsRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
8
|
+
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
|
9
|
+
import * as logger from '../../src/lib/logger.js';
|
|
8
10
|
// 模拟i18n模块
|
|
9
|
-
|
|
11
|
+
vi.mock('../../src/lib/i18n/index.js', () => ({
|
|
10
12
|
t: (key) => {
|
|
11
13
|
const translations = {
|
|
12
14
|
'prompts.fetchWebsite.description': '获取网站内容',
|
|
@@ -44,56 +46,57 @@ jest.mock('../../src/lib/i18n/index.js', () => ({
|
|
|
44
46
|
}
|
|
45
47
|
}));
|
|
46
48
|
// 模拟logger模块
|
|
47
|
-
|
|
48
|
-
log:
|
|
49
|
+
vi.mock('../../src/lib/logger.js', () => ({
|
|
50
|
+
log: vi.fn(),
|
|
49
51
|
COMPONENTS: {
|
|
50
52
|
PROMPTS: 'prompts'
|
|
51
53
|
}
|
|
52
54
|
}));
|
|
53
|
-
describe('
|
|
54
|
-
let
|
|
55
|
+
describe('提示模块测试 (Prompts Module Tests)', () => {
|
|
56
|
+
let mockServer;
|
|
57
|
+
let mockSetRequestHandler;
|
|
55
58
|
let listPromptsHandler;
|
|
56
59
|
let getPromptHandler;
|
|
57
60
|
beforeEach(() => {
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
61
|
+
// 重置所有模拟
|
|
62
|
+
vi.clearAllMocks();
|
|
63
|
+
// 创建模拟的 Server 实例
|
|
64
|
+
mockSetRequestHandler = vi.fn((schema, handler) => {
|
|
65
|
+
if (schema === ListPromptsRequestSchema) {
|
|
66
|
+
listPromptsHandler = handler;
|
|
67
|
+
}
|
|
68
|
+
else if (schema === GetPromptRequestSchema) {
|
|
69
|
+
getPromptHandler = handler;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
mockServer = {
|
|
73
|
+
setRequestHandler: mockSetRequestHandler
|
|
68
74
|
};
|
|
69
75
|
// 注册提示处理程序
|
|
70
|
-
registerPrompts(
|
|
76
|
+
registerPrompts(mockServer);
|
|
71
77
|
});
|
|
72
78
|
describe('registerPrompts', () => {
|
|
73
79
|
it('应该注册ListPromptsRequestSchema和GetPromptRequestSchema处理程序', () => {
|
|
74
|
-
expect(
|
|
75
|
-
expect(
|
|
76
|
-
expect(
|
|
80
|
+
expect(mockServer.setRequestHandler).toHaveBeenCalledTimes(2);
|
|
81
|
+
expect(mockServer.setRequestHandler).toHaveBeenCalledWith(ListPromptsRequestSchema, expect.any(Function));
|
|
82
|
+
expect(mockServer.setRequestHandler).toHaveBeenCalledWith(GetPromptRequestSchema, expect.any(Function));
|
|
77
83
|
});
|
|
78
84
|
});
|
|
79
85
|
describe('ListPromptsRequestSchema处理程序', () => {
|
|
80
86
|
it('应该返回所有可用的提示', async () => {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
expect(
|
|
84
|
-
expect(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
expect(
|
|
89
|
-
expect(promptNames).toContain('mult-fetch-mcp:prompt:extract-content');
|
|
90
|
-
expect(promptNames).toContain('mult-fetch-mcp:prompt:debug-fetch');
|
|
87
|
+
const result = await listPromptsHandler({});
|
|
88
|
+
expect(result).toHaveProperty('prompts');
|
|
89
|
+
expect(Array.isArray(result.prompts)).toBe(true);
|
|
90
|
+
expect(result.prompts.length).toBeGreaterThan(0);
|
|
91
|
+
// 验证提示格式
|
|
92
|
+
const prompt = result.prompts[0];
|
|
93
|
+
expect(prompt).toHaveProperty('name');
|
|
94
|
+
expect(prompt).toHaveProperty('description');
|
|
91
95
|
});
|
|
92
96
|
it('应该处理debug参数', async () => {
|
|
93
|
-
const
|
|
94
|
-
await listPromptsHandler(request);
|
|
97
|
+
const result = await listPromptsHandler({ params: { debug: true } });
|
|
95
98
|
// 验证日志调用
|
|
96
|
-
expect(
|
|
99
|
+
expect(logger.log).toHaveBeenCalledWith('prompts.list.request', true, expect.any(Object), 'prompts');
|
|
97
100
|
});
|
|
98
101
|
});
|
|
99
102
|
describe('GetPromptRequestSchema处理程序', () => {
|