How to implement drag and drop in cypress test?

后端 未结 6 1386
青春惊慌失措
青春惊慌失措 2020-12-14 07:47

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

6条回答
  •  隐瞒了意图╮
    2020-12-14 08:25

    It seems cy.trigger isn't sending the proper events at the correct target elements. I expect this to be fixed in version 4.0

    ...but, I've written up a small plugin for drag and drop.

    It works by adding a dragTo command like so:

    /// 
    
    it('works', () => {
      cy.visit('https://angular-oxkc7l-zirwfs.stackblitz.io/')
      cy.contains('To do', { timeout: 15000 }) // ensure page is loaded -__-
    
      const item = '.example-box:not(.cdk-drag-placeholder)'
    
      cy.get('#cdk-drop-list-1').children(item).should('have.length', 5)
    
      cy.get('.example-box:contains("Get to work")').dragTo('.example-box:contains("Get up")')
      cy.get('#cdk-drop-list-1').children(item).should('have.length', 6)
    
      // interpolates 10 extra mousemove events on the way
      cy.get('#cdk-drop-list-0').dragTo('#cdk-drop-list-1', { steps: 10 })
      cy.get('#cdk-drop-list-1').children(item).should('have.length', 7)
    
      // sets steps >= 10
      cy.get('#cdk-drop-list-0').dragTo('#cdk-drop-list-1', { smooth: true })
      cy.get('#cdk-drop-list-1').children(item).should('have.length', 8)
    
      cy.get('#cdk-drop-list-0').dragTo('#cdk-drop-list-1')
      cy.get('#cdk-drop-list-1').children(item).should('have.length', 9)
    })
    
    

    To add it, try putting this in your support/index.js or pasting it at the bottom of a spec file (warning: poor code quality):

    
    const getCoords = ($el) => {
      const domRect = $el[0].getBoundingClientRect()
      const coords = { x: domRect.left + (domRect.width / 2 || 0), y: domRect.top + (domRect.height / 2 || 0) }
    
      return coords
    }
    
    const dragTo = (subject, to, opts) => {
    
      opts = Cypress._.defaults(opts, {
        // delay inbetween steps
        delay: 0,
        // interpolation between coords
        steps: 0,
        // >=10 steps
        smooth: false,
      })
    
      if (opts.smooth) {
        opts.steps = Math.max(opts.steps, 10)
      }
    
      const win = subject[0].ownerDocument.defaultView
    
      const elFromCoords = (coords) => win.document.elementFromPoint(coords.x, coords.y)
      const winMouseEvent = win.MouseEvent
    
      const send = (type, coords, el) => {
    
        el = el || elFromCoords(coords)
    
        el.dispatchEvent(
          new winMouseEvent(type, Object.assign({}, { clientX: coords.x, clientY: coords.y }, { bubbles: true, cancelable: true }))
        )
      }
    
      const toSel = to
    
      function drag (from, to, steps = 1) {
    
        const fromEl = elFromCoords(from)
    
        const _log = Cypress.log({
          $el: fromEl,
          name: 'drag to',
          message: toSel,
        })
    
        _log.snapshot('before', { next: 'after', at: 0 })
    
        _log.set({ coords: to })
    
        send('mouseover', from, fromEl)
        send('mousedown', from, fromEl)
    
        cy.then(() => {
          return Cypress.Promise.try(() => {
    
            if (steps > 0) {
    
              const dx = (to.x - from.x) / steps
              const dy = (to.y - from.y) / steps
    
              return Cypress.Promise.map(Array(steps).fill(), (v, i) => {
                i = steps - 1 - i
    
                let _to = {
                  x: from.x + dx * (i),
                  y: from.y + dy * (i),
                }
    
                send('mousemove', _to, fromEl)
    
                return Cypress.Promise.delay(opts.delay)
    
              }, { concurrency: 1 })
            }
          })
          .then(() => {
    
            send('mousemove', to, fromEl)
            send('mouseover', to)
            send('mousemove', to)
            send('mouseup', to)
            _log.snapshot('after', { at: 1 }).end()
    
          })
    
        })
    
      }
    
      const $el = subject
      const fromCoords = getCoords($el)
      const toCoords = getCoords(cy.$$(to))
    
      drag(fromCoords, toCoords, opts.steps)
    }
    
    Cypress.Commands.addAll(
      { prevSubject: 'element' },
      {
        dragTo,
      }
    )
    
    

提交回复
热议问题