diff --git a/packages-content-model/roosterjs-content-model-editor/lib/editor/plugins/PastePlugin/ContentModelPastePlugin.ts b/packages-content-model/roosterjs-content-model-editor/lib/editor/plugins/PastePlugin/ContentModelPastePlugin.ts index 121f8a8f922..f2ecf3257a3 100644 --- a/packages-content-model/roosterjs-content-model-editor/lib/editor/plugins/PastePlugin/ContentModelPastePlugin.ts +++ b/packages-content-model/roosterjs-content-model-editor/lib/editor/plugins/PastePlugin/ContentModelPastePlugin.ts @@ -87,6 +87,7 @@ export default class ContentModelFormatPlugin implements EditorPlugin { processPastedContentWacComponents(ev); break; case KnownPasteSourceType.ExcelOnline: + case KnownPasteSourceType.ExcelDesktop: if ( event.pasteType === PasteType.Normal || event.pasteType === PasteType.MergeFormat diff --git a/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromExcelOnlineTest.ts b/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromExcelOnlineTest.ts new file mode 100644 index 00000000000..7e66eb2f79a --- /dev/null +++ b/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromExcelOnlineTest.ts @@ -0,0 +1,46 @@ +import * as processPastedContentFromExcel from '../../../../../lib/editor/plugins/PastePlugin/Excel/processPastedContentFromExcel'; +import paste from '../../../../../lib/publicApi/utils/paste'; +import { ClipboardData } from 'roosterjs-editor-types'; +import { IContentModelEditor } from '../../../../../lib/publicTypes/IContentModelEditor'; +import { initEditor } from './cmPasteFromExcelTest'; +import { tableProcessor } from 'roosterjs-content-model-dom'; + +const ID = 'CM_Paste_From_ExcelOnline_E2E'; +const clipboardData = ({ + types: ['text/plain', 'text/html'], + text: 'Test\tTest', + image: null, + files: [], + rawHtml: + "\r\n\r\n
TestTest
\r\n\r\n", + customValues: {}, + snapshotBeforePaste: '
', + htmlFirstLevelChildTags: ['DIV'], + html: + "
TestTest
", +}); + +describe(ID, () => { + let editor: IContentModelEditor = undefined!; + + beforeEach(() => { + editor = initEditor(ID); + }); + + afterEach(() => { + document.getElementById(ID)?.remove(); + }); + + it('E2E', () => { + spyOn(processPastedContentFromExcel, 'processPastedContentFromExcel').and.callThrough(); + + paste(editor, clipboardData); + editor.createContentModel({ + processorOverride: { + table: tableProcessor, + }, + }); + + expect(processPastedContentFromExcel.processPastedContentFromExcel).toHaveBeenCalled(); + }); +}); diff --git a/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromExcelTest.ts b/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromExcelTest.ts new file mode 100644 index 00000000000..be8028bc2e5 --- /dev/null +++ b/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromExcelTest.ts @@ -0,0 +1,115 @@ +import * as processPastedContentFromExcel from '../../../../../lib/editor/plugins/PastePlugin/Excel/processPastedContentFromExcel'; +import ContentModelEditor from '../../../../../lib/editor/ContentModelEditor'; +import ContentModelPastePlugin from '../../../../../lib/editor/plugins/PastePlugin/ContentModelPastePlugin'; +import paste from '../../../../../lib/publicApi/utils/paste'; +import { Browser } from 'roosterjs-editor-dom'; +import { ClipboardData, ExperimentalFeatures } from 'roosterjs-editor-types'; +import { tableProcessor } from 'roosterjs-content-model-dom'; +import { + ContentModelEditorOptions, + IContentModelEditor, +} from '../../../../../lib/publicTypes/IContentModelEditor'; + +export function initEditor(id: string) { + let node = document.createElement('div'); + node.id = id; + document.body.insertBefore(node, document.body.childNodes[0]); + + let options: ContentModelEditorOptions = { + plugins: [new ContentModelPastePlugin()], + experimentalFeatures: [ExperimentalFeatures.ContentModelPaste], + defaultDomToModelOptions: { + disableCacheElement: true, + }, + }; + + let editor = new ContentModelEditor(node as HTMLDivElement, options); + + return editor as IContentModelEditor; +} + +const ID = 'CM_Paste_From_Excel_E2E'; +const clipboardData = ({ + types: ['image/png', 'text/plain', 'text/html'], + text: 'Test\tTest\r\n', + image: {}, + files: [], + rawHtml: '\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n
TestTest
\r\n\r\n\r\n\r\n\r\n'.replace( + '\r\n', + '' + ), + customValues: {}, + imageDataUri: 'https://github.com/microsoft/roosterjs', + snapshotBeforePaste: '

', +}); + +describe(ID, () => { + let editor: IContentModelEditor = undefined!; + + beforeEach(() => { + editor = initEditor(ID); + }); + + afterEach(() => { + document.getElementById(ID)?.remove(); + }); + + it('E2E', () => { + if (Browser.isFirefox) { + return; + } + spyOn(processPastedContentFromExcel, 'processPastedContentFromExcel').and.callThrough(); + + paste(editor, clipboardData); + editor.createContentModel({}); + + expect(processPastedContentFromExcel.processPastedContentFromExcel).toHaveBeenCalled(); + }); + + it('E2E paste a simage', () => { + if (Browser.isFirefox) { + return; + } + spyOn(processPastedContentFromExcel, 'processPastedContentFromExcel').and.callThrough(); + + paste(editor, clipboardData, false, false, true); + const model = editor.createContentModel({ + processorOverride: { + table: tableProcessor, + }, + }); + + expect(model).toEqual({ + blockGroupType: 'Document', + blocks: [ + { + blockType: 'Paragraph', + segments: [ + { + segmentType: 'Image', + src: 'https://github.com/microsoft/roosterjs', + format: { maxWidth: '100%' }, + dataset: {}, + }, + { + segmentType: 'SelectionMarker', + isSelected: true, + format: {}, + }, + ], + format: {}, + }, + ], + format: { + fontWeight: undefined, + italic: undefined, + underline: undefined, + fontFamily: undefined, + fontSize: undefined, + textColor: undefined, + backgroundColor: undefined, + }, + }); + expect(processPastedContentFromExcel.processPastedContentFromExcel).not.toHaveBeenCalled(); + }); +}); diff --git a/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromWacTest.ts b/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromWacTest.ts new file mode 100644 index 00000000000..a2bfefe78bf --- /dev/null +++ b/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromWacTest.ts @@ -0,0 +1,52 @@ +import * as processPastedContentWacComponents from '../../../../../lib/editor/plugins/PastePlugin/WacComponents/processPastedContentWacComponents'; +import paste from '../../../../../lib/publicApi/utils/paste'; +import { ClipboardData } from 'roosterjs-editor-types'; +import { IContentModelEditor } from '../../../../../lib/publicTypes/IContentModelEditor'; +import { initEditor } from './cmPasteFromExcelTest'; +import { tableProcessor } from 'roosterjs-content-model-dom'; + +const ID = 'CM_Paste_From_WORD_Online_E2E'; +const clipboardData = ({ + types: ['text/plain', 'text/html'], + text: 'asd\r\n\r\nTest ', + image: null, + files: [], + rawHtml: + '\r\n\r\n

asd 

  • Test 

\r\n\r\n', + customValues: {}, + snapshotBeforePaste: + '
Test 
', + htmlFirstLevelChildTags: ['DIV', 'DIV'], + html: + '

asd 

  • Test 

', +}); + +describe(ID, () => { + let editor: IContentModelEditor = undefined!; + + beforeEach(() => { + editor = initEditor(ID); + }); + + afterEach(() => { + document.getElementById(ID)?.remove(); + }); + + it('E2E', () => { + spyOn( + processPastedContentWacComponents, + 'processPastedContentWacComponents' + ).and.callThrough(); + + paste(editor, clipboardData); + editor.createContentModel({ + processorOverride: { + table: tableProcessor, + }, + }); + + expect( + processPastedContentWacComponents.processPastedContentWacComponents + ).toHaveBeenCalled(); + }); +}); diff --git a/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromWordTest.ts b/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromWordTest.ts new file mode 100644 index 00000000000..09564a147cd --- /dev/null +++ b/packages-content-model/roosterjs-content-model-editor/test/editor/plugins/paste/e2e/cmPasteFromWordTest.ts @@ -0,0 +1,53 @@ +import * as processPastedContentFromWordDesktop from '../../../../../lib/editor/plugins/PastePlugin/WordDesktop/processPastedContentFromWordDesktop'; +import paste from '../../../../../lib/publicApi/utils/paste'; +import { ClipboardData } from 'roosterjs-editor-types'; +import { DomToModelOption } from 'roosterjs-content-model-types'; +import { IContentModelEditor } from '../../../../../lib/publicTypes/IContentModelEditor'; +import { initEditor } from './cmPasteFromExcelTest'; +import { tableProcessor } from 'roosterjs-content-model-dom'; + +const ID = 'CM_Paste_From_WORD_E2E'; +const clipboardData = ({ + types: ['text/plain', 'text/html'], + text: 'Test\r\nasdsad\r\n', + image: null, + files: [], + rawHtml: + '\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n

Test

\r\n\r\n

asdsad

\r\n\r\n\r\n\r\n\r\n\r\n', + customValues: {}, + snapshotBeforePaste: + '

Test

', + htmlFirstLevelChildTags: ['P', 'P'], + html: + '

Test

asdsad

', +}); + +describe(ID, () => { + let editor: IContentModelEditor = undefined!; + + beforeEach(() => { + editor = initEditor(ID); + }); + + afterEach(() => { + document.getElementById(ID)?.remove(); + }); + + it('E2E', () => { + spyOn( + processPastedContentFromWordDesktop, + 'processPastedContentFromWordDesktop' + ).and.callThrough(); + + paste(editor, clipboardData); + editor.createContentModel({ + processorOverride: { + table: tableProcessor, + }, + }); + + expect( + processPastedContentFromWordDesktop.processPastedContentFromWordDesktop + ).toHaveBeenCalled(); + }); +}); diff --git a/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromExcelOnlineTest.ts b/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromExcelOnlineTest.ts new file mode 100644 index 00000000000..43ed221da47 --- /dev/null +++ b/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromExcelOnlineTest.ts @@ -0,0 +1,57 @@ +import * as convertPastedContentFromExcel from '../../../lib/plugins/Paste/excelConverter/convertPastedContentFromExcel'; +import * as moveChildNodes from 'roosterjs-editor-dom/lib/utils/moveChildNodes'; +import { ClipboardData, IEditor } from 'roosterjs-editor-types'; +import { initEditor } from '../../TestHelper'; +import { Paste } from '../../../lib/index'; + +const ID = 'Paste_From_ExcelOnline_E2E'; +const clipboardData = ({ + types: ['text/plain', 'text/html'], + text: 'Test\tTest', + image: null, + files: [], + rawHtml: + "\r\n\r\n
TestTest
\r\n\r\n", + customValues: {}, + snapshotBeforePaste: '
', + htmlFirstLevelChildTags: ['DIV'], + html: + "
TestTest
", +}); + +describe(ID, () => { + let editor: IEditor = undefined!; + + beforeEach(() => { + editor = initEditor(ID, [new Paste()]); + }); + + afterEach(() => { + document.getElementById(ID)?.remove(); + }); + + it('E2E', () => { + spyOn(convertPastedContentFromExcel, 'default').and.callThrough(); + spyOn(moveChildNodes, 'default').and.callThrough(); + + editor.paste(clipboardData); + + expect(convertPastedContentFromExcel.default).toHaveBeenCalled(); + expect(moveChildNodes.default).toHaveBeenCalledTimes(1); + }); + + it('E2E paste a simage', () => { + spyOn(convertPastedContentFromExcel, 'default').and.callThrough(); + spyOn(moveChildNodes, 'default').and.callThrough(); + + editor.paste( + clipboardData, + false /* asText */, + false /* applyCurrentFormat */, + true /* pasteImage */ + ); + + expect(convertPastedContentFromExcel.default).not.toHaveBeenCalled(); + expect(moveChildNodes.default).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromExcelTest.ts b/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromExcelTest.ts new file mode 100644 index 00000000000..0540fded937 --- /dev/null +++ b/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromExcelTest.ts @@ -0,0 +1,57 @@ +import * as convertPastedContentFromExcel from '../../../lib/plugins/Paste/excelConverter/convertPastedContentFromExcel'; +import * as moveChildNodes from 'roosterjs-editor-dom/lib/utils/moveChildNodes'; +import { ClipboardData, IEditor } from 'roosterjs-editor-types'; +import { initEditor } from '../../TestHelper'; +import { Paste } from '../../../lib/index'; + +const ID = 'Paste_From_Excel_E2E'; +const clipboardData = ({ + types: ['image/png', 'text/plain', 'text/html'], + text: 'Test\tTest\r\n', + image: {}, + files: [], + rawHtml: '\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n \r\n \r\n\r\n \r\n \r\n\r\n \r\n
TestTest
\r\n\r\n\r\n\r\n\r\n'.replace( + '\r\n', + '' + ), + customValues: {}, + imageDataUri: 'https://github.com/microsoft/roosterjs', + snapshotBeforePaste: '

', +}); + +describe(ID, () => { + let editor: IEditor = undefined!; + + beforeEach(() => { + editor = initEditor(ID, [new Paste()]); + }); + + afterEach(() => { + document.getElementById(ID)?.remove(); + }); + + it('E2E', () => { + spyOn(convertPastedContentFromExcel, 'default').and.callThrough(); + spyOn(moveChildNodes, 'default').and.callThrough(); + + editor.paste(clipboardData); + + expect(convertPastedContentFromExcel.default).toHaveBeenCalled(); + expect(moveChildNodes.default).toHaveBeenCalledTimes(2); + }); + + it('E2E paste a simage', () => { + spyOn(convertPastedContentFromExcel, 'default').and.callThrough(); + spyOn(moveChildNodes, 'default').and.callThrough(); + + editor.paste( + clipboardData, + false /* asText */, + false /* applyCurrentFormat */, + true /* pasteImage */ + ); + + expect(convertPastedContentFromExcel.default).not.toHaveBeenCalled(); + expect(moveChildNodes.default).toHaveBeenCalledTimes(0); + }); +}); diff --git a/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromWacTest.ts b/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromWacTest.ts new file mode 100644 index 00000000000..69113351362 --- /dev/null +++ b/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromWacTest.ts @@ -0,0 +1,47 @@ +import * as convertPastedContentFromOfficeOnline from '../../../lib/plugins/Paste/officeOnlineConverter/convertPastedContentFromOfficeOnline'; +import * as convertPastedContentFromWord from '../../../lib/plugins/Paste/wordConverter/convertPastedContentFromWord'; +import * as convertPastedContentFromWordOnline from '../../../lib/plugins/Paste/officeOnlineConverter/convertPastedContentFromWordOnline'; +import { ClipboardData, IEditor } from 'roosterjs-editor-types'; +import { initEditor } from '../../TestHelper'; +import { Paste } from '../../../lib/index'; + +const ID = 'Paste_From_WORD_Online_E2E'; + +const clipboardData = ({ + types: ['text/plain', 'text/html'], + text: 'asd \r\n\r\nTest ', + image: null, + files: [], + rawHtml: + '\r\n\r\n

asd 

  • Test 

\r\n\r\n', + customValues: {}, + snapshotBeforePaste: + '
Test 
', + htmlFirstLevelChildTags: ['DIV', 'DIV'], + html: + '

asd 

  • Test 

', +}); + +describe(ID, () => { + let editor: IEditor = undefined!; + + beforeEach(() => { + editor = initEditor(ID, [new Paste()]); + }); + + afterEach(() => { + document.getElementById(ID)?.remove(); + }); + + it('E2E', () => { + spyOn(convertPastedContentFromWord, 'default').and.callThrough(); + spyOn(convertPastedContentFromOfficeOnline, 'default').and.callThrough(); + spyOn(convertPastedContentFromWordOnline, 'default').and.callThrough(); + + editor.paste(clipboardData); + + expect(convertPastedContentFromWord.default).not.toHaveBeenCalled(); + expect(convertPastedContentFromOfficeOnline.default).toHaveBeenCalled(); + expect(convertPastedContentFromWordOnline.default).toHaveBeenCalled(); + }); +}); diff --git a/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromWordTest.ts b/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromWordTest.ts new file mode 100644 index 00000000000..0c536bf086d --- /dev/null +++ b/packages/roosterjs-editor-plugins/test/paste/e2e/pasteFromWordTest.ts @@ -0,0 +1,45 @@ +import * as convertPastedContentFromWord from '../../../lib/plugins/Paste/wordConverter/convertPastedContentFromWord'; +import { Browser } from 'roosterjs-editor-dom'; +import { Browser } from 'roosterjs-editor-dom'; +import { ClipboardData, IEditor } from 'roosterjs-editor-types'; +import { initEditor } from '../../TestHelper'; +import { Paste } from '../../../lib/index'; + +const ID = 'Paste_From_WORD_E2E'; + +describe(ID, () => { + let editor: IEditor = undefined!; + + beforeEach(() => { + editor = initEditor(ID, [new Paste()]); + }); + + afterEach(() => { + document.getElementById(ID)?.remove(); + }); + + it('E2E', () => { + if (Browser.isFirefox) { + return; + } + spyOn(convertPastedContentFromWord, 'default').and.callThrough(); + const clipboardData = ({ + types: ['text/plain', 'text/html'], + text: 'Test\r\nasdsad\r\n', + image: null, + files: [], + rawHtml: + '\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n

Test

\r\n\r\n

asdsad

\r\n\r\n\r\n\r\n\r\n\r\n', + customValues: {}, + snapshotBeforePaste: + '

Test

', + htmlFirstLevelChildTags: ['P', 'P'], + html: + '

Test

asdsad

', + }); + + editor.paste(clipboardData); + + expect(convertPastedContentFromWord.default).toHaveBeenCalled(); + }); +});