UnitTest.asynctest('browser.tinymce.core.selection.SelectionUtilsTest', function () { const success = arguments[arguments.length - 2]; const failure = arguments[arguments.length - 1]; const viewBlock = ViewBlock(); const cSetHtml = function (html) { return Chain.op(function () { viewBlock.update(html); }); }; const cHasAllContentsSelected = function (startPath, startOffset, endPath, endOffset) { return Chain.mapper(function (viewBlock) { const sc = Hierarchy.follow(Element.fromDom(viewBlock.get()), startPath).getOrDie(); const ec = Hierarchy.follow(Element.fromDom(viewBlock.get()), endPath).getOrDie(); const rng = document.createRange(); rng.setStart(sc.dom(), startOffset); rng.setEnd(ec.dom(), endOffset); return SelectionUtils.hasAllContentsSelected(Element.fromDom(viewBlock.get()), rng); }); }; viewBlock.attach(); Pipeline.async({}, [ Logger.t('All text is selected in paragraph', Chain.asStep(viewBlock, [ cSetHtml('<p>a</p>'), cHasAllContentsSelected([0, 0], 0, [0, 0], 1), Assertions.cAssertEq('Should be true since all contents is selected', true) ])), Logger.t('All text is selected in paragraph', Chain.asStep(viewBlock, [ cSetHtml('<p>ab</p>'), cHasAllContentsSelected([0, 0], 0, [0, 0], 2), Assertions.cAssertEq('Should be true since all contents is selected', true) ])), Logger.t('All text is selected in paragraph and sub element', Chain.asStep(viewBlock, [ cSetHtml('<p>a<b>b</b></p>'), cHasAllContentsSelected([0, 0], 0, [0, 1, 0], 1), Assertions.cAssertEq('Should be true since all contents is selected', true) ])), Logger.t('All text is selected in paragraph and with traling br', Chain.asStep(viewBlock, [ cSetHtml('<p>a<br></p>'), cHasAllContentsSelected([0, 0], 0, [0, 0], 1), Assertions.cAssertEq('Should be true since all contents is selected', true) ])), Logger.t('Collapsed range in paragraph', Chain.asStep(viewBlock, [ cSetHtml('<p>a</p>'), cHasAllContentsSelected([0, 0], 0, [0, 0], 0), Assertions.cAssertEq('Should be false since only some contents is selected', false) ])), Logger.t('Partial text selection in paragraph', Chain.asStep(viewBlock, [ cSetHtml('<p>ab</p>'), cHasAllContentsSelected([0, 0], 0, [0, 0], 1), Assertions.cAssertEq('Should be false since only some contents is selected', false) ])), Logger.t('Partial text selection in paragraph', Chain.asStep(viewBlock, [ cSetHtml('<p>ab</p>'), cHasAllContentsSelected([0, 0], 1, [0, 0], 2), Assertions.cAssertEq('Should be false since only some contents is selected', false) ])), Logger.t('Partial mixed selection in paragraph', Chain.asStep(viewBlock, [ cSetHtml('<p>a<b>bc</b></p>'), cHasAllContentsSelected([0, 0], 1, [0, 1, 0], 1), Assertions.cAssertEq('Should be false since only some contents is selected', false) ])) ], function () { viewBlock.detach(); success(); }, failure); });
TinyLoader.setup(function (editor, onSuccess, onFailure) { const tinyApis = TinyApis(editor); const body = Element.fromDom(editor.getBody()); Pipeline.async({}, [ tinyApis.sFocus, Logger.t('Enter in paragraph', GeneralSteps.sequence([ Logger.t('Insert block before', GeneralSteps.sequence([ tinyApis.sSetContent('<p>ab</p>'), tinyApis.sSetCursor([0, 0], 0), sInsertNewline(editor, { }), tinyApis.sAssertContent('<p> </p><p>ab</p>'), tinyApis.sAssertSelection([1, 0], 0, [1, 0], 0) ])), Logger.t('Split block in the middle', GeneralSteps.sequence([ tinyApis.sSetContent('<p>ab</p>'), tinyApis.sSetCursor([0, 0], 1), sInsertNewline(editor, { }), tinyApis.sAssertContent('<p>a</p><p>b</p>'), tinyApis.sAssertSelection([1, 0], 0, [1, 0], 0) ])), Logger.t('Insert block after', GeneralSteps.sequence([ tinyApis.sSetContent('<p>ab</p>'), tinyApis.sSetCursor([0, 0], 2), sInsertNewline(editor, { }), tinyApis.sAssertContent('<p>ab</p><p> </p>'), tinyApis.sAssertSelection([1], 0, [1], 0) ])), Logger.t('Insert block after bookmark', GeneralSteps.sequence([ tinyApis.sSetRawContent(`<p>${bookmarkSpan}<br data-mce-bogus="1"></p>`), tinyApis.sSetCursor([0], 1), sInsertNewline(editor, { }), Assertions.sAssertStructure('Content should only have one bookmark span', ApproxStructure.build((s, str) => { return s.element('body', { children: [ s.element('p', { children: [ ApproxStructure.fromHtml(bookmarkSpan), s.element('br', { attrs: { 'data-mce-bogus': str.is('1') } }) ] }), s.element('p', { children: [ s.element('br', { attrs: { 'data-mce-bogus': str.is('1') } }) ] }) ] }); }), body), tinyApis.sAssertSelection([1], 0, [1], 0) ])) ])), Logger.t('br_newline_selector', GeneralSteps.sequence([ tinyApis.sSetSetting('br_newline_selector', 'p,div.test'), Logger.t('Insert newline where br is forced', GeneralSteps.sequence([ tinyApis.sSetContent('<p>ab</p>'), tinyApis.sSetCursor([0, 0], 1), sInsertNewline(editor, { }), tinyApis.sNodeChanged, tinyApis.sAssertContent('<p>a<br />b</p>') ])), Logger.t('Insert newline where br is forced', GeneralSteps.sequence([ tinyApis.sSetContent('<div class="test">ab</div>'), tinyApis.sSetCursor([0, 0], 1), sInsertNewline(editor, { }), tinyApis.sNodeChanged, tinyApis.sAssertContent('<div class="test">a<br />b</div>') ])), Logger.t('Insert newline where br is not forced', GeneralSteps.sequence([ tinyApis.sSetContent('<div>ab</div>'), tinyApis.sSetCursor([0, 0], 1), sInsertNewline(editor, { }), tinyApis.sNodeChanged, tinyApis.sAssertContent('<div>a</div><div>b</div>') ])), tinyApis.sDeleteSetting('br_newline_selector') ])), Logger.t('no_newline_selector', GeneralSteps.sequence([ tinyApis.sSetSetting('no_newline_selector', [ 'p,div.test' ]), Logger.t('Insert newline where newline is blocked', GeneralSteps.sequence([ tinyApis.sSetContent('<p>ab</p>'), tinyApis.sSetCursor([0, 0], 1), sInsertNewline(editor, { }), tinyApis.sNodeChanged, tinyApis.sAssertContent('<p>ab</p>') ])), Logger.t('Insert newline where newline is blocked', GeneralSteps.sequence([ tinyApis.sSetContent('<div class="test">ab</div>'), tinyApis.sSetCursor([0, 0], 1), sInsertNewline(editor, { }), tinyApis.sNodeChanged, tinyApis.sAssertContent('<div class="test">ab</div>') ])), Logger.t('Insert newline where newline is not blocked', GeneralSteps.sequence([ tinyApis.sSetContent('<div>ab</div>'), tinyApis.sSetCursor([0, 0], 1), sInsertNewline(editor, { }), tinyApis.sNodeChanged, tinyApis.sAssertContent('<div>a</div><div>b</div>') ])), tinyApis.sDeleteSetting('no_newline_selector') ])), Logger.t('Insert newline before image in link', GeneralSteps.sequence([ tinyApis.sSetContent('<p><a href="#">a<img src="about:blank" /></a></p>'), tinyApis.sSetCursor([0, 0], 1), sInsertNewline(editor, { }), tinyApis.sAssertContent('<p><a href="#">a</a></p><p><a href="#"><img src="about:blank" /></a></p>'), // For some bizarre IE issue getSelection().addRange() creates a zwsp from nowhere and moves the caret after it browser.isIE() ? tinyApis.sAssertSelection([1, 0, 0], 1, [1, 0, 0], 1) : tinyApis.sAssertSelection([1, 0], 0, [1, 0], 0) ])) ], onSuccess, onFailure); }, {
TinyLoader.setup(function (editor, onSuccess, onFailure) { const api = TinyApis(editor); const ui = TinyUi(editor); const sInitAndOpenDialog = (content: string, cursorPos: any) => { return GeneralSteps.sequence([ api.sSetSetting('image_advtab', true), api.sSetSetting('image_dimensions', false), api.sSetContent(content), // api.sSetCursor([0], 1), api.sSetCursor(cursorPos.elementPath, cursorPos.offset), api.sExecCommand('mceImage', true), ui.sWaitForPopup('Wait for Image dialog', 'div[role="dialog"]'), ]); }; const createTestWithContent = (name: string, content: string, cursorPos: any, data: Partial<ImageDialogData>, expectedContent: string) => { return Log.stepsAsStep('TBA', 'Image: ' + name, [ sInitAndOpenDialog(content, cursorPos), Chain.asStep({}, [ cFillActiveDialog(data, true) ]), ui.sClickOnUi('click save', 'div[role="dialog"] button:contains("Save")'), api.sAssertContent(expectedContent) ]); }; const createTestOnEmptyEditor = (name: string, data: Partial<ImageDialogData>, expectedContent: string) => { return createTestWithContent(name, '', { elementPath: [0], offset: 0 }, data, expectedContent); }; const createTestUpdatedStyle = (name: string, style: string, assertion: Step<any, any>) => { return Log.stepsAsStep('TBA', 'Image: ' + name, [ sInitAndOpenDialog('', { elementPath: [0], offset: 0 }), ui.sClickOnUi('Switch to Advanced tab', '.tox-tab:contains("Advanced")'), Chain.asStep(Body.body(), [ cSetInputValue(advancedTabSelectors.style, style) ]), assertion, ui.sClickOnUi('click save', 'div[role="dialog"] button:contains("Save")'), ]); }; const suiteArr = [ createTestOnEmptyEditor( 'Advanced image dialog margin space options on empty editor', { alt: 'alt', hspace: '10', src: { value: 'src', }, vspace: '10' }, '<p><img style="margin: 10px;" src="src" alt="alt" /></p>' ), createTestOnEmptyEditor( 'Advanced image dialog border style only options on empty editor', { alt: 'alt', src: { value: 'src' }, style: 'border-width: 10px; border-style: solid;' }, '<p><img style="border-width: 10px; border-style: solid;" src="src" alt="alt" /></p>' ), createTestOnEmptyEditor( 'Advanced image dialog margin style only options on empty editor', { alt: 'alt', src: { value: 'src' }, style: 'margin: 10px;' }, '<p><img style="margin: 10px;" src="src" alt="alt" /></p>' ), createTestOnEmptyEditor( 'Advanced image dialog overriden border style options on empty editor', { alt: 'alt', border: '10', src: { value: 'src' }, style: 'border-width: 15px;' }, '<p><img style="border-width: 10px;" src="src" alt="alt" /></p>' ), createTestOnEmptyEditor( 'Advanced image dialog overriden margin style options on empty editor', { alt: 'alt', hspace: '10', src: { value: 'src' }, style: 'margin-left: 15px; margin-top: 20px;', vspace: '10' }, '<p><img style="margin: 10px;" src="src" alt="alt" /></p>' ), createTestWithContent( 'Advanced image dialog border option on editor with content', '<p>a</p>', { elementPath: [0], offset: 1 }, { alt: 'alt', border: '10', borderstyle: 'dashed', src: { value: 'src' } }, '<p>a<img style="border-width: 10px; border-style: dashed;" src="src" alt="alt" /></p>'), createTestUpdatedStyle( 'Advanced image dialog non-shorthand horizontal margin style change test', 'margin-left: 15px; margin-right: 15px;', Chain.asStep({}, [ cAssertInputValue(advancedTabSelectors.vspace, ''), cAssertInputValue(advancedTabSelectors.hspace, '15'), cAssertInputValue(advancedTabSelectors.style, 'margin-left: 15px; margin-right: 15px;') ]) ), createTestUpdatedStyle( 'Advanced image dialog non-shorthand vertical margin style change test', 'margin-top: 15px; margin-bottom: 15px;', Chain.asStep({}, [ cAssertInputValue(advancedTabSelectors.vspace, '15'), cAssertInputValue(advancedTabSelectors.hspace, ''), cAssertInputValue(advancedTabSelectors.style, 'margin-top: 15px; margin-bottom: 15px;') ]) ), createTestUpdatedStyle( 'Advanced image dialog shorthand margin 1 value style change test', 'margin: 5px;', Chain.asStep({}, [ cAssertInputValue(advancedTabSelectors.vspace, '5'), cAssertInputValue(advancedTabSelectors.hspace, '5'), cAssertInputValue(advancedTabSelectors.style, 'margin: 5px;') ]) ), createTestUpdatedStyle( 'Advanced image dialog shorthand margin 2 value style change test', 'margin: 5px 10px;', Chain.asStep({}, [ cAssertInputValue(advancedTabSelectors.vspace, '5'), cAssertInputValue(advancedTabSelectors.hspace, '10'), cAssertInputValue(advancedTabSelectors.style, 'margin: 5px 10px 5px 10px;') ]) ), createTestUpdatedStyle( 'Advanced image dialog shorthand margin 3 value style change test', 'margin: 5px 10px 15px;', Chain.asStep({}, [ cAssertInputValue(advancedTabSelectors.vspace, ''), cAssertInputValue(advancedTabSelectors.hspace, '10'), cAssertInputValue(advancedTabSelectors.style, 'margin: 5px 10px 15px 10px;') ]) ), createTestUpdatedStyle( 'Advanced image dialog shorthand margin 4 value style change test', 'margin: 5px 10px 15px 20px;', Chain.asStep({}, [ cAssertInputValue(advancedTabSelectors.vspace, ''), cAssertInputValue(advancedTabSelectors.hspace, ''), cAssertInputValue(advancedTabSelectors.style, 'margin: 5px 10px 15px 20px;') ]) ), createTestUpdatedStyle( 'Advanced image dialog shorthand margin 4 value style change test', 'margin: 5px 10px 15px 20px; margin-top: 15px;', Chain.asStep({}, [ cAssertInputValue(advancedTabSelectors.vspace, '15'), cAssertInputValue(advancedTabSelectors.hspace, ''), cAssertInputValue(advancedTabSelectors.style, 'margin: 15px 10px 15px 20px;') ]) ) ]; Pipeline.async({}, suiteArr, onSuccess, onFailure); }, {
TinyLoader.setup(function (editor, onSuccess, onFailure) { Pipeline.async({}, Log.steps('TBA', 'Media: Test media content formats', suite.toSteps(editor)), onSuccess, onFailure); }, {
UnitTest.asynctest('browser.tinymce.core.dom.ElementTypeTest', function () { const success = arguments[arguments.length - 2]; const failure = arguments[arguments.length - 1]; const sCheckElement = function (name, predicate, expectedValue) { return Step.sync(function () { Assertions.assertEq('Should be the expected value for specified element', expectedValue, predicate(Element.fromTag(name))); }); }; const sCheckText = function (predicate) { return Step.sync(function () { Assertions.assertEq('Should be false for non element', false, predicate(Element.fromText('text'))); }); }; Pipeline.async({}, [ Logger.t('Check block elements', GeneralSteps.sequence([ sCheckElement('p', ElementType.isBlock, true), sCheckElement('h1', ElementType.isBlock, true), sCheckElement('table', ElementType.isBlock, true), sCheckElement('span', ElementType.isBlock, false), sCheckElement('b', ElementType.isBlock, false), sCheckText(ElementType.isBlock) ])), Logger.t('Check inline elements', GeneralSteps.sequence([ sCheckElement('b', ElementType.isInline, true), sCheckElement('span', ElementType.isInline, true), sCheckElement('p', ElementType.isInline, false), sCheckElement('h1', ElementType.isInline, false), sCheckText(ElementType.isInline) ])), Logger.t('Check heading elements', GeneralSteps.sequence([ sCheckElement('h1', ElementType.isHeading, true), sCheckElement('h2', ElementType.isHeading, true), sCheckElement('span', ElementType.isHeading, false), sCheckElement('table', ElementType.isHeading, false), sCheckText(ElementType.isHeading) ])), Logger.t('Check text block elements', GeneralSteps.sequence([ sCheckElement('p', ElementType.isTextBlock, true), sCheckElement('h1', ElementType.isTextBlock, true), sCheckElement('table', ElementType.isTextBlock, false), sCheckText(ElementType.isTextBlock) ])), Logger.t('Check void elements', GeneralSteps.sequence([ sCheckElement('img', ElementType.isVoid, true), sCheckElement('hr', ElementType.isVoid, true), sCheckElement('h1', ElementType.isVoid, false), sCheckElement('span', ElementType.isVoid, false), sCheckText(ElementType.isVoid) ])), Logger.t('Check table cell elements', GeneralSteps.sequence([ sCheckElement('th', ElementType.isTableCell, true), sCheckElement('td', ElementType.isTableCell, true), sCheckElement('h1', ElementType.isTableCell, false), sCheckElement('span', ElementType.isTableCell, false), sCheckText(ElementType.isTableCell) ])), Logger.t('Check br elements', GeneralSteps.sequence([ sCheckElement('br', ElementType.isBr, true), sCheckElement('b', ElementType.isBr, false), sCheckText(ElementType.isBr) ])), Logger.t('Check list item elements', GeneralSteps.sequence([ sCheckElement('br', ElementType.isListItem, false), sCheckElement('div', ElementType.isListItem, false), sCheckElement('li', ElementType.isListItem, true), sCheckElement('dd', ElementType.isListItem, true), sCheckElement('dt', ElementType.isListItem, true), sCheckText(ElementType.isListItem) ])), Logger.t('Check list elements', GeneralSteps.sequence([ sCheckElement('br', ElementType.isList, false), sCheckElement('div', ElementType.isList, false), sCheckElement('ul', ElementType.isList, true), sCheckElement('ol', ElementType.isList, true), sCheckElement('dl', ElementType.isList, true), sCheckText(ElementType.isList) ])), Logger.t('Check table section elements', GeneralSteps.sequence([ sCheckElement('br', ElementType.isTableSection, false), sCheckElement('div', ElementType.isTableSection, false), sCheckElement('thead', ElementType.isTableSection, true), sCheckElement('tbody', ElementType.isTableSection, true), sCheckElement('tfoot', ElementType.isTableSection, true), sCheckText(ElementType.isTableSection) ])) ], function () { success(); }, failure); });
UnitTest.asynctest('browser.tinymce.core.dom.ParentsTest', function () { const success = arguments[arguments.length - 2]; const failure = arguments[arguments.length - 1]; const cCreateStructure = function (html) { return Chain.mapper(function (_) { return Element.fromHtml(html); }); }; const cParentsUntil = function (startPath, rootPath, predicate) { return Chain.mapper(function (structure) { const startNode = Hierarchy.follow(structure, startPath).getOrDie(); const rootNode = Hierarchy.follow(structure, rootPath).getOrDie(); return Parents.parentsUntil(startNode, rootNode, predicate); }); }; const cParents = function (startPath, rootPath) { return Chain.mapper(function (structure) { const startNode = Hierarchy.follow(structure, startPath).getOrDie(); const rootNode = Hierarchy.follow(structure, rootPath).getOrDie(); return Parents.parents(startNode, rootNode); }); }; const cParentsAndSelf = function (startPath, rootPath) { return Chain.mapper(function (structure) { const startNode = Hierarchy.follow(structure, startPath).getOrDie(); const rootNode = Hierarchy.follow(structure, rootPath).getOrDie(); return Parents.parentsAndSelf(startNode, rootNode); }); }; const cAssertElementNames = function (expectedNames) { return Chain.mapper(function (parents) { const names = Arr.map(parents, Node.name); Assertions.assertEq('Should be expected names', expectedNames, names); return {}; }); }; const hasName = function (name) { return function (elm) { return Node.name(elm) === name; }; }; Pipeline.async({}, [ Logger.t('parentsUntil', GeneralSteps.sequence([ Logger.t('parentsUntil root', Chain.asStep({}, [ cCreateStructure('<p><b>a</b></p>'), cParentsUntil([0, 0], [], hasName('p')), cAssertElementNames(['b']) ])), Logger.t('parentsUntil root on elm', Chain.asStep({}, [ cCreateStructure('<p><b><i></i></b></p>'), cParentsUntil([0, 0], [], hasName('p')), cAssertElementNames(['b']) ])), Logger.t('parentsUntil root deeper', Chain.asStep({}, [ cCreateStructure('<p><b><i><u>a</u></i></b></p>'), cParentsUntil([0, 0, 0, 0], [], hasName('p')), cAssertElementNames(['u', 'i', 'b']) ])), Logger.t('parentsUntil end at b', Chain.asStep({}, [ cCreateStructure('<p><b><i><u>a</u></i></b></p>'), cParentsUntil([0, 0, 0, 0], [], hasName('b')), cAssertElementNames(['u', 'i']) ])), Logger.t('parentsUntil end at b', Chain.asStep({}, [ cCreateStructure('<p><b>a</b></p>'), cParentsUntil([0, 0], [], hasName('b')), cAssertElementNames([]) ])), Logger.t('parentsUntil root scope', Chain.asStep({}, [ cCreateStructure('<p><b><i><u>a</u></i></b></p>'), cParentsUntil([0, 0, 0, 0], [0], hasName('p')), cAssertElementNames(['u', 'i']) ])) ])), Logger.t('parents', GeneralSteps.sequence([ Logger.t('parents', Chain.asStep({}, [ cCreateStructure('<p><b><i><u>a</u></i></b></p>'), cParents([0, 0, 0, 0], []), cAssertElementNames(['u', 'i', 'b']) ])), Logger.t('parents scoped', Chain.asStep({}, [ cCreateStructure('<p><b><i><u>a</u></i></b></p>'), cParents([0, 0, 0, 0], [0]), cAssertElementNames(['u', 'i']) ])) ])), Logger.t('parentsAndSelf', GeneralSteps.sequence([ Logger.t('parentsAndSelf', Chain.asStep({}, [ cCreateStructure('<p><b><i><u>a</u></i></b></p>'), cParentsAndSelf([0, 0, 0, 0], []), cAssertElementNames(['#text', 'u', 'i', 'b']) ])), Logger.t('parentsAndSelf scoped', Chain.asStep({}, [ cCreateStructure('<p><b><i><u>a</u></i></b></p>'), cParentsAndSelf([0, 0, 0, 0], [0]), cAssertElementNames(['#text', 'u', 'i']) ])) ])) ], function () { success(); }, failure); });
UnitTest.asynctest('browser.tinymce.core.AddOnManagerTest', (success, failure) => { const suite = LegacyUnit.createSuite(); let languagePackUrl; const patch = function (proto, name, patchFunc) { let originalFunc = proto[name]; let originalFuncs = proto.__originalFuncs; if (!originalFuncs) { proto.__originalFuncs = originalFuncs = {}; } if (!originalFuncs[name]) { originalFuncs[name] = originalFunc; } else { originalFunc = originalFuncs[name]; } proto[name] = function () { const args = Array.prototype.slice.call(arguments); args.unshift(originalFunc); return patchFunc.apply(this, args); }; }; const unpatch = function (proto, name?) { const originalFuncs = proto.__originalFuncs; if (!originalFuncs) { return; } if (name) { proto[name] = originalFuncs[name]; delete originalFuncs[name]; } else { for (const key in originalFuncs) { proto[key] = originalFuncs[key]; } delete proto.__originalFuncs; } }; const getLanguagePackUrl = function (code, languages?) { languagePackUrl = null; I18n.setCode(code); PluginManager.requireLangPack('plugin', languages); return languagePackUrl; }; suite.test('requireLangPack', function () { AddOnManager.PluginManager.urls.plugin = '/root'; LegacyUnit.equal(getLanguagePackUrl('sv_SE'), '/root/langs/sv_SE.js'); LegacyUnit.equal(getLanguagePackUrl('sv_SE', 'sv,en,us'), '/root/langs/sv.js'); LegacyUnit.equal(getLanguagePackUrl('sv_SE', 'sv_SE,en_US'), '/root/langs/sv_SE.js'); LegacyUnit.equal(getLanguagePackUrl('sv'), '/root/langs/sv.js'); LegacyUnit.equal(getLanguagePackUrl('sv', 'sv'), '/root/langs/sv.js'); LegacyUnit.equal(getLanguagePackUrl('sv', 'sv,en,us'), '/root/langs/sv.js'); LegacyUnit.equal(getLanguagePackUrl('sv', 'en,sv,us'), '/root/langs/sv.js'); LegacyUnit.equal(getLanguagePackUrl('sv', 'en,us,sv'), '/root/langs/sv.js'); LegacyUnit.strictEqual(getLanguagePackUrl('sv', 'en,us'), null); AddOnManager.languageLoad = false; LegacyUnit.strictEqual(getLanguagePackUrl('sv', 'sv'), null); }); patch(ScriptLoader.ScriptLoader, 'add', function (origFunc, url) { languagePackUrl = url; }); Pipeline.async({}, suite.toSteps({}), function () { success(); unpatch(ScriptLoader.ScriptLoader); }, failure); });
TinyLoader.setup(function (editor, onSuccess, onFailure) { // This is a weird test that only checks that the skinloaded event is fired even if skin is set to false Pipeline.async({}, [ ], onSuccess, onFailure); }, {
TinyLoader.setup(function (editor, onSuccess, onFailure) { const tinyApis = TinyApis(editor); const tinyActions = TinyActions(editor); let count; // hijack editor.selection.normalize() to count how many times it will be invoked const backupNormalize = editor.selection.normalize; const normalize = function () { count = count === undefined ? 1 : count + 1; backupNormalize.apply(this, arguments); }; editor.selection.normalize = normalize; const sResetNormalizeCounter = function () { return Step.sync(function () { count = 0; }); }; const sAssertNormalizeCounter = function (expected) { return Step.sync(function () { Assertions.assertEq('checking normalization counter', expected, count); }); }; const sClickBody = function (editor) { return Step.sync(function () { const target = editor.getBody(); editor.fire('mousedown', { target }); editor.fire('mouseup', { target }); editor.fire('click', { target }); }); }; Pipeline.async({}, [ tinyApis.sFocus, Logger.t('Test normalization for floated images', GeneralSteps.sequence([ tinyApis.sSetContent('<p>a<img src="about:blank" style="float: right"></p>'), tinyApis.sSetSelection([0], 1, [0], 2), Step.sync(function () { const selection = editor.selection.getSel(); Assertions.assertEq('Anchor node should be the paragraph not the text node', 'P', selection.anchorNode.nodeName); Assertions.assertEq('Anchor offset should be the element index', 1, selection.anchorOffset); }) ])), Logger.t('Normalize on key events when range is collapsed', GeneralSteps.sequence([ tinyApis.sSetContent('<p>a</p><p>b</p>'), tinyApis.sSetSelection([], 1, [], 1), tinyActions.sContentKeystroke(Keys.escape(), {}), tinyApis.sAssertSelection([1, 0], 0, [1, 0], 0) ])), Logger.t('Normalize on mouse events when range is expanded', GeneralSteps.sequence([ tinyApis.sSetContent('<p>a</p><p>b</p>'), tinyApis.sSetSelection([], 0, [], 1), sClickBody(editor), tinyApis.sAssertSelection([0, 0], 0, [0, 0], 1) ])), Logger.t('Normalize on mouse events when range is collapsed', GeneralSteps.sequence([ tinyApis.sSetContent('<p>a</p><p>b</p>'), tinyApis.sSetSelection([], 1, [], 1), sClickBody(editor), tinyApis.sAssertSelection([1, 0], 0, [1, 0], 0) ])), Logger.t('Normalization during operations with modifier keys, should run only once in the end when user releases modifier key.', GeneralSteps.sequence([ sResetNormalizeCounter(), tinyApis.sSetContent('<p><b>a</b><i>a</i></p>'), tinyApis.sSetSelection([0, 0, 0], 0, [0, 0], 0), Keyboard.sKeyup(Element.fromDom(editor.getDoc()), Keys.left(), { shift: true }), sAssertNormalizeCounter(0), Keyboard.sKeyup(Element.fromDom(editor.getDoc()), 17, {}), // single ctrl sAssertNormalizeCounter(1), tinyApis.sAssertSelection([0, 0], 0, [0, 0], 0) ])) ], onSuccess, onFailure); }, {
TinyLoader.setup(function (editor: Editor, onSuccess, onFailure) { const tinyApis = TinyApis(editor); const sTestAnnotationEvents = (label: string, start: number[], soffset: number, expected: Array<{ uid: string, name: string, state: boolean}>): any => { return GeneralSteps.sequence([ tinyApis.sSetSelection(start, soffset, start, soffset), Waiter.sTryUntil( label, sAssertChanges('sTestAnnotationEvents.sAssertChanges', expected), 10, 1000 ), ]); }; const sTestChanges = GeneralSteps.sequence([ // '<p>This |is the first paragraph</p><p>This is the second.</p><p>This is| the third.</p><p>Spanning |multiple</p><p>par||ag||raphs| now</p>' tinyApis.sSetContent([ '<p>This is the first paragraph</p>', '<p>This is the second.</p>', '<p>This is the third.</p>', '<p>Spanning multiple</p>', '<p>paragraphs now</p>' ].join('')), tinyApis.sSetSelection([ 0, 0 ], 'This '.length, [ 0, 0 ], 'This is'.length), sAnnotate(editor, 'alpha', 'id-one', { anything: 'comment-1' }), tinyApis.sSetSelection([ 1, 0 ], 'T'.length, [ 1, 0 ], 'This is'.length), sAnnotate(editor, 'alpha', 'id-two', { anything: 'comment-two' }), tinyApis.sSetSelection([ 2, 0 ], 'This is the th'.length, [ 2, 0 ], 'This is the thir'.length), sAnnotate(editor, 'beta', 'id-three', { something: 'comment-three' }), tinyApis.sSetSelection([ 3, 0 ], 'Spanning '.length, [ 4, 0 ], 'paragraphs'.length), sAnnotate(editor, 'gamma', 'id-four', { something: 'comment-four' }), tinyApis.sSetSelection([ 4, 0, 0 ], 'par'.length, [ 4, 0, 0 ], 'parag'.length ), sAnnotate(editor, 'delta', 'id-five', { something: 'comment-five' }), Step.wait(1000), sClearChanges, sAssertHtmlContent(tinyApis, [ `<p>This <span data-mce-annotation="alpha" data-test-anything="comment-1" data-mce-annotation-uid="id-one" class="mce-annotation">is</span> the first paragraph</p>`, `<p>T<span data-mce-annotation="alpha" data-test-anything="comment-two" data-mce-annotation-uid="id-two" class="mce-annotation">his is</span> the second.</p>`, `<p>This is the th<span data-mce-annotation="beta" data-test-something="comment-three" data-mce-annotation-uid="id-three" class="mce-annotation">ir</span>d.</p>`, `<p>Spanning <span data-mce-annotation="gamma" data-test-something="comment-four" data-mce-annotation-uid="id-four" class="mce-annotation">multiple</span></p>`, `<p><span data-mce-annotation="gamma" data-test-something="comment-four" data-mce-annotation-uid="id-four" class="mce-annotation">par` + `<span data-mce-annotation="delta" data-test-something="comment-five" data-mce-annotation-uid="id-five" class="mce-annotation delta-test">ag</span>` + `raphs</span> now</p>` ]), // Outside: p(0) > text(0) > "Th".length // Inside: p(0) > span(1) > text(0) > 'i'.length // Inside: p(1) > span(1) > text(0), 'hi'.length // Outside: p(1) > text(2) > ' the '.length Waiter.sTryUntil( 'Waiting for no changes', sAssertChanges('Should be no changes', [ ]), 10, 1000 ), sTestAnnotationEvents( 'No annotation at cursor', [ 0, 0 ], 'Th'.length, [ { state: false, name: 'delta', uid: null }, { state: false, name: 'gamma', uid: null } ] ), sTestAnnotationEvents( 'At annotation alpha, id = id-one', [ 0, 1, 0 ], 'i'.length, [ { state: false, name: 'delta', uid: null }, { state: false, name: 'gamma', uid: null }, { state: true, name: 'alpha', uid: 'id-one' } ] ), sTestAnnotationEvents( 'At annotation alpha, id = id-two', [ 1, 1, 0 ], 'hi'.length, [ { state: false, name: 'delta', uid: null }, { state: false, name: 'gamma', uid: null }, { state: true, name: 'alpha', uid: 'id-one' }, { state: true, name: 'alpha', uid: 'id-two' } ] ), tinyApis.sSetSelection([ 1, 1, 0 ], 'his'.length, [ 1, 1, 0 ], 'his'.length), // Give it time to throttle a node change. Step.wait(400), Waiter.sTryUntil( 'Moving selection within the same marker (alpha id-two) ... shoud not fire change', sAssertChanges('checking changes', [ { state: false, name: 'delta', uid: null }, { state: false, name: 'gamma', uid: null }, { state: true, name: 'alpha', uid: 'id-one' }, { state: true, name: 'alpha', uid: 'id-two' } ] ), 10, 1000 ), sTestAnnotationEvents( 'Outside annotations again', [ 1, 2 ], ' the '.length, [ { state: false, name: 'delta', uid: null }, { state: false, name: 'gamma', uid: null }, { state: true, name: 'alpha', uid: 'id-one' }, { state: true, name: 'alpha', uid: 'id-two' }, { state: false, name: 'alpha', uid: null } ] ), sTestAnnotationEvents( 'Inside annotation beta, id = id-three', [ 2, 1, 0 ], 'i'.length, [ { state: false, name: 'delta', uid: null }, { state: false, name: 'gamma', uid: null }, { state: true, name: 'alpha', uid: 'id-one' }, { state: true, name: 'alpha', uid: 'id-two' }, { state: false, name: 'alpha', uid: null }, { state: true, name: 'beta', uid: 'id-three' } ] ), tinyApis.sSetSelection([ 2, 0 ], 'T'.length, [ 2, 0 ], 'T'.length), Waiter.sTryUntil( 'Moving selection outside all annotations. Should fire null', sAssertChanges('checking changes', [ { state: false, name: 'delta', uid: null }, { state: false, name: 'gamma', uid: null }, { state: true, name: 'alpha', uid: 'id-one' }, { state: true, name: 'alpha', uid: 'id-two' }, { state: false, name: 'alpha', uid: null }, { state: true, name: 'beta', uid: 'id-three' }, { state: false, name: 'beta', uid: null } ] ), 10, 1000 ), tinyApis.sSetSelection([ 2, 2 ], 'd'.length, [ 2, 2 ], 'd'.length), // Give it time to throttle a node change. Step.wait(400), Waiter.sTryUntil( 'Moving selection outside all annotations (again). Should NOT fire null because it already has', sAssertChanges('checking changes', [ { state: false, name: 'delta', uid: null }, { state: false, name: 'gamma', uid: null }, { state: true, name: 'alpha', uid: 'id-one' }, { state: true, name: 'alpha', uid: 'id-two' }, { state: false, name: 'alpha', uid: null }, { state: true, name: 'beta', uid: 'id-three' }, { state: false, name: 'beta', uid: null } ] ), 10, 1000 ), sClearChanges, tinyApis.sSetSelection([ 4, 0, 1, 0 ], 'a'.length, [ 4, 0, 1, 0 ], 'a'.length), // Give it time to throttle a node change. Step.wait(400), Waiter.sTryUntil( 'Moving selection inside delta (which is inside gamma)', sAssertChanges('checking changes', [ { state: true, name: 'delta', uid: 'id-five' }, { state: true, name: 'gamma', uid: 'id-four' } ] ), 10, 1000 ), tinyApis.sSetSelection([ 4, 0, 0 ], 'p'.length, [ 4, 0, 0 ], 'p'.length), // Give it time to throttle a node change. Step.wait(400), Waiter.sTryUntil( 'Moving selection inside just gamma (but not delta)', sAssertChanges('checking changes', [ { state: true, name: 'delta', uid: 'id-five' }, { state: true, name: 'gamma', uid: 'id-four' }, { state: false, name: 'delta', uid: null } ] ), 10, 1000 ), ]); Pipeline.async({}, [ tinyApis.sFocus, sTestChanges ], onSuccess, onFailure); }, {