Files
Momento/memento-note/tests/unit/adaptive-weighting.test.ts
Antigravity 8283c4e140
Some checks failed
CI / Lint, Test & Build (push) Successful in 12m12s
Deploy to Production / Build and Deploy (push) Has been cancelled
fix(ci): tests unitaires Vitest uniquement, sans Playwright ni migrations
Les tests migration exigent un schéma aligné via db push (hors scope CI).
Trois fichiers unitaires importaient @playwright/test par erreur.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 09:01:27 +00:00

193 lines
7.1 KiB
TypeScript

import { describe, test, expect } from 'vitest';
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);
});
});