Executing simulated paste from clipboard in Cypress with Typescript

I encountered an obstacle while trying to find solutions for simulating a paste event in Cypress using Typescript. Most of the solutions I came across are in Javascript and none of them seem to be working. :/

Here's the scenario: The user clicks on the "Copy" button and then pastes the copied value into a text field.

I attempted the following methods but unfortunately, they are not yielding the desired results (these are written in JS but I need them to be in TS). Is there something crucial that I might be missing? Currently, none of these methods are working and I've been stuck on this issue for days now. Thank you!

Attempt 1: (not functioning, added in commands.ts)

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

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 1:

    cy.window().then(win => {
        win.navigator.clipboard.readText().then(classCodeFromClipboard => {
            let classCode = classCodeFromClipboard
            element.paste(classCode)
        })
    })

Attempt 2: (not working)

element.trigger('paste')

Attempt 3: (not functional, attempted from here)

cy.wrap(Cypress.automation('remote:debugger:protocol', {
    command: 'Browser.grantPermissions',
    params: {
        permissions: ['clipboardReadWrite', 'clipboardSanitizedWrite'],
        origin: window.location.origin,
    }
}))

cy.get('@copiedClassCode').then(copiedClassCode => {
    let copyClass = String(copiedClassCode)
    cy.window().its('navigator.permissions').invoke('query', {name: 'clipboard-read'}).its('state').then(cy.log)
    cy.window().its('navigator.clipboard').invoke('readText').should('eq', copyClass)
})

Attempt 4: (not effective)

element.type('{ctrl}', {release: false}).type('v')

Attempt 5: (not producing desired outcome)

Cypress.Commands.add('paste', { prevSubject: true }, (selector: any, pastePayload: any) => {
    // https://developer.mozilla.org/en-US/docs/Web/API/Element/paste_event
    cy.wrap(selector).then($destination => {
      const pasteEvent = Object.assign(new Event("paste", { bubbles: true, cancelable: true }), {
        clipboardData: {
          getData: () => pastePayload
        }
      });
      $destination[0].dispatchEvent(pasteEvent);
    });
  });

Usage 5:

    cy.window().then(win => {
        win.navigator.clipboard.readText().then(classCodeFromClipboard => {
            let classCode = classCodeFromClipboard
            element.paste(classCode)
        })
    })

Answer №1

If you're having trouble, refer to Gleb's comments for assistance.

In cases where verification is necessary, utilizing a stub can be helpful to ensure the value is copied accurately.

cy.visit(myUrl, {
  onBeforeLoad: (win) => {
    cy.stub(win.navigator.clipboard, 'writeText').as('writeText')
  },
})
cy.contains('Copy text').click()
cy.get('@writeText').should(
  'have.been.calledOnceWith',
  Cypress.sinon.match.string,
)

https://i.sstatic.net/2fW17YWM.png

Answer №2

Regrettably, in order to implement the technique suggested by Faith Berrya, an outdated version of Chrome is required.

The current iteration obstructs the process with a request for manual authorization, rendering it unsuitable for automated testing purposes.

For those who are interested, utilizing the stubbing pattern is recommended as it can be used across different browsers such as Firefox and Safari.

This outcome was achieved when conducting the test within the copy-to-clipboard repository


https://i.sstatic.net/7AgrzdCel.png

Answer №3

Stumbled upon a helpful resource at this link that addressed my issue perfectly. Since direct pasting is no longer an option, I considered using stub or spy methods as suggested here. Initially attempted stub without success, but this alternative method of accessing clipboard value worked like a charm for me :) I'll resort to manually entering the value into the text field since it has already been verified as correct. Much appreciation for all the support and advice provided! :)

Cypress.Commands.add('assertValueCopiedToClipboard', (value: any) => {
    cy.window().then(win => {
      win.navigator.clipboard.readText().then(text => {
        expect(text).to.eq(value)
      })
    })
  })

cy.assertValueCopiedToClipboard(copyClass)

Update: Included code snippet to authorize clipboard access

cy.wrap(Cypress.automation('remote:debugger:protocol', {
    command: 'Browser.grantPermissions',
    params: {
        permissions: ['clipboardReadWrite', 'clipboardSanitizedWrite'],
        origin: window.location.origin,
    }
}))

https://i.sstatic.net/l014wn9F.png

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Doing a simple HTTP GET request with RxJS does not do anything

I'm encountering an issue with my code: export class Test { constructor(private http: Http) {} logResponse(): Observable<any> { return this.http.get('http://google.com') .do(data => console.log("All: " + JSON.stringify(dat ...

Debugging with Typescript in Visual Studio Code

I attempted to use the solution found here: how to debug typescript files in visual studio code However, when I set a breakpoint in my .ts files, the debugger indicates that the file is not found. Oddly enough, breakpoints in the .js files are working fin ...

