import { test, expect } from '@playwright/test'; import { detectQueryType, getSearchWeights } from '../../lib/utils'; import { QueryType } from '../../lib/types'; test.describe('Query Type Detection Tests', () => { test('should detect exact queries with quotes', () => { expect(detectQueryType('"Error 404"')).toBe('exact'); expect(detectQueryType("'exact phrase'")).toBe('exact'); expect(detectQueryType('"multiple words"')).toBe('exact'); }); test('should detect conceptual queries', () => { // Question words expect(detectQueryType('how to cook pasta')).toBe('conceptual'); expect(detectQueryType('what is python')).toBe('conceptual'); expect(detectQueryType('where to find')).toBe('conceptual'); expect(detectQueryType('why does this happen')).toBe('conceptual'); expect(detectQueryType('who invented')).toBe('conceptual'); // Conceptual phrases expect(detectQueryType('ways to improve')).toBe('conceptual'); expect(detectQueryType('best way to learn')).toBe('conceptual'); expect(detectQueryType('guide for beginners')).toBe('conceptual'); expect(detectQueryType('tips for cooking')).toBe('conceptual'); expect(detectQueryType('learn about javascript')).toBe('conceptual'); expect(detectQueryType('understand recursion')).toBe('conceptual'); // Learning patterns expect(detectQueryType('tutorial on react')).toBe('conceptual'); expect(detectQueryType('guide to typescript')).toBe('conceptual'); expect(detectQueryType('introduction to python')).toBe('conceptual'); expect(detectQueryType('overview of microservices')).toBe('conceptual'); expect(detectQueryType('explanation of quantum computing')).toBe('conceptual'); expect(detectQueryType('examples of callbacks')).toBe('conceptual'); }); test('should detect mixed queries', () => { // Simple terms expect(detectQueryType('javascript')).toBe('mixed'); expect(detectQueryType('programming')).toBe('mixed'); expect(detectQueryType('cooking')).toBe('mixed'); // Multiple words without patterns expect(detectQueryType('javascript programming')).toBe('mixed'); expect(detectQueryType('react components')).toBe('mixed'); expect(detectQueryType('database design')).toBe('mixed'); }); test('should be case-insensitive', () => { expect(detectQueryType('How To Cook')).toBe('conceptual'); expect(detectQueryType('WHAT IS PYTHON')).toBe('conceptual'); expect(detectQueryType('"Error 404"')).toBe('exact'); }); test('should handle empty and whitespace queries', () => { expect(detectQueryType('')).toBe('mixed'); expect(detectQueryType(' ')).toBe('mixed'); }); }); test.describe('Search Weight Calculation Tests', () => { test('should return correct weights for exact queries', () => { const weights = getSearchWeights('exact'); expect(weights.keywordWeight).toBe(2.0); expect(weights.semanticWeight).toBe(0.7); }); test('should return correct weights for conceptual queries', () => { const weights = getSearchWeights('conceptual'); expect(weights.keywordWeight).toBe(0.7); expect(weights.semanticWeight).toBe(1.5); }); test('should return correct weights for mixed queries', () => { const weights = getSearchWeights('mixed'); expect(weights.keywordWeight).toBe(1.0); expect(weights.semanticWeight).toBe(1.0); }); test('should handle unknown query type as mixed', () => { const weights = getSearchWeights('unknown' as QueryType); expect(weights.keywordWeight).toBe(1.0); expect(weights.semanticWeight).toBe(1.0); }); }); test.describe('Adaptive Weighting Integration Tests', () => { test('exact query boosts keyword matches', () => { const queryType = detectQueryType('"exact phrase"'); const weights = getSearchWeights(queryType); // Keyword matches should be 2x more important expect(weights.keywordWeight).toBeGreaterThan(weights.semanticWeight); expect(weights.keywordWeight / weights.semanticWeight).toBeCloseTo(2.0 / 0.7, 1); }); test('conceptual query boosts semantic matches', () => { const queryType = detectQueryType('how to cook'); const weights = getSearchWeights(queryType); // Semantic matches should be more important expect(weights.semanticWeight).toBeGreaterThan(weights.keywordWeight); expect(weights.semanticWeight / weights.keywordWeight).toBeCloseTo(1.5 / 0.7, 1); }); test('mixed query treats both equally', () => { const queryType = detectQueryType('javascript programming'); const weights = getSearchWeights(queryType); // Both should have equal weight expect(weights.keywordWeight).toBe(weights.semanticWeight); expect(weights.keywordWeight).toBe(1.0); }); test('weights significantly affect ranking scores', () => { const k = 20; const rank = 5; // Same rank with different weights const exactQueryScore = (1 / (k + rank)) * 2.0; // keyword const conceptualQueryScore = (1 / (k + rank)) * 1.5; // semantic // Exact keyword match should get highest score expect(exactQueryScore).toBeGreaterThan(conceptualQueryScore); }); }); test.describe('Weight Impact on Scenarios', () => { test('scenario 1: User searches for "Error 404"', () => { const query = '"Error 404"'; const queryType = detectQueryType(query); const weights = getSearchWeights(queryType); // Should be exact match type expect(queryType).toBe('exact'); // Keyword matches should be heavily prioritized expect(weights.keywordWeight).toBe(2.0); // Semantic matches should be deprioritized expect(weights.semanticWeight).toBe(0.7); // This ensures that notes with "Error 404" appear first, // even if semantic search might suggest other error types }); test('scenario 2: User searches for "how to cook pasta"', () => { const query = 'how to cook pasta'; const queryType = detectQueryType(query); const weights = getSearchWeights(queryType); // Should be conceptual type expect(queryType).toBe('conceptual'); // Semantic matches should be boosted expect(weights.semanticWeight).toBe(1.5); // Keyword matches should be reduced expect(weights.keywordWeight).toBe(0.7); // This ensures that notes about cooking, pasta, recipes appear, // even if they don't contain the exact words "how to cook pasta" }); test('scenario 3: User searches for "tutorial javascript"', () => { const query = 'tutorial javascript'; const queryType = detectQueryType(query); const weights = getSearchWeights(queryType); // Should be conceptual type (starts with "tutorial") expect(queryType).toBe('conceptual'); // Semantic search should be prioritized expect(weights.semanticWeight).toBeGreaterThan(weights.keywordWeight); }); test('scenario 4: User searches for "react hooks"', () => { const query = 'react hooks'; const queryType = detectQueryType(query); const weights = getSearchWeights(queryType); // Should be mixed type (no specific pattern) expect(queryType).toBe('mixed'); // Both should have equal weight expect(weights.keywordWeight).toBe(weights.semanticWeight); }); });