Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/__tests__/__snapshots__/options.defaults.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`options defaults should return specific properties: defaults 1`] = `
{
"apiBaseUrl": "https://staging.patternfly.org",
"contextPath": "/",
"contextUrl": "file:///",
"docsPath": "/documentation",
Expand Down
132 changes: 8 additions & 124 deletions src/__tests__/__snapshots__/tool.componentSchemas.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,8 @@ exports[`componentSchemasTool, callback should parse parameters, default 1`] = `
{
"content": [
{
"text": "{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"title": "Button Props",
"description": "Props for the Button component",
"properties": {
"variant": {
"type": "string",
"enum": [
"primary",
"secondary"
]
},
"size": {
"type": "string",
"enum": [
"sm",
"md",
"lg"
]
},
"children": {
"type": "string",
"description": "Content rendered inside the button"
}
},
"required": [
"children"
],
"additionalProperties": false
}",
"text": "| Prop | Type |
|---|---|",
"type": "text",
},
],
Expand All @@ -53,37 +24,8 @@ exports[`componentSchemasTool, callback should parse parameters, with lower case
{
"content": [
{
"text": "{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"title": "Button Props",
"description": "Props for the Button component",
"properties": {
"variant": {
"type": "string",
"enum": [
"primary",
"secondary"
]
},
"size": {
"type": "string",
"enum": [
"sm",
"md",
"lg"
]
},
"children": {
"type": "string",
"description": "Content rendered inside the button"
}
},
"required": [
"children"
],
"additionalProperties": false
}",
"text": "| Prop | Type |
|---|---|",
"type": "text",
},
],
Expand All @@ -94,37 +36,8 @@ exports[`componentSchemasTool, callback should parse parameters, with trimmed co
{
"content": [
{
"text": "{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"title": "Button Props",
"description": "Props for the Button component",
"properties": {
"variant": {
"type": "string",
"enum": [
"primary",
"secondary"
]
},
"size": {
"type": "string",
"enum": [
"sm",
"md",
"lg"
]
},
"children": {
"type": "string",
"description": "Content rendered inside the button"
}
},
"required": [
"children"
],
"additionalProperties": false
}",
"text": "| Prop | Type |
|---|---|",
"type": "text",
},
],
Expand All @@ -135,37 +48,8 @@ exports[`componentSchemasTool, callback should parse parameters, with upper case
{
"content": [
{
"text": "{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"title": "Button Props",
"description": "Props for the Button component",
"properties": {
"variant": {
"type": "string",
"enum": [
"primary",
"secondary"
]
},
"size": {
"type": "string",
"enum": [
"sm",
"md",
"lg"
]
},
"children": {
"type": "string",
"description": "Content rendered inside the button"
}
},
"required": [
"children"
],
"additionalProperties": false
}",
"text": "| Prop | Type |
|---|---|",
"type": "text",
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ exports[`searchPatternFlyDocsTool should have a consistent return structure: str

exports[`searchPatternFlyDocsTool, callback should parse parameters, default: search 1`] = `"# Search results for "Button", 1 matches found:"`;

exports[`searchPatternFlyDocsTool, callback should parse parameters, with "*" searchQuery all: search 1`] = `"# Search results for "all components", 8 matches found:"`;
exports[`searchPatternFlyDocsTool, callback should parse parameters, with "*" searchQuery all: search 1`] = `"# Search results for "all components", 4 matches found:"`;

exports[`searchPatternFlyDocsTool, callback should parse parameters, with "all" searchQuery all: search 1`] = `"# Search results for "all components", 8 matches found:"`;
exports[`searchPatternFlyDocsTool, callback should parse parameters, with "all" searchQuery all: search 1`] = `"# Search results for "all components", 4 matches found:"`;

exports[`searchPatternFlyDocsTool, callback should parse parameters, with empty searchQuery all: search 1`] = `"# Search results for "all components", 8 matches found:"`;
exports[`searchPatternFlyDocsTool, callback should parse parameters, with empty searchQuery all: search 1`] = `"# Search results for "all components", 4 matches found:"`;

exports[`searchPatternFlyDocsTool, callback should parse parameters, with lower case componentName: search 1`] = `"# Search results for "button", 1 matches found:"`;

exports[`searchPatternFlyDocsTool, callback should parse parameters, with made up componentName: search 1`] = `"No PatternFly documentation found matching "lorem ipsum dolor sit amet""`;

exports[`searchPatternFlyDocsTool, callback should parse parameters, with multiple words: search 1`] = `"# Search results for "Button Card Table", 3 matches found:"`;

exports[`searchPatternFlyDocsTool, callback should parse parameters, with partial componentName: search 1`] = `"# Search results for "ton", 2 matches found:"`;
exports[`searchPatternFlyDocsTool, callback should parse parameters, with partial componentName: search 1`] = `"# Search results for "ton", 1 matches found:"`;

exports[`searchPatternFlyDocsTool, callback should parse parameters, with trimmed componentName: search 1`] = `"# Search results for " Button ", 1 matches found:"`;

Expand Down
36 changes: 35 additions & 1 deletion src/__tests__/resource.patternFlyDocsIndex.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,39 @@ import { patternFlyDocsIndexResource } from '../resource.patternFlyDocsIndex';
import { getLocalDocs } from '../docs.local';
import { isPlainObject } from '../server.helpers';

// Mock dependencies
jest.mock('../docs.local');
jest.mock('../server.caching', () => ({
memo: jest.fn(fn => fn)
}));

jest.mock('../api.client', () => ({
getComponentList: Object.assign(
jest.fn(async () => ['Alert', 'Button', 'Card']),
{ memo: jest.fn(async () => ['Alert', 'Button', 'Card']) }
),
getComponentInfo: Object.assign(
jest.fn(async (name: string) => ({
name,
section: 'components',
page: name.toLowerCase(),
tabs: ['react'],
hasProps: true,
hasCss: false,
exampleCount: 0
})),
{
memo: jest.fn(async (name: string) => ({
name,
section: 'components',
page: name.toLowerCase(),
tabs: ['react'],
hasProps: true,
hasCss: false,
exampleCount: 0
}))
}
)
}));

const mockGetLocalDocs = getLocalDocs as jest.MockedFunction<typeof getLocalDocs>;

Expand Down Expand Up @@ -43,5 +74,8 @@ describe('patternFlyDocsIndexResource, callback', () => {
expect(result.contents).toBeDefined();
expect(Object.keys(result.contents[0])).toEqual(['uri', 'mimeType', 'text']);
expect(result.contents[0].text).toContain('[@patternfly/react-guidelines](./guidelines/README.md)');
expect(result.contents[0].text).toContain('Alert');
expect(result.contents[0].text).toContain('Button');
expect(result.contents[0].text).toContain('Card');
});
});
43 changes: 12 additions & 31 deletions src/__tests__/resource.patternFlyDocsTemplate.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { McpError } from '@modelcontextprotocol/sdk/types.js';
import { patternFlyDocsTemplateResource } from '../resource.patternFlyDocsTemplate';
import { processDocsFunction } from '../server.getResources';
import { fetchComponentData } from '../api.fetcher';
import { searchComponents } from '../tool.searchPatternFlyDocs';
import { isPlainObject } from '../server.helpers';

// Mock dependencies
jest.mock('../server.getResources');
jest.mock('../api.fetcher');
jest.mock('../tool.searchPatternFlyDocs');
jest.mock('../server.caching', () => ({
memo: jest.fn(fn => fn)
Expand All @@ -14,7 +13,7 @@ jest.mock('../options.context', () => ({
getOptions: jest.fn(() => ({}))
}));

const mockProcessDocs = processDocsFunction as jest.MockedFunction<typeof processDocsFunction>;
const mockFetchComponentData = fetchComponentData as jest.MockedFunction<typeof fetchComponentData>;
const mockSearchComponents = searchComponents as jest.MockedFunction<typeof searchComponents>;

describe('patternFlyDocsTemplateResource', () => {
Expand Down Expand Up @@ -43,47 +42,29 @@ describe('patternFlyDocsTemplateResource, callback', () => {
{
description: 'default',
name: 'Button',
urls: ['components/button.md'],
result: 'Button documentation content'
},
{
description: 'with multiple matched URLs',
name: 'Card',
urls: ['components/card.md', 'components/card-examples.md'],
result: 'Card documentation content'
docs: '# Button documentation content'
},
{
description: 'with trimmed name',
name: ' Table ',
urls: ['components/table.md'],
result: 'Table documentation content'
docs: '# Table documentation content'
},
{
description: 'with lower case name',
name: 'button',
urls: ['components/button.md'],
result: 'Button documentation content'
docs: '# Button documentation content'
}
])('should parse parameters and return documentation, $description', async ({ name, urls, result: mockResult }) => {
mockSearchComponents.mockReturnValue({
isSearchWildCardAll: false,
firstExactMatch: undefined,
exactMatches: [{ urls } as any],
searchResults: []
});
mockProcessDocs.mockResolvedValue([{ content: mockResult }] as any);
])('should parse parameters and return documentation, $description', async ({ name, docs }) => {
mockFetchComponentData.mockResolvedValue({ name: name.trim(), info: {} as any, docs });

const [_name, _uri, _config, callback] = patternFlyDocsTemplateResource();
const uri = new URL('patternfly://docs/Button');
const variables = { name };
const result = await callback(uri, variables);

expect(mockSearchComponents).toHaveBeenCalledWith(name);
expect(mockProcessDocs).toHaveBeenCalledWith(urls);

expect(result.contents).toBeDefined();
expect(Object.keys(result.contents[0])).toEqual(['uri', 'mimeType', 'text']);
expect(result.contents[0].text).toContain(mockResult);
expect(result.contents[0].text).toContain(docs);
});

it.each([
Expand Down Expand Up @@ -115,14 +96,14 @@ describe('patternFlyDocsTemplateResource, callback', () => {
await expect(callback(uri, variables)).rejects.toThrow(error);
});

it('should handle documentation loading errors', async () => {
mockSearchComponents.mockReturnValue({
it('should handle documentation not found errors', async () => {
mockFetchComponentData.mockResolvedValue(undefined);
mockSearchComponents.mockResolvedValue({
isSearchWildCardAll: false,
firstExactMatch: undefined,
exactMatches: [],
searchResults: []
});
mockProcessDocs.mockRejectedValue(new Error('File not found'));

const [_name, _uri, _config, handler] = patternFlyDocsTemplateResource();
const uri = new URL('patternfly://docs/Button');
Expand Down
Loading
Loading