import htmlUtils, { extractHtmlBody, htmlDocIsImageOnly, ProcessAnchorTagsAction, ProcessAnchorTagsEvent, removeWrappingParagraphAndTrailingEmptyElements } from './htmlUtils'; describe('htmlUtils', () => { test('should strip off HTML', () => { const testCases = [ [ '', '', ], [ 'test', 'test', ], [ 'Joplin®', 'JoplinĀ®', ], [ '<b>test</b>', '<b>test</b>', ], ]; for (const t of testCases) { const [input, expected] = t; const actual = htmlUtils.stripHtml(input); expect(actual).toBe(expected); } }); test('should extract the HTML body', () => { const testCases: [string, string][] = [ [ 'Just testing', 'Just testing', ], [ '', '', ], [ 'Here is the body', 'Here is the body', ], ]; for (const [input, expected] of testCases) { const actual = extractHtmlBody(input); expect(actual).toBe(expected); } }); test('should tell if an HTML document is an image only', () => { const testCases: [string, boolean][] = [ [ // This is the kind of HTML that's pasted when copying an image from Chrome '\n', true, ], [ '', false, ], [ '', true, ], [ '', false, ], [ '

Some text

', false, ], [ ' Some text', false, ], ]; for (const [input, expected] of testCases) { const actual = htmlDocIsImageOnly(input); expect(actual).toBe(expected); } }); it.each([ ['

Test

', 'Test'], ['

Testing

A test

', '

Testing

A test

'], ['

Testing


', '

Testing


'], ['

Testing

', '

Testing

'], ['

Testing

', 'Testing'], ['

is

\n', 'is\n'], ])('should remove empty elements (case %#)', (before, expected) => { expect(removeWrappingParagraphAndTrailingEmptyElements(before)).toBe(expected); }); it.each([ [':/0123456789abcdef0123456789abcdef', true], [':/0123456789abcdef0123456789abcdef/anchor', true], ['javascript:/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;alert(1)', false], ['data:/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;alert(1)', false], ['vbscript:/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', false], [':/short', false], ])('should only allow resource-style URLs anchored to the start (input: %s)', (href, shouldKeep) => { const output = htmlUtils.sanitizeHtml(`Click`); if (shouldKeep) { expect(output).toContain(`href="${href}"`); } else { expect(output).not.toContain(`href="${href}"`); expect(output).toContain('href="#"'); } }); it.each([ ['href', 'https://example.com/', true], ['href', 'ms-msdt:/id/PCWDiagnostic', false], ['xlink:href', 'https://example.com/', true], ['xlink:href', 'ms-msdt:/id/PCWDiagnostic', false], ['xlink:href', 'javascript:alert(1)', false], ])('should scheme-filter %s links (input: %s)', (attrName, url, shouldKeep) => { const output = htmlUtils.sanitizeHtml(`Click`); if (shouldKeep) { expect(output).toContain(`${attrName}="${url}"`); } else { expect(output).not.toContain(`${attrName}="${url}"`); expect(output).toContain(`${attrName}="#"`); } }); it.each([ { label: 'should replace anchor href attributes', input: 'test
another
', mapper: (): ProcessAnchorTagsAction => ( { type: 'replaceSource', href: 'updated' } ), expected: 'test
another
', }, { label: 'should replace full anchor opening tags', input: 'test', mapper: (): ProcessAnchorTagsAction => ( { type: 'replaceElement', html: '' } ), expected: 'test', }, { label: 'should preserve comments', input: 'test ', mapper: (): null => null, expected: 'test ', }, { label: 'should gracefully handle unbalanced tags', input: '
test test', mapper: (): null => null, expected: '
test test', }, { label: 'should escape "s and >s in attribute names', input: 'Test', mapper: (event: ProcessAnchorTagsEvent): ProcessAnchorTagsAction => ( { type: 'replaceSource', href: `${event.href}">` } ), expected: 'Test', }, ])('should replace anchor tags: $label', ({ input, mapper, expected }) => { expect(htmlUtils.processAnchorTags(input, mapper)).toBe(expected); }); });