/* * Copyright (C) 2026 Fluxer Contributors * * This file is part of Fluxer. * * Fluxer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Fluxer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Fluxer. If not, see . */ import {decodeHTMLEntities, htmlToMarkdown, stripHtmlTags} from '@fluxer/api/src/utils/DOMUtils'; import {describe, expect, it} from 'vitest'; describe('decodeHTMLEntities', () => { it('returns empty string for null input', () => { expect(decodeHTMLEntities(null)).toBe(''); }); it('returns empty string for undefined input', () => { expect(decodeHTMLEntities(undefined)).toBe(''); }); it('returns empty string for empty string input', () => { expect(decodeHTMLEntities('')).toBe(''); }); it('decodes basic HTML entities', () => { expect(decodeHTMLEntities('&')).toBe('&'); expect(decodeHTMLEntities('<')).toBe('<'); expect(decodeHTMLEntities('>')).toBe('>'); expect(decodeHTMLEntities('"')).toBe('"'); expect(decodeHTMLEntities(''')).toBe("'"); }); it('decodes numeric HTML entities', () => { expect(decodeHTMLEntities('<')).toBe('<'); expect(decodeHTMLEntities('<')).toBe('<'); }); it('decodes mixed content', () => { expect(decodeHTMLEntities('Hello & World')).toBe('Hello & World'); expect(decodeHTMLEntities('<script>alert("xss")</script>')).toBe( '', ); }); it('preserves plain text without entities', () => { expect(decodeHTMLEntities('Hello World')).toBe('Hello World'); }); it('decodes special characters', () => { expect(decodeHTMLEntities(' ')).toBe('\u00A0'); expect(decodeHTMLEntities('©')).toBe('\u00A9'); expect(decodeHTMLEntities('€')).toBe('\u20AC'); }); }); describe('stripHtmlTags', () => { it('returns empty string for null input', () => { expect(stripHtmlTags(null)).toBe(''); }); it('returns empty string for undefined input', () => { expect(stripHtmlTags(undefined)).toBe(''); }); it('returns empty string for empty string input', () => { expect(stripHtmlTags('')).toBe(''); }); it('strips simple HTML tags', () => { expect(stripHtmlTags('

Hello

')).toBe('Hello'); expect(stripHtmlTags('
World
')).toBe('World'); }); it('strips self-closing tags', () => { expect(stripHtmlTags('Hello
World')).toBe('HelloWorld'); expect(stripHtmlTags('Hello
World')).toBe('HelloWorld'); }); it('strips tags with attributes', () => { expect(stripHtmlTags('Link')).toBe('Link'); expect(stripHtmlTags('Image')).toBe(''); }); it('strips nested tags', () => { expect(stripHtmlTags('

Nested

')).toBe('Nested'); }); it('preserves plain text', () => { expect(stripHtmlTags('Hello World')).toBe('Hello World'); }); it('strips multiple tags', () => { expect(stripHtmlTags('

One

Two

Three

')).toBe('OneTwoThree'); }); it('handles malformed tags', () => { expect(stripHtmlTags('
Content
')).toBe('Content'); }); }); describe('htmlToMarkdown', () => { it('returns empty string for null input', () => { expect(htmlToMarkdown(null)).toBe(''); }); it('returns empty string for undefined input', () => { expect(htmlToMarkdown(undefined)).toBe(''); }); it('returns empty string for empty string input', () => { expect(htmlToMarkdown('')).toBe(''); }); it('converts paragraph tags', () => { expect(htmlToMarkdown('

First paragraph

Second paragraph

')).toBe('First paragraph\n\nSecond paragraph'); }); it('converts br tags to newlines', () => { expect(htmlToMarkdown('Line one
Line two')).toBe('Line one\nLine two'); expect(htmlToMarkdown('Line one
Line two')).toBe('Line one\nLine two'); expect(htmlToMarkdown('Line one
Line two')).toBe('Line one\nLine two'); }); it('converts heading tags to bold', () => { expect(htmlToMarkdown('

Heading

')).toBe('**Heading**'); expect(htmlToMarkdown('

Heading

')).toBe('**Heading**'); expect(htmlToMarkdown('
Heading
')).toBe('**Heading**'); }); it('converts list items', () => { const html = '
  • Item 1
  • Item 2
'; const result = htmlToMarkdown(html); expect(result).toContain('Item 1'); expect(result).toContain('Item 2'); }); it('converts code blocks', () => { expect(htmlToMarkdown('
const x = 1;
')).toContain('```\nconst x = 1;\n```'); }); it('converts inline code', () => { expect(htmlToMarkdown('Use npm install to install')).toBe('Use `npm install` to install'); }); it('converts bold tags', () => { expect(htmlToMarkdown('Bold text')).toBe('**Bold text**'); expect(htmlToMarkdown('Bold text')).toBe('**Bold text**'); }); it('converts italic tags', () => { expect(htmlToMarkdown('Italic text')).toBe('_Italic text_'); expect(htmlToMarkdown('Italic text')).toBe('_Italic text_'); }); it('converts links', () => { expect(htmlToMarkdown('Example')).toBe('[Example](https://example.com)'); }); it('collapses multiple newlines', () => { expect(htmlToMarkdown('

A

B

')).toBe('A\n\nB'); }); it('trims whitespace', () => { expect(htmlToMarkdown('

Content

')).toBe('Content'); }); it('decodes HTML entities in the result', () => { expect(htmlToMarkdown('

Hello & World

')).toBe('Hello & World'); }); it('handles complex mixed HTML', () => { const html = '

This is bold and italic with a link.

'; const expected = 'This is **bold** and _italic_ with a [link](https://example.com).'; expect(htmlToMarkdown(html)).toBe(expected); }); });