import { GeneralSteps, Logger, Pipeline, RawAssertions, Step, Waiter } from '@ephox/agar'; import { UnitTest } from '@ephox/bedrock'; import { TinyApis, TinyLoader } from '@ephox/mcagar'; import InternalHtml from 'tinymce/plugins/paste/core/InternalHtml'; import Utils from 'tinymce/plugins/paste/core/Utils'; import Plugin from 'tinymce/plugins/paste/Plugin'; import Theme from 'tinymce/themes/modern/Theme'; import MockDataTransfer from '../module/test/MockDataTransfer'; UnitTest.asynctest('browser.tinymce.plugins.paste.InternalClipboardTest', function () { const success = arguments[arguments.length - 2]; const failure = arguments[arguments.length - 1]; let dataTransfer, lastPreProcessEvent, lastPostProcessEvent; Plugin(); Theme(); const sResetProcessEvents = Step.sync(function () { lastPreProcessEvent = null; lastPostProcessEvent = null; }); const sCutCopyDataTransferEvent = function (editor, type) { return Step.sync(function () { dataTransfer = MockDataTransfer.create({}); editor.fire(type, { clipboardData: dataTransfer }); }); }; const sPasteDataTransferEvent = function (editor, data) { return Step.sync(function () { dataTransfer = MockDataTransfer.create(data); editor.fire('paste', { clipboardData: dataTransfer }); }); }; const sAssertClipboardData = function (expectedHtml, expectedText) { return Step.sync(function () { RawAssertions.assertEq('text/html data should match', expectedHtml, dataTransfer.getData('text/html')); RawAssertions.assertEq('text/plain data should match', expectedText, dataTransfer.getData('text/plain')); }); }; const sCopy = function (editor, tinyApis, html, spath, soffset, fpath, foffset) { return GeneralSteps.sequence([ tinyApis.sSetContent(html), tinyApis.sSetSelection(spath, soffset, fpath, foffset), sCutCopyDataTransferEvent(editor, 'copy') ]); }; const sCut = function (editor, tinyApis, html, spath, soffset, fpath, foffset) { return GeneralSteps.sequence([ tinyApis.sSetContent(html), tinyApis.sSetSelection(spath, soffset, fpath, foffset), sCutCopyDataTransferEvent(editor, 'cut') ]); }; const sPaste = function (editor, tinyApis, startHtml, pasteData, spath, soffset, fpath, foffset) { return GeneralSteps.sequence([ tinyApis.sSetContent(startHtml), tinyApis.sSetSelection(spath, soffset, fpath, foffset), sResetProcessEvents, sPasteDataTransferEvent(editor, pasteData) ]); }; const sTestCopy = function (editor, tinyApis) { return Logger.t('Copy tests', GeneralSteps.sequence([ Logger.t('Copy simple text', GeneralSteps.sequence([ sCopy(editor, tinyApis, '

text

', [0, 0], 0, [0, 0], 4), sAssertClipboardData('text', 'text'), tinyApis.sAssertContent('

text

'), tinyApis.sAssertSelection([0, 0], 0, [0, 0], 4) ])), Logger.t('Copy inline elements', GeneralSteps.sequence([ sCopy(editor, tinyApis, '

text

', [0, 0], 0, [0, 2], 1), sAssertClipboardData('text', 'text'), tinyApis.sAssertContent('

text

'), tinyApis.sAssertSelection([0, 0], 0, [0, 2], 1) ])), Logger.t('Copy partialy selected inline elements', GeneralSteps.sequence([ sCopy(editor, tinyApis, '

acde

', [0, 0], 0, [0, 1, 0], 1), sAssertClipboardData('ac', 'ac'), tinyApis.sAssertContent('

acde

'), tinyApis.sAssertSelection([0, 0], 0, [0, 1, 0], 1) ])), Logger.t('Copy collapsed selection', GeneralSteps.sequence([ sCopy(editor, tinyApis, '

abc

', [0, 0], 1, [0, 0], 1), sAssertClipboardData('', ''), tinyApis.sAssertContent('

abc

'), tinyApis.sAssertSelection([0, 0], 1, [0, 0], 1) ])) ])); }; const sTestCut = function (editor, tinyApis) { const sWaitUntilAssertContent = function (expected) { return Waiter.sTryUntil('Cut is async now, so need to wait for content', tinyApis.sAssertContent(expected), 100, 1000); }; return Logger.t('Cut tests', GeneralSteps.sequence([ Logger.t('Cut simple text', GeneralSteps.sequence([ sCut(editor, tinyApis, '

text

', [0, 0], 0, [0, 0], 4), sAssertClipboardData('text', 'text'), sWaitUntilAssertContent(''), tinyApis.sAssertSelection([0], 0, [0], 0) ])), Logger.t('Cut inline elements', GeneralSteps.sequence([ sCut(editor, tinyApis, '

text

', [0, 0], 0, [0, 2], 1), sAssertClipboardData('text', 'text'), sWaitUntilAssertContent(''), tinyApis.sAssertSelection([0], 0, [0], 0) ])), Logger.t('Cut partialy selected inline elements', GeneralSteps.sequence([ sCut(editor, tinyApis, '

acde

', [0, 0], 0, [0, 1, 0], 1), sAssertClipboardData('ac', 'ac'), sWaitUntilAssertContent('

de

'), tinyApis.sAssertSelection([0, 0, 0], 0, [0, 0, 0], 0) ])), Logger.t('Cut collapsed selection', GeneralSteps.sequence([ sCut(editor, tinyApis, '

abc

', [0, 0], 1, [0, 0], 1), sAssertClipboardData('', ''), sWaitUntilAssertContent('

abc

'), tinyApis.sAssertSelection([0, 0], 1, [0, 0], 1) ])) ])); }; const sAssertLastPreProcessEvent = function (expectedData) { return Step.sync(function () { RawAssertions.assertEq('Internal property should be equal', expectedData.internal, lastPreProcessEvent.internal); RawAssertions.assertEq('Content property should be equal', expectedData.content, lastPreProcessEvent.content); }); }; const sAssertLastPostProcessEvent = function (expectedData) { return Step.sync(function () { RawAssertions.assertEq('Internal property should be equal', expectedData.internal, lastPostProcessEvent.internal); RawAssertions.assertEq('Content property should be equal', expectedData.content, lastPostProcessEvent.node.innerHTML); }); }; const sWaitForProcessEvents = Waiter.sTryUntil('Did not get any events fired', Step.sync(function () { RawAssertions.assertEq('PastePreProcess event object', lastPreProcessEvent !== null, true); RawAssertions.assertEq('PastePostProcess event object', lastPostProcessEvent !== null, true); }), 100, 100); const sTestPaste = function (editor, tinyApis) { return Logger.t('Paste tests', GeneralSteps.sequence([ Logger.t('Paste external content', GeneralSteps.sequence([ sPaste(editor, tinyApis, '

abc

', { 'text/plain': 'X', 'text/html': '

X

' }, [0, 0], 0, [0, 0], 3), sWaitForProcessEvents, sAssertLastPreProcessEvent({ internal: false, content: 'X' }), sAssertLastPostProcessEvent({ internal: false, content: 'X' }) ])), Logger.t('Paste external content treated as plain text', GeneralSteps.sequence([ sPaste(editor, tinyApis, '

abc

', { 'text/html': '

X

' }, [0, 0], 0, [0, 0], 3), sWaitForProcessEvents, sAssertLastPreProcessEvent({ internal: false, content: 'X' }), sAssertLastPostProcessEvent({ internal: false, content: 'X' }) ])), Logger.t('Paste internal content with mark', GeneralSteps.sequence([ sPaste(editor, tinyApis, '

abc

', { 'text/plain': 'X', 'text/html': InternalHtml.mark('

X

') }, [0, 0], 0, [0, 0], 3), sWaitForProcessEvents, sAssertLastPreProcessEvent({ internal: true, content: '

X

' }), sAssertLastPostProcessEvent({ internal: true, content: '

X

' }) ])), Logger.t('Paste internal content with mime', GeneralSteps.sequence([ sPaste(editor, tinyApis, '

abc

', { 'text/plain': 'X', 'text/html': '

X

', 'x-tinymce/html': '

X

' }, [0, 0], 0, [0, 0], 3 ), sWaitForProcessEvents, sAssertLastPreProcessEvent({ internal: true, content: '

X

' }), sAssertLastPostProcessEvent({ internal: true, content: '

X

' }) ])) ])); }; TinyLoader.setup(function (editor, onSuccess, onFailure) { const tinyApis = TinyApis(editor); // Disabled tests on Edge 15 due to broken clipboard API Pipeline.async({}, Utils.isMsEdge() ? [ ] : [ sTestCopy(editor, tinyApis), sTestCut(editor, tinyApis), sTestPaste(editor, tinyApis) ], onSuccess, onFailure); }, { plugins: 'paste', init_instance_callback (editor) { editor.on('PastePreProcess', function (evt) { lastPreProcessEvent = evt; }); editor.on('PastePostProcess', function (evt) { lastPostProcessEvent = evt; }); }, skin_url: '/project/js/tinymce/skins/lightgray' }, success, failure); });