import { describe, it, expect } from 'vitest'; import { detectMention, extractContent, renderBody } from './mention'; import type { MentionDTO } from '$lib/types'; // ─── detectMention ──────────────────────────────────────────────────────────── describe('detectMention', () => { it('returns null when text has no @', () => { expect(detectMention('hello world', 11)).toBeNull(); }); it('returns null when @ is not the most recent trigger word', () => { // cursor is past a completed mention (next word started) expect(detectMention('hello @Hans Müller more', 22)).toBeNull(); }); it('returns empty string immediately after @', () => { expect(detectMention('hello @', 7)).toBe(''); }); it('returns query text after @', () => { expect(detectMention('hello @Han', 10)).toBe('Han'); }); it('returns null when @ is preceded by a letter (email address pattern)', () => { expect(detectMention('user@example', 12)).toBeNull(); }); it('returns query for @ at the very start of string', () => { expect(detectMention('@Hans', 5)).toBe('Hans'); }); it('returns null when cursor is before the @', () => { expect(detectMention('@Hans', 0)).toBeNull(); }); }); // ─── extractContent ─────────────────────────────────────────────────────────── describe('extractContent', () => { it('returns empty arrays for empty string', () => { const result = extractContent('', []); expect(result.content).toBe(''); expect(result.mentionedUserIds).toEqual([]); }); it('returns plain content unchanged when no candidates', () => { const result = extractContent('Hello world', []); expect(result.content).toBe('Hello world'); expect(result.mentionedUserIds).toEqual([]); }); it('extracts user id when @FirstName LastName is in content', () => { const candidates: MentionDTO[] = [{ id: 'uuid-1', firstName: 'Hans', lastName: 'Müller' }]; const result = extractContent('Hey @Hans Müller how are you?', candidates); expect(result.mentionedUserIds).toContain('uuid-1'); }); it('deduplicates user ids when same user mentioned twice', () => { const candidates: MentionDTO[] = [{ id: 'uuid-1', firstName: 'Hans', lastName: 'Müller' }]; const result = extractContent('@Hans Müller and @Hans Müller again', candidates); expect(result.mentionedUserIds).toHaveLength(1); expect(result.mentionedUserIds).toContain('uuid-1'); }); it('collects multiple distinct users', () => { const candidates: MentionDTO[] = [ { id: 'uuid-1', firstName: 'Hans', lastName: 'Müller' }, { id: 'uuid-2', firstName: 'Anna', lastName: 'Schmidt' } ]; const result = extractContent('@Hans Müller and @Anna Schmidt', candidates); expect(result.mentionedUserIds).toContain('uuid-1'); expect(result.mentionedUserIds).toContain('uuid-2'); }); }); // ─── renderBody ─────────────────────────────────────────────────────────────── describe('renderBody', () => { it('returns escaped plain text when no mentions', () => { expect(renderBody('Hello world', [])).toBe('Hello world'); }); it('escapes < and > in content', () => { const result = renderBody('', []); expect(result).toContain('<script>'); expect(result).not.toContain('