Troubleshooting issue with problemMatcher in VSCode TypeScript compiler not functioning

I am looking for a problem matcher that can detect two types of issues: compilation problems related to TypeScript issues flagged by tslint This feature seems to be causing trouble in one of my projects, although it functions properly in others. Below i ...

Aurelia TypeScript app experiencing compatibility issues with Safari version 7.1, runs smoothly on versions 8 onwards

Our team developed an application using the Aurelia framework that utilizes ES6 decorators. While the app works smoothly on Chrome, Firefox, and Safari versions 8 and above, it encounters difficulties on Safari 7.1. What steps should we take to resolve th ...

For editing values that have been dynamically inserted

In my JSON data, there is a variable named address that contains multiple objects (i.e., multiple addresses). I am displaying these multiple addresses as shown in the following image: https://i.sstatic.net/1AG34.png When clicking on a specific address ( ...

What is the best way to convert a promise using an async await function into an observable?

Currently, I have set up a Nestjs rest server that includes a controller and a service. Within the controller, there is a get function that is triggered when a get request is made: @Get() getAllFoos() { return this.fooService.getAllFoos(); } Inside ...

Adding up nested arrays based on their respective indices

If I have two nested arrays within a corresponding array like this: const nums = [ [4, 23, 20, 23, 6, 8, 4, 0], // Each array consists of 8 items [7, 5, 2, 2, 0, 0, 0, 0] ]; How can I add the values based on their indexes? Expected Result: ...

How can I transform this imperative reducer into a more declarative format using Ramda?

I am currently working with a reducer function that aggregates values in a specific way. The first argument is the aggregated value, while the second argument represents the next value. This function reduces over the same reaction argument, aggregating th ...

Chai.request does not exist as a method

I'm encountering an issue with the code below: import app from '../src/app'; import * as chai from 'chai'; import chaiHttp = require('chai-http'); chai.use(chaiHttp); const expect = chai.expect; describe('Get /&ap ...

Executing a NestJs cron job at precise intervals three times each day: a guide

I am developing a notifications trigger method that needs to run three times per day at specific times. Although I have reviewed the documentation, I am struggling to understand the regex code and how to customize it according to my requirements! Current ...

Using MongoDB to swap out an object within an array

I'm facing a challenge in replacing/updating an entire object in an array with its latest values, and I can't seem to make it work. Here's how the database looks: (Please note that there is only one main object in this collection) { ...

Discovering the current page using ons-navigator in Onsen UI

I am currently attempting to determine the page I am on while using the popPage() function with Onsen UI's ons-navigator. I have tried the following methods, but they always return false regardless: this.navigator.nativeElement.popPage().then((page: a ...

Exploring the Depths of Angular 11's Named Nested Router Outlets

I am facing an issue with my router configuration. Here is the current setup: const appRoutes: Routes = [ { path: '', component: LoginComponent}, { path: 'login', component: LoginComponent }, { path: 'main', component: M ...

Galactic design and unadulterated HTML

I incorporate 2 nebulous motifs: one light and one dark. A component that binds the HTML output from a library to the innerHtml looks like this: <div [innerHtml]="songHtml"></div> To style this content with custom CSS, I added the fo ...

The data type 'string' cannot be assigned to the data type 'Position'

Currently, I am in the process of converting React js to typescript. The component being used is a Class Component. I would like to obtain CSS settings through props and apply them to an element. How can I resolve this issue? render(){return( <span st ...

What is the best way to update the displayed data when using Mobx with an observable array?

Is there a way to re-render observable array data in Mobx? I have used the observer decorator in this class. interface IQuiz { quizProg: TypeQuizProg; qidx: number; state: IStateCtx; actions: IActionsCtx; } @observer class Comp extends Rea ...

Design buttons that are generated dynamically to match the style

I have a challenge in styling dynamically generated buttons. I've developed a component responsible for generating these dynamic buttons. const TIMER_PRESETS: Record<string, number> = { FIFTHTEENSEC: 15, THIRTYSEC: 30, FORTYFIVESEC: 45, ...

When using Angular SSR, the transferState.get(key, null) method may return null even though objects are visible when logged (both in the browser)

While working on my Angular application, I've noticed a flicker when simulating a mid-tier mobile browser. It seems like Angular is not properly rehydrating the DOM when transitioning from Server to Browser, resulting in a full replace of the DOM. Th ...

After triggering an action, I am eager to make a selection from the store

To accomplish my task, I must first select from the store and verify if there is no data available. If no data is found, I need to dispatch an action and then re-select from the store once again. Here is the code snippet that I am currently using: t ...

Using Azure AD for authentication: Implementing Msal authentication in a React Next.js application with TypeScript and App Router

Working on a React Next.js web application with Microsoft Authentication Library (MSAL) login integration, using Azure. The app utilizes Next.js with the App Router for routing. But encountering an error when attempting to run the app: createContext only w ...