UNPKG

substance

Version:

Substance is a JavaScript library for web-based content editing. It provides building blocks for realizing custom text editors and web-based publishing systems.

183 lines (165 loc) 6.34 kB
import { module } from 'substance-test' import { DOMImporter, DefaultDOMElement } from 'substance' import getTestConfig from './fixture/getTestConfig' const test = module('DOMImporter') const pConverter = { type: 'paragraph', tagName: 'p', import(el, node, converter) { node.content = converter.annotatedText(el, [node.id, 'content']) } } test("creating a DOMImporter", (t) => { const schema = getTestConfig().getSchema() // fail without converters t.throws(() => { new DOMImporter({ schema }) }, 'should throw if no converters are given') // fail without DocumentClass t.throws(() => { new DOMImporter({ converters: [] }) }, 'should throw if schema is not given') // fail if a converter has no associated type t.throws(() => { new DOMImporter({ schema, converters: [{ matchElement() { return true } }] }) }, 'should throw if a converter does not have associated type') // fail if a converter has no matcher t.throws(() => { new DOMImporter({ schema, converters: [{ type: 'paragraph' }] }) }, 'should throw if a converter does not have a matcher function') t.throws(() => { new DOMImporter({ schema, converters: [{ type: 'heading', tagName: 'h1' }] }) }, 'should throw if there is no converter for the defaultTextType') t.throws(() => { new DOMImporter({ schema, converters: [{ type: 'foo', tagName: 'h1' }] }) }, 'should throw if a converter is associated with an unknown node type') t.end() }) test("default matchElement()", (t) => { const testConverter = { type: 'paragraph', tagName: 'p' } const importer = createImporter([testConverter]) t.notNil(importer._allConverters[0].matchElement, 'registered converter should have a matchElement() function') t.end() }) test("using a Converter class", (t) => { class MyConverter { get type() { return 'paragraph' } get tagName() { return 'p' } } const importer = createImporter([MyConverter]) t.equal(importer._allConverters[0].tagName, 'p', 'there should be one converter registered for <p>') t.end() }) test("convertElement() -- block element", (t) => { const importer = createImporter() const el = DefaultDOMElement.parseSnippet('<p>TEST</p>', 'html') const node = importer.convertElement(el) t.equal(node.type, 'paragraph', 'should have converted element to node') t.end() }) // Note: it is not common to convert inline nodes outside of their context -- that's why they are called inline test("convertElement() -- inline node", (t) => { const testConverter = { type: 'test-inline-node', matchElement(el) { return el.is('[data-type=test-inline-node]') }, import(el, node) { node.content = el.textContent } } const importer = createImporter([pConverter, testConverter]) const el = DefaultDOMElement.parseSnippet('<span data-type="test-inline-node">TEST</span>', 'html') const node = importer.convertElement(el) t.equal(node.type, 'test-inline-node', 'should have converted element to node') t.end() }) // Note: it is not common to convert annotations outside of their context test("convertElement() -- annotation element", (t) => { const importer = createImporter() const el = DefaultDOMElement.parseSnippet('<b>TEST</b>', 'html') const node = importer.convertElement(el) t.equal(node.type, 'strong', 'should have converted element to node') t.end() }) test("convertElement() should throw if no converter found", (t) => { const importer = createImporter([pConverter]) const el = DefaultDOMElement.parseSnippet('<h1>TEST</h1>', 'html') t.throws(() => { importer.convertElement(el) }, 'should throw if no converter found') t.end() }) test("converting paragraph with inline node", (t) => { const testConverter = { type: 'test-inline-node', matchElement(el) { return el.is('[data-type=test-inline-node]') } } const importer = createImporter([pConverter, testConverter]) const el = DefaultDOMElement.parseSnippet('<p>abc <span data-type="test-inline-node">TEST</span> def</p>', 'html') const node = importer.convertElement(el) t.equal(node.content, `abc ${DOMImporter.INVISIBLE_CHARACTER} def`, 'should have inserted an invisible character') t.end() }) test("converting an annotated paragraph", (t) => { const importer = createImporter() const el = DefaultDOMElement.parseSnippet('<p>abc <b>TEST</b> def</p>', 'html') const node = importer.convertElement(el) const doc = node.getDocument() const annos = doc.getAnnotations([node.id]) t.equal(annos.length, 1, 'there should be one annotation') t.end() }) test("plainText()", (t) => { const testConverter = Object.assign({}, pConverter, { import(el, node, converter) { node.content = converter.plainText(el) } }) const importer = createImporter([testConverter]) const el = DefaultDOMElement.parseSnippet('<p>abc <b>TEST</b> def</p>', 'html') const node = importer.convertElement(el) t.equal(node.content, `abc TEST def`, 'should have converted plain text') t.end() }) test("convertContainer() -- trailing text", (t) => { const importer = createImporter() const els = DefaultDOMElement.parseSnippet('<p>A paragraph</p> and some trailing text', 'html') let container = importer.convertContainer(els, 'body') t.equal(container.getLength(), 2, 'should have two nodes') t.deepEqual(container.getNodes().map(n=>n.type), ['paragraph', 'paragraph'], 'both should be paragraphs') t.end() }) test("resolving id collisions", (t) => { // converter with 'tagName' gets a default matcher const importer = createImporter() const els = DefaultDOMElement.parseSnippet('<p id="foo">A paragraph</p><p id="foo">and another one with the same id</p>', 'html') let container = importer.convertContainer(els, 'body') t.equal(container.getLength(), 2, 'should have two nodes') t.equal(container.getNodeIdAt(0), 'foo', 'first should have the original id') t.notEqual(container.getNodeIdAt(1), 'foo', 'second should have a new one') t.end() }) /* TODO: - import with options */ function createImporter(converters) { const config = getTestConfig() const schema = config.getSchema() if (!converters) { converters = config.getConverterRegistry().get('html').values() } return new DOMImporter({ schema, converters: converters }) }