import { expect } from '@open-wc/testing'; import { TextSelection, NodeSelection, AllSelection } from 'prosemirror-state'; import { defaultSchema, htmlToDoc, htmlToSlice, docToHtml, isOfficeHtml, cleanOfficeHtml, docToMarkdown, sanitizeHtml, createEditorState, getCommand, computeToolbarState, isDocEmpty, countWords, getFindState, searchTr, findStepTr, replaceActiveTr, replaceAllTr, plainTextSlice, stripSliceFormatting, } from './index'; import type { SuggestionMatch } from './plugins/suggestions'; import { toEmbedUrl, isAllowedEmbedSrc } from './plugins/embeds'; import { codeHighlightKey } from './plugins/code-highlight'; /** Builds an editor state with the whole document selected. */ function stateWithAllSelected(html: string) { const doc = htmlToDoc(defaultSchema, html); const state = createEditorState({ doc }); const selection = TextSelection.create(state.doc, 1, state.doc.content.size - 1); return state.apply(state.tr.setSelection(selection)); } describe('sanitizeHtml', () => { it('removes script elements entirely', () => { expect(sanitizeHtml('

hi

')).to.equal('

hi

'); }); it('removes inline event handlers', () => { const out = sanitizeHtml('

hi

'); expect(out).to.not.include('onclick').and.to.not.include('onmouseover'); }); it('drops javascript: URLs', () => { const out = sanitizeHtml('x'); expect(out).to.not.include('javascript:'); }); it('keeps safe links and forces noopener on _blank', () => { const out = sanitizeHtml('x'); expect(out).to.include('https://example.com'); expect(out).to.include('noopener'); }); it('filters style declarations to the allowed set', () => { const out = sanitizeHtml( 'x' ); expect(out).to.include('color: red'); expect(out).to.not.include('position'); expect(out).to.not.include('url('); }); it('unwraps unknown elements but keeps their content', () => { expect(sanitizeHtml('

kept

')).to.equal('

kept

'); }); it('drops non-https iframes and forms with content', () => { const out = sanitizeHtml( '

ok

' ); expect(out).to.equal('

ok

'); }); it('keeps

ok

' ); expect(out).to.include('' ); expect(out).to.include('url(data:image/png'); expect(out).to.include('url(#f)'); }); }); describe('serializer round-trip', () => { const cases = [ '

plain text

', '

heading

body

', '

bold and italic and underlined

', '', '
  1. first

', '

quoted

', '

link

', '

centered

', '

red

', '

line
break

', '
', ]; for (const html of cases) { it(`round-trips ${html.slice(0, 40)}`, () => { const doc = htmlToDoc(defaultSchema, html); const out = docToHtml(doc); const reparsed = htmlToDoc(defaultSchema, out); expect(reparsed.eq(doc), `stable parse for ${html}`).to.equal(true); }); } it('parses Word-style font-weight styles as bold', () => { const doc = htmlToDoc(defaultSchema, '

x

'); expect(docToHtml(doc)).to.include(''); }); it('round-trips an author

hi

'); expect(doc.firstChild!.type.name).to.equal('styleBlock'); const out = docToHtml(doc); expect(out).to.include('

ok

') ); expect(evil).to.include('