@splunk/splunk-ui-mcp 0.1.0 → 0.2.0

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.
Files changed (33) hide show
  1. package/README.md +10 -3
  2. package/lib/constants/versions.js +3 -3
  3. package/lib/index.js +6 -4
  4. package/lib/resources/components.js +12 -6
  5. package/lib/resources/design-tokens.d.ts +17 -0
  6. package/lib/resources/design-tokens.js +113 -0
  7. package/lib/tools/find_component.d.ts +19 -0
  8. package/lib/tools/find_component.js +93 -0
  9. package/lib/tools/find_design_token.d.ts +16 -0
  10. package/lib/tools/find_design_token.js +126 -0
  11. package/lib/tools/{find_icons.d.ts → find_icon.d.ts} +2 -2
  12. package/lib/tools/{find_icons.js → find_icon.js} +5 -5
  13. package/lib/utils/component-catalog.d.ts +19 -2
  14. package/lib/utils/component-catalog.js +77 -29
  15. package/lib/utils/design-token-catalog.d.ts +33 -0
  16. package/lib/utils/design-token-catalog.js +158 -0
  17. package/lib/utils/package-assets.d.ts +8 -0
  18. package/lib/utils/package-assets.js +35 -0
  19. package/package.json +14 -10
  20. package/lib/resources/tests/components.unit.d.ts +0 -1
  21. package/lib/resources/tests/components.unit.js +0 -133
  22. package/lib/resources/tests/icons.unit.d.ts +0 -1
  23. package/lib/resources/tests/icons.unit.js +0 -161
  24. package/lib/tools/get_component_docs.d.ts +0 -19
  25. package/lib/tools/get_component_docs.js +0 -82
  26. package/lib/tools/tests/find_icons.unit.d.ts +0 -1
  27. package/lib/tools/tests/find_icons.unit.js +0 -149
  28. package/lib/tools/tests/get_component_docs.unit.d.ts +0 -1
  29. package/lib/tools/tests/get_component_docs.unit.js +0 -131
  30. package/lib/tools/tests/requirements.unit.d.ts +0 -1
  31. package/lib/tools/tests/requirements.unit.js +0 -34
  32. package/lib/utils/tests/component-catalog.unit.d.ts +0 -1
  33. package/lib/utils/tests/component-catalog.unit.js +0 -144
@@ -1,161 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- const ICON_CATALOG_FIXTURE = vi.hoisted(() => [
3
- {
4
- name: 'SearchIcon',
5
- category: 'Interface',
6
- description: 'Use for search interactions.',
7
- keywords: 'search, magnify, find',
8
- variants: ['default', 'filled'],
9
- },
10
- {
11
- name: 'AlertIcon',
12
- keywords: 'alert, warning',
13
- },
14
- ]);
15
- vi.mock('@splunk/react-icons/icon-catalog.json', () => ({
16
- default: ICON_CATALOG_FIXTURE,
17
- }));
18
- describe('createIconResourceUri', () => {
19
- it('builds an encoded MCP URI for the provided icon name', async () => {
20
- const { createIconResourceUri, ICON_RESOURCE_URI_BASE } = await import("../icons.js");
21
- expect(createIconResourceUri('SimpleIcon')).toBe(`${ICON_RESOURCE_URI_BASE}/SimpleIcon`);
22
- expect(createIconResourceUri('Icon With Spaces')).toBe(`${ICON_RESOURCE_URI_BASE}/Icon%20With%20Spaces`);
23
- expect(createIconResourceUri('Icon/Separators')).toBe(`${ICON_RESOURCE_URI_BASE}/Icon%2FSeparators`);
24
- });
25
- });
26
- describe('icon resources', () => {
27
- beforeEach(() => {
28
- vi.resetModules();
29
- });
30
- describe('createIconResourceLink', () => {
31
- it('includes catalog metadata when the icon exists', async () => {
32
- const { createIconResourceLink, createIconResourceUri } = await import("../icons.js");
33
- const link = createIconResourceLink('SearchIcon');
34
- expect(link).toMatchObject({
35
- type: 'resource_link',
36
- name: 'SearchIcon',
37
- title: 'SearchIcon',
38
- uri: createIconResourceUri('SearchIcon'),
39
- description: 'Use for search interactions.',
40
- mimeType: 'application/json',
41
- });
42
- });
43
- it('falls back to minimal metadata when the icon is unknown', async () => {
44
- const { createIconResourceLink, createIconResourceUri } = await import("../icons.js");
45
- const link = createIconResourceLink('MissingIcon');
46
- expect(link).toMatchObject({
47
- type: 'resource_link',
48
- name: 'MissingIcon',
49
- title: 'MissingIcon',
50
- uri: createIconResourceUri('MissingIcon'),
51
- description: undefined,
52
- mimeType: 'application/json',
53
- });
54
- });
55
- });
56
- describe('getIconResourceDetails', () => {
57
- it('returns structured details for known icons', async () => {
58
- const { getIconResourceDetails } = await import("../icons.js");
59
- const details = getIconResourceDetails('SearchIcon');
60
- expect(details).toMatchObject({
61
- name: 'SearchIcon',
62
- importPath: '@splunk/react-icons/SearchIcon',
63
- category: 'Interface',
64
- description: 'Use for search interactions.',
65
- keywords: 'search, magnify, find',
66
- variants: ['default', 'filled'],
67
- });
68
- expect(details?.usageExample).toContain('SearchIcon');
69
- });
70
- it('returns undefined when the icon is missing', async () => {
71
- const { getIconResourceDetails } = await import("../icons.js");
72
- expect(getIconResourceDetails('MissingIcon')).toBeUndefined();
73
- });
74
- it('accepts catalog entries directly', async () => {
75
- const { getIconResourceDetails } = await import("../icons.js");
76
- const details = getIconResourceDetails({
77
- name: 'AlertIcon',
78
- key: './AlertIcon',
79
- keywords: 'alert, warning',
80
- variants: ['default'],
81
- description: 'An alert icon.',
82
- category: '',
83
- });
84
- expect(details).toMatchObject({
85
- name: 'AlertIcon',
86
- importPath: '@splunk/react-icons/AlertIcon',
87
- });
88
- expect(details.usageExample).toContain('AlertIcon');
89
- });
90
- });
91
- describe('iconResource', () => {
92
- const setup = async () => {
93
- const { default: iconResource, createIconResourceUri } = await import("../icons.js");
94
- return {
95
- iconResource,
96
- createIconResourceUri,
97
- };
98
- };
99
- it('provides the expected metadata configuration', async () => {
100
- const { iconResource } = await setup();
101
- expect(iconResource.name).toBe('splunk-ui-icons');
102
- expect(iconResource.config).toMatchObject({
103
- title: expect.stringContaining('Icon Catalog'),
104
- mimeType: 'application/json',
105
- });
106
- });
107
- it('lists icons from the catalog', async () => {
108
- const { iconResource } = await setup();
109
- const { template } = iconResource;
110
- const listResult = await template.listCallback?.();
111
- expect(listResult).toMatchObject({
112
- resources: expect.arrayContaining([
113
- expect.objectContaining({ name: 'SearchIcon' }),
114
- expect.objectContaining({ name: 'AlertIcon' }),
115
- ]),
116
- });
117
- });
118
- it('suggests icon names using the completion handler', async () => {
119
- const { iconResource } = await setup();
120
- const complete = iconResource.template.completeCallback?.('iconName');
121
- const completions = (await complete?.('se')) ?? [];
122
- expect(completions).toContain('SearchIcon');
123
- expect(completions).not.toContain('AlertIcon');
124
- });
125
- it('reads icon details using request variables', async () => {
126
- const { iconResource, createIconResourceUri } = await setup();
127
- expect(typeof iconResource.handler).toBe('function');
128
- const readResult = await iconResource.handler(new URL(createIconResourceUri('AlertIcon')), { iconName: 'AlertIcon' });
129
- const [content] = readResult.contents;
130
- expect(content).toMatchObject({
131
- uri: createIconResourceUri('AlertIcon'),
132
- mimeType: 'application/json',
133
- });
134
- const parsed = JSON.parse(String(content.text ?? '{}'));
135
- expect(parsed).toMatchObject({
136
- name: 'AlertIcon',
137
- importPath: '@splunk/react-icons/AlertIcon',
138
- keywords: 'alert, warning',
139
- });
140
- expect(parsed.usageExample).toContain('AlertIcon');
141
- // Ensure the template reference is exercised for coverage.
142
- expect(iconResource.template).toBeDefined();
143
- });
144
- it('derives the icon name from the URI when variables are absent', async () => {
145
- const { iconResource, createIconResourceUri } = await setup();
146
- const readWithoutVariable = (await iconResource.handler(new URL(createIconResourceUri('SearchIcon')), {}));
147
- const [content] = readWithoutVariable.contents;
148
- expect(JSON.parse(String(content.text))).toMatchObject({ name: 'SearchIcon' });
149
- });
150
- it('throws when the icon cannot be resolved from variables or the URI', async () => {
151
- const { iconResource } = await setup();
152
- expect(() => iconResource.handler(new URL('mcp://splunk-ui'), {})).toThrowError('Icon name missing in resource request: mcp://splunk-ui');
153
- });
154
- it('throws when the requested icon is not found in the catalog', async () => {
155
- const { iconResource, createIconResourceUri } = await setup();
156
- expect(() => iconResource.handler(new URL(createIconResourceUri('MissingIcon')), {
157
- iconName: 'MissingIcon',
158
- })).toThrowError('Unknown icon "MissingIcon"');
159
- });
160
- });
161
- });
@@ -1,19 +0,0 @@
1
- import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
- import { z } from 'zod';
3
- /**
4
- * Tool to get documentation for a specific React UI component
5
- */
6
- declare const getComponentDocsTool: {
7
- name: string;
8
- config: {
9
- title: string;
10
- description: string;
11
- inputSchema: {
12
- componentName: z.ZodString;
13
- };
14
- };
15
- handler: ({ componentName }: {
16
- componentName?: string;
17
- }) => CallToolResult;
18
- };
19
- export default getComponentDocsTool;
@@ -1,82 +0,0 @@
1
- import { z } from 'zod';
2
- import { createComponentResourceLink } from "../resources/components.js";
3
- import { componentExists, getComponentDocs, getComponentList } from "../utils/component-catalog.js";
4
- /**
5
- * Tool to get documentation for a specific React UI component
6
- */
7
- const getComponentDocsTool = {
8
- name: 'get_component_docs',
9
- config: {
10
- title: 'Get Component Documentation',
11
- description: 'Retrieves the full documentation for a specific @splunk/react-ui component. ' +
12
- 'Includes overview, usage guidelines, examples, API documentation, and accessibility information.',
13
- inputSchema: {
14
- componentName: z
15
- .string()
16
- .describe('The exact name of the component (e.g., "Button", "Card Layout", "Text"). ' +
17
- 'Case-sensitive. Use the component name as it appears in the catalog.'),
18
- },
19
- },
20
- handler: ({ componentName }) => {
21
- if (!componentName || componentName.trim().length === 0) {
22
- return {
23
- content: [
24
- {
25
- type: 'text',
26
- text: 'Component name is required. Please provide a component name.',
27
- },
28
- ],
29
- };
30
- }
31
- // Check if component exists
32
- if (!componentExists(componentName)) {
33
- const components = getComponentList();
34
- const availableNames = components.map((c) => c.name).slice(0, 10);
35
- return {
36
- content: [
37
- {
38
- type: 'text',
39
- text: `Component "${componentName}" not found.\n\n` +
40
- `Available components include: ${availableNames.join(', ')}, and more.\n\n` +
41
- 'Component names are case-sensitive. Please check the spelling and try again.',
42
- },
43
- ],
44
- };
45
- }
46
- // Get the documentation
47
- try {
48
- const docs = getComponentDocs(componentName);
49
- return {
50
- content: [
51
- {
52
- type: 'text',
53
- text: docs,
54
- },
55
- createComponentResourceLink(componentName),
56
- ],
57
- };
58
- }
59
- catch (error) {
60
- return {
61
- content: [
62
- {
63
- type: 'text',
64
- text: `Failed to retrieve documentation for "${componentName}": ${error.message}`,
65
- },
66
- ],
67
- isError: true,
68
- };
69
- }
70
- },
71
- };
72
- export default getComponentDocsTool;
73
- // TODO: Future enhancement - add section extraction
74
- // Allow requesting specific sections of documentation:
75
- // - Overview
76
- // - Examples
77
- // - API/Props
78
- // - Accessibility
79
- // - Test Hooks
80
- //
81
- // Example:
82
- // export function getComponentSection(componentName: string, section: string): CallToolResult
@@ -1 +0,0 @@
1
- export {};
@@ -1,149 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest';
2
- const NO_RESULTS_TEXT = 'No icons found. Try different keywords like "search", "notification", "user", "chart", etc.';
3
- const ICON_CATALOG_FIXTURE = vi.hoisted(() => [
4
- {
5
- name: 'SearchIcon',
6
- key: './SearchIcon',
7
- category: 'Interface',
8
- description: 'Use for search interactions.',
9
- keywords: 'search, magnify, find',
10
- variants: ['default', 'filled'],
11
- },
12
- {
13
- name: 'AlertIcon',
14
- key: './AlertIcon',
15
- description: 'Communicates alert or warning states.',
16
- keywords: 'alert, warning',
17
- },
18
- {
19
- name: 'UserIcon',
20
- key: './UserIcon',
21
- keywords: 'profile, account',
22
- },
23
- { name: 'PrimaryIcon', key: './PrimaryIcon' },
24
- { name: 'AltOne', key: './AltOne' },
25
- { name: 'AltTwo', key: './AltTwo' },
26
- { name: 'AltThree', key: './AltThree' },
27
- { name: 'AltFour', key: './AltFour' },
28
- { name: 'AltFive', key: './AltFive' },
29
- { name: 'SoloIcon', key: './SoloIcon' },
30
- ]);
31
- const INDEXED_DATA = { indexed: true };
32
- const addSearchDataMock = vi.fn();
33
- const searchMock = vi.fn();
34
- vi.mock('@splunk/react-icons/icon-catalog.json', () => ({
35
- default: ICON_CATALOG_FIXTURE,
36
- }));
37
- vi.mock('@splunk/ui-utils/search', () => ({
38
- addSearchData: addSearchDataMock,
39
- search: searchMock,
40
- }));
41
- describe('find_icons tool', () => {
42
- beforeEach(() => {
43
- vi.resetModules();
44
- addSearchDataMock.mockReset();
45
- searchMock.mockReset();
46
- searchMock.mockReturnValue([]);
47
- addSearchDataMock.mockReturnValue(INDEXED_DATA);
48
- });
49
- it('exposes metadata and prepares search index', async () => {
50
- const { default: tool } = await import("../find_icons.js");
51
- expect(tool.name).toBe('find_icons');
52
- expect('config' in tool).toBe(true);
53
- expect(tool.config?.title).toBeDefined();
54
- expect(tool.config?.description).toBeDefined();
55
- expect(tool.config.inputSchema?.query).toBeDefined();
56
- });
57
- it('prepares search index', async () => {
58
- addSearchDataMock.mockReturnValue({
59
- mock: true,
60
- });
61
- await import("../find_icons.js");
62
- expect(addSearchDataMock).toHaveBeenCalledWith(ICON_CATALOG_FIXTURE);
63
- expect(addSearchDataMock).toHaveReturnedWith({ mock: true });
64
- });
65
- describe('handler', () => {
66
- it('returns guidance when query is empty', async () => {
67
- const { default: tool } = await import("../find_icons.js");
68
- const result = tool.handler({ query: '' });
69
- expect(searchMock).not.toHaveBeenCalled();
70
- expect(result.content[0]?.type).toBe('text');
71
- expect(result.content[0]?.text).toBe(NO_RESULTS_TEXT);
72
- });
73
- it('returns guidance when no icons match search', async () => {
74
- const { default: tool } = await import("../find_icons.js");
75
- const result = tool.handler({ query: 'alert' });
76
- expect(searchMock).toHaveBeenCalledWith('alert', INDEXED_DATA);
77
- expect(result.content[0]?.text).toBe(NO_RESULTS_TEXT);
78
- });
79
- it('returns icon details and alternative resource links when matches are found', async () => {
80
- searchMock.mockReturnValue([
81
- {
82
- name: 'SearchIcon',
83
- description: 'Use for search interactions.',
84
- searchScore: { nameScore: 100, keywordsScore: 20, descriptionScore: 0 },
85
- },
86
- { name: 'AlertIcon', description: 'Communicates alert or warning states.' },
87
- { name: 'UserIcon', keywords: 'profile, account' },
88
- ]);
89
- const { default: tool } = await import("../find_icons.js");
90
- const result = tool.handler({ query: 'search' });
91
- expect(searchMock).toHaveBeenCalledWith('search', INDEXED_DATA);
92
- const [summary, ...rest] = result.content;
93
- const resourceLinks = rest.filter((item) => item?.type === 'resource_link');
94
- expect(summary).toMatchObject({ type: 'text' });
95
- const summaryText = summary?.text ?? '';
96
- expect(summaryText).toContain('# Icons for "search"');
97
- expect(summaryText).toContain('## Recommended Icon');
98
- expect(summaryText).toContain('Recommended to use <SearchIcon /> for "search"');
99
- expect(summaryText).toContain('- Import: `@splunk/react-icons/SearchIcon`');
100
- expect(summaryText).toContain('- Category: Interface');
101
- expect(summaryText).toContain('- Keywords: search, magnify, find');
102
- expect(summaryText).toContain('```tsx');
103
- expect(summaryText).toContain('Follow the resource links below for full metadata and usage snippets.');
104
- expect(summaryText).toContain('## Alternative Icons');
105
- expect(summaryText).toContain('- AlertIcon');
106
- expect(summaryText).toContain('- UserIcon');
107
- expect(resourceLinks).toHaveLength(3);
108
- expect(resourceLinks[0]).toMatchObject({
109
- name: 'SearchIcon',
110
- uri: 'mcp://splunk-ui/icons/SearchIcon',
111
- });
112
- expect(resourceLinks[1]).toMatchObject({
113
- name: 'AlertIcon',
114
- uri: 'mcp://splunk-ui/icons/AlertIcon',
115
- });
116
- expect(resourceLinks[2]).toMatchObject({
117
- name: 'UserIcon',
118
- uri: 'mcp://splunk-ui/icons/UserIcon',
119
- });
120
- });
121
- it('limits alternative icons to four entries', async () => {
122
- searchMock.mockReturnValue([
123
- { name: 'PrimaryIcon' },
124
- { name: 'AltOne' },
125
- { name: 'AltTwo' },
126
- { name: 'AltThree' },
127
- { name: 'AltFour' },
128
- { name: 'AltFive' },
129
- ]);
130
- const { default: tool } = await import("../find_icons.js");
131
- const result = tool.handler({ query: 'primary' });
132
- const summaryText = result.content[0]?.type === 'text' ? (result.content[0]?.text ?? '') : '';
133
- expect(summaryText).toContain('- AltOne');
134
- expect(summaryText).toContain('- AltTwo');
135
- expect(summaryText).toContain('- AltThree');
136
- expect(summaryText).toContain('- AltFour');
137
- expect(summaryText).not.toContain('- AltFive');
138
- });
139
- it('omits alternative section when only one icon matches', async () => {
140
- const { default: tool } = await import("../find_icons.js");
141
- const { handler } = tool;
142
- const args = { query: 'solo' };
143
- searchMock.mockReturnValue([{ name: 'SoloIcon' }]);
144
- const result = await handler(args);
145
- const summaryText = result.content[0]?.type === 'text' ? (result.content[0]?.text ?? '') : '';
146
- expect(summaryText).not.toContain('## Alternative Icons');
147
- });
148
- });
149
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,131 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach } from 'vitest';
2
- const MOCK_COMPONENT_LIST = [
3
- {
4
- name: 'Button',
5
- filename: 'Button.md',
6
- category: 'Base',
7
- },
8
- {
9
- name: 'Card Layout',
10
- filename: 'Card Layout.md',
11
- category: 'Base',
12
- },
13
- {
14
- name: 'Text',
15
- filename: 'Text.md',
16
- category: 'Data Entry',
17
- },
18
- ];
19
- const MOCK_BUTTON_DOCS = `# Button
20
-
21
- ## Overview
22
-
23
- A button component for triggering actions.
24
-
25
- ## Examples
26
-
27
- \`\`\`typescript
28
- import Button from '@splunk/react-ui/Button';
29
-
30
- <Button label="Click me" />
31
- \`\`\`
32
-
33
- ## API
34
-
35
- ### Props
36
-
37
- - label: string
38
- - onClick: () => void
39
- `;
40
- // Mock the component catalog
41
- vi.mock('../../utils/component-catalog.ts', () => ({
42
- getComponentList: vi.fn(() => MOCK_COMPONENT_LIST),
43
- componentExists: vi.fn((name) => MOCK_COMPONENT_LIST.some((c) => c.name === name)),
44
- getComponentDocs: vi.fn((name) => {
45
- if (name === 'Button') {
46
- return MOCK_BUTTON_DOCS;
47
- }
48
- throw new Error(`Component "${name}" not found in catalog`);
49
- }),
50
- }));
51
- // Mock the components resource
52
- vi.mock('../../resources/components.ts', () => ({
53
- createComponentResourceLink: vi.fn((name) => ({
54
- type: 'resource_link',
55
- uri: `mcp://splunk-ui/components/${encodeURIComponent(name)}`,
56
- name,
57
- })),
58
- }));
59
- describe('get_component_docs tool', () => {
60
- beforeEach(() => {
61
- vi.clearAllMocks();
62
- });
63
- it('returns documentation for an existing component', async () => {
64
- const tool = (await import("../get_component_docs.js")).default;
65
- const result = tool.handler({ componentName: 'Button' });
66
- expect(result.content).toHaveLength(2);
67
- expect(result.content[0]).toMatchObject({
68
- type: 'text',
69
- text: MOCK_BUTTON_DOCS,
70
- });
71
- expect(result.content[1]).toMatchObject({
72
- type: 'resource_link',
73
- name: 'Button',
74
- });
75
- });
76
- it('returns error message for non-existent component', async () => {
77
- const tool = (await import("../get_component_docs.js")).default;
78
- const result = tool.handler({ componentName: 'NonExistent' });
79
- expect(result.content).toHaveLength(1);
80
- expect(result.content[0]).toMatchObject({
81
- type: 'text',
82
- });
83
- expect(result.content[0].text).toContain('Component "NonExistent" not found');
84
- expect(result.content[0].text).toContain('Available components include');
85
- });
86
- it('handles empty component name', async () => {
87
- const tool = (await import("../get_component_docs.js")).default;
88
- const result = tool.handler({ componentName: '' });
89
- expect(result.content).toHaveLength(1);
90
- expect(result.content[0]).toMatchObject({
91
- type: 'text',
92
- });
93
- expect(result.content[0].text).toContain('Component name is required');
94
- });
95
- it('handles whitespace-only component name', async () => {
96
- const tool = (await import("../get_component_docs.js")).default;
97
- const result = tool.handler({ componentName: ' ' });
98
- expect(result.content).toHaveLength(1);
99
- expect(result.content[0]).toMatchObject({
100
- type: 'text',
101
- });
102
- expect(result.content[0].text).toContain('Component name is required');
103
- });
104
- it('handles errors when reading documentation', async () => {
105
- const { getComponentDocs } = await import("../../utils/component-catalog.js");
106
- // Mock an error for a specific component
107
- getComponentDocs.mockImplementationOnce(() => {
108
- throw new Error('File system error');
109
- });
110
- const tool = (await import("../get_component_docs.js")).default;
111
- const result = tool.handler({ componentName: 'Button' });
112
- expect(result.isError).toBe(true);
113
- expect(result.content).toHaveLength(1);
114
- expect(result.content[0].text).toContain('Failed to retrieve documentation');
115
- expect(result.content[0].text).toContain('File system error');
116
- });
117
- it('includes resource link in successful response', async () => {
118
- const { createComponentResourceLink } = await import("../../resources/components.js");
119
- const tool = (await import("../get_component_docs.js")).default;
120
- tool.handler({ componentName: 'Button' });
121
- expect(createComponentResourceLink).toHaveBeenCalledWith('Button');
122
- });
123
- it('works with components that have spaces in name', async () => {
124
- const tool = (await import("../get_component_docs.js")).default;
125
- // Card Layout exists in mock data
126
- const result = tool.handler({ componentName: 'Card Layout' });
127
- // Should try to get docs (will fail in mock, but proves it checked existence)
128
- expect(result.isError).toBe(true);
129
- expect(result.content[0].text).toContain('Failed to retrieve documentation');
130
- });
131
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,34 +0,0 @@
1
- import { describe, expect, it, test } from 'vitest';
2
- import requirements from "../requirements.js";
3
- import VERSIONS from "../../constants/versions.js";
4
- describe('requirements tool', () => {
5
- describe('configuration', () => {
6
- it('should have correct tool name', () => {
7
- expect(requirements.name).toBe('list_splunk_ui_requirements');
8
- });
9
- it('should have proper config structure', () => {
10
- expect(requirements.config).toBeDefined();
11
- expect(requirements.config.title).toBeDefined();
12
- expect(requirements.config.description).toBeDefined();
13
- expect(requirements.config.inputSchema).toEqual({});
14
- });
15
- it('should have a handler function', () => {
16
- expect(typeof requirements.handler).toBe('function');
17
- });
18
- });
19
- describe('handler', () => {
20
- it('returns the correct JSON structure', () => {
21
- const result = requirements.handler();
22
- const text = result.content[0].text;
23
- const parsed = JSON.parse(text);
24
- expect(parsed).toBeDefined();
25
- expect(typeof parsed).toBe('object');
26
- });
27
- test.each(Object.entries(VERSIONS))('should include %s and version in JSON response', (pkg, version) => {
28
- const result = requirements.handler();
29
- const text = result.content[0].text;
30
- const parsed = JSON.parse(text);
31
- expect(parsed[pkg]).toBe(version);
32
- });
33
- });
34
- });
@@ -1 +0,0 @@
1
- export {};