Cypress: Event trigger("dragstart") without dataTransfer

Created on 14 Sep 2017  ·  11Comments  ·  Source: cypress-io/cypress

  • Operating System: Linux
  • Cypress Version: 0.20.0

Is this a Feature or Bug?

Bug

Current behavior:

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.

Desired behavior:

Provide the event handler with DragEvent not just only Event type of object.

How to reproduce:

Test code:

<!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");
  })
})

Additional Info (images, stack traces, etc)

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…}


duplicate

Most helpful comment

This would be a great feature to add to Cypress 👍

All 11 comments

Yup, this is true.

We have a few options:

  • mock the dataTransfer interface entirely
  • instantiate a 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.

screen shot 2017-09-13 at 8 05 27 pm

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();
Was this page helpful?
0 / 5 - 0 ratings