import { expect, tap } from '@push.rocks/tapbundle'; import * as tsclass from '@tsclass/tsclass'; import * as smartfuzzy from '../ts/index.js'; // Create fixed timestamps for consistent test results const timestamp1 = 1620000000000; // May 2021 const timestamp2 = 1620086400000; // May 2021 + 1 day // Test articles with known content const testArticles: tsclass.content.IArticle[] = [ { title: 'Berlin has a ambivalent history', content: 'it is known that Berlin has an interesting history', author: null, tags: ['city', 'Europe', 'history', 'travel'], timestamp: timestamp1, featuredImageUrl: null, url: null, }, { title: 'Washington is a great city', content: 'it is known that Washington is one of the greatest cities in the world', author: null, tags: ['city', 'USA', 'travel', 'politics'], timestamp: timestamp2, featuredImageUrl: null, url: null, }, { title: 'Travel tips for European cities', content: 'Here are some travel tips for European cities including Berlin and Paris', author: null, tags: ['travel', 'Europe', 'tips'], timestamp: timestamp2, featuredImageUrl: null, url: null, } ]; let articleSearch: smartfuzzy.ArticleSearch; tap.test('should create an ArticleSearch instance', async () => { // Test creation with constructor articleSearch = new smartfuzzy.ArticleSearch(testArticles); expect(articleSearch).toBeInstanceOf(smartfuzzy.ArticleSearch); expect(articleSearch.articles.length).toEqual(testArticles.length); // Test empty constructor const emptySearch = new smartfuzzy.ArticleSearch(); expect(emptySearch.articles).toBeArray(); expect(emptySearch.articles.length).toEqual(0); }); tap.test('should search by exact tag match', async () => { const result = await articleSearch.search('USA'); // Should have results expect(result).toBeArray(); expect(result.length).toBeGreaterThan(0); // First result should be the Washington article (contains USA tag) expect(result[0].item.title).toInclude('Washington'); // Should include match information expect(result[0].matches).toBeDefined(); expect(result[0].matches.length).toBeGreaterThan(0); // At least one match should be for the 'USA' tag const tagMatch = result[0].matches.find(m => m.key === 'tags' && m.value === 'USA'); expect(tagMatch).toBeDefined(); }); tap.test('should search by title and content', async () => { // Search for term in the title and content of one article const result = await articleSearch.search('Berlin'); expect(result.length).toBeGreaterThan(0); expect(result[0].item.title).toInclude('Berlin'); // The Travel article mentions Berlin in content, so it should be included // but ranked lower const berlinArticleIndex = result.findIndex(r => r.item.title.includes('Berlin')); const travelArticleIndex = result.findIndex(r => r.item.title.includes('Travel')); expect(berlinArticleIndex).toBeLessThan(travelArticleIndex); }); tap.test('should add articles incrementally', async () => { const newSearch = new smartfuzzy.ArticleSearch(); expect(newSearch.articles.length).toEqual(0); // Add one article const newArticle: tsclass.content.IArticle = { title: 'New Article', content: 'This is a new article about technology', author: null, tags: ['technology', 'new'], timestamp: Date.now(), featuredImageUrl: null, url: null, }; newSearch.addArticle(newArticle); expect(newSearch.articles.length).toEqual(1); expect(newSearch.needsUpdate).toBeTrue(); // Search should update the index const result = await newSearch.search('technology'); expect(result.length).toEqual(1); expect(newSearch.needsUpdate).toBeFalse(); // Add another article and check if updates work const anotherArticle: tsclass.content.IArticle = { title: 'Another Tech Article', content: 'Another article about technology innovations', author: null, tags: ['technology', 'innovation'], timestamp: Date.now(), featuredImageUrl: null, url: null, }; newSearch.addArticle(anotherArticle); expect(newSearch.needsUpdate).toBeTrue(); // Search again should now return both articles const newResult = await newSearch.search('technology'); expect(newResult.length).toEqual(2); }); export default tap.start();