In this article, we will discuss in detail how we can perform drag and drop operations on HTML and Angular sites.
For, HTML Sites:
1. Open the URL https://the-internet.herokuapp.com/drag_and_drop
2. Interchange the positions of Block ‘A’ and ‘B’ by dragging Block ‘A’
First, we will install the plugin cypress-drag-drop.
1 | npm install --save-dev @4tw/cypress-drag-drop |
Once installed it should be reflected in your package.json
Next, go to cypress/support/commands.js and write:
1 2 | //For Cypress drag and drop plugin require('@4tw/cypress-drag-drop') |
Next, We will write our Test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | it('Using the cyess-drag-drop plugin on a HTML site', function () { cy.visit('https://the-internet.herokuapp.com/drag_and_drop') //Before Drag and Drop column-a has 'A' and 'column-b' has 'B' cy.get('#column-a') .should('have.text', 'A') cy.get('#column-b') .should('have.text', 'B') //Drag and drop using cyess-drag-drop plugin cy.get('#column-a').drag('#column-b') //After Drag and Drop column-a has 'B' and 'column-b' has 'A' cy.get('#column-a') .should('have.text', 'B') cy.get('#column-b') .should('have.text', 'A') }) |
1 | cy.visit('https://the-internet.herokuapp.com/drag_and_drop') |
Opens the URL in the browser.
1 2 3 4 5 | //Before Drag and Drop column-a has 'A' and 'column-b' has 'B' cy.get('#column-a') .should('have.text', 'A') cy.get('#column-b') .should('have.text', 'B') |
Here, we are checking that column-a has the box ‘A’ and column-b has the box ‘B’.
1 2 | //Drag and drop using cyess-drag-drop plugin cy.get('#column-a').drag('#column-b') |
Here, we are dragging the Box ‘A’ to the position of Box ‘B’. #column-a is the source selector. #column-b is the destination selector.
1 2 3 4 5 | //After Drag and Drop column-a has 'B' and 'column-b' has 'A' cy.get('#column-a') .should('have.text', 'B') cy.get('#column-b') .should('have.text', 'A') |
After the drag and drop, we are validating that column-a has the box ‘B’ and column-b has the box ‘A’.
For, Angular Sites:
1. Open the URL https://material.angular.io/cdk/drag-drop/overview#cdk-drag-drop-connected-sorting
2. Move the ‘Get to Work’ block from To do list to Done list
For Angular sites, the above plugin doesn’t work. While I was trying out different ways to trigger the drag and drop, I found this Stackoverflow Thread and the solution discussed there worked like a charm.
We will first create a custom command. Go to cypress/support/commands.js and write:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //For Cypress drag and drop custom command Cypress.Commands.add('draganddrop', (dragSelector, dropSelector) => { cy.get(dragSelector).should('exist') .get(dropSelector).should('exist'); const draggable = Cypress.$(dragSelector)[0]; // Pick up this const droppable = Cypress.$(dropSelector)[0]; // Drop over this const coords = droppable.getBoundingClientRect() draggable.dispatchEvent(new MouseEvent('mousedown')); draggable.dispatchEvent(new MouseEvent('mousemove', { clientX: 10, clientY: 0 })); draggable.dispatchEvent(new MouseEvent('mousemove', { clientX: coords.left + 10, clientY: coords.top + 10 // A few extra pixels to get the ordering right })); draggable.dispatchEvent(new MouseEvent('mouseup')); return cy.get(dropSelector); }) |
Next, we will write our test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | it('Using custom commands on a Angular Material site', function () { cy.visit('https://material.angular.io/cdk/drag-drop/overview#cdk-drag-drop-connected-sorting') //Click on 'Accept Cookies' button cy.get('.buttons > .mat-primary').should('be.visible').click() //Check the drop list is visible cy.get('#cdk-drop-list-1 > div:nth-child(1)', { timeout: 7000 }) .should('be.visible') //Before Drag and Drop the first item is 'Get up' cy.get('#cdk-drop-list-2 > :nth-child(1)') .should('have.text', 'Get up') //Drag and Drop using custom command cy.draganddrop('#cdk-drop-list-1 > div:nth-child(1)', '#cdk-drop-list-2') //After Drag and Drop the first item is 'Get to work' cy.get('#cdk-drop-list-2 > :nth-child(1)') .should('have.text', 'Get to work') }) |
1 | cy.visit('https://material.angular.io/cdk/drag-drop/overview#cdk-drag-drop-connected-sorting') |
Opens the URL in the browser.
1 2 3 4 5 6 | //Click on 'Accept Cookies' button cy.get('.buttons > .mat-primary').should('be.visible').click() //Check the drop list is visible cy.get('#cdk-drop-list-1 > div:nth-child(1)', { timeout: 7000 }) .should('be.visible') |
Here, we are first clicking the ‘OK, GOT IT’ button for cookies acceptance. Then we are validating that the ‘To do’ list is visible on the web page.
1 2 3 | //Before Drag and Drop the first item is 'Get up' cy.get('#cdk-drop-list-2 > :nth-child(1)') .should('have.text', 'Get up') |
Here, we are validating that before drag and drop the first item in the ‘Done’ list is Get Up.
1 2 | //Drag and Drop using custom command cy.draganddrop('#cdk-drop-list-1 > div:nth-child(1)', '#cdk-drop-list-2') |
Now, using the custom command we will drag Get to Work block from ‘To do’ list to ‘Done’ list. #cdk-drop-list-1 > div:nth-child(1) is the source selector. #cdk-drop-list-2 is the destination selector.
1 2 3 | //After Drag and Drop the first item is 'Get to work' cy.get('#cdk-drop-list-2 > :nth-child(1)') .should('have.text', 'Get to work') |
Here, we are validating that after drag and drop the first item in the ‘Done’ list is Get to work.
Let’s execute the above two tests and we should see ‘PASS’.
Do check out 🙂
Github:Â https://github.com/alapanme/Cypress-Automation
All Cypress Articles: https://testersdock.com/cypress-tutorial/
Hey Alapan, thanks for this explanation. This helped me to get dragNDrop testing partly working in Angular. However, I’ve noticed that you access the draggable and droppable elements synchronously, which will fail if the only become available after a short while. I’ve adjusted the code to fix this:
//For Cypress drag and drop custom command
Cypress.Commands.add(‘dragAndDrop’, (dragSelector: string, dropSelector: string) => {
cy.get(dragSelector).then(function (draggable) {
cy.get(dropSelector).then(function (droppable) {
const coords = droppable.get()[0].getBoundingClientRect()
draggable.get()[0].dispatchEvent(new MouseEvent(‘mousedown’));
draggable.get()[0].dispatchEvent(new MouseEvent(‘mousemove’, {clientX: 10, clientY: 0}));
draggable.get()[0].dispatchEvent(new MouseEvent(‘mousemove’, {
clientX: coords.left + 10,
clientY: coords.top + 10 // A few extra pixels to get the ordering right
}));
draggable.get()[0].dispatchEvent(new MouseEvent(‘mouseup’));
})
})
return cy.get(dropSelector);
});
However, as I mentioned, this does not work always. In particular, I’m trying to move an element, to another place, and the move it back again. The first move (which ends up going for out of view at the bottom of the page to the top) works fine, while moving it back (out of view, to the bottom) never works, no matter what adjustments I’ve tried. Also, I don’t quite understand what you’re trying to accomplish with the first mousemove event. I realize it’s required, as I’ve tried removing it, I just don’t get why. It’d be great if you could elaborate all these commands in greater detail (I’m not familiar with mouse event and found it surprisingly difficult to research). In particular, issuing such an event on a HTML-Element, does that mean the passed coordinates are relative to this element? ARE the coordinates relative, or absolute?