Cypress: Enable access to clipboard in test

Created on 9 Nov 2018  Â·  7Comments  Â·  Source: cypress-io/cypress

Current behavior:

There is no way to access the clipboard in a test, as far as I can tell.

Desired behavior:

There should be an easy way to test what the clipboard holds. Useful for websites where text is placed in the clipboard using JS to transfere it somewhere.

Versions

all versions

pkdriver proposal 💡 feature

Most helpful comment

Accessing clipboard can be worked around, but the main issue is that the document.execCommand('copy') doesn't work (as stated above), which I reckon is the primary (and only?) way for your app to programmatically put a text to user's clipboard.

Assuming it happens somehow (or is fixed upstream), the checking the clipboard's contents can be done e.g. by using clipboardy:

npm i -D clipboardy

plugins/index.js:

const clipboardy = require('clipboardy');
module.exports = ( on ) => {
    on('task', {
        getClipboard () {
            return clipboardy.readSync();
        }
    });
};

In your spec:

describe('test', () => {
    it('test', () => {
        cy.document().then( doc => {
            doc.body.innerHTML = '<input id="inp">';
        });
        cy.get('#inp').type('test{selectall}');
        cy.document().then( doc => {
            // this currently doesn't work unless you manually put focus
            //  into the AUT preview window (e.g. by clicking)
            doc.execCommand('copy');
        });
        cy.task('getClipboard').should('contain', 'test');
    });
});

All 7 comments

Related issues

Accessing clipboard can be worked around, but the main issue is that the document.execCommand('copy') doesn't work (as stated above), which I reckon is the primary (and only?) way for your app to programmatically put a text to user's clipboard.

Assuming it happens somehow (or is fixed upstream), the checking the clipboard's contents can be done e.g. by using clipboardy:

npm i -D clipboardy

plugins/index.js:

const clipboardy = require('clipboardy');
module.exports = ( on ) => {
    on('task', {
        getClipboard () {
            return clipboardy.readSync();
        }
    });
};

In your spec:

describe('test', () => {
    it('test', () => {
        cy.document().then( doc => {
            doc.body.innerHTML = '<input id="inp">';
        });
        cy.get('#inp').type('test{selectall}');
        cy.document().then( doc => {
            // this currently doesn't work unless you manually put focus
            //  into the AUT preview window (e.g. by clicking)
            doc.execCommand('copy');
        });
        cy.task('getClipboard').should('contain', 'test');
    });
});

I have a workaround for pasting in the interim. It fits the use case I have for pasting data, so I thought I'd share. See https://gist.github.com/nickytonline/bcdef8ef00211b0faf7c7c0e7777aaf6

Is there a reason why Cypress would block a .click() action when clicking a button that is doing a copy action? I keep getting a growl on our site during test runs and it states "Copy to clipboard not compatible with this browser! Try Chrome!" except, i'm running Cypress with Chrome.

HTML (The formatting might look off, that's just to fit it on screen without a scrollbar):

<a message-element="" class="btn btn-test btn-block btn-sm print-hide ng-isolate-scope" href="javascript:void(0)" 
ng-click="copyLink()" title="" data-toggle="tooltip" data-container="body" data-placement="top" 
data-original-title="Click to copy">
<i class="fa fa-clipboard"></i> <span class="notranslate" data-cy="detailsLinkButton">Link< /span>
</a>

This fails every time I do a cy.get('[data-cy=detailsLinkButton]').click(); Which prevents me from using clipboardy to verify results.

After the test has run in the Test Runner I can click the button and I'll get the proper green growl that states it's been copied to my clipboard, but it won't work while the test is running. Any ideas?

I originally thought this was an issue with clipboardy, but it works elsewhere on our site, and I eventually stripped clipboardy out of the test entirely just to see what would happen with the click. That's when i found Cypress seems to be blocking the action.

We're currently experiencing the same: You can't copy to clipboard in cypress… in Firefox. In Chrome it seems to work fine.
This could be related to the special handling of copying in Firefox mentioned on can I use.

Writing to the clipboard is available without permission in secure contexts and browser extensions, but only from user-initiated event callbacks. Browser extensions with the "clipboardWrite" permission can write to the clipboard at any time.

As nobody want's to introduce https to the e2e testing stage (I think), maybe cypress could use the mentioned "clipboardWrite" permission in Firefox?

@zepatrik Here's my current approach:

  1. Spy or stub out the navigator.clipboard.writeText method that your application calls to copy text.
  2. Assert that the method was called with the correct content.

This is what that looks like when implemented in Typescript:

describe('My website page', () => {
  it('copies signup links to clipboard', () => {
    cy.visit(`/${school.id}/users`, {
      onBeforeLoad(win: Window): void {
        cy.spy(win.navigator.clipboard, 'writeText').as('copy');
      },
    });
    cy.contains('button', 'Share signup link').click();
    cy.get('@copy').should('be.calledWithExactly', `http://localhost:3000/${school.id}/signup`);
  });
});

Note that this approach doesn't solve every problem. For example, if you use the invisible textarea workaround (for older browsers), I still don't know of any way to assert about the actual content of the system clipboard.

Was this page helpful?
0 / 5 - 0 ratings