forked from patternfly/patternfly-mcp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtool.patternFlyDocs.test.ts
More file actions
147 lines (132 loc) · 4.42 KB
/
tool.patternFlyDocs.test.ts
File metadata and controls
147 lines (132 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { McpError } from '@modelcontextprotocol/sdk/types.js';
import { usePatternFlyDocsTool } from '../tool.patternFlyDocs';
import { processDocsFunction } from '../server.getResources';
import { isPlainObject } from '../server.helpers';
// Mock dependencies
jest.mock('../server.getResources');
jest.mock('../server.caching', () => ({
memo: jest.fn(fn => fn)
}));
const mockProcessDocs = processDocsFunction as jest.MockedFunction<typeof processDocsFunction>;
describe('usePatternFlyDocsTool', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should have a consistent return structure', () => {
const tool = usePatternFlyDocsTool();
expect({
name: tool[0],
schema: isPlainObject(tool[1]),
callback: tool[2]
}).toMatchSnapshot('structure');
});
});
describe('usePatternFlyDocsTool, callback', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it.each([
{
description: 'single file, mock path',
processedValue: {
path: 'components/button.md',
content: 'single documentation content'
},
urlList: ['components/button.md']
},
{
description: 'multiple files, mock paths',
processedValue: {
path: 'components/button.md',
content: 'combined documentation content'
},
urlList: ['components/button.md', 'components/card.md', 'components/table.md']
},
{
description: 'with invalid urlList',
processedValue: {
path: 'invalid-path',
content: 'Failed to load'
},
urlList: ['invalid-url']
},
{
description: 'with name and actual path',
processedValue: {
path: 'documentation:chatbot/README.md',
content: 'chatbot documentation content'
},
name: 'chatbot'
}
])('should attempt to parse parameters, $description', async ({ processedValue, urlList, name }) => {
mockProcessDocs.mockResolvedValue([processedValue] as any);
const [_name, _schema, callback] = usePatternFlyDocsTool();
const result = await callback({ urlList, name });
expect(mockProcessDocs).toHaveBeenCalledTimes(1);
expect(result.content[0].text).toBeDefined();
expect(result.content[0].text.split('\n')[0]).toMatchSnapshot();
});
it.each([
{
description: 'with missing or undefined urlList',
error: 'Provide either a string',
urlList: undefined
},
{
description: 'with null urlList',
error: 'Provide either a string',
urlList: null
},
{
description: 'when urlList is not an array',
error: 'Provide either a string',
urlList: 'not-an-array'
},
{
description: 'with empty files',
error: 'array must contain strings',
urlList: ['components/button.md', '', ' ', 'components/card.md', 'components/table.md']
},
{
description: 'with empty urlList',
error: 'Provide either a string',
urlList: []
},
{
description: 'with empty strings in a urlList',
error: 'array must contain strings',
urlList: ['', ' ']
},
{
description: 'with both urlList and name',
error: 'Provide either a string',
urlList: ['components/button.md'],
name: 'lorem ipsum'
}
])('should handle errors, $description', async ({ error, urlList, name }) => {
const [_name, _schema, callback] = usePatternFlyDocsTool();
await expect(callback({ urlList, name })).rejects.toThrow(McpError);
await expect(callback({ urlList, name })).rejects.toThrow(error);
});
it('should handle processing errors', async () => {
mockProcessDocs.mockRejectedValue(new Error('File not found'));
const [_name, _schema, callback] = usePatternFlyDocsTool();
await expect(callback({ urlList: ['https://www.patternfly.org//missing.md'] })).rejects.toThrow(McpError);
await expect(callback({ urlList: ['https://www.patternfly.org/missing.md'] })).rejects.toThrow('Failed to fetch documentation');
});
it('should have a specific markdown format', async () => {
mockProcessDocs.mockResolvedValue([
{
path: 'components/loremButton.md',
content: 'lorem documentation content'
},
{
path: 'components/ipsumButton.md',
content: 'ipsum documentation content'
}
] as any);
const [_name, _schema, callback] = usePatternFlyDocsTool();
const result = await callback({ name: 'button' });
expect(result.content).toMatchSnapshot('Button');
});
});