Reputation: 498
I have an SVG object which uses d3-zoom for zoom and pan functionality. It works flawlessly but the problem showed up when I started to work on integration tests using Cypress.js.
I tried using standard mouse events on the svg
element, to simulate drag behavior:
cy.get('svg')
.trigger('mousedown', { which: 1, force: true })
.trigger('mousemove', { position: 'left' })
.trigger('mouseup', { position: 'left', force: true });
The example above is taken from the Cypress drag and drop recipe, and it produces the following error in the nodrag.js file:
cannot read property document of undefined
Below you can see where the error occurs (view is undefined
):
__webpack_exports__["default"] = (function(view) {
var root = view.document.documentElement,
...
I spent a lot of hours trying to trigger the event in another way, but without a success - like trying the snippet above with the svg
container.
Please keep in mind that I cannot access any d3.js package from the Cypress test because it's imported as an NPM package in a React application.
Thank you in advance for you help!
Upvotes: 14
Views: 2588
Reputation: 45
FWIW I had this same issue and using this library allowed me to interact with the D3 elements: https://github.com/dmtrKovalenko/cypress-real-events
Upvotes: 0
Reputation: 2290
Try this:
cy.window().then(win => {
cy.get('svg')
.trigger('mousedown', {
which: 1,
force: true,
view: win,
})
.trigger('mousemove', {
clientX: 300,
clientY: 500,
force: true,
})
.trigger('mouseup', {
force: true,
view: win,
});
});
Referencing Jennifer Shehane's answer in this GitHub issue, the answer to the cannot read property document of undefined
part is to plug the window object into view
in the trigger options. The issue mentioned in jacefarm's answer, where no movement occurred, seems to be resolved by specifying clientX
/clientY
rather than using positions relative to the selected element.
Upvotes: 6
Reputation: 7451
I could only arrive at a partial answer before I had to move on, but perhaps this can help you, or someone else, find the ultimate solution.
To remedy the error, a view
property must be provided for mousedown
. Providing window
, like this, allowed the D3 methods to fire properly:
cy.get('svg')
.trigger('mousedown', { which: 1, force: true, view: window }) // <-- here
.trigger('mousemove', { position: 'left', view: window }) // <-- here
.trigger('mouseup', { position: 'left', force: true });
However, no dragging or movement occurred during the test run, and other questions emerged from there. Starting with... Is this the right context to send along with the event? It seemed so, since window
seems to be the only context that has the property chain that D3 anticipates:
view.document.documentElement
Or is that an anti-pattern... a code smell?
Running down those subsequent questions led to a few observations that seemed to have significance.
The first concerns how D3 handles mouse and drag events. D3 has numerous event listeners and callbacks that override standard events and their respective handlers.
The second, is that iframes
are in play with the Cypress test runner.
Could it be that Cypress's programmatically triggered events are firing properly in the Cypress iframe, but due to D3's aggressive event handling, the translation of those events into the application iframe are getting lost? Especially considering that manually dragging a circle in the testing viewport worked fine.
Which, again, leads back to:
I selected the Zoomable Force Directed Graph as my D3 subject, inside of a simple Ember application, for researching this question. It perfectly reproduced the error mentioned, so it definitely seems to be a D3 + Cypress challenge, and unrelated to the front-end framework.
I hope this effort is helpful.
Continued...
After some further reading – Cypress's Trade-offs, and particularly, their open pull request Support for Native Browser Events – it seems likely that the event handling overrides within D3 are not yet fully reconcilable within Cypress. Simpler implementations, like those detailed in the drag and drop example, do not present the event handling challenges introduced by a 3rd party library like D3. However, this support does appear to be under development within the Cypress team.
Upvotes: 5
Reputation: 1422
I used a little bit different from your code so you can try
cy.get('svg')
.trigger('mousedown', { which: 1 })
.trigger('dragstart', {})
.trigger('drag', {});
Upvotes: 0