import { describe, it, expect } from 'vitest' import { sanitizeHtml, sanitizeText } from '../../../src/lib/sanitize.js' describe('sanitize', () => { describe('sanitizeHtml', () => { it('returns empty string for empty input', () => { expect(sanitizeHtml('')).toBe('') }) it('preserves valid markdown-rendered HTML tags', () => { const input = '

Hello bold and italic

' + '
A quote
' + '' + '
  1. Numbered
' + '
code block
' + '

Heading

H2

H3

H4

H5
H6
' + '
' + '
Col
Cell
' + 'strikethroughsupsub
' const result = sanitizeHtml(input) // All these tags should survive expect(result).toContain('') expect(result).toContain('') expect(result).toContain('
') expect(result).toContain('
    ') expect(result).toContain('
      ') expect(result).toContain('
    1. ') expect(result).toContain('
      ')
            expect(result).toContain('')
            expect(result).toContain('

      ') expect(result).toContain('') expect(result).toContain('') expect(result).toContain('') expect(result).toContain('') expect(result).toContain('
      ') expect(result).toContain('
      ') }) it('preserves allowed attributes on links', () => { const input = 'Link' const result = sanitizeHtml(input) expect(result).toContain('href="https://example.com"') expect(result).toContain('rel="noopener noreferrer"') }) it('preserves img tags with src and alt', () => { const input = 'Photo' const result = sanitizeHtml(input) expect(result).toContain('src="https://example.com/img.png"') expect(result).toContain('alt="Photo"') }) it('strips script tags', () => { const input = '

      Hello

      ' const result = sanitizeHtml(input) expect(result).not.toContain('' const result = sanitizeHtml(input) expect(result).not.toContain('' const result = sanitizeText(input) expect(result).not.toContain('<') expect(result).not.toContain('>') expect(result).toContain('Bold') expect(result).not.toContain('evil') }) it('preserves plain text', () => { const input = 'How to configure PostgreSQL?' expect(sanitizeText(input)).toBe('How to configure PostgreSQL?') }) it('applies NFC normalization', () => { const nfd = 'caf\u0065\u0301' const nfc = 'caf\u00E9' expect(sanitizeText(nfd)).toBe(nfc) }) it('strips bidirectional override characters', () => { const input = '\u202AHello\u202E World\u200F' const result = sanitizeText(input) expect(result).toBe('Hello World') }) it('strips HTML from titles with injection attempts', () => { const input = 'Topic Title' const result = sanitizeText(input) expect(result).not.toContain(' { const large = 'A'.repeat(100_000) const result = sanitizeText(large) expect(result.length).toBe(100_000) }) it('strips nested HTML tags', () => { const input = '

      Nested

      ' const result = sanitizeText(input) expect(result).not.toContain('<') expect(result).toContain('Nested') }) it('handles homoglyph-style text (NFC normalization of composed chars)', () => { // Latin Small Letter A with Ring Above: U+0061 + U+030A -> U+00E5 const decomposed = '\u0061\u030A' const composed = '\u00E5' expect(sanitizeText(decomposed)).toBe(composed) }) }) })