Skip to content

Instantly share code, notes, and snippets.

@nickytonline
Last active January 25, 2024 06:01
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nickytonline/bcdef8ef00211b0faf7c7c0e7777aaf6 to your computer and use it in GitHub Desktop.
Save nickytonline/bcdef8ef00211b0faf7c7c0e7777aaf6 to your computer and use it in GitHub Desktop.
Simulate a paste event in Cypress
/**
* Simulates a paste event.
*
* @param pasteOptions Set of options for a simulated paste event.
* @param pasteOptions.destinationSelector Selector representing the DOM element that the paste event should be dispatched to.
* @param pasteOptions.pastePayload Simulated data that is on the clipboard.
* @param pasteOptions.pasteFormat The format of the simulated paste payload. Default value is 'text'.
*/
function paste({ destinationSelector, pastePayload, pasteType = 'text' }) {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event
cy.get(destinationSelector).then($destination => {
const pasteEvent = Object.assign(new Event('paste', { bubbles: true, cancelable: true }), {
clipboardData: {
getData: (type = pasteType) => pastePayload,
},
});
$destination[0].dispatchEvent(pasteEvent);
});
}
@OriMarron
Copy link

For what it's worth, I think that these changes make a more-precise simulation of a paste event using DataTransfer and ClipboardEvent, if your application is expecting JSON data attached:

/**
 * Simulates a paste event.
 * Modified from https://gist.github.com/nickytonline/bcdef8ef00211b0faf7c7c0e7777aaf6
 *
 * @param subject A jQuery context representing a DOM element.
 * @param pasteOptions Set of options for a simulated paste event.
 * @param pasteOptions.pastePayload Simulated data that is on the clipboard.
 * @param pasteOptions.pasteFormat The format of the simulated paste payload. Default value is 'text'.
 *
 * @returns The subject parameter.
 *
 * @example
 * cy.get('body').paste({
 *   pasteType: 'application/json',
 *   pastePayload: {hello: 'yolo'},
 * });
*/
Cypress.Commands.add(
  'paste',
  {prevSubject: true},
  function (subject, pasteOptions) {
    const {pastePayload, pasteType} = pasteOptions;
    const data = pasteType === 'application/json' ? JSON.stringify(pastePayload) : pastePayload;
    // https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer
    const clipboardData = new DataTransfer();
    clipboardData.setData(pasteType, data);
    // https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event
    const pasteEvent = new ClipboardEvent('paste', {
      bubbles: true,
      cancelable: true,
      dataType: pasteType,
      data,
      clipboardData,
    });
    subject[0].dispatchEvent(pasteEvent);

    return subject;
  }
);

Thanks for sharing, worked for me 🤘
This should be considered the right way to simulate a paste event in the browser, both in cypress and puppeteer

@nickytonline
Copy link
Author

Thanks for the share. When I originally did this snippet it fit my use case, so thanks so much for all the folks who have continually provided improvements and suggestions! 😎

@tigerabrodi
Copy link

Your code inspired me to simply try .trigger('paste');, which works perfectly on its own. Thanks!

@Abelhawk so this works!!?? 🔥 😄

@tigerabrodi
Copy link

For what it's worth, I think that these changes make a more-precise simulation of a paste event using DataTransfer and ClipboardEvent, if your application is expecting JSON data attached:

/**
 * Simulates a paste event.
 * Modified from https://gist.github.com/nickytonline/bcdef8ef00211b0faf7c7c0e7777aaf6
 *
 * @param subject A jQuery context representing a DOM element.
 * @param pasteOptions Set of options for a simulated paste event.
 * @param pasteOptions.pastePayload Simulated data that is on the clipboard.
 * @param pasteOptions.pasteFormat The format of the simulated paste payload. Default value is 'text'.
 *
 * @returns The subject parameter.
 *
 * @example
 * cy.get('body').paste({
 *   pasteType: 'application/json',
 *   pastePayload: {hello: 'yolo'},
 * });
*/
Cypress.Commands.add(
  'paste',
  {prevSubject: true},
  function (subject, pasteOptions) {
    const {pastePayload, pasteType} = pasteOptions;
    const data = pasteType === 'application/json' ? JSON.stringify(pastePayload) : pastePayload;
    // https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer
    const clipboardData = new DataTransfer();
    clipboardData.setData(pasteType, data);
    // https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event
    const pasteEvent = new ClipboardEvent('paste', {
      bubbles: true,
      cancelable: true,
      dataType: pasteType,
      data,
      clipboardData,
    });
    subject[0].dispatchEvent(pasteEvent);

    return subject;
  }
);

Thanks for sharing, worked for me metal This should be considered the right way to simulate a paste event in the browser, both in cypress and puppeteer

@OriMarron Imma try trigger('paste'), if it doesn't work, I'm going with this manual command, a'ight

lets hope it works tomorrow lul 🛌

@NaserYasar
Copy link

pastePayload, how this value came ??

@erwinvanlun
Copy link

erwinvanlun commented Oct 12, 2023

Inspired by above, this what I have added:

declaration:
paste(input: string | { pastePayload: string; pasteType: string }): Chainable<JQuery<HTMLElement>>;

definition:

/**
 * usages:
 * cy.paste('text to paste') OR:
 * cy.paste({ pastePayload: 'text to paste', pasteType: 'text/plain' })
 */
Cypress.Commands.add('paste', { prevSubject: true }, (subject, pasteInput) => {
  const isSimpleText = typeof pasteInput === 'string';

  const pastePayload = isSimpleText ? pasteInput : pasteInput.pastePayload;
  const pasteType = isSimpleText ? 'text/plain' : pasteInput.pasteType || 'text/plain';

  const data = pasteType === 'application/json' ? JSON.stringify(pastePayload) : pastePayload;

  const clipboardData = new DataTransfer();
  clipboardData.setData(pasteType, data);

  const pasteEvent = new ClipboardEvent('paste', {
    clipboardData
  });
  subject[0].dispatchEvent(pasteEvent);

  return subject;
});

usage
cy.paste('github is great!')
OR

cy.paste({pastePayload: 'text to paste', pasteType: 'text/plain' })

(other types work as well)

@nickytonline
Copy link
Author

Nice one @erwinvanlun!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment