I am struggling to test drag and drop with Cypress and Angular Material Drag and Drop. So the goal is to move "Get to work" from Todo to Done. I have created the following test, that should make it easy for you to reproduce:
You can play with the Stackblitz here.
describe('Trying to implement drag-n-drop', () => {
before(() => {
Cypress.config('baseUrl', null);
cy.viewport(1000, 600);
cy.visit('https://angular-oxkc7l-zirwfs.stackblitz.io')
.url().should('contain', 'angular')
.get('h2').should('contain', 'To do');
});
it('Should work, based on this https://stackoverflow.com/a/54119137/3694288', () => {
const dataTransfer = new DataTransfer;
cy.get('#cdk-drop-list-0 > :nth-child(1)')
.trigger('dragstart', { dataTransfer });
cy.get('#cdk-drop-list-1')
.trigger('drop', { dataTransfer });
cy.get('#cdk-drop-list-0 > :nth-child(1)')
.trigger('dragend');
cy.get('#cdk-drop-list-1').should('contain', 'Get to work');
});
it('Should work, with this library https://github.com/4teamwork/cypress-drag-drop', () => {
cy.get('#cdk-drop-list-0 > :nth-child(1)')
.drag('#cdk-drop-list-1');
cy.get('#cdk-drop-list-1').should('contain', 'Get to work');
});
});
The result from running the above test, looks like this:
Here is a repo to develop a solution.
Thanks for the help.
Events fired, found using the chrome debugger:
Item
- pointerover
- pointerenter
- mouseover
- mousedown
- pointermove
- mousemove
- pointerout
- pointerleave
- mouseout
- mouseleave
Drop zone
- pointerover
- pointerenter
- mouseover
- pointermove
- mousemove
- pointerleave
- mouseout
- mouseleave
Solution
After @Richard Matsen's awesome answer I ended up with adding his answer as a custom command. The solution looks like this
support/drag-support.ts
export function drag(dragSelector: string, dropSelector: string) {
// Based on this answer: https://stackoverflow.com/a/55436989/3694288
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(<any>new MouseEvent('mousedown'));
draggable.dispatchEvent(<any>new MouseEvent('mousemove', {clientX: 10, clientY: 0}));
draggable.dispatchEvent(<any>new MouseEvent('mousemove', {
// I had to add (as any here --> maybe this can help solve the issue??)
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);
}
support/commands.ts
// Add typings for the custom command
declare global {
namespace Cypress {
interface Chainable {
drag: (dragSelector: string, dropSelector: string) => Chainable;
}
}
}
// Finally add the custom command
Cypress.Commands.add('drag', drag);
in the spec file
it(' Thx to Stackoverflow, drag and drop support now works ', () => {
cy.drag('#cdk-drop-list-0 > :nth-child(1)', '#cdk-drop-list-1')
.should('contain', 'Get to work');
});
A small giph, because I'm just so happy it finally works
CI
Now it also works in CI (and electron locally). Tested with CircleCI 2.0.