Skip to main content
Glama
getDocumentationHandler.test.ts6.59 kB
import { describe, it, expect, vi, beforeEach } from 'vitest' import { getDocumentationHandler } from './getDocumentationHandler' import { ContentDbService } from '$lib/server/contentDb' import { mockSvelteContent } from '$lib/test-fixtures/mockSvelteContent' // Mock ContentDbService vi.mock('$lib/server/contentDb', () => ({ ContentDbService: { searchContent: vi.fn() } })) // Mock path utils vi.mock('$lib/utils/pathUtils', () => ({ cleanDocumentationPath: vi.fn((path: string) => { const prefix = 'apps/svelte.dev/content/' if (path.startsWith(prefix)) { return path.substring(prefix.length) } return path }), extractTitleFromPath: vi.fn((filePath: string) => { const filename = filePath.split('/').pop() || filePath return filename.replace('.md', '').replace(/^\d+-/, '') }) })) describe('getDocumentationHandler', () => { beforeEach(() => { // Reset mocks before each test vi.clearAllMocks() // Setup default mock implementation for searchContent const mockSearchContent = vi.mocked(ContentDbService.searchContent) mockSearchContent.mockImplementation(async (searchQuery) => { // Find matching content from mock data const lowerQuery = searchQuery.toLowerCase() // Try exact title match first let match = mockSvelteContent.find((item) => { const title = (item.metadata?.title as string) || '' return title.toLowerCase() === lowerQuery }) // Try partial title match if (!match) { match = mockSvelteContent.find((item) => { const title = (item.metadata?.title as string) || '' return title.toLowerCase().includes(lowerQuery) }) } // Try path match if (!match) { match = mockSvelteContent.find((item) => item.path.toLowerCase().includes(lowerQuery)) } return match || null }) }) it('should clean paths in documentation responses', async () => { const result = await getDocumentationHandler({ section: '$state' }) const responseText = result.content[0].text // Should contain cleaned path in the header expect(responseText).toContain('## docs/svelte/02-runes.md') // Should NOT contain the full database path expect(responseText).not.toContain('## apps/svelte.dev/content/docs/svelte/02-runes.md') }) it('should handle trailing commas in search queries', async () => { // Test with trailing comma const resultWithComma = await getDocumentationHandler({ section: '$state,' }) expect(resultWithComma.content[0].text).toContain( '$state rune is used to create reactive state in Svelte 5' ) expect(resultWithComma.content[0].text).not.toContain('❌') // Test with trailing comma and whitespace const resultWithCommaSpace = await getDocumentationHandler({ section: '$state, ' }) expect(resultWithCommaSpace.content[0].text).toContain( '$state rune is used to create reactive state in Svelte 5' ) expect(resultWithCommaSpace.content[0].text).not.toContain('❌') }) it('should search by both title and path', async () => { // Search by title const resultByTitle = await getDocumentationHandler({ section: '$derived' }) expect(resultByTitle.content[0].text).toContain( '$derived rune is used to create derived state that automatically updates' ) expect(resultByTitle.content[0].text).not.toContain('❌') // Search by path const resultByPath = await getDocumentationHandler({ section: 'apps/svelte.dev/content/docs/svelte/03-derived.md' }) expect(resultByPath.content[0].text).toContain( '$derived rune is used to create derived state that automatically updates' ) expect(resultByPath.content[0].text).not.toContain('❌') }) it('should return error for non-existent sections', async () => { const result = await getDocumentationHandler({ section: 'non-existent-section-12345' }) expect(result.content[0].text).toContain('not found') }) it('should handle array of section names', async () => { // Test with multiple valid sections const result = await getDocumentationHandler({ section: ['$state', '$derived', '$effect'] }) expect(result.content).toBeDefined() expect(result.content[0].type).toBe('text') expect(result.content[0].text).toContain('$state') expect(result.content[0].text).toContain('$derived') expect(result.content[0].text).toContain('$effect') expect(result.content[0].text).toContain('---') // Should have separators expect(result.content[0].text).not.toContain('❌') }) it('should handle mixed valid and invalid sections in array', async () => { // Test with mix of valid and invalid sections const result = await getDocumentationHandler({ section: ['$state', 'non-existent-section', '$derived'] }) expect(result.content).toBeDefined() expect(result.content[0].type).toBe('text') expect(result.content[0].text).toContain('$state') expect(result.content[0].text).toContain('$derived') expect(result.content[0].text).toContain('not found') expect(result.content[0].text).toContain('non-existent-section') }) it('should handle JSON string arrays from Claude', async () => { // Test with JSON string array (like Claude sends) const result = await getDocumentationHandler({ section: '["$state", "$derived"]' }) expect(result.content).toBeDefined() expect(result.content[0].type).toBe('text') expect(result.content[0].text).toContain('$state') expect(result.content[0].text).toContain('$derived') expect(result.content[0].text).toContain('---') // Should have separators expect(result.content[0].text).not.toContain('❌') }) it('should handle malformed JSON arrays gracefully', async () => { // Test with malformed JSON that should be treated as a single string const result = await getDocumentationHandler({ section: '["$state", "$derived"' }) expect(result.content).toBeDefined() expect(result.content[0].type).toBe('text') expect(result.content[0].text).toContain('not found') }) it('should handle empty section arrays', async () => { const result = await getDocumentationHandler({ section: [] }) expect(result.content).toBeDefined() expect(result.content[0].type).toBe('text') expect(result.content[0].text).toContain('not found') }) it('should handle database errors gracefully', async () => { // Mock database error const mockSearchContent = vi.mocked(ContentDbService.searchContent) mockSearchContent.mockRejectedValue(new Error('Database error')) const result = await getDocumentationHandler({ section: '$state' }) expect(result.content[0].type).toBe('text') expect(result.content[0].text).toContain('❌ Section(s) "$state" not found') }) })

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/khromov/llmctx'

If you have feedback or need assistance with the MCP directory API, please join our Discord server