import { findLinkSuggestions, applyWikiLinks } from '@/lib/link-suggestions' // Mock prisma jest.mock('@/lib/prisma', () => ({ prisma: { note: { findMany: jest.fn(), }, }, })) import { prisma } from '@/lib/prisma' describe('link-suggestions.ts', () => { beforeEach(() => { jest.clearAllMocks() }) describe('findLinkSuggestions', () => { it('returns empty array for short content', async () => { const result = await findLinkSuggestions('Hi') expect(result).toEqual([]) }) it('returns empty array for empty content', async () => { const result = await findLinkSuggestions('') expect(result).toEqual([]) }) it('finds matching note titles in content', async () => { ;(prisma.note.findMany as jest.Mock).mockResolvedValue([ { id: '1', title: 'Docker Commands' }, { id: '2', title: 'Git Tutorial' }, ]) const content = 'I use Docker Commands for containers and Git Tutorial for version control.' const result = await findLinkSuggestions(content) expect(result).toHaveLength(2) expect(result.map(r => r.noteTitle)).toContain('Docker Commands') expect(result.map(r => r.noteTitle)).toContain('Git Tutorial') }) it('excludes current note from suggestions', async () => { ;(prisma.note.findMany as jest.Mock).mockResolvedValue([ { id: '1', title: 'Current Note' }, { id: '2', title: 'Related Note' }, ]) const content = 'See Related Note for details.' const result = await findLinkSuggestions(content, '1') expect(result).toHaveLength(1) expect(result[0].noteTitle).toBe('Related Note') }) it('sorts by title length (longer first)', async () => { ;(prisma.note.findMany as jest.Mock).mockResolvedValue([ { id: '1', title: 'Short' }, { id: '2', title: 'Very Long Title' }, { id: '3', title: 'Medium Title' }, ]) const content = 'Short and Medium Title and Very Long Title' const result = await findLinkSuggestions(content) expect(result[0].noteTitle).toBe('Very Long Title') expect(result[1].noteTitle).toBe('Medium Title') expect(result[2].noteTitle).toBe('Short') }) it('returns empty when no matches found', async () => { ;(prisma.note.findMany as jest.Mock).mockResolvedValue([ { id: '1', title: 'Docker' }, { id: '2', title: 'Git' }, ]) const content = 'Python and JavaScript are programming languages.' const result = await findLinkSuggestions(content) expect(result).toEqual([]) }) it('handles case-insensitive matching', async () => { ;(prisma.note.findMany as jest.Mock).mockResolvedValue([ { id: '1', title: 'Docker Commands' }, ]) const content = 'I use DOCKER COMMANDS for my project.' const result = await findLinkSuggestions(content) expect(result).toHaveLength(1) expect(result[0].noteTitle).toBe('Docker Commands') }) it('matches whole words only', async () => { ;(prisma.note.findMany as jest.Mock).mockResolvedValue([ { id: '1', title: 'Git' }, ]) const content = 'GitHub uses Git internally.' const result = await findLinkSuggestions(content) // Should match standalone 'Git' but not 'Git' within 'GitHub' // Note: the regex \bGit\b matches standalone 'Git', not 'Git' in 'GitHub' expect(result.some(r => r.noteTitle === 'Git')).toBe(true) }) it('returns empty when no notes exist', async () => { ;(prisma.note.findMany as jest.Mock).mockResolvedValue([]) const result = await findLinkSuggestions('Some content with potential matches') expect(result).toEqual([]) }) }) describe('applyWikiLinks', () => { it('replaces terms with wiki-links', () => { const content = 'I use Docker and Git for projects.' const replacements = [ { term: 'Docker', noteId: '1' }, { term: 'Git', noteId: '2' }, ] const result = applyWikiLinks(content, replacements) expect(result).toBe('I use [[Docker]] and [[Git]] for projects.') }) it('handles multiple occurrences', () => { const content = 'Docker is great. Docker is fast.' const replacements = [{ term: 'Docker', noteId: '1' }] const result = applyWikiLinks(content, replacements) expect(result).toBe('[[Docker]] is great. [[Docker]] is fast.') }) it('handles case-insensitive matching and replaces with link term', () => { const content = 'DOCKER and docker and Docker' const replacements = [{ term: 'Docker', noteId: '1' }] const result = applyWikiLinks(content, replacements) // All variations matched and replaced with the link text expect(result).toBe('[[Docker]] and [[Docker]] and [[Docker]]') }) it('returns original content when no replacements', () => { const content = 'Original content' const replacements: { term: string; noteId: string }[] = [] const result = applyWikiLinks(content, replacements) expect(result).toBe('Original content') }) it('replaces multiple different terms', () => { const content = 'Use React and TypeScript together.' const replacements = [ { term: 'React', noteId: '1' }, { term: 'TypeScript', noteId: '2' }, ] const result = applyWikiLinks(content, replacements) expect(result).toBe('Use [[React]] and [[TypeScript]] together.') }) }) })