drag.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /**
  2. * This entire file was coppied from the following github repo: https://github.com/4teamwork/cypress-drag-drop/blob/master/index.js
  3. *
  4. * Full credit to the "cypress-drag-drop" package...
  5. */
  6. const dataTransfer = new DataTransfer()
  7. function omit(object = {}, keys = []) {
  8. return Object.entries(object).reduce((accum, [key, value]) => (key in keys ? accum : { ...accum, [key]: value }), {})
  9. }
  10. function isAttached(element) {
  11. return !!element.closest('html')
  12. }
  13. const DragSimulator = {
  14. MAX_TRIES: 5,
  15. DELAY_INTERVAL_MS: 10,
  16. counter: 0,
  17. targetElement: null,
  18. rectsEqual(r1, r2) {
  19. return r1.top === r2.top && r1.right === r2.right && r1.bottom === r2.bottom && r1.left === r2.left
  20. },
  21. createDefaultOptions(options) {
  22. const commonOptions = omit(options, ['source', 'target'])
  23. const source = { ...commonOptions, ...options.source }
  24. const target = { ...commonOptions, ...options.target }
  25. return { source, target }
  26. },
  27. get dropped() {
  28. const currentSourcePosition = this.source.getBoundingClientRect()
  29. return !this.rectsEqual(this.initialSourcePosition, currentSourcePosition)
  30. },
  31. get hasTriesLeft() {
  32. return this.counter < this.MAX_TRIES
  33. },
  34. set target(target) {
  35. this.targetElement = target
  36. },
  37. get target() {
  38. return cy.wrap(this.targetElement)
  39. },
  40. dragstart(clientPosition = {}) {
  41. return cy
  42. .wrap(this.source)
  43. .trigger('pointerdown', {
  44. which: 1,
  45. button: 0,
  46. ...clientPosition,
  47. eventConstructor: 'PointerEvent',
  48. ...this.options.source,
  49. })
  50. .trigger('mousedown', {
  51. which: 1,
  52. button: 0,
  53. ...clientPosition,
  54. eventConstructor: 'MouseEvent',
  55. ...this.options.source,
  56. })
  57. .trigger('dragstart', { dataTransfer, eventConstructor: 'DragEvent', ...this.options.source })
  58. },
  59. drop(clientPosition = {}) {
  60. return this.target
  61. .trigger('drop', {
  62. dataTransfer,
  63. eventConstructor: 'DragEvent',
  64. ...this.options.target,
  65. })
  66. .then(() => {
  67. if (isAttached(this.targetElement)) {
  68. this.target
  69. .trigger('mouseup', {
  70. which: 1,
  71. button: 0,
  72. ...clientPosition,
  73. eventConstructor: 'MouseEvent',
  74. ...this.options.target,
  75. })
  76. .then(() => {
  77. if (isAttached(this.targetElement)) {
  78. this.target.trigger('pointerup', {
  79. which: 1,
  80. button: 0,
  81. ...clientPosition,
  82. eventConstructor: 'PointerEvent',
  83. ...this.options.target,
  84. })
  85. }
  86. })
  87. }
  88. })
  89. },
  90. dragover(clientPosition = {}) {
  91. if (!this.counter || (!this.dropped && this.hasTriesLeft)) {
  92. this.counter += 1
  93. return this.target
  94. .trigger('dragover', {
  95. dataTransfer,
  96. eventConstructor: 'DragEvent',
  97. ...this.options.target,
  98. })
  99. .trigger('mousemove', {
  100. ...this.options.target,
  101. ...clientPosition,
  102. eventConstructor: 'MouseEvent',
  103. })
  104. .trigger('pointermove', {
  105. ...this.options.target,
  106. ...clientPosition,
  107. eventConstructor: 'PointerEvent',
  108. })
  109. .wait(this.DELAY_INTERVAL_MS)
  110. .then(() => this.dragover(clientPosition))
  111. }
  112. if (!this.dropped) {
  113. console.error(`Exceeded maximum tries of: ${this.MAX_TRIES}, aborting`)
  114. return false
  115. } else {
  116. return true
  117. }
  118. },
  119. init(source, target, options = {}) {
  120. this.options = this.createDefaultOptions(options)
  121. this.counter = 0
  122. this.source = source.get(0)
  123. this.initialSourcePosition = this.source.getBoundingClientRect()
  124. return cy.get(target).then((targetWrapper) => {
  125. this.target = targetWrapper.get(0)
  126. })
  127. },
  128. drag(sourceWrapper, targetSelector, options) {
  129. this.init(sourceWrapper, targetSelector, options)
  130. .then(() => this.dragstart())
  131. .then(() => this.dragover())
  132. .then((success) => {
  133. if (success) {
  134. return this.drop().then(() => true)
  135. } else {
  136. return false
  137. }
  138. })
  139. },
  140. move(sourceWrapper, options) {
  141. const { deltaX, deltaY } = options
  142. const { top, left } = sourceWrapper.offset()
  143. const finalCoords = { clientX: left + deltaX, clientY: top + deltaY }
  144. this.init(sourceWrapper, sourceWrapper, options)
  145. .then(() => this.dragstart({ clientX: left, clientY: top }))
  146. .then(() => this.dragover(finalCoords))
  147. .then(() => this.drop(finalCoords))
  148. },
  149. }
  150. function addChildCommand(name, command) {
  151. Cypress.Commands.add(name, { prevSubject: 'element' }, (...args) => command(...args))
  152. }
  153. addChildCommand('drag', DragSimulator.drag.bind(DragSimulator))
  154. addChildCommand('move', DragSimulator.move.bind(DragSimulator))