vOn.spec.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import { patchEvent } from '../../src/modules/events'
  2. import { withModifiers, withKeys } from '@vue/runtime-dom'
  3. function triggerEvent(
  4. target: Element,
  5. event: string,
  6. process?: (e: any) => any
  7. ) {
  8. const e = document.createEvent('HTMLEvents')
  9. e.initEvent(event, true, true)
  10. if (event === 'click') {
  11. ;(e as any).button = 0
  12. }
  13. if (process) process(e)
  14. target.dispatchEvent(e)
  15. return e
  16. }
  17. describe('runtime-dom: v-on directive', () => {
  18. test('it should support "stop" and "prevent"', () => {
  19. const parent = document.createElement('div')
  20. const child = document.createElement('input')
  21. parent.appendChild(child)
  22. const childNextValue = withModifiers(jest.fn(), ['prevent', 'stop'])
  23. patchEvent(child, 'onClick', null, childNextValue, null)
  24. const parentNextValue = jest.fn()
  25. patchEvent(parent, 'onClick', null, parentNextValue, null)
  26. expect(triggerEvent(child, 'click').defaultPrevented).toBe(true)
  27. expect(parentNextValue).not.toBeCalled()
  28. })
  29. test('it should support "self"', () => {
  30. const parent = document.createElement('div')
  31. const child = document.createElement('input')
  32. parent.appendChild(child)
  33. const fn = jest.fn()
  34. const handler = withModifiers(fn, ['self'])
  35. patchEvent(parent, 'onClick', null, handler, null)
  36. triggerEvent(child, 'click')
  37. expect(fn).not.toBeCalled()
  38. })
  39. test('it should support key modifiers and system modifiers', () => {
  40. const el = document.createElement('div')
  41. const fn = jest.fn()
  42. // <div @keyup.ctrl.esc="test"/>
  43. const nextValue = withKeys(withModifiers(fn, ['ctrl']), [
  44. 'esc',
  45. 'arrow-left'
  46. ])
  47. patchEvent(el, 'onKeyup', null, nextValue, null)
  48. triggerEvent(el, 'keyup', e => (e.key = 'a'))
  49. expect(fn).not.toBeCalled()
  50. triggerEvent(el, 'keyup', e => {
  51. e.ctrlKey = false
  52. e.key = 'esc'
  53. })
  54. expect(fn).not.toBeCalled()
  55. triggerEvent(el, 'keyup', e => {
  56. e.ctrlKey = true
  57. e.key = 'Escape'
  58. })
  59. expect(fn).toBeCalledTimes(1)
  60. triggerEvent(el, 'keyup', e => {
  61. e.ctrlKey = true
  62. e.key = 'ArrowLeft'
  63. })
  64. expect(fn).toBeCalledTimes(2)
  65. })
  66. test('it should support "exact" modifier', () => {
  67. const el = document.createElement('div')
  68. // Case 1: <div @keyup.exact="test"/>
  69. const fn1 = jest.fn()
  70. const next1 = withModifiers(fn1, ['exact'])
  71. patchEvent(el, 'onKeyup', null, next1, null)
  72. triggerEvent(el, 'keyup')
  73. expect(fn1.mock.calls.length).toBe(1)
  74. triggerEvent(el, 'keyup', e => (e.ctrlKey = true))
  75. expect(fn1.mock.calls.length).toBe(1)
  76. // Case 2: <div @keyup.ctrl.a.exact="test"/>
  77. const fn2 = jest.fn()
  78. const next2 = withKeys(withModifiers(fn2, ['ctrl', 'exact']), ['a'])
  79. patchEvent(el, 'onKeyup', null, next2, null)
  80. triggerEvent(el, 'keyup', e => (e.key = 'a'))
  81. expect(fn2).not.toBeCalled()
  82. triggerEvent(el, 'keyup', e => {
  83. e.key = 'a'
  84. e.ctrlKey = true
  85. })
  86. expect(fn2.mock.calls.length).toBe(1)
  87. triggerEvent(el, 'keyup', e => {
  88. // should not trigger if has other system modifiers
  89. e.key = 'a'
  90. e.ctrlKey = true
  91. e.altKey = true
  92. })
  93. expect(fn2.mock.calls.length).toBe(1)
  94. })
  95. it('should support mouse modifiers', () => {
  96. const buttons = ['left', 'middle', 'right'] as const
  97. const buttonCodes = { left: 0, middle: 1, right: 2 }
  98. buttons.forEach(button => {
  99. const el = document.createElement('div')
  100. const fn = jest.fn()
  101. const handler = withModifiers(fn, [button])
  102. patchEvent(el, 'onMousedown', null, handler, null)
  103. buttons.filter(b => b !== button).forEach(button => {
  104. triggerEvent(el, 'mousedown', e => (e.button = buttonCodes[button]))
  105. })
  106. expect(fn).not.toBeCalled()
  107. triggerEvent(el, 'mousedown', e => (e.button = buttonCodes[button]))
  108. expect(fn).toBeCalled()
  109. })
  110. })
  111. })