Bug
It seems that after trigger the dragstart event. The generated event for handling function is type of Event not DragEvent.
The event parameter is without dataTransfer method.
Provide the event handler with DragEvent not just only Event type of object.
<!DOCTYPE HTML>
<html>
<head>
<script>
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
// THERE SHOULD BE DragEvent not only Event
console.log('EV: ', ev);
ev.dataTransfer.setData("text", ev.target.id); // This die
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)" width="200px" height="200px" style="border: 1px solid red">DROP</div>
<div id="drag1" draggable="true"
ondragstart="drag(event)" width="100px" height="80px">DRAG</div>
</body>
</html>
Test:
describe('Drag test html5', function() {
it('main', function() {
cy.visit('http://localhost:8080/');
cy.get('#drag1').trigger("dragstart");
})
})
Event from Cypress.io:
EV: Event {isTrusted: false, clientX: 500, clientY: 16, pageX: 500, pageY: 16…}
Event from browser:
EV: DragEvent {isTrusted: true, dataTransfer: DataTransfer, screenX: 668, screenY: 133, clientX: 34…}
Yup, this is true.
We have a few options:
new DataTransfer
object and use Object.defineProperty
on the event (but it seems MDN says it's not a constructor but it is...)We'll likely need a real cy.drag
command for this since this is specialized to this one event.
Another option is just to wait until we land native event support.
Yup, in Firefox you cannot instantiate a new DataTransfer
but in chrome you can.
I try to create constructor in Electron but without success (I agree that Chrome is working):
cypress_runner.js:136100 TypeError: Illegal constructor
Currently to test DND I have created this test:
describe('DND example', function() {
it('Add empty report to the created dashboard', function() {
cy.visit('http://localhost:8080/#/main');
var MyDataTransfer = function () {};
var dt = new MyDataTransfer ();
dt.types = [];
cy.get('div[class^="dragEmpty"]').trigger("dragstart", {dataTransfer: dt});
cy.get('div[class^="grid"]').trigger("drop", {dataTransfer: dt});
})
})
because I only need "types" method in Drag event.
But It will be nice to have .drag command.
I think Chrome added this recently as a feature for something else (copy/paste stuff maybe?).
To get this to consistently work we'll need to mock the whole interface, which is fine. We can try to instantiate it and then fallback if it doesn't work.
After reading about this more we definitely need a cy.drag
command to juggle the event to the drop target.
You mean something like: cy.drag(startPosition, stopPosition, options)
?
Where options will have drop: false/true
possibility.
Because it is very useful to test app without drop, something like we need to test if the underline object moved when the dragging object is over etc.
Sure, it'd be a pretty complex method signature.
Likely taking all of that, plus a potential drop target that's a selector, or perhaps an element if you already have a reference to one.
We'd then need to fire all of the underlying events that would normally fire.
I'd just go look at other test frameworks to see what they expose and then do it in our Cypress-y way.
This would be a great feature to add to Cypress 👍
How about this issue? Do you have some prediction to implement this?
Closing as duplicate of https://github.com/cypress-io/cypress/issues/857 which proposes an API for cy.drag
Here is a temporary workaround for the dataTransfer
property. It's value is DataTransfer which I am mocking in my tests. I don't believe my current implementation covers all use cases of it:
// within my test...
const dataTransfer = new DataTransfer();
cy.get('.shapes-parent-category')
.click()
.get('[data-tip="Rectangle"]')
.trigger('mousedown')
.trigger('dragstart', {
dataTransfer: dataTransfer,
})
.get('#div-wrapper')
.trigger('dragenter', { dataTransfer: dataTransfer })
.trigger('dragover', { dataTransfer: dataTransfer })
.trigger('drop', { dataTransfer: dataTransfer });
});
});
class DataTransfer {
constructor() {
this.data = {};
this.types = [];
this.files = [];
}
setData(format, data) {
this.data[format] = data;
}
getData(format) {
return this.data[format];
}
}
To get more info about dataTransfer
, play around with it in your browser's console:
var d = new DataTransfer();
Most helpful comment
This would be a great feature to add to Cypress 👍