简体   繁体   中英

Cypress drag and drop by offset

I am trying to make DnD work in Cypress and React app.

At first I was trying all examples around those with simulating by mouse events but it is not working in general in my environment. :(

I was able to write a test where I know the drag element and drop element using this code.

const dataTransfer = new DataTransfer();


   cy.get(dragSelector).trigger("dragstart", {
       dataTransfer,
       force: true,
   });


   cy.get(dropSelector).trigger("drop", {
       dataTransfer,
       force: true,
   });

And it's working well. Similar sample code I have found in Cypress cookbook.

But now I need to do DnD where I don't know the drop zone / elem. Its resizer and I need dnd by offset for example 20px on Y axis. (Resize element height by 20px)

So is it possible to do it somehow like this?

const dataTransfer = new DataTransfer();

   // drag selector is element with draggable attribute and I need move it by 20px from top to down  
   cy.get(dragSelector).trigger("dragstart", {
       dataTransfer,
       force: true,
   }).trigger("drop",{...how to set drop offset if is possible...})

trigger drop event as some parameters like offsetX and offsetY or x or y and pageX or pageY... but I was not successful.

Like I sad I am not able use it by simulating mouse events in my app from unknow reason its not working.

This is how I'm testing a divider (resizer) using mouse events.

I did add cypress-real-events for mousedown and mouseup, but it may be ok to use .trigger('mousedown') instead.

My app is React hooks, and I found it needed a small wait before checking. I think that can be optimized with a .should() , but for my tests now this is working.

Cypress.Commands.add('checkPosition', 
  {prevSubject: true}, 
  (subject, start, delta = {dx:0}) => {

    cy.wait(75, {log:false}).then(function () {
      
      const deltaValue = delta.dx || delta.dy
      const measurePoint = measurePoint || (delta.dx ? 'pageX' : 'pageY')
      const current = getClientRect(subject[0])[measurePoint]
      const expected = start[measurePoint] + deltaValue 
      expect(current).to.be.closeTo(expected, variance)
    })
  }
)

let start;
cy.get(divider)
  .then(subject => start = getClientRect(subject[0]))
  .realMouseDown({position:'center'})
  .then($el => {
    cy.wrap($el, {log:false})
      .trigger('mousemove', { pageX: start.pageX +20 })
      .checkPosition(start, {dx:20})
      .trigger('mousemove', { pageX: start.pageX +40 })
      .checkPosition(start, {dx:40})
      // more steps as required
      .realMouseUp()
      .checkPosition(start, {dx:100})
  })

You can do x or y movements in the test, my divider is either horizontal or vertical (can it be anything else?)

The calculation on position isn't exact, so I've added close.to assertion in /cypress/support/e2e.js .

const closeTo = (_chai, utils) => {
  function assertIscloseTo(expected, delta, msg) {
    msg = msg || utils.flag(this, 'message')
    msg = msg ? `${msg}: ` : ''
    _chai.assert(
      Math.abs(this._obj - expected) <= delta
        , msg + 'expected ' + this._obj + ' to be close to ' + expected + ' +/- ' + delta
        , msg + 'expected ' + this._obj + ' not to be close to ' + expected + ' +/- ' + delta
    )
  }
  _chai.Assertion.addMethod('closeTo', assertIscloseTo)
}
chai.use(closeTo)

getClientRect()

This is just to provide some rounding on the native getBoundingClientRect() function.

I also added centerX and centerY calc as it is sometimes useful to vary the mousedown location, if the React app records it's start position from the mousedown event.

function getClientRect(el) {
  const bb = el.getBoundingClientRect()
  return {
    top: Math.round(bb.top),
    bottom: Math.round(bb.bottom),
    left: Math.round(bb.left),
    right: Math.round(bb.right),
    height: Math.round(bb.height),
    width: Math.round(bb.width),
    x: Math.round(bb.x),
    y: Math.round(bb.y),
    centerX: Math.round(bb.left + (bb.width/2)),
    centerY: Math.round(bb.top + (bb.height/2)),
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM