jodit
Version:
Jodit is awesome and usefully wysiwyg editor with filebrowser
1,204 lines (929 loc) • 29 kB
JavaScript
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2020 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
describe('Test Style module', function() {
let editor;
const Style = Jodit.ns.Style;
beforeEach(function() {
editor = getJodit();
editor.value = '<p>test</p>';
editor.execCommand('selectall');
});
describe('Apply style', function() {
it('Should apply style to element', function() {
const style = new Style({
style: {
color: 'red',
backgroundColor: 'yellow'
}
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p><span style="background-color:yellow;color:red">test</span></p>'
);
});
describe('Two times', function() {
it('Should do nothing', function() {
const style = function () {
return new Style({
style: {
color: '#FF0000'
}
});
}
style().apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p><span style="color:#FF0000">test</span></p>'
);
style().apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p>test</p>'
);
});
});
describe('For collapsed selection', function() {
it('Should create SPAN element with this style', function() {
editor.s.setCursorAfter(editor.editor.firstChild.firstChild);
const style = new Style({
style: {
fontSize: 12
}
});
style.apply(editor);
editor.s.insertHTML('stop');
expect(sortAttributes(editor.value)).equals(
'<p>test<span style="font-size:12px">stop</span></p>'
);
});
describe('Double times', function() {
it('Should create new SPAN inside first', function() {
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
style: {
fontSize: 12
}
});
style.apply(editor);
editor.s.insertHTML('stop');
const style2 = new Style({
style: {
color: '#ff00ff'
}
});
style2.apply(editor);
editor.s.insertHTML('elem');
expect(sortAttributes(editor.value)).equals(
'<p>test<span style="font-size:12px">stop<span style="color:#FF00FF">elem</span></span></p>'
);
});
describe('With same style', function() {
it('Should break first SPAN', function() {
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
style: {
fontSize: 12
}
});
style.apply(editor);
editor.s.insertHTML('stop');
style.apply(editor);
editor.s.insertHTML('elem');
expect(sortAttributes(editor.value)).equals(
'<p>test<span style="font-size:12px">stop</span>elem</p>'
);
});
describe('Without editing', function() {
it('Should unwap empty SPAN', function() {
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
style: {
fontSize: 12
}
});
style.apply(editor);
style.apply(editor);
editor.s.insertHTML('elem');
expect(sortAttributes(editor.value)).equals(
'<p>testelem</p>'
);
});
});
});
describe('Apply different styles', function() {
it('Should combine all of it', function() {
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
style: {
backgroundColor: 'yellow'
}
});
style.apply(editor);
const style2 = new Style({
style: {
fontSize: '12px'
}
});
style2.apply(editor);
editor.s.insertHTML('stop');
expect(sortAttributes(editor.value)).equals(
'<p>test<span style="background-color:yellow;font-size:12px">stop</span></p>'
);
});
});
});
});
describe('Apply different styles', function() {
it('Should combine all of it', function() {
const style = new Style({
style: {
backgroundColor: 'yellow'
}
});
style.apply(editor);
const style2 = new Style({
style: {
fontSize: '12px'
}
});
style2.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p><span style="background-color:yellow;font-size:12px">test</span></p>'
);
});
});
describe('For text inside some SPAN', function() {
describe('Select SPAN', function() {
it('Should apply style to this SPAN', function() {
editor.value = '<span>test</span>';
editor.s.select(editor.editor.firstChild.firstChild);
const style = new Style({
style: {
fontSize: 11
}
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p><span style="font-size:11px">test</span></p>'
);
});
});
describe('Select SPAN content', function() {
it('Should apply style to this SPAN', function() {
editor.value = '<span>test</span>';
editor.s.select(editor.editor.firstChild.firstChild);
const style = new Style({
style: {
fontSize: 11
}
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p><span style="font-size:11px">test</span></p>'
);
});
});
});
});
describe('Apply element', function() {
it('Should wrap selection in element', function() {
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals('<h1>test</h1>');
});
describe('Block or inline element', function() {
describe('Block element', function() {
it('Should wrap whole text for selection part', function() {
const range = editor.s.createRange();
range.setStart(editor.editor.firstChild.firstChild, 2);
range.setEndAfter(editor.editor.firstChild.firstChild);
editor.s.selectRange(range);
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<h1>test</h1>'
);
});
describe('Selected part inside inline element', function() {
it('Should wrap whole text with this part', function() {
editor.value = 'test<strong>stop</strong>left';
const range = editor.s.createRange();
range.setStart(
editor.editor.querySelector('strong').firstChild,
2
);
range.setEnd(
editor.editor.querySelector('strong').firstChild,
3
);
editor.s.selectRange(range);
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<h1>test<strong>stop</strong>left</h1>'
);
});
});
describe('In empty editor', function() {
it('Should insert this new block element with BR', function() {
editor.value = '';
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<h1><br></h1>'
);
editor.s.insertHTML('test');
expect(sortAttributes(editor.value)).equals(
'<h1>test<br></h1>'
);
});
});
});
describe('inline element', function() {
it('Should wrap only selection part', function() {
const range = editor.s.createRange();
range.setStart(editor.editor.firstChild.firstChild, 2);
range.setEndAfter(editor.editor.firstChild.firstChild);
editor.s.selectRange(range);
const style = new Style({
element: 'strong'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p>te<strong>st</strong></p>'
);
});
});
});
describe('For collapsed selection', function() {
describe('Block element', function() {
it('Should wrap whole text in element', function() {
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<h1>test</h1>'
);
});
describe('Double time', function() {
it('Should unwrap element', function() {
editor.value = '<h1>test</h1>';
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals('test');
});
});
describe('Selected Block element', function() {
it('Should replace this element to new style', function() {
editor.value = '<p>test</p>';
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<h1>test</h1>'
);
});
});
});
});
describe('For suitable element', function() {
it('Should replace it to new element', function() {
editor.value = '<h2>test</h2>';
editor.execCommand('selectall');
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals('<h1>test</h1>');
});
describe('With style', function() {
it('Should wrap contents again', function() {
editor.value = '<strong>test</strong>';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
0
);
range.setEnd(
editor.editor.firstChild.firstChild.firstChild,
4
);
editor.s.selectRange(range);
const style = new Style({
element: 'em',
style: {
fontStyle: 'italic'
}
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p><strong><em>test</em></strong></p>'
);
});
describe('For collapsed selection', function() {
it('Should add several tags', function() {
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const strong = new Style({
element: 'strong',
style: {
fontWeight: 700
}
});
strong.apply(editor);
editor.s.insertHTML('stop');
expect(sortAttributes(editor.value)).equals(
'<p>test<strong>stop</strong></p>'
);
const em = new Style({
element: 'em',
style: {
fontStyle: 'italic'
}
});
em.apply(editor);
editor.s.insertHTML('last');
expect(sortAttributes(editor.value)).equals(
'<p>test<strong>stop<em>last</em></strong></p>'
);
});
describe('Double times', function() {
it('Should create new SPAN inside first', function() {
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
style: {
fontSize: 12
}
});
style.apply(editor);
editor.s.insertHTML('stop');
const style2 = new Style({
style: {
color: '#ff00ff'
}
});
style2.apply(editor);
editor.s.insertHTML('elem');
expect(sortAttributes(editor.value)).equals(
'<p>test<span style="font-size:12px">stop<span style="color:#FF00FF">elem</span></span></p>'
);
});
describe('With same style', function() {
it('Should break first SPAN', function() {
editor.s.setCursorAfter(
editor.editor.firstChild.firstChild
);
const style = new Style({
style: {
fontSize: 12
}
});
style.apply(editor);
editor.s.insertHTML('stop');
style.apply(editor);
editor.s.insertHTML('elem');
expect(sortAttributes(editor.value)).equals(
'<p>test<span style="font-size:12px">stop</span>elem</p>'
);
});
});
});
});
});
describe('For several block elements', function() {
it('Should replace all these element to new', function() {
editor.value = '<p>test</p>\n<p>test2</p>';
const range = editor.s.createRange();
range.setStartBefore(editor.editor.firstChild);
range.setEndAfter(editor.editor.lastChild);
editor.s.selectRange(range);
const style = new Style({
element: 'h5'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<h5>test</h5>\n<h5>test2</h5>'
);
});
});
});
describe('For same element', function() {
it('Should unwrap selection', function() {
editor.value = '<h1>test</h1>';
editor.execCommand('selectall');
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals('test');
});
});
describe('For part of same element', function() {
it('Should unwrap selection', function() {
editor.value = '<strong>test</strong> some';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
2
);
range.setEnd(editor.editor.firstChild.lastChild, 3);
editor.s.selectRange(range);
const style = new Style({
element: 'strong',
style: {
fontWeight: 700
}
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p><strong>te</strong>st some</p>'
);
});
});
describe('Apply UL/OL', function() {
describe('UL', function() {
it('Should create LI inside new element', function() {
const style = new Style({
element: 'ul'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<ul><li>test</li></ul>'
);
});
});
describe('OL', function() {
it('Should create LI inside new element', function() {
const style = new Style({
element: 'ol'
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<ol><li>test</li></ol>'
);
});
});
});
describe('Apply H1 inside LI', function() {
it('Should create H1 inside LI', function() {
editor.value =
'<ul>' +
'<li>1</li>' +
'<li>2</li>' +
'<li>3</li>' +
'</ul> test';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
0
);
range.setEnd(editor.editor.firstChild.lastChild.firstChild, 1);
editor.s.selectRange(range);
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(editor.value).equals(
'<ul>' +
'<li><h1>1</h1></li>' +
'<li><h1>2</h1></li>' +
'<li><h1>3</h1></li>' +
'</ul><p> test</p>'
);
});
describe('Apply H1 for whole UL', function() {
it('Should create H1 inside every LI inside UL', function() {
editor.value =
'<ul>' +
'<li>1</li>' +
'<li>2</li>' +
'<li>3</li>' +
'</ul>';
const range = editor.s.createRange();
range.selectNodeContents(editor.editor);
editor.s.selectRange(range);
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(editor.value).equals(
'<ul>' +
'<li><h1>1</h1></li>' +
'<li><h1>2</h1></li>' +
'<li><h1>3</h1></li>' +
'</ul>'
);
});
describe('Apply H1 for whole UL with text', function() {
it('Should create H1 inside every LI inside UL and wrap text', function() {
editor.value =
'<ul>' +
'<li>1</li>' +
'<li>2</li>' +
'<li>3</li>' +
'</ul> test';
const range = editor.s.createRange();
range.selectNodeContents(editor.editor);
editor.s.selectRange(range);
const style = new Style({
element: 'h1'
});
style.apply(editor);
expect(editor.value).equals(
'<ul>' +
'<li><h1>1</h1></li>' +
'<li><h1>2</h1></li>' +
'<li><h1>3</h1></li>' +
'</ul><h1> test</h1>'
);
});
});
});
});
});
describe('Combine style or element', function() {
describe('For Styled element with style equaled STRONG', function() {
describe('Apply STRONG', function() {
it('Should unwrap this element', function() {
editor.value = '<span style="font-weight:700">test</span>';
editor.execCommand('selectall');
const style = new Style({
element: 'strong',
style: {
fontWeight: 700
}
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals('<p>test</p>');
});
});
});
describe('For Styled element with style contains STRONG', function() {
describe('Apply STRONG', function() {
it('Should remove STRONG from element', function() {
editor.value =
'<span style="font-weight:700;font-size:24px;">test</span>';
editor.execCommand('selectall');
const style = new Style({
element: 'strong',
style: {
fontWeight: 700
}
});
style.apply(editor);
expect(sortAttributes(editor.value)).equals(
'<p><span style="font-size:24px">test</span></p>'
);
});
});
});
});
});
describe('Test Selection.applyStyle method', function() {
describe('Bold command', function() {
describe('For box with style="font-weight:bold"', function() {
it('should wrap selected text in STRONG element without questions', function() {
const editor = getJodit(),
style = document.createElement('style');
editor.value = '<p>test</p>';
style.innerHTML = 'p {font-weight: bold !important};';
document.body.appendChild(style);
const sel = editor.s.sel,
range = editor.s.createRange();
range.setStart(editor.editor.firstChild.firstChild, 0);
range.setEnd(editor.editor.firstChild.firstChild, 4);
sel.removeAllRanges();
sel.addRange(range);
editor.execCommand('bold');
style.parentNode.removeChild(style);
expect(editor.value).equals('<p><strong>test</strong></p>');
});
});
it('Should insert a few chars and again exec bold. Bold mode should be switch off', function() {
const editor = getJodit();
editor.value = 'test';
const sel = editor.s.sel,
range = editor.s.createRange();
range.selectNodeContents(editor.editor.firstChild);
range.collapse(false);
sel.removeAllRanges();
sel.addRange(range);
editor.execCommand('bold');
editor.s.insertNode(editor.createInside.text('abc'));
editor.execCommand('bold');
editor.s.insertNode(editor.createInside.text('def'));
expect(editor.value).equals('<p>test<strong>abc</strong>def</p>');
});
describe('for some text', function() {
it('should wrap this text in STRONG element', function() {
const editor = getJodit();
editor.value = 'test';
const sel = editor.s.sel,
range = editor.s.createRange();
range.selectNodeContents(editor.editor.firstChild);
sel.removeAllRanges();
sel.addRange(range);
editor.execCommand('bold');
expect(editor.value).equals('<p><strong>test</strong></p>');
});
describe('inside STRONG element ', function() {
it('from start of this element, should unwrap this text', function() {
const editor = getJodit();
editor.value = '<strong>test</strong>';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
0
);
range.setEnd(
editor.editor.firstChild.firstChild.firstChild,
2
);
editor.s.selectRange(range);
editor.execCommand('bold');
expect(editor.value).equals('<p>te<strong>st</strong></p>');
});
it('near end of this element, should unwrap this text', function() {
const editor = getJodit();
editor.value = '<strong>test</strong>';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
2
);
range.setEnd(
editor.editor.firstChild.firstChild.firstChild,
4
);
editor.s.selectRange(range);
editor.execCommand('bold');
expect(editor.value).equals('<p><strong>te</strong>st</p>');
});
it('in the middle of this element, should unwrap this text', function() {
const editor = getJodit();
editor.value = '<strong>test</strong>';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
1
);
range.setEnd(
editor.editor.firstChild.firstChild.firstChild,
3
);
editor.s.selectRange(range);
editor.execCommand('bold');
expect(editor.value).equals(
'<p><strong>t</strong>es<strong>t</strong></p>'
);
});
it('should unwrap this part and after exec "bold" again it should create 3 STRONG elements', function() {
const editor = getJodit();
editor.value = '<strong>1 2 3</strong>';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
1
);
range.setEnd(
editor.editor.firstChild.firstChild.firstChild,
4
);
editor.s.selectRange(range);
editor.execCommand('bold');
editor.execCommand('bold');
expect(editor.value).equals(
'<p><strong>1</strong><strong> 2 </strong><strong>3</strong></p>'
);
});
describe('For collapsed selection', function() {
it('should split this element and set cursor between two parts', function() {
const editor = getJodit();
editor.value = '<strong>test</strong>';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
2
);
range.collapse(true);
editor.s.selectRange(range);
editor.execCommand('bold');
editor.s.insertHTML('stop');
expect(editor.value).equals(
'<p><strong>te</strong>stop<strong>st</strong></p>'
);
});
});
});
it('that contains a few STRONG elements, should unwrap all of these', function() {
const editor = getJodit();
editor.value =
'<strong>test</strong> test <strong>test</strong>';
const range = editor.s.createRange();
range.setStart(
editor.editor.firstChild.firstChild.firstChild,
0
);
range.setEnd(editor.editor.firstChild.lastChild.firstChild, 4);
editor.s.selectRange(range);
editor.execCommand('bold');
expect(editor.value).equals('<p>test test test</p>');
});
});
describe('Try exec the command "bold"', function() {
it('Should wrap selected text in STRONG element', function() {
const editor = getJodit();
editor.value = '<p>test</p>';
const sel = editor.s.sel,
range = editor.s.createRange();
range.selectNodeContents(editor.editor.firstChild);
sel.removeAllRanges();
sel.addRange(range);
editor.execCommand('bold');
expect(editor.value).equals('<p><strong>test</strong></p>');
});
describe('Try exec the command "bold" twice', function() {
it('Should unwrap strong elements', function() {
const editor = getJodit();
editor.value = '<p>test</p>';
const sel = editor.s.sel,
range = editor.s.createRange();
range.selectNodeContents(editor.editor.firstChild);
sel.removeAllRanges();
sel.addRange(range);
editor.execCommand('bold');
editor.execCommand('bold');
expect(editor.value).equals('<p>test</p>');
});
});
});
describe('Try exec the command "bold" for font-weight: 700 Element', function() {
it('should ubnwrap selected srtong element', function() {
const editor = getJodit();
editor.value = '<span style="font-weight: 700">test</span>';
const range = editor.s.createRange();
range.selectNodeContents(editor.editor.firstChild);
editor.s.selectRange(range);
editor.execCommand('bold');
expect(editor.value).equals('<p>test</p>');
});
});
describe('Exec bold for collapsed range and move cursor in another place', function() {
it('Should remove STRONG element', function() {
const editor = getJodit({
cleanHTML: {
timeout: 0
}
});
editor.value = 'testtest';
const range = editor.s.createRange();
range.setStart(editor.editor.firstChild.firstChild, 4);
range.collapse(true);
editor.s.selectRange(range);
editor.execCommand('bold');
expect(editor.value).equals('<p>test<strong></strong>test</p>');
range.setStart(editor.editor.firstChild.lastChild, 2);
range.collapse(true);
editor.s.selectRange(range);
simulateEvent('mousedown', 0, editor.editor);
expect(editor.value).equals('<p>testtest</p>');
});
});
describe('Exec bold command for SPAN with font-size', function() {
it('Should leave both font-size and font-weight rules', function() {
const editor = getJodit();
editor.value = '<span style="font-size: 36px;">asdasd</span>';
const range = editor.s.createRange();
range.setStart(editor.editor.firstChild.firstChild.firstChild, 0);
range.setEnd(editor.editor.firstChild.firstChild.firstChild, 6);
editor.s.selectRange(range);
editor.execCommand('bold');
expect(sortAttributes(editor.value)).equals(
sortAttributes(
'<p><span style="font-size: 36px;"><strong>asdasd</strong></span></p>'
)
);
});
});
});
describe('Fonts', function() {
describe('Set font size', function() {
it('should create attribute style="font-size:value"', function() {
const editor = getJodit();
editor.value = '<p> testy oprst <span>lets go</span></p>';
const sel = editor.s.sel,
range = editor.s.createRange();
range.selectNode(editor.editor.querySelector('span'));
sel.removeAllRanges();
sel.addRange(range);
editor.execCommand('fontSize', false, 12);
expect(editor.value).equals(
'<p> testy oprst <span style="font-size: 12px;">lets go</span></p>'
);
editor.execCommand('fontSize', false, '12%');
expect(editor.value).equals(
'<p> testy oprst <span style="font-size: 12%;">lets go</span></p>'
);
});
describe('For box with style="font-size:12px"', function() {
it('should wrap selected text in SPAN with style="font-size:12px" element without questions', function() {
const editor = getJodit();
editor.value = 'test';
const sel = editor.s.sel,
range = editor.s.createRange();
range.selectNodeContents(editor.editor.firstChild.firstChild);
sel.removeAllRanges();
sel.addRange(range);
editor.editor.style.fontSize = '12px';
editor.execCommand('fontSize', false, 12);
expect(editor.value).equals(
'<p><span style="font-size: 12px;">test</span></p>'
);
});
});
});
describe('Set font family', function() {
describe('For box with style="font-name:Arial"', function() {
it('should wrap selected text in SPAN with style="font-family:Arial" element without questions', function() {
const editor = getJodit();
editor.value = '<p>test</p>';
const sel = editor.s.sel,
range = editor.s.createRange();
range.setStart(editor.editor.firstChild.firstChild, 2);
range.setEnd(editor.editor.firstChild.firstChild, 4);
sel.removeAllRanges();
sel.addRange(range);
editor.editor.style.fontFamily = 'Arial';
editor.execCommand('fontName', false, 'Arial');
expect(editor.value).equals(
'<p>te<span style="font-family: Arial;">st</span></p>'
);
});
});
it('should create attribute style="font-family:value"', function() {
const editor = getJodit();
editor.value = '<p>test</p>';
const sel = editor.s.sel,
range = editor.s.createRange();
range.setStart(editor.editor.firstChild.firstChild, 2);
range.setEnd(editor.editor.firstChild.firstChild, 4);
sel.removeAllRanges();
sel.addRange(range);
editor.execCommand('fontName', false, 'Arial');
expect(editor.value).equals(
'<p>te<span style="font-family: Arial;">st</span></p>'
);
});
});
describe('Set font size and family', function() {
it('should create attribute style="font-family:value;font-size:value"', function() {
const editor = getJodit();
editor.value = '<p>test</p>';
const sel = editor.s.sel,
range = editor.s.createRange();
range.setStart(editor.editor.firstChild.firstChild, 2);
range.setEnd(editor.editor.firstChild.firstChild, 4);
sel.removeAllRanges();
sel.addRange(range);
editor.execCommand('fontName', false, 'Arial');
editor.execCommand('fontSize', false, 12);
expect(sortAttributes(editor.value)).equals(
'<p>te<span style="font-family:Arial;font-size:12px">st</span></p>'
);
});
});
});
});