import { after, before, beforeEach, context, describe, it } from '@ephox/bedrock-client'; import { Singleton } from '@ephox/katamari'; import { DomEvent, Insert, Remove, SugarBody, SugarElement } from '@ephox/sugar'; import { assert } from 'chai'; import { copy, cut, pasteDataTransfer, pasteFiles, pasteItems, pPasteUrlItems } from 'ephox/agar/api/Clipboard'; import { createFileFromString, getFileDataAsString } from 'ephox/agar/api/Files'; describe('ClipboardTest', () => { const pasteState = Singleton.value(); const pastebinState = Singleton.value>(); const unbinderState = Singleton.value<() => void>(); const getItemData = async (item: DataTransferItem) => { if (item.kind === 'string') { return new Promise((resolve) => { item.getAsString((data) => { resolve(data); }); }); } else { return getFileDataAsString(item.getAsFile()); } }; const pAssertStringItem = async (item: DataTransferItem, expected: { type: string; data: string }): Promise => { assert.equal(item.type, expected.type); assert.equal(item.kind, 'string'); assert.equal(await getItemData(item), expected.data); }; const pAssertFileItem = async (item: DataTransferItem, expected: { type: string; name: string; data: string }): Promise => { assert.equal(item.type, expected.type); assert.equal(item.kind, 'file'); assert.equal(item.getAsFile().name, expected.name); assert.equal(await getItemData(item), expected.data); }; before(() => { pastebinState.set(SugarElement.fromHtml('
')); pastebinState.on((pastebin) => { Insert.append(SugarBody.body(), pastebin); const cutUnbinder = DomEvent.bind(pastebin, 'cut', (evt) => { const dataTransfer = evt.raw.clipboardData; dataTransfer.clearData(); dataTransfer.setData('text/plain', 'cut-data'); }); const copyUnbinder = DomEvent.bind(pastebin, 'copy', (evt) => { const dataTransfer = evt.raw.clipboardData; dataTransfer.clearData(); dataTransfer.setData('text/plain', 'copy-data'); }); const pasteUnbinder = DomEvent.bind(pastebin, 'paste', (evt) => { const dataTransfer = evt.raw.clipboardData; pasteState.set(dataTransfer); }); unbinderState.set(() => { cutUnbinder.unbind(); copyUnbinder.unbind(); pasteUnbinder.unbind(); }); }); }); beforeEach(() => { pasteState.clear(); }); after(() => { pastebinState.on(Remove.remove); pastebinState.clear(); unbinderState.on((unbind) => unbind()); unbinderState.clear(); }); it('Paste text and html items', async () => { const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); pasteItems(pastebin, { 'text/plain': 'Hello world!', 'text/html': 'Hello world!' }); const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); assert.equal(dataTransfer.items.length, 2); await pAssertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'Hello world!' }); await pAssertStringItem(dataTransfer.items[1], { type: 'text/html', data: 'Hello world!' }); }); it('Paste text and html files', async () => { const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); pasteFiles(pastebin, [ createFileFromString('a.txt', 123, 'Hello world!', 'text/plain'), createFileFromString('a.html', 123, 'Hello world!', 'text/html') ]); const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); assert.equal(dataTransfer.items.length, 2); await pAssertFileItem(dataTransfer.items[1], { type: 'text/html', name: 'a.html', data: 'Hello world!' }); await pAssertFileItem(dataTransfer.items[0], { type: 'text/plain', name: 'a.txt', data: 'Hello world!' }); }); it('Paste using dataTransfer mutator', async () => { const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); pasteDataTransfer(pastebin, (dataTransfer) => { dataTransfer.items.add(createFileFromString('a.txt', 123, 'Hello world!', 'text/plain')); dataTransfer.items.add('Hello world!', 'text/html'); }); const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); assert.equal(dataTransfer.items.length, 2); await pAssertFileItem(dataTransfer.items[0], { type: 'text/plain', name: 'a.txt', data: 'Hello world!' }); await pAssertStringItem(dataTransfer.items[1], { type: 'text/html', data: 'Hello world!' }); }); it('Cut', async () => { const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); const dataTransfer = cut(pastebin); assert.equal(dataTransfer.items.length, 1); await pAssertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'cut-data' }); }); it('Copy', async () => { const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); const dataTransfer = copy(pastebin); assert.equal(dataTransfer.items.length, 1); await pAssertStringItem(dataTransfer.items[0], { type: 'text/plain', data: 'copy-data' }); }); it('PasteUrlItems as strings', async () => { const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); await pPasteUrlItems(pastebin, [ { kind: 'string', url: 'project/@ephox/agar/src/test/resources/clipboard.html' }, { kind: 'string', url: 'project/@ephox/agar/src/test/resources/clipboard.txt' }, ]); const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); assert.equal(dataTransfer.items.length, 2); await pAssertStringItem(dataTransfer.items[0], { type: 'text/html', data: '\n\n\n

Hello world

\n\n\n' }); await pAssertStringItem(dataTransfer.items[1], { type: 'text/plain', data: 'Hello world\n' }); }); it('PasteUrlItems as files', async () => { const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); await pPasteUrlItems(pastebin, [ { kind: 'file', url: 'project/@ephox/agar/src/test/resources/clipboard.html' }, { kind: 'file', url: 'project/@ephox/agar/src/test/resources/clipboard.txt' }, ]); const dataTransfer = pasteState.get().getOrDie('Could not get dataTransfer from state'); assert.equal(dataTransfer.items.length, 2); await pAssertFileItem(dataTransfer.items[0], { type: 'text/html', name: 'clipboard.html', data: '\n\n\n

Hello world

\n\n\n' }); await pAssertFileItem(dataTransfer.items[1], { type: 'text/plain', name: 'clipboard.txt', data: 'Hello world\n' }); }); context('DataTransfer instance type', () => { const testDataTransferInstance = (eventName: 'cut' | 'copy', operation: (target: SugarElement) => DataTransfer) => { const pastebin = pastebinState.get().getOrDie('Could not get pastebin from state'); let event: ClipboardEvent = null; const unbinder = DomEvent.bind(pastebin, eventName, (evt) => { event = evt.raw; }); const dataTransfer = operation(pastebin); assert.instanceOf(event.clipboardData, window.DataTransfer); assert.instanceOf(dataTransfer, window.DataTransfer); unbinder.unbind(); }; it('TINY-10386: Cut dataTransfer should be an instanceof DataTransfer', () => testDataTransferInstance('cut', cut)); it('TINY-10386: Copy dataTransfer should be an instanceof DataTransfer', () => testDataTransferInstance('copy', copy)); }); });