UNPKG

@testing-library/user-event

Version:
164 lines (161 loc) 6.25 kB
import '../click/isClickableInput.js'; import { readBlobText } from './Blob.js'; import { createDataTransfer, getBlobFromDataTransferItem } from './DataTransfer.js'; import '../../event/eventMap.js'; import '../../event/behavior/click.js'; import '../../event/behavior/cut.js'; import '../../event/behavior/keydown.js'; import '../../event/behavior/keypress.js'; import '../../event/behavior/keyup.js'; import '../../event/behavior/paste.js'; import '@testing-library/dom'; import '../edit/maxLength.js'; import '../edit/isEditable.js'; import { getWindow } from '../misc/getWindow.js'; import '../keyDef/readNextDescriptor.js'; import '../misc/level.js'; import '../../options.js'; // Clipboard is not available in jsdom // MDN lists string|Blob|Promise<Blob|string> as possible types in ClipboardItemData // lib.dom.d.ts lists only Promise<Blob|string> // https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem#syntax function createClipboardItem(window, ...blobs) { const dataMap = Object.fromEntries(blobs.map((b)=>[ typeof b === 'string' ? 'text/plain' : b.type, Promise.resolve(b), ])); // use real ClipboardItem if available /* istanbul ignore if */ if (typeof window.ClipboardItem !== 'undefined') { return new window.ClipboardItem(dataMap); } return new class ClipboardItem { get types() { return Array.from(Object.keys(this.data)); } async getType(type) { const value = await this.data[type]; if (!value) { throw new Error(`${type} is not one of the available MIME types on this item.`); } return value instanceof window.Blob ? value : new window.Blob([ value ], { type }); } constructor(d){ this.data = d; } }(dataMap); } const ClipboardStubControl = Symbol('Manage ClipboardSub'); function createClipboardStub(window, control) { return Object.assign(new class Clipboard extends window.EventTarget { async read() { return Array.from(this.items); } async readText() { let text = ''; for (const item of this.items){ const type = item.types.includes('text/plain') ? 'text/plain' : item.types.find((t)=>t.startsWith('text/')); if (type) { text += await item.getType(type).then((b)=>readBlobText(b, window.FileReader)); } } return text; } async write(data) { this.items = data; } async writeText(text) { this.items = [ createClipboardItem(window, text) ]; } constructor(...args){ super(...args); this.items = []; } }(), { [ClipboardStubControl]: control }); } function isClipboardStub(clipboard) { var ref; return !!((ref = clipboard) === null || ref === void 0 ? void 0 : ref[ClipboardStubControl]); } function attachClipboardStubToView(window) { if (isClipboardStub(window.navigator.clipboard)) { return window.navigator.clipboard[ClipboardStubControl]; } const realClipboard = Object.getOwnPropertyDescriptor(window.navigator, 'clipboard'); let stub; const control = { resetClipboardStub: ()=>{ stub = createClipboardStub(window, control); }, detachClipboardStub: ()=>{ /* istanbul ignore if */ if (realClipboard) { Object.defineProperty(window.navigator, 'clipboard', realClipboard); } else { Object.defineProperty(window.navigator, 'clipboard', { value: undefined, configurable: true }); } } }; stub = createClipboardStub(window, control); Object.defineProperty(window.navigator, 'clipboard', { get: ()=>stub, configurable: true }); return stub[ClipboardStubControl]; } function resetClipboardStubOnView(window) { if (isClipboardStub(window.navigator.clipboard)) { window.navigator.clipboard[ClipboardStubControl].resetClipboardStub(); } } function detachClipboardStubFromView(window) { if (isClipboardStub(window.navigator.clipboard)) { window.navigator.clipboard[ClipboardStubControl].detachClipboardStub(); } } async function readDataTransferFromClipboard(document) { const window = document.defaultView; const clipboard = window === null || window === void 0 ? void 0 : window.navigator.clipboard; const items = clipboard && await clipboard.read(); if (!items) { throw new Error('The Clipboard API is unavailable.'); } const dt = createDataTransfer(window); for (const item of items){ for (const type of item.types){ dt.setData(type, await item.getType(type).then((b)=>readBlobText(b, window.FileReader))); } } return dt; } async function writeDataTransferToClipboard(document, clipboardData) { const window = getWindow(document); const clipboard = window.navigator.clipboard; const items = []; for(let i = 0; i < clipboardData.items.length; i++){ const dtItem = clipboardData.items[i]; const blob = getBlobFromDataTransferItem(window, dtItem); items.push(createClipboardItem(window, blob)); } const written = clipboard && await clipboard.write(items).then(()=>true, // Can happen with other implementations that e.g. require permissions /* istanbul ignore next */ ()=>false); if (!written) { throw new Error('The Clipboard API is unavailable.'); } } /* istanbul ignore else */ if (typeof globalThis.afterEach === 'function') { globalThis.afterEach(()=>resetClipboardStubOnView(globalThis.window)); } /* istanbul ignore else */ if (typeof globalThis.afterAll === 'function') { globalThis.afterAll(()=>detachClipboardStubFromView(globalThis.window)); } export { attachClipboardStubToView, createClipboardItem, detachClipboardStubFromView, readDataTransferFromClipboard, resetClipboardStubOnView, writeDataTransferToClipboard };