UNPKG

apple-dev-mcp

Version:

Complete Apple development guidance: Human Interface Guidelines (design) + Technical Documentation for iOS, macOS, watchOS, tvOS, and visionOS

213 lines 12.9 kB
/** * Search Improvements Validation Tests * * These tests validate the specific search improvements made to fix * the field test issues and prevent regressions. */ import { StaticContentSearchService } from '../services/static-content-search.service.js'; // import type { SearchResult } from '../types.js'; describe('Search Improvements Validation', () => { let searchService; beforeEach(() => { searchService = new StaticContentSearchService('content'); }); describe('Synonym Expansion', () => { test('should treat "search" and "searching" as related terms', async () => { const searchResults = await searchService.searchContent('search', 'iOS', undefined, 5); const searchingResults = await searchService.searchContent('searching', 'iOS', undefined, 5); expect(searchResults.length).toBeGreaterThan(0); expect(searchingResults.length).toBeGreaterThan(0); // Both should find search-related content const searchTitles = searchResults.map(r => r.title.toLowerCase()); const searchingTitles = searchingResults.map(r => r.title.toLowerCase()); // Should have significant overlap in results const hasSearchContent = searchTitles.some(title => title.includes('search')); const hasSearchingContent = searchingTitles.some(title => title.includes('search')); expect(hasSearchContent).toBe(true); expect(hasSearchingContent).toBe(true); }); test('should expand "guidelines" to include "best practices"', async () => { const guidelinesResults = await searchService.searchContent('guidelines', 'iOS', undefined, 5); const bestPracticesResults = await searchService.searchContent('best practices', 'iOS', undefined, 5); expect(guidelinesResults.length).toBeGreaterThan(0); expect(bestPracticesResults.length).toBeGreaterThan(0); // Both queries should find relevant content expect(guidelinesResults[0].relevanceScore).toBeGreaterThan(0.5); expect(bestPracticesResults[0].relevanceScore).toBeGreaterThan(0.5); }); test('should expand "interface" to include "component" terms', async () => { const interfaceResults = await searchService.searchContent('interface', 'iOS', undefined, 3); const componentResults = await searchService.searchContent('component', 'iOS', undefined, 3); expect(interfaceResults.length).toBeGreaterThan(0); expect(componentResults.length).toBeGreaterThan(0); // Should find UI-related content for both const interfaceContent = interfaceResults.map(r => (r.title + ' ' + r.content).toLowerCase()); const componentContent = componentResults.map(r => (r.title + ' ' + r.content).toLowerCase()); const hasUIContent = interfaceContent.some(content => content.includes('interface') || content.includes('component') || content.includes('ui')); const hasComponentContent = componentContent.some(content => content.includes('interface') || content.includes('component') || content.includes('ui')); expect(hasUIContent).toBe(true); expect(hasComponentContent).toBe(true); }); }); describe('Multi-term Query Handling', () => { test('should handle complex multi-term queries effectively', async () => { const result = await searchService.searchContent('search guidelines best practices interface', 'iOS', undefined, 5); expect(result.length).toBeGreaterThan(0); // Should prioritize results that match multiple terms const topResult = result[0]; expect(topResult.relevanceScore).toBeGreaterThan(0.8); // Content should relate to multiple query terms const content = (topResult.title + ' ' + topResult.content).toLowerCase(); const termMatches = ['search', 'guideline', 'practice', 'interface'].filter(term => content.includes(term)); expect(termMatches.length).toBeGreaterThan(1); }); test('should score partial term matches appropriately', async () => { const fullTermResult = await searchService.searchContent('searching', 'iOS', undefined, 1); const partialTermResult = await searchService.searchContent('search field guide', 'iOS', undefined, 1); expect(fullTermResult.length).toBeGreaterThan(0); expect(partialTermResult.length).toBeGreaterThan(0); // Exact term match should score higher than partial matches expect(fullTermResult[0].relevanceScore).toBeGreaterThan(partialTermResult[0].relevanceScore); }); }); describe('Relevance Threshold Improvements', () => { test('should find more relevant results with lowered threshold', async () => { // This query previously returned only fallback content const result = await searchService.searchContent('search bar best practices', 'iOS', undefined, 5); expect(result.length).toBeGreaterThan(0); // Should find search-related content (not just generic fallback) const searchResults = result.filter(r => { const content = (r.title + ' ' + r.content).toLowerCase(); return content.includes('search'); }); expect(searchResults.length).toBeGreaterThan(0); // Top result should have reasonable relevance expect(result[0].relevanceScore).toBeGreaterThan(0.3); }); test('should still filter out completely irrelevant results', async () => { const result = await searchService.searchContent('xyz123nonexistent', 'iOS', undefined, 5); // Should return some results (fallback) but they should have low scores expect(result.length).toBeGreaterThan(0); // Fallback system provides results expect(result.length).toBeLessThanOrEqual(5); // Respects limit // Any results returned should have low but non-zero scores if (result.length > 0) { expect(result[0].relevanceScore).toBeGreaterThan(0); expect(result[0].relevanceScore).toBeLessThan(1.5); // Allow for quality bonuses } }); }); describe('Content Quality Validation', () => { test('should prioritize high-quality guideline content', async () => { const result = await searchService.searchContent('button guidelines', 'iOS', undefined, 5); expect(result.length).toBeGreaterThan(0); // Should find button-related content const buttonResults = result.filter(r => r.title.toLowerCase().includes('button') || r.content.toLowerCase().includes('button')); expect(buttonResults.length).toBeGreaterThan(0); // Content should be substantial (not just snippets) const topResult = result[0]; expect(topResult.content.length).toBeGreaterThan(100); // Should include structured guidance expect(topResult.content).toBeTruthy(); }); test('should return full content instead of just snippets', async () => { const result = await searchService.searchContent('accessibility guidelines', 'iOS', undefined, 1); expect(result.length).toBeGreaterThan(0); const topResult = result[0]; // Content should be the full markdown content, not just snippet expect(topResult.content.length).toBeGreaterThan(500); // Should contain substantial content (full markdown content) // Content is processed to remove front matter, so check for substantial content expect(topResult.content).toMatch(/[A-Z][a-z]+\s+[A-Z][a-z]+/); // Should have proper content structure }); }); describe('Platform Filtering', () => { test('should respect platform filters while maintaining relevance', async () => { const iOSResult = await searchService.searchContent('button', 'iOS', undefined, 5); const universalResult = await searchService.searchContent('button', 'universal', undefined, 5); expect(iOSResult.length).toBeGreaterThan(0); expect(universalResult.length).toBeGreaterThan(0); // iOS results should include iOS and universal content const iOSPlatforms = iOSResult.map(r => r.platform); const validPlatforms = iOSPlatforms.every(platform => platform === 'iOS' || platform === 'universal'); expect(validPlatforms).toBe(true); // Universal results should primarily be universal platform const universalPlatforms = universalResult.map(r => r.platform); const hasUniversal = universalPlatforms.some(platform => platform === 'universal'); expect(hasUniversal).toBe(true); // Should have at least some universal content }); }); describe('Regression Prevention', () => { test('should find "Searching" content for search-related queries', async () => { const queries = [ 'search guidelines', 'search bar best practices', 'searching interface', 'search patterns' ]; for (const query of queries) { const result = await searchService.searchContent(query, 'iOS', undefined, 3); expect(result.length).toBeGreaterThan(0); // Should find search-related content const searchResults = result.filter(r => r.title.toLowerCase().includes('search') || r.content.toLowerCase().includes('search')); expect(searchResults.length).toBeGreaterThan(0); // Top result should have good relevance expect(result[0].relevanceScore).toBeGreaterThan(0.5); } }); test('should not return only accessibility fallback for specific queries', async () => { const specificQueries = [ 'search guidelines search bar best practices', 'search patterns search interface components', 'button interaction guidelines', 'navigation patterns' ]; for (const query of specificQueries) { const result = await searchService.searchContent(query, 'iOS', undefined, 3); expect(result.length).toBeGreaterThan(0); // Should not have all results be "Accessibility" (old fallback behavior) const accessibilityCount = result.filter(r => r.title.toLowerCase() === 'accessibility').length; expect(accessibilityCount).toBeLessThan(result.length); // Should find specific content related to the query const relevantResults = result.filter(r => { const content = (r.title + ' ' + r.content).toLowerCase(); const queryTerms = query.toLowerCase().split(' '); return queryTerms.some(term => content.includes(term)); }); expect(relevantResults.length).toBeGreaterThan(0); } }); }); describe('Performance Validation', () => { test('should maintain fast search performance', async () => { const startTime = Date.now(); const result = await searchService.searchContent('button guidelines interface', 'iOS', undefined, 5); const endTime = Date.now(); const duration = endTime - startTime; expect(result.length).toBeGreaterThan(0); // Should complete within 2 seconds for static content expect(duration).toBeLessThan(2000); }); test('should handle multiple concurrent searches efficiently', async () => { const startTime = Date.now(); const searches = [ searchService.searchContent('button', 'iOS'), searchService.searchContent('search', 'iOS'), searchService.searchContent('navigation', 'iOS'), searchService.searchContent('accessibility', 'iOS'), searchService.searchContent('layout', 'iOS') ]; const results = await Promise.all(searches); const endTime = Date.now(); const duration = endTime - startTime; // All searches should succeed results.forEach(result => { expect(result.length).toBeGreaterThan(0); }); // Should complete within 3 seconds total expect(duration).toBeLessThan(3000); }); }); }); //# sourceMappingURL=search-improvements.test.js.map