Current Path : /var/www/www-root/data/www/monolith-realty.ru/bitrix/js/ui/bbcode/model/test/nodes/ |
Current File : /var/www/www-root/data/www/monolith-realty.ru/bitrix/js/ui/bbcode/model/test/nodes/nodes.test.js |
import { BBCodeNode } from '../../src/nodes/node'; import { BBCodeScheme } from '../../src/scheme/bbcode-scheme'; import { BBCodeTagScheme } from '../../src/scheme/node-schemes/tag-scheme'; import { DefaultBBCodeScheme } from '../../src/scheme/default-bbcode-scheme'; describe('ui.bbcode.model/nodes', () => { let scheme; beforeEach(() => { scheme = new DefaultBBCodeScheme(); }); describe('TextNode', () => { it('Create TextNode with options object', () => { const parent = scheme.createNode({ name: 'p' }); const node = scheme.createText({ content: 'test text', name: '1111', parent, }); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === 'test text'); assert.ok(node.toString() === 'test text'); assert.ok(node.getParent() === parent); assert.ok(node.getName() === '#text'); }); it('Create TextNode with options string', () => { const node = scheme.createText('test text'); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === 'test text'); assert.ok(node.toString() === 'test text'); }); it('Should return decoded content', () => { const node = scheme.createText('[text]'); assert.ok(node.getContent() === '[text]'); assert.ok(node.toString() === '[text]'); }); it('TextNode.setParent()', () => { const node = scheme.createText(); const parent1 = scheme.createNode({ name: 'p' }); const parent2 = scheme.createNode({ name: 'p' }); assert.ok(node.getParent() === null); node.setParent(parent1); assert.ok(node.getParent() === parent1); node.setParent(parent2); assert.ok(node.getParent() === parent2); node.setParent(null); assert.ok(node.getParent() === null); }); it('TextNode.toJSON()', () => { const node = scheme.createText('test text'); assert.deepEqual(node.toJSON(), {content: 'test text', name: '#text'}); }); it('TextNode.setName()', () => { const node = scheme.createText(); assert.ok(node.getName() === '#text'); node.setName('11111'); assert.ok(node.getName() === '#text'); }); it('TextNode.clone()', () => { const sourceNode = scheme.createText('test text'); const clonedNode = sourceNode.clone(); assert.deepEqual(sourceNode.toString(), clonedNode.toString()); assert.ok(sourceNode.getScheme() === clonedNode.getScheme()); }); describe('TextNode.split()', () => { it('should throws if passed offset less than 0', () => { const textNode = scheme.createText('test text'); assert.throws(() => { textNode.split({ offset: -1}); }); assert.throws(() => { textNode.split({ offset: -20 }); }); }); it('should throws if passed offset more than text length', () => { const textNode = scheme.createText('test text'); assert.throws(() => { textNode.split({ offset: 10 }); }); assert.throws(() => { textNode.split({ offset: 20 }); }); }); it('should returns null for left node if passed 0 offset', () => { const textNode = scheme.createText('test text'); const [leftNode, rightNode] = textNode.split({ offset: 0 }); assert.ok(leftNode === null); assert.ok(rightNode.getName() === '#text'); }); it('should returns null for right node if offset equal text length', () => { const textNode = scheme.createText('test text'); const [leftNode, rightNode] = textNode.split({ offset: 9 }); assert.ok(leftNode.getName() === '#text'); assert.ok(rightNode === null); }); it('should split node if passed offset in text range', () => { const textNode = scheme.createText('test text'); const [leftNode1, rightNode1] = textNode.split({ offset: 1 }); assert.ok(leftNode1.getContent() === 't'); assert.ok(rightNode1.getContent() === 'est text'); const [leftNode2, rightNode2] = textNode.split({ offset: 2 }); assert.ok(leftNode2.getContent() === 'te'); assert.ok(rightNode2.getContent() === 'st text'); const [leftNode3, rightNode3] = textNode.split({ offset: 3 }); assert.ok(leftNode3.getContent() === 'tes'); assert.ok(rightNode3.getContent() === 't text'); const [leftNode4, rightNode4] = textNode.split({ offset: 4 }); assert.ok(leftNode4.getContent() === 'test'); assert.ok(rightNode4.getContent() === ' text'); const [leftNode5, rightNode5] = textNode.split({ offset: 5 }); assert.ok(leftNode5.getContent() === 'test '); assert.ok(rightNode5.getContent() === 'text'); const [leftNode6, rightNode6] = textNode.split({ offset: 6 }); assert.ok(leftNode6.getContent() === 'test t'); assert.ok(rightNode6.getContent() === 'ext'); const [leftNode7, rightNode7] = textNode.split({ offset: 7 }); assert.ok(leftNode7.getContent() === 'test te'); assert.ok(rightNode7.getContent() === 'xt'); const [leftNode8, rightNode8] = textNode.split({ offset: 8 }); assert.ok(leftNode8.getContent() === 'test tex'); assert.ok(rightNode8.getContent() === 't'); }); it('should returns this node as left node if offset is equal content length', () => { const textNode = scheme.createText('test text'); const [leftNode, rightNode] = textNode.split({ offset: 9 }); assert.ok(leftNode === textNode); assert.ok(rightNode === null); }); it('should returns this node as right node if offset is equal 0', () => { const textNode = scheme.createText('test text'); const [leftNode, rightNode] = textNode.split({ offset: 0 }); assert.ok(leftNode === null); assert.ok(rightNode === textNode); }); }); }); describe('NewLineNode', () => { it('Create NewLineNode without options', () => { const node = scheme.createNewLine(); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === '\n'); assert.ok(node.toString() === '\n'); }); it('Create NewLineNode with options object', () => { const parent = scheme.createNode({ name: 'p' }); const node = scheme.createNewLine({ content: '1111', name: '11111', parent, }); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === '\n'); assert.ok(node.toString() === '\n'); assert.ok(node.getParent() === parent); assert.ok(node.getName() === '#linebreak'); }); it('Create NewLineNode with options string', () => { const node = scheme.createNewLine('1111'); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === '\n'); assert.ok(node.toString() === '\n'); }); it('NewLineNode.setContent() do not affected content property', () => { const node = scheme.createNewLine(); node.setContent('1111111'); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === '\n'); assert.ok(node.toString() === '\n'); }); it('NewLineNode.setParent()', () => { const node = scheme.createNewLine(); const parent1 = scheme.createNode({ name: 'p' }); const parent2 = scheme.createNode({ name: 'p' }); assert.ok(node.getParent() === null); node.setParent(parent1); assert.ok(node.getParent() === parent1); node.setParent(parent2); assert.ok(node.getParent() === parent2); node.setParent(null); assert.ok(node.getParent() === null); }); it('NewLineNode.toJSON()', () => { const node = scheme.createNewLine(); assert.deepEqual(node.toJSON(), {content: '\n', name: '#linebreak'}); }); it('NewLineNode.setName()', () => { const node = scheme.createNewLine(); assert.ok(node.getName() === '#linebreak'); node.setName('111111'); assert.ok(node.getName() === '#linebreak'); }); it('NewLineNode.setContent()', () => { const node = scheme.createNewLine(); assert.ok(node.getContent() === '\n'); node.setContent('111111'); assert.ok(node.getContent() === '\n'); }); it('NewLineNode.clone()', () => { const sourceNode = scheme.createNewLine(); const clonedNode = sourceNode.clone(); assert.deepEqual(sourceNode.toString(), clonedNode.toString()); assert.ok(sourceNode.getScheme() === clonedNode.getScheme()); }); }); describe('TabNode', () => { it('Create TabNode without options', () => { const node = scheme.createTab(); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === '\t'); assert.ok(node.toString() === '\t'); }); it('Create TabNode with options object', () => { const parent = scheme.createNode({ name: 'p' }); const node = scheme.createTab({ content: '1111', parent }); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === '\t'); assert.ok(node.toString() === '\t'); assert.ok(node.getParent() === parent); }); it('Create TabNode with options string', () => { const node = scheme.createTab('1111'); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === '\t'); assert.ok(node.toString() === '\t'); }); it('TabNode.setContent() do not affected content property', () => { const node = scheme.createTab(); node.setContent('1111111'); assert.ok(node.getType() === BBCodeNode.TEXT_NODE); assert.ok(node.getContent() === '\t'); assert.ok(node.toString() === '\t'); }); it('TabNode.setParent()', () => { const node = scheme.createTab(); const parent1 = scheme.createNode({ name: 'p' }); const parent2 = scheme.createNode({ name: 'p' }); assert.ok(node.getParent() === null); node.setParent(parent1); assert.ok(node.getParent() === parent1); node.setParent(parent2); assert.ok(node.getParent() === parent2); node.setParent(null); assert.ok(node.getParent() === null); }); it('TabNode.toJSON()', () => { const node = scheme.createTab(); assert.deepEqual(node.toJSON(), {content: '\t', name: '#tab'}); }); it('TabNode.setName()', () => { const node = scheme.createTab(); assert.ok(node.getName() === '#tab'); node.setName('111111'); assert.ok(node.getName() === '#tab'); }); it('TabNode.setContent()', () => { const node = scheme.createTab(); assert.ok(node.getContent() === '\t'); node.setContent('111111'); assert.ok(node.getContent() === '\t'); }); it('TabNode.clone()', () => { const sourceNode = scheme.createTab(); const clonedNode = sourceNode.clone(); assert.deepEqual(sourceNode.toString(), clonedNode.toString()); assert.ok(sourceNode.getScheme() === clonedNode.getScheme()); }); }); describe('FragmentNode', () => { it('Create FragmentNode with options', () => { const node = scheme.createFragment({ children: [ scheme.createText('text'), scheme.createFragment({ children: [ scheme.createText('text2'), ], }) ], }); assert.ok(node.getType() === BBCodeNode.FRAGMENT_NODE); assert.ok(node.getChildrenCount() === 2); assert.ok(node.getChildren().at(0).getContent() === 'text'); assert.ok(node.getChildren().at(1).getContent() === 'text2'); }); it('FragmentNode.clone()', () => { const sourceNode = scheme.createFragment(); const clonedNode = sourceNode.clone(); assert.deepEqual(sourceNode.toString(), clonedNode.toString()); }); it('FragmentNode.clone({ deep: true })', () => { const sourceNode = scheme.createFragment({ children: [ scheme.createElement({ name: 'b', children: [ scheme.createText('test text'), ], }), ], }); const clonedNode = sourceNode.clone({ deep: true }); assert.deepEqual(sourceNode.toString(), clonedNode.toString()); assert.ok(sourceNode.getScheme() === clonedNode.getScheme()); }); it('Must be able to include any elements', () => { const fragment = scheme.createFragment(); const p = scheme.createElement({ name: 'p' }); const b = scheme.createElement({ name: 'b' }); const table = scheme.createElement({ name: 'table' }); const td = scheme.createElement({ name: 'td' }); const spoiler = scheme.createElement({ name: 'spoiler' }); const newline = scheme.createNewLine(); const tab = scheme.createTab(); fragment.appendChild(p, b, table, td, spoiler, newline, tab); assert.ok(fragment.getChildren().includes(p)); assert.ok(fragment.getChildren().includes(b)); assert.ok(fragment.getChildren().includes(table)); assert.ok(fragment.getChildren().includes(td)); assert.ok(fragment.getChildren().includes(spoiler)); assert.ok(fragment.getChildren().includes(newline)); assert.ok(fragment.getChildren().includes(tab)); }); }); describe('ElementNode', () => { it('Create ElementNode with options object', () => { const node = scheme.createElement({ name: 'p', }); assert.ok(node.getType() === BBCodeNode.ELEMENT_NODE); assert.ok(node.getName() === 'p'); assert.ok(node.getValue() === ''); assert.ok(node.isVoid() === false); assert.deepEqual(node.getAttributes(), {}); assert.ok(node.getChildrenCount() === 0); assert.deepEqual(node.getChildren(), []); assert.ok(node.hasChildren() === false); const node2 = scheme.createElement({ name: 'disk', value: 'test', attributes: { key1: 'value1', key2: true, key3: 33, }, }); assert.ok(node2.getType() === BBCodeNode.ELEMENT_NODE); assert.ok(node2.getName() === 'disk'); assert.ok(node2.getValue() === 'test'); assert.ok(node2.isVoid() === true); assert.deepEqual(node2.getAttributes(), { key1: 'value1', key2: true, key3: 33 }); const node3 = scheme.createElement({ name: 'p', children: [ scheme.createText('test'), scheme.createElement({ name: 'b', children: [ scheme.createText('bold'), ], }), scheme.createNewLine(), scheme.createNewLine(), scheme.createElement({ name: 'i', }), scheme.createFragment({ children: [ scheme.createElement({ name: 'b', value: 'fragment1', }), scheme.createText('fragment2'), scheme.createNewLine(), scheme.createTab(), ], }), ], }); assert.ok(node3.getType() === BBCodeNode.ELEMENT_NODE); assert.ok(node3.getName() === 'p'); assert.ok(node3.getChildrenCount() === 8); assert.ok(node3.hasChildren() === true); assert.ok(node3.getChildren().at(0).getType() === BBCodeNode.TEXT_NODE); assert.ok(node3.getChildren().at(0).getContent() === 'test'); assert.ok(node3.getChildren().at(1).getType() === BBCodeNode.ELEMENT_NODE); assert.ok(node3.getChildren().at(1).getName() === 'b'); assert.ok(node3.getChildren().at(1).getChildrenCount() === 1); assert.ok(node3.getChildren().at(1).getChildren().at(0).getType() === BBCodeNode.TEXT_NODE); assert.ok(node3.getChildren().at(1).getChildren().at(0).getContent() === 'bold'); assert.ok(node3.getChildren().at(2).getType() === BBCodeNode.TEXT_NODE); assert.ok(node3.getChildren().at(2).getContent() === '\n'); assert.ok(node3.getChildren().at(3).getType() === BBCodeNode.TEXT_NODE); assert.ok(node3.getChildren().at(3).getContent() === '\n'); assert.ok(node3.getChildren().at(4).getType() === BBCodeNode.ELEMENT_NODE); assert.ok(node3.getChildren().at(4).getName() === 'i'); assert.ok(node3.getChildren().at(5).getType() === BBCodeNode.ELEMENT_NODE); assert.ok(node3.getChildren().at(5).getName() === 'b'); assert.ok(node3.getChildren().at(5).getValue() === 'fragment1'); assert.ok(node3.getChildren().at(6).getType() === BBCodeNode.TEXT_NODE); assert.ok(node3.getChildren().at(6).getContent() === 'fragment2'); assert.ok(node3.getChildren().at(7).getType() === BBCodeNode.TEXT_NODE); assert.ok(node3.getChildren().at(7).getContent() === '\n'); }); it('ElementNode.appendChild()', () => { const node = scheme.createElement({ name: 'p', }); const bold = scheme.createElement({ name: 'b', }); const italic = scheme.createElement({ name: 'i', }); assert.ok(node.hasChildren() === false); node.appendChild(bold); assert.ok(node.hasChildren() === true); assert.ok(node.getChildrenCount() === 1); assert.ok(node.getChildren().at(0) === bold); assert.ok(bold.getParent() === node); node.appendChild(italic); assert.ok(node.hasChildren() === true); assert.ok(node.getChildrenCount() === 2); assert.ok(node.getChildren().at(0) === bold); assert.ok(node.getChildren().at(1) === italic); assert.ok(italic.getParent() === node); node.appendChild(bold); assert.ok(node.getChildrenCount() === 2); assert.ok(node.getChildren().at(0) === italic); assert.ok(node.getChildren().at(1) === bold); assert.ok(bold.getParent() === node); }); it('ElementNode.replaceChild()', () => { const node = scheme.createElement({ name: 'p', }); const bold = scheme.createElement({ name: 'b', }); const italic = scheme.createElement({ name: 'i', }); node.appendChild(bold); assert.ok(node.getChildrenCount() === 1); assert.ok(node.getChildren().at(0) === bold); assert.ok(node.getChildren().at(0).getParent() === node); node.replaceChild(bold, italic); assert.ok(node.getChildrenCount() === 1); assert.ok(node.getChildren().at(0) === italic); assert.ok(node.getChildren().at(0).getParent() === node); assert.ok(bold.getParent() === null); const strike = scheme.createElement({ name: 's' }); const text = scheme.createText('test'); const fragment = scheme.createFragment({ children: [ strike, text, ], }); node.replaceChild(italic, fragment); assert.ok(node.getChildrenCount() === 2); assert.ok(node.getChildren().at(0) === strike); assert.ok(node.getChildren().at(1) === text); }); it('ElementNode.removeChild()', () => { const node = scheme.createElement({ name: 'p', }); const bold = scheme.createElement({ name: 'b', }); const text = scheme.createText('test'); const newLine = scheme.createNewLine(); node.appendChild(...[bold, text, newLine]); assert.ok(node.getChildrenCount() === 3); assert.ok(node.getChildren().at(0) === bold); assert.ok(node.getChildren().at(1) === text); assert.ok(node.getChildren().at(2) === newLine); node.removeChild(text); assert.ok(text.getParent() === null); assert.ok(node.getChildrenCount() === 2); assert.ok(node.getChildren().at(0) === bold); assert.ok(node.getChildren().at(1) === newLine); node.removeChild(bold); assert.ok(node.getChildrenCount() === 1); assert.ok(bold.getParent() === null); assert.ok(node.getChildren().at(0) === newLine); }); it('Table child filter', () => { const table = scheme.createElement({ name: 'table', children: [ scheme.createElement({ name: 'p' }), scheme.createElement({ name: 'td' }), scheme.createElement({ name: 'th' }), scheme.createElement({ name: 'tr' }), scheme.createText('test'), scheme.createNewLine(), scheme.createTab(), ], }); assert.ok(table.getChildrenCount() === 1); assert.ok(table.getChildren().at(0).getType() === BBCodeNode.ELEMENT_NODE); assert.ok(table.getChildren().at(0).getName() === 'tr'); table.appendChild(scheme.createElement({ name: 'p' })); table.appendChild(scheme.createText('test')); table.appendChild(scheme.createNewLine()); assert.ok(table.getChildrenCount() === 1); assert.ok(table.getChildren().at(0).getType() === BBCodeNode.ELEMENT_NODE); assert.ok(table.getChildren().at(0).getName() === 'tr'); table.appendChild(scheme.createElement({ name: 'tr' })); assert.ok(table.getChildrenCount() === 2); assert.ok(table.getChildren().at(0).getType() === BBCodeNode.ELEMENT_NODE); assert.ok(table.getChildren().at(0).getName() === 'tr'); assert.ok(table.getChildren().at(1).getType() === BBCodeNode.ELEMENT_NODE); assert.ok(table.getChildren().at(1).getName() === 'tr'); }); it('Table row child filter', () => { const row = scheme.createElement({ name: 'tr', }); const tr = scheme.createElement({ name: 'tr' }); const td = scheme.createElement({ name: 'td' }); const th = scheme.createElement({ name: 'th' }); const p = scheme.createElement({ name: 'p' }); const text = scheme.createText('test'); row.appendChild(...[tr, td, th, p, text]); assert.ok(row.getChildrenCount() === 2); assert.ok(row.getChildren().at(0) === td); assert.ok(row.getChildren().at(1) === th); }); xit('Table cell child filter', () => { const td = scheme.createElement({ name: 'td' }); const table = scheme.createElement({ name: 'table' }); const tr = scheme.createElement({ name: 'tr' }); const p = scheme.createElement({ name: 'p' }); const bold = scheme.createElement({ name: 'b' }); const strike = scheme.createElement({ name: 's' }); const text = scheme.createText('test'); const newLine = scheme.createNewLine(); const tab = scheme.createTab(); td.appendChild(...[table, tr, p, bold, strike, text, newLine, tab]); assert.ok(td.getChildrenCount() === 4); assert.ok(td.getChildren().at(0) === bold); assert.ok(td.getChildren().at(1) === strike); assert.ok(td.getChildren().at(2) === text); assert.ok(td.getChildren().at(3) === newLine); }); it('Propagate unresolved nodes from constructor options', () => { const rootNode = scheme.createRoot({ children: [ scheme.createElement({ name: 'p', value: 'p1', children: [ scheme.createElement({ name: 'p', value: 'p2', }), ], }), ], }); assert.ok(rootNode.getChildrenCount() === 2); assert.ok(rootNode.getFirstChild().getValue() === 'p2'); assert.ok(rootNode.getLastChild().getValue() === 'p1'); }); it('Node name and attribute names must always be in lowercase', () => { const p = scheme.createElement({ name: 'P', attributes: { ATTR1: 'UPPER', aTTR2: 'LOWER', }, children: [ scheme.createElement({ name: 'B', }), ], }); assert.ok(p.getName() === 'p'); assert.ok(p.getAttribute('attr1') === 'UPPER'); assert.ok(p.getAttribute('attr2') === 'LOWER'); assert.deepEqual(p.getAttributes(), {attr1: 'UPPER', attr2: 'LOWER'}); assert.ok(p.getFirstChild().getName() === 'b'); }); it('Must return the tag name and attribute names with lowerCase', () => { const localFactory =new BBCodeScheme({ tagSchemes: [ new BBCodeTagScheme({ name: 'p', }), ], tagCase: BBCodeScheme.Case.LOWER, }); const p = localFactory.createElement({ name: 'P', attributes: { attr1: 'value1', attr2: 'value2', }, }); assert.ok(p.toString() === '[p attr1=value1 attr2=value2][/p]'); }); it('Must return the tag name and attribute names with upperCase', () => { const localScheme = new BBCodeScheme({ tagSchemes: [ new BBCodeTagScheme({ name: 'p', }), ], outputTagCase: BBCodeScheme.Case.UPPER, }); const p = localScheme.createElement({ name: 'P', attributes: { attr1: 'value1', attr2: 'value2', }, }); assert.ok(p.toString() === '[P ATTR1=value1 ATTR2=value2][/P]'); }); it('getName should return tag name in lowerCase', () => { const tagSchemes = [ new BBCodeTagScheme({ name: 'p', }), ]; const localScheme1 = new BBCodeScheme({ tagSchemes, }); const localScheme2 = new BBCodeScheme({ tagSchemes, tagCase: BBCodeScheme.Case.LOWER, }); const localScheme3 = new BBCodeScheme({ tagSchemes, tagCase: BBCodeScheme.Case.UPPER, }); const p1 = localScheme1.createElement({ name: 'P' }); const p2 = localScheme2.createElement({ name: 'P' }); const p3 = localScheme3.createElement({ name: 'P' }); assert.ok(p1.getName() === 'p'); assert.ok(p2.getName() === 'p'); assert.ok(p3.getName() === 'p'); }); it('getAttribute should be case-insensitive', () => { const tagSchemes = [ new BBCodeTagScheme({ name: 'p', }), ]; const localScheme = new BBCodeScheme({ tagSchemes, }); const localScheme2 = new BBCodeScheme({ tagSchemes, tagCase: BBCodeScheme.Case.LOWER, }); const localScheme3 = new BBCodeScheme({ tagSchemes, tagCase: BBCodeScheme.Case.UPPER, }); const p1 = localScheme.createElement({ name: 'p', attributes: { Attr1: 'value1', ATTR2: 'value2', attr3: 'value3', }, }); const p2 = localScheme2.createElement({ name: 'p', attributes: { Attr1: 'value1', ATTR2: 'value2', attr3: 'value3', }, }); const p3 = localScheme3.createElement({ name: 'p', attributes: { Attr1: 'value1', ATTR2: 'value2', attr3: 'value3', }, }); assert.ok(p1.getAttribute('attr1') === 'value1'); assert.ok(p1.getAttribute('Attr1') === 'value1'); assert.ok(p1.getAttribute('ATTR1') === 'value1'); assert.ok(p1.getAttribute('attr2') === 'value2'); assert.ok(p1.getAttribute('Attr2') === 'value2'); assert.ok(p1.getAttribute('ATTR2') === 'value2'); assert.ok(p1.getAttribute('attr3') === 'value3'); assert.ok(p1.getAttribute('Attr3') === 'value3'); assert.ok(p1.getAttribute('ATTR3') === 'value3'); assert.ok(p2.getAttribute('attr1') === 'value1'); assert.ok(p2.getAttribute('Attr1') === 'value1'); assert.ok(p2.getAttribute('ATTR1') === 'value1'); assert.ok(p2.getAttribute('attr2') === 'value2'); assert.ok(p2.getAttribute('Attr2') === 'value2'); assert.ok(p2.getAttribute('ATTR2') === 'value2'); assert.ok(p2.getAttribute('attr3') === 'value3'); assert.ok(p2.getAttribute('Attr3') === 'value3'); assert.ok(p2.getAttribute('ATTR3') === 'value3'); assert.ok(p3.getAttribute('attr1') === 'value1'); assert.ok(p3.getAttribute('Attr1') === 'value1'); assert.ok(p3.getAttribute('ATTR1') === 'value1'); assert.ok(p3.getAttribute('attr2') === 'value2'); assert.ok(p3.getAttribute('Attr2') === 'value2'); assert.ok(p3.getAttribute('ATTR2') === 'value2'); assert.ok(p3.getAttribute('attr3') === 'value3'); assert.ok(p3.getAttribute('Attr3') === 'value3'); assert.ok(p3.getAttribute('ATTR3') === 'value3'); }); describe('ElementNode.clone()', () => { it('Clone without options', () => { const sourceNode = scheme.createElement({ name: 'p', value: 'test', attributes: { x: 1, y: '2', }, children: [ scheme.createText('test text'), scheme.createElement({ name: 'b', children: [ scheme.createText('bold'), ], }), ], }); const clonedNode = sourceNode.clone(); assert.deepEqual(clonedNode.toString(), '[p=test x=1 y=2][/p]'); }); it('Clone with { deep: true }', () => { const sourceNode = scheme.createElement({ name: 'p', value: 'test', attributes: { x: 1, y: '2', }, children: [ scheme.createText('test text'), scheme.createElement({ name: 'b', children: [ scheme.createText('bold'), ], }), ], }); const clonedNode = sourceNode.clone(); assert.deepEqual(clonedNode.toString(), clonedNode.toString()); }); }); describe('Formatting', () => { it('Should add linebreak before opening tag if previews sibling is plain text', () => { const root = scheme.createRoot({ children: [ scheme.createText({ content: 'text' }), scheme.createElement({ name: 'p' }) ], }); assert.deepEqual(root.toString(), 'text\n[p][/p]'); }); it('Should not add linebreak before opening tag if previews sibling is linebreak', () => { const root = scheme.createRoot({ children: [ scheme.createText({ content: 'text' }), scheme.createNewLine(), scheme.createElement({ name: 'p' }) ], }); assert.deepEqual(root.toString(), 'text\n[p][/p]'); }); it('Should not add linebreak before opening tag if node is first child', () => { const root = scheme.createRoot({ children: [ scheme.createElement({ name: 'p' }), scheme.createText({ content: 'text' }), scheme.createNewLine(), ], }); assert.deepEqual(root.toString(), '[p][/p]\ntext\n'); }); it('Should add linebreak before opening tag if previews sibling is inline', () => { const root = scheme.createRoot({ children: [ scheme.createElement({ name: 'b' }), scheme.createElement({ name: 'p' }), ], }); assert.deepEqual(root.toString(), '[b][/b]\n[p][/p]'); }); it('Should add linebreak after closing tag if new sibling is plain text', () => { const root = scheme.createRoot({ children: [ scheme.createElement({ name: 'p' }), scheme.createText({ content: 'text' }), ], }); assert.deepEqual(root.toString(), '[p][/p]\ntext'); }); it('Should add linebreak after closing tag if new sibling is inline', () => { const root = scheme.createRoot({ children: [ scheme.createElement({ name: 'p' }), scheme.createElement({ name: 'b' }), ], }); assert.deepEqual(root.toString(), '[p][/p]\n[b][/b]'); }); it('Should not add linebreak after closing tag if new sibling is linebreak', () => { const root = scheme.createRoot({ children: [ scheme.createElement({ name: 'p' }), scheme.createNewLine() ], }); assert.deepEqual(root.toString(), '[p][/p]\n'); }); it('Should not add linebreak after closing tag if node is last child', () => { const root = scheme.createRoot({ children: [ scheme.createText({ content: 'text' }), scheme.createElement({ name: 'p' }), ], }); assert.deepEqual(root.toString(), 'text\n[p][/p]'); }); }); describe('ElementNode.splitByChildIndex()', () => { it('should return left and right node if passed index', () => { const node = scheme.createElement({ name: 'p', children: [ scheme.createElement({ name: 'b', children: [ scheme.createText('bold'), ], }), scheme.createElement({ name: 'i', children: [ scheme.createText('italic'), ], }), scheme.createElement({ name: 's', children: [ scheme.createText('strike'), ], }), ], }); const [leftNode, rightNode] = node.splitByChildIndex(1); assert.deepEqual(leftNode.toString(), '[p]\n[b]bold[/b]\n[/p]'); assert.deepEqual(rightNode.toString(), '[p]\n[i]italic[/i][s]strike[/s]\n[/p]'); }); it('should replaces this node with left and right nodes', () => { const node = scheme.createElement({ name: 'p', children: [ scheme.createElement({ name: 'b', children: [ scheme.createText('bold'), ], }), scheme.createElement({ name: 'i', children: [ scheme.createText('italic'), ], }), scheme.createElement({ name: 's', children: [ scheme.createText('strike'), ], }), ], }); const rootNode = scheme.createRoot({ children: [ node, ], }); const [leftNode, rightNode] = node.splitByChildIndex(1); assert.ok(rootNode.getChildrenCount() === 2); assert.ok(rootNode.getFirstChild() === leftNode); assert.ok(rootNode.getLastChild() === rightNode); }); it('should throws if passed index more than children count', () => { const node = scheme.createElement({ name: 'p', children: [ scheme.createText('test text'), ], }); assert.throws(() => { node.splitByChildIndex(2); }); assert.throws(() => { node.splitByChildIndex(99); }); }); it('should throws if passed index less than 0', () => { const node = scheme.createElement({ name: 'p', children: [ scheme.createText('test text'), ], }); assert.throws(() => { node.splitByChildIndex(-1); }); assert.throws(() => { node.splitByChildIndex(-22); }); }); }); describe('ElementNode.toPlainText()', () => { it('should returns plain text', () => { scheme.setTagScheme( new BBCodeTagScheme({ name: 'div', }), ); const node = scheme.createElement({ name: 'div', children: [ scheme.createElement({ name: 'b', children: [ scheme.createText('bold'), ], }), scheme.createElement({ name: 'i', children: [ scheme.createText(' italic'), ], }), scheme.createElement({ name: 's', children: [ scheme.createText(' strike'), ], }), scheme.createElement({ name: 'div', children: [ scheme.createText(' p1'), scheme.createText(' p2'), scheme.createElement({ name: 'div', children: [ scheme.createText(' pp1'), scheme.createText(' pp2'), ], }), ], }), ], }); assert.equal(node.toPlainText(), 'bold italic strike p1 p2 pp1 pp2'); }); }); describe('Node.split()', () => { it('Should split tree into left and right parts by index', () => { const localScheme = new BBCodeScheme({ tagSchemes: [ new BBCodeTagScheme({ name: ['b', 'i', 's'], }), new BBCodeTagScheme({ name: ['div1', 'div2', 'div3'], stringify: BBCodeTagScheme.defaultBlockStringifier, }), new BBCodeTagScheme({ name: '#text', }), ], }); const node = localScheme.createElement({ name: 'div1', children: [ localScheme.createElement({ name: 'b', children: [ localScheme.createText('bold'), ], }), localScheme.createElement({ name: 'i', children: [ localScheme.createText(' italic'), ], }), localScheme.createElement({ name: 's', children: [ localScheme.createText(' strike'), ], }), localScheme.createElement({ name: 'div2', children: [ localScheme.createText(' p1'), localScheme.createText(' p2'), localScheme.createElement({ name: 'div3', children: [ localScheme.createText(' pp1'), localScheme.createText(' pp2'), ], }), ], }), ], }); const [left0, right0] = node.split({ offset: 0 }); assert.ok(left0 === null); assert.deepEqual(right0, node); const [left1, right1] = node.split({ offset: 1 }); assert.deepEqual(left1.toString(), '[div1]\n[b]b[/b]\n[/div1]'); assert.deepEqual(right1.toString(), '[div1]\n[b]old[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left1.toPlainText(), 'b'); assert.deepEqual(right1.toPlainText(), 'old italic strike p1 p2 pp1 pp2'); const [left2, right2] = node.split({ offset: 2 }); assert.deepEqual(left2.toString(), '[div1]\n[b]bo[/b]\n[/div1]'); assert.deepEqual(right2.toString(), '[div1]\n[b]ld[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left2.toPlainText(), 'bo'); assert.deepEqual(right2.toPlainText(), 'ld italic strike p1 p2 pp1 pp2'); const [left3, right3] = node.split({ offset: 3 }); assert.deepEqual(left3.toString(), '[div1]\n[b]bol[/b]\n[/div1]'); assert.deepEqual(right3.toString(), '[div1]\n[b]d[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left3.toPlainText(), 'bol'); assert.deepEqual(right3.toPlainText(), 'd italic strike p1 p2 pp1 pp2'); const [left4, right4] = node.split({ offset: 4 }); assert.deepEqual(left4.toString(), '[div1]\n[b]bold[/b]\n[/div1]'); assert.deepEqual(right4.toString(), '[div1]\n[i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left4.toPlainText(), 'bold'); assert.deepEqual(right4.toPlainText(), ' italic strike p1 p2 pp1 pp2'); const [left5, right5] = node.split({ offset: 5 }); assert.deepEqual(left5.toString(), '[div1]\n[b]bold[/b][i] [/i]\n[/div1]'); assert.deepEqual(right5.toString(), '[div1]\n[i]italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left5.toPlainText(), 'bold '); assert.deepEqual(right5.toPlainText(), 'italic strike p1 p2 pp1 pp2'); const [left6, right6] = node.split({ offset: 6 }); assert.deepEqual(left6.toString(), '[div1]\n[b]bold[/b][i] i[/i]\n[/div1]'); assert.deepEqual(right6.toString(), '[div1]\n[i]talic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left6.toPlainText(), 'bold i'); assert.deepEqual(right6.toPlainText(), 'talic strike p1 p2 pp1 pp2'); const [left7, right7] = node.split({ offset: 7 }); assert.deepEqual(left7.toString(), '[div1]\n[b]bold[/b][i] it[/i]\n[/div1]'); assert.deepEqual(right7.toString(), '[div1]\n[i]alic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left7.toPlainText(), 'bold it'); assert.deepEqual(right7.toPlainText(), 'alic strike p1 p2 pp1 pp2'); const [left8, right8] = node.split({ offset: 8 }); assert.deepEqual(left8.toString(), '[div1]\n[b]bold[/b][i] ita[/i]\n[/div1]'); assert.deepEqual(right8.toString(), '[div1]\n[i]lic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left8.toPlainText(), 'bold ita'); assert.deepEqual(right8.toPlainText(), 'lic strike p1 p2 pp1 pp2'); const [left9, right9] = node.split({ offset: 9 }); assert.deepEqual(left9.toString(), '[div1]\n[b]bold[/b][i] ital[/i]\n[/div1]'); assert.deepEqual(right9.toString(), '[div1]\n[i]ic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left9.toPlainText(), 'bold ital'); assert.deepEqual(right9.toPlainText(), 'ic strike p1 p2 pp1 pp2'); const [left10, right10] = node.split({ offset: 10 }); assert.deepEqual(left10.toString(), '[div1]\n[b]bold[/b][i] itali[/i]\n[/div1]'); assert.deepEqual(right10.toString(), '[div1]\n[i]c[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left10.toPlainText(), 'bold itali'); assert.deepEqual(right10.toPlainText(), 'c strike p1 p2 pp1 pp2'); const [left11, right11] = node.split({ offset: 11 }); assert.deepEqual(left11.toString(), '[div1]\n[b]bold[/b][i] italic[/i]\n[/div1]'); assert.deepEqual(right11.toString(), '[div1]\n[s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left11.toPlainText(), 'bold italic'); assert.deepEqual(right11.toPlainText(), ' strike p1 p2 pp1 pp2'); const [left12, right12] = node.split({ offset: 12 }); assert.deepEqual(left12.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] [/s]\n[/div1]'); assert.deepEqual(right12.toString(), '[div1]\n[s]strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left12.toPlainText(), 'bold italic '); assert.deepEqual(right12.toPlainText(), 'strike p1 p2 pp1 pp2'); const [left13, right13] = node.split({ offset: 13 }); assert.deepEqual(left13.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] s[/s]\n[/div1]'); assert.deepEqual(right13.toString(), '[div1]\n[s]trike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left13.toPlainText(), 'bold italic s'); assert.deepEqual(right13.toPlainText(), 'trike p1 p2 pp1 pp2'); const [left14, right14] = node.split({ offset: 14 }); assert.deepEqual(left14.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] st[/s]\n[/div1]'); assert.deepEqual(right14.toString(), '[div1]\n[s]rike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left14.toPlainText(), 'bold italic st'); assert.deepEqual(right14.toPlainText(), 'rike p1 p2 pp1 pp2'); const [left15, right15] = node.split({ offset: 15 }); assert.deepEqual(left15.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] str[/s]\n[/div1]'); assert.deepEqual(right15.toString(), '[div1]\n[s]ike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left15.toPlainText(), 'bold italic str'); assert.deepEqual(right15.toPlainText(), 'ike p1 p2 pp1 pp2'); const [left16, right16] = node.split({ offset: 16 }); assert.deepEqual(left16.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] stri[/s]\n[/div1]'); assert.deepEqual(right16.toString(), '[div1]\n[s]ke[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left16.toPlainText(), 'bold italic stri'); assert.deepEqual(right16.toPlainText(), 'ke p1 p2 pp1 pp2'); const [left17, right17] = node.split({ offset: 17 }); assert.deepEqual(left17.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strik[/s]\n[/div1]'); assert.deepEqual(right17.toString(), '[div1]\n[s]e[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left17.toPlainText(), 'bold italic strik'); assert.deepEqual(right17.toPlainText(), 'e p1 p2 pp1 pp2'); const [left18, right18] = node.split({ offset: 18 }); assert.deepEqual(left18.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[/div1]'); assert.deepEqual(right18.toString(), '[div1]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left18.toPlainText(), 'bold italic strike'); assert.deepEqual(right18.toPlainText(), ' p1 p2 pp1 pp2'); const [left19, right19] = node.split({ offset: 19 }); assert.deepEqual(left19.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n \n[/div2]\n[/div1]'); assert.deepEqual(right19.toString(), '[div1]\n[div2]\np1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left19.toPlainText(), 'bold italic strike '); assert.deepEqual(right19.toPlainText(), 'p1 p2 pp1 pp2'); const [left20, right20] = node.split({ offset: 20 }); assert.deepEqual(left20.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p\n[/div2]\n[/div1]'); assert.deepEqual(right20.toString(), '[div1]\n[div2]\n1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left20.toPlainText(), 'bold italic strike p'); assert.deepEqual(right20.toPlainText(), '1 p2 pp1 pp2'); const [left21, right21] = node.split({ offset: 21 }); assert.deepEqual(left21.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1\n[/div2]\n[/div1]'); assert.deepEqual(right21.toString(), '[div1]\n[div2]\n p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left21.toPlainText(), 'bold italic strike p1'); assert.deepEqual(right21.toPlainText(), ' p2 pp1 pp2'); const [left22, right22] = node.split({ offset: 22 }); assert.deepEqual(left22.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 \n[/div2]\n[/div1]'); assert.deepEqual(right22.toString(), '[div1]\n[div2]\np2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left22.toPlainText(), 'bold italic strike p1 '); assert.deepEqual(right22.toPlainText(), 'p2 pp1 pp2'); const [left23, right23] = node.split({ offset: 23 }); assert.deepEqual(left23.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p\n[/div2]\n[/div1]'); assert.deepEqual(right23.toString(), '[div1]\n[div2]\n2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left23.toPlainText(), 'bold italic strike p1 p'); assert.deepEqual(right23.toPlainText(), '2 pp1 pp2'); const [left24, right24] = node.split({ offset: 24 }); assert.deepEqual(left24.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[/div2]\n[/div1]'); assert.deepEqual(right24.toString(), '[div1]\n[div2]\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left24.toPlainText(), 'bold italic strike p1 p2'); assert.deepEqual(right24.toPlainText(), ' pp1 pp2'); const [left25, right25] = node.split({ offset: 25 }); assert.deepEqual(left25.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n \n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(right25.toString(), '[div1]\n[div2]\n[div3]\npp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left25.toPlainText(), 'bold italic strike p1 p2 '); assert.deepEqual(right25.toPlainText(), 'pp1 pp2'); const [left26, right26] = node.split({ offset: 26 }); assert.deepEqual(left26.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n p\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(right26.toString(), '[div1]\n[div2]\n[div3]\np1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left26.toPlainText(), 'bold italic strike p1 p2 p'); assert.deepEqual(right26.toPlainText(), 'p1 pp2'); const [left27, right27] = node.split({ offset: 27 }); assert.deepEqual(left27.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(right27.toString(), '[div1]\n[div2]\n[div3]\n1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left27.toPlainText(), 'bold italic strike p1 p2 pp'); assert.deepEqual(right27.toPlainText(), '1 pp2'); const [left28, right28] = node.split({ offset: 28 }); assert.deepEqual(left28.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(right28.toString(), '[div1]\n[div2]\n[div3]\n pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left28.toPlainText(), 'bold italic strike p1 p2 pp1'); assert.deepEqual(right28.toPlainText(), ' pp2'); const [left29, right29] = node.split({ offset: 29 }); assert.deepEqual(left29.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 \n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(right29.toString(), '[div1]\n[div2]\n[div3]\npp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left29.toPlainText(), 'bold italic strike p1 p2 pp1 '); assert.deepEqual(right29.toPlainText(), 'pp2'); const [left30, right30] = node.split({ offset: 30 }); assert.deepEqual(left30.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 p\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(right30.toString(), '[div1]\n[div2]\n[div3]\np2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left30.toPlainText(), 'bold italic strike p1 p2 pp1 p'); assert.deepEqual(right30.toPlainText(), 'p2'); const [left31, right31] = node.split({ offset: 31 }); assert.deepEqual(left31.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(right31.toString(), '[div1]\n[div2]\n[div3]\n2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left31.toPlainText(), 'bold italic strike p1 p2 pp1 pp'); assert.deepEqual(right31.toPlainText(), '2'); const [left32, right32] = node.split({ offset: 32 }); assert.deepEqual(left32.toString(), '[div1]\n[b]bold[/b][i] italic[/i][s] strike[/s]\n[div2]\n p1 p2\n[div3]\n pp1 pp2\n[/div3]\n[/div2]\n[/div1]'); assert.deepEqual(left32.toPlainText(), 'bold italic strike p1 p2 pp1 pp2'); assert.deepEqual(right32, null); }); it('Should split node with text nodes only', () => { const node = scheme.createElement({ name: 'p', children: [ scheme.createText('text1'), scheme.createText('text2'), scheme.createText('text3'), ], }); const [left1, right1] = node.split({ offset: 0 }); assert.deepEqual(left1, null); assert.deepEqual(right1.toString(), '[p]\ntext1text2text3\n[/p]'); assert.deepEqual(right1.toPlainText(), 'text1text2text3'); const [left5, right5] = node.split({ offset: 5 }); assert.deepEqual(left5.toString(), '[p]\ntext1\n[/p]'); assert.deepEqual(right5.toString(), '[p]\ntext2text3\n[/p]'); assert.deepEqual(left5.toPlainText(), 'text1'); assert.deepEqual(right5.toPlainText(), 'text2text3'); const [left15, right15] = node.split({ offset: 15 }); assert.deepEqual(left15.toString(), '[p]\ntext1text2text3\n[/p]'); assert.deepEqual(right15, null); assert.deepEqual(left15.toPlainText(), 'text1text2text3'); }); it('Should split tree by words', () => { const node = scheme.createElement({ name: 'p', children: [ scheme.createText('text1 text2 text3'), scheme.createText('text4'), scheme.createText('text5'), ], }); const [left0, right0] = node.split({ offset: 0, byWord: true }); assert.deepEqual(left0, null); assert.deepEqual(right0.toPlainText(), 'text1 text2 text3text4text5'); const [left1, right1] = node.split({ offset: 1, byWord: true }); assert.deepEqual(left1.toPlainText(), ''); assert.deepEqual(right1.toPlainText(), 'text1 text2 text3text4text5'); const [left2, right2] = node.split({ offset: 2, byWord: true }); assert.deepEqual(left2.toPlainText(), ''); assert.deepEqual(right2.toPlainText(), 'text1 text2 text3text4text5'); const [left3, right3] = node.split({ offset: 3, byWord: true }); assert.deepEqual(left3.toPlainText(), ''); assert.deepEqual(right3.toPlainText(), 'text1 text2 text3text4text5'); const [left4, right4] = node.split({ offset: 4, byWord: true }); assert.deepEqual(left4.toPlainText(), ''); assert.deepEqual(right4.toPlainText(), 'text1 text2 text3text4text5'); const [left5, right5] = node.split({ offset: 5, byWord: true }); assert.deepEqual(left5.toPlainText(), 'text1'); assert.deepEqual(right5.toPlainText(), ' text2 text3text4text5'); const [left6, right6] = node.split({ offset: 6, byWord: true }); assert.deepEqual(left6.toPlainText(), 'text1 '); assert.deepEqual(right6.toPlainText(), 'text2 text3text4text5'); const [left7, right7] = node.split({ offset: 7, byWord: true }); assert.deepEqual(left7.toPlainText(), 'text1 '); assert.deepEqual(right7.toPlainText(), 'text2 text3text4text5'); const [left8, right8] = node.split({ offset: 8, byWord: true }); assert.deepEqual(left8.toPlainText(), 'text1 '); assert.deepEqual(right8.toPlainText(), 'text2 text3text4text5'); const [left9, right9] = node.split({ offset: 9, byWord: true }); assert.deepEqual(left9.toPlainText(), 'text1 '); assert.deepEqual(right9.toPlainText(), 'text2 text3text4text5'); const [left10, right10] = node.split({ offset: 10, byWord: true }); assert.deepEqual(left10.toPlainText(), 'text1 '); assert.deepEqual(right10.toPlainText(), 'text2 text3text4text5'); const [left11, right11] = node.split({ offset: 11, byWord: true }); assert.deepEqual(left11.toPlainText(), 'text1 text2'); assert.deepEqual(right11.toPlainText(), ' text3text4text5'); const [left12, right12] = node.split({ offset: 12, byWord: true }); assert.deepEqual(left12.toPlainText(), 'text1 text2 '); assert.deepEqual(right12.toPlainText(), 'text3text4text5'); const [left13, right13] = node.split({ offset: 13, byWord: true }); assert.deepEqual(left13.toPlainText(), 'text1 text2 '); assert.deepEqual(right13.toPlainText(), 'text3text4text5'); const [left14, right14] = node.split({ offset: 14, byWord: true }); assert.deepEqual(left14.toPlainText(), 'text1 text2 '); assert.deepEqual(right14.toPlainText(), 'text3text4text5'); const [left15, right15] = node.split({ offset: 15, byWord: true }); assert.deepEqual(left15.toPlainText(), 'text1 text2 '); assert.deepEqual(right15.toPlainText(), 'text3text4text5'); const [left16, right16] = node.split({ offset: 16, byWord: true }); assert.deepEqual(left16.toPlainText(), 'text1 text2 '); assert.deepEqual(right16.toPlainText(), 'text3text4text5'); const [left17, right17] = node.split({ offset: 17, byWord: true }); assert.deepEqual(left17.toPlainText(), 'text1 text2 text3'); assert.deepEqual(right17.toPlainText(), 'text4text5'); const [left18, right18] = node.split({ offset: 18, byWord: true }); assert.deepEqual(left18.toPlainText(), 'text1 text2 text3'); assert.deepEqual(right18.toPlainText(), 'text4text5'); const [left19, right19] = node.split({ offset: 19, byWord: true }); assert.deepEqual(left19.toPlainText(), 'text1 text2 text3'); assert.deepEqual(right19.toPlainText(), 'text4text5'); const [left20, right20] = node.split({ offset: 20, byWord: true }); assert.deepEqual(left20.toPlainText(), 'text1 text2 text3'); assert.deepEqual(right20.toPlainText(), 'text4text5'); const [left21, right21] = node.split({ offset: 21, byWord: true }); assert.deepEqual(left21.toPlainText(), 'text1 text2 text3'); assert.deepEqual(right21.toPlainText(), 'text4text5'); const [left22, right22] = node.split({ offset: 22, byWord: true }); assert.deepEqual(left22.toPlainText(), 'text1 text2 text3text4'); assert.deepEqual(right22.toPlainText(), 'text5'); const [left23, right23] = node.split({ offset: 23, byWord: true }); assert.deepEqual(left23.toPlainText(), 'text1 text2 text3text4'); assert.deepEqual(right23.toPlainText(), 'text5'); const [left24, right24] = node.split({ offset: 24, byWord: true }); assert.deepEqual(left24.toPlainText(), 'text1 text2 text3text4'); assert.deepEqual(right24.toPlainText(), 'text5'); const [left25, right25] = node.split({ offset: 25, byWord: true }); assert.deepEqual(left25.toPlainText(), 'text1 text2 text3text4'); assert.deepEqual(right25.toPlainText(), 'text5'); const [left26, right26] = node.split({ offset: 26, byWord: true }); assert.deepEqual(left26.toPlainText(), 'text1 text2 text3text4'); assert.deepEqual(right26.toPlainText(), 'text5'); const [left27, right27] = node.split({ offset: 27, byWord: true }); assert.deepEqual(left27.toPlainText(), 'text1 text2 text3text4text5'); assert.deepEqual(right27, null); }); it('should split node with linebreaks', () => { const node = scheme.createElement({ name: 'b', children: [ scheme.createText('text'), scheme.createNewLine(), scheme.createText('text2'), scheme.createNewLine(), scheme.createNewLine(), scheme.createText('text3'), ], }); const [leftTree, rightTree] = node.split({ offset: 5 }); assert.deepEqual(leftTree.toString(), '[b]text\n[/b]'); assert.deepEqual(rightTree.toString(), '[b]text2\n\ntext3[/b]'); }); it('should split node with tabs', () => { const node = scheme.createRoot({ children: [ scheme.createText('text'), scheme.createTab(), scheme.createText('text2'), scheme.createTab(), scheme.createTab(), scheme.createText('text3'), ], }); const [leftTree, rightTree] = node.split({ offset: 5 }); assert.deepEqual(leftTree.toString(), 'text\t'); assert.deepEqual(rightTree.toString(), 'text2\t\ttext3'); }); }); describe('ElementNode.insertBefore()', () => { it('should insert nodes before current node', () => { const p1 = scheme.createElement({ name: 'p', value: 1 }); const p2 = scheme.createElement({ name: 'p', value: 2 }); const p3 = scheme.createElement({ name: 'p', value: 3 }); const p4 = scheme.createElement({ name: 'p', value: 4 }); const root = scheme.createRoot({ children: [ p1, p2, p3, p4, ], }); const p11 = scheme.createElement({ name: 'p', value: 11 }); const p22 = scheme.createElement({ name: 'p', value: 22 }); p2.insertBefore(p11, p22); assert.ok(root.getChildrenCount() === 6); const children = root.getChildren(); assert.ok(children.at(0) === p1); assert.ok(children.at(1) === p11); assert.ok(children.at(2) === p22); assert.ok(children.at(3) === p2); assert.ok(children.at(4) === p3); assert.ok(children.at(5) === p4); }); it('should insert nodes before current nodes if current node is first child of parent', () => { const p1 = scheme.createElement({ name: 'p', value: 1 }); const p2 = scheme.createElement({ name: 'p', value: 2 }); const root = scheme.createRoot({ children: [ p1, p2, ], }); const p3 = scheme.createElement({ name: 'p', value: 3 }); const p4 = scheme.createElement({ name: 'p', value: 4 }); p1.insertBefore(p3, p4); assert.ok(root.getChildrenCount() === 4); const children = root.getChildren(); assert.ok(children.at(0) === p3); assert.ok(children.at(1) === p4); assert.ok(children.at(2) === p1); assert.ok(children.at(3) === p2); }); }); describe('ElementNode.insertAfter()', () => { it('should insert nodes before current node', () => { const p1 = scheme.createElement({ name: 'p', value: 1 }); const p2 = scheme.createElement({ name: 'p', value: 2 }); const p3 = scheme.createElement({ name: 'p', value: 3 }); const p4 = scheme.createElement({ name: 'p', value: 4 }); const root = scheme.createRoot({ children: [ p1, p2, p3, p4, ], }); const p11 = scheme.createElement({ name: 'p', value: 11 }); const p22 = scheme.createElement({ name: 'p', value: 22 }); p2.insertAfter(p11, p22); assert.ok(root.getChildrenCount() === 6); const children = root.getChildren(); assert.ok(children.at(0) === p1); assert.ok(children.at(1) === p2); assert.ok(children.at(2) === p11); assert.ok(children.at(3) === p22); assert.ok(children.at(4) === p3); assert.ok(children.at(5) === p4); }); it('should insert nodes before current nodes if current node is last child of parent', () => { const p1 = scheme.createElement({ name: 'p', value: 1 }); const p2 = scheme.createElement({ name: 'p', value: 2 }); const root = scheme.createRoot({ children: [ p1, p2, ], }); const p3 = scheme.createElement({ name: 'p', value: 3 }); const p4 = scheme.createElement({ name: 'p', value: 4 }); p2.insertAfter(p3, p4); assert.ok(root.getChildrenCount() === 4); const children = root.getChildren(); assert.ok(children.at(0) === p1); assert.ok(children.at(1) === p2); assert.ok(children.at(2) === p3); assert.ok(children.at(3) === p4); }); }); }); describe('Default scheme rules', () => { describe('allowedChildren', () => { it('b, i, u, s, span should include allowed tags only', () => { const b = scheme.createElement({ name: 'b', children: [ scheme.createElement({ name: 'i' }), scheme.createElement({ name: 'u' }), scheme.createElement({ name: 's' }), scheme.createElement({ name: 'span' }), scheme.createText('text'), scheme.createNewLine(), scheme.createElement({ name: 'p' }), ], }); assert.ok(b.getChildrenCount() === 6, '#1'); assert.ok(b.getChildren().at(0).getName() === 'i', '#2'); assert.ok(b.getChildren().at(1).getName() === 'u', '#3'); assert.ok(b.getChildren().at(2).getName() === 's', '#4'); assert.ok(b.getChildren().at(3).getName() === 'span', '#5'); assert.ok(b.getChildren().at(4).getName() === '#text', '#6'); assert.ok(b.getChildren().at(5).getName() === '#linebreak', '#7'); }); it('img, url should include only allowed child', () => { const img = scheme.createElement({ name: 'img', children: [ scheme.createElement({ name: 'b' }), scheme.createNewLine(), scheme.createTab(), scheme.createText('test'), ], }); assert.ok(img.getChildrenCount() === 1); assert.ok(img.getLastChild().getName() === '#text'); const url = scheme.createElement({ name: 'url', children: [ scheme.createElement({ name: 'b' }), scheme.createNewLine(), scheme.createTab(), scheme.createText('test'), ], }); assert.ok(url.getChildrenCount() === 2); assert.ok(url.getFirstChild().getName() === 'b'); assert.ok(url.getLastChild().getName() === '#text'); }); it('p should include only allowed child', () => { const p = scheme.createElement({ name: 'p', children: [ scheme.createElement({ name: 'b' }), scheme.createElement({ name: 'i' }), scheme.createText('test'), scheme.createNewLine(), scheme.createTab(), scheme.createElement({ name: 'p' }), scheme.createElement({ name: 'disk' }), ], }); assert.ok(p.getChildrenCount() === 5); assert.ok(p.getChildren().at(0).getName() === 'b'); assert.ok(p.getChildren().at(1).getName() === 'i'); assert.ok(p.getChildren().at(2).getName() === '#text'); assert.ok(p.getChildren().at(3).getName() === '#linebreak'); assert.ok(p.getChildren().at(4).getName() === 'disk'); }); }); describe('void', () => { it('disk should be void', () => { const disk = scheme.createElement({ name: 'disk' }); assert.ok(disk.isVoid()); }); it('table should not be void', () => { const table = scheme.createElement({ name: 'table' }); assert.ok(table.isVoid() === false); }); }); describe('stringify', () => { it('* content should be without final line break', () => { const item = scheme.createElement({ name: '*', children: [ scheme.createText('test'), scheme.createNewLine(), ], }); assert.deepEqual(item.toString(), '[*]test'); const item2 = scheme.createElement({ name: '*', children: [ scheme.createText('test\n'), ], }); assert.deepEqual(item2.toString(), '[*]test'); }); it('p should includes line breaks after opening tag and before closing tag', () => { const p = scheme.createElement({ name: 'p', children: [ scheme.createText('test'), ], }); assert.deepEqual(p.toString(), '[p]\ntest\n[/p]'); }); it('p should includes line breaks before opening tag and after closing tag', () => { const p = scheme.createElement({ name: 'p', children: [ scheme.createText('test'), ], }); void scheme.createRoot({ children: [ scheme.createElement({ name: 'b' }), p, scheme.createElement({ name: 'i' }), ], }); assert.deepEqual(p.toString(), '\n[p]\ntest\n[/p]\n'); }); }); describe('convertChild', () => { it('code should include strings, line breaks and tabs', () => { const code = scheme.createElement({ name: 'code', children: [ scheme.createElement({ name: 'p', children: [ scheme.createText('test'), ], }), scheme.createNewLine(), scheme.createTab(), scheme.createText('test1'), ], }); }); it('should return correct canBeEmpty value', () => { const scheme = new BBCodeScheme({ tagSchemes: [ new BBCodeTagScheme({ name: 'div', canBeEmpty: true, }), new BBCodeTagScheme({ name: 'div2', canBeEmpty: false, }), new BBCodeTagScheme({ name: 'div3', }), ], }); assert.ok(scheme.createElement({ name: 'div'}).canBeEmpty()); assert.ok(scheme.createElement({ name: 'div2'}).canBeEmpty() === false); assert.ok(scheme.createElement({ name: 'div3'}).canBeEmpty()); }); }); }); });