on.spec.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. import Vue from 'vue'
  2. import { supportsPassive } from 'core/util/env'
  3. describe('Directive v-on', () => {
  4. let vm, spy, el
  5. beforeEach(() => {
  6. vm = null
  7. spy = jasmine.createSpy()
  8. el = document.createElement('div')
  9. document.body.appendChild(el)
  10. })
  11. afterEach(() => {
  12. if (vm) {
  13. document.body.removeChild(vm.$el)
  14. }
  15. })
  16. it('should bind event to a method', () => {
  17. vm = new Vue({
  18. el,
  19. template: '<div v-on:click="foo"></div>',
  20. methods: { foo: spy }
  21. })
  22. triggerEvent(vm.$el, 'click')
  23. expect(spy.calls.count()).toBe(1)
  24. const args = spy.calls.allArgs()
  25. const event = args[0] && args[0][0] || {}
  26. expect(event.type).toBe('click')
  27. })
  28. it('should bind event to a inline statement', () => {
  29. vm = new Vue({
  30. el,
  31. template: '<div v-on:click="foo(1,2,3,$event)"></div>',
  32. methods: { foo: spy }
  33. })
  34. triggerEvent(vm.$el, 'click')
  35. expect(spy.calls.count()).toBe(1)
  36. const args = spy.calls.allArgs()
  37. const firstArgs = args[0]
  38. expect(firstArgs.length).toBe(4)
  39. expect(firstArgs[0]).toBe(1)
  40. expect(firstArgs[1]).toBe(2)
  41. expect(firstArgs[2]).toBe(3)
  42. expect(firstArgs[3].type).toBe('click')
  43. })
  44. it('should support inline function expression', () => {
  45. const spy = jasmine.createSpy()
  46. vm = new Vue({
  47. el,
  48. template: `<div class="test" @click="function (e) { log(e.target.className) }"></div>`,
  49. methods: {
  50. log: spy
  51. }
  52. }).$mount()
  53. triggerEvent(vm.$el, 'click')
  54. expect(spy).toHaveBeenCalledWith('test')
  55. })
  56. it('should support shorthand', () => {
  57. vm = new Vue({
  58. el,
  59. template: '<a href="#test" @click.prevent="foo"></a>',
  60. methods: { foo: spy }
  61. })
  62. triggerEvent(vm.$el, 'click')
  63. expect(spy.calls.count()).toBe(1)
  64. })
  65. it('should support stop propagation', () => {
  66. vm = new Vue({
  67. el,
  68. template: `
  69. <div @click.stop="foo"></div>
  70. `,
  71. methods: { foo: spy }
  72. })
  73. const hash = window.location.hash
  74. triggerEvent(vm.$el, 'click')
  75. expect(window.location.hash).toBe(hash)
  76. })
  77. it('should support prevent default', () => {
  78. vm = new Vue({
  79. el,
  80. template: `
  81. <input type="checkbox" ref="input" @click.prevent="foo">
  82. `,
  83. methods: {
  84. foo ($event) {
  85. spy($event.defaultPrevented)
  86. }
  87. }
  88. })
  89. vm.$refs.input.checked = false
  90. triggerEvent(vm.$refs.input, 'click')
  91. expect(spy).toHaveBeenCalledWith(true)
  92. })
  93. it('should support capture', () => {
  94. const callOrder = []
  95. vm = new Vue({
  96. el,
  97. template: `
  98. <div @click.capture="foo">
  99. <div @click="bar"></div>
  100. </div>
  101. `,
  102. methods: {
  103. foo () { callOrder.push(1) },
  104. bar () { callOrder.push(2) }
  105. }
  106. })
  107. triggerEvent(vm.$el.firstChild, 'click')
  108. expect(callOrder.toString()).toBe('1,2')
  109. })
  110. it('should support once', () => {
  111. vm = new Vue({
  112. el,
  113. template: `
  114. <div @click.once="foo">
  115. </div>
  116. `,
  117. methods: { foo: spy }
  118. })
  119. triggerEvent(vm.$el, 'click')
  120. expect(spy.calls.count()).toBe(1)
  121. triggerEvent(vm.$el, 'click')
  122. expect(spy.calls.count()).toBe(1) // should no longer trigger
  123. })
  124. // #4655
  125. it('should handle .once on multiple elements properly', () => {
  126. vm = new Vue({
  127. el,
  128. template: `
  129. <div>
  130. <button ref="one" @click.once="foo">one</button>
  131. <button ref="two" @click.once="foo">two</button>
  132. </div>
  133. `,
  134. methods: { foo: spy }
  135. })
  136. triggerEvent(vm.$refs.one, 'click')
  137. expect(spy.calls.count()).toBe(1)
  138. triggerEvent(vm.$refs.one, 'click')
  139. expect(spy.calls.count()).toBe(1)
  140. triggerEvent(vm.$refs.two, 'click')
  141. expect(spy.calls.count()).toBe(2)
  142. triggerEvent(vm.$refs.one, 'click')
  143. triggerEvent(vm.$refs.two, 'click')
  144. expect(spy.calls.count()).toBe(2)
  145. })
  146. it('should support capture and once', () => {
  147. const callOrder = []
  148. vm = new Vue({
  149. el,
  150. template: `
  151. <div @click.capture.once="foo">
  152. <div @click="bar"></div>
  153. </div>
  154. `,
  155. methods: {
  156. foo () { callOrder.push(1) },
  157. bar () { callOrder.push(2) }
  158. }
  159. })
  160. triggerEvent(vm.$el.firstChild, 'click')
  161. expect(callOrder.toString()).toBe('1,2')
  162. triggerEvent(vm.$el.firstChild, 'click')
  163. expect(callOrder.toString()).toBe('1,2,2')
  164. })
  165. // #4846
  166. it('should support once and other modifiers', () => {
  167. vm = new Vue({
  168. el,
  169. template: `<div @click.once.self="foo"><span/></div>`,
  170. methods: { foo: spy }
  171. })
  172. triggerEvent(vm.$el.firstChild, 'click')
  173. expect(spy).not.toHaveBeenCalled()
  174. triggerEvent(vm.$el, 'click')
  175. expect(spy).toHaveBeenCalled()
  176. triggerEvent(vm.$el, 'click')
  177. expect(spy.calls.count()).toBe(1)
  178. })
  179. it('should support keyCode', () => {
  180. vm = new Vue({
  181. el,
  182. template: `<input @keyup.enter="foo">`,
  183. methods: { foo: spy }
  184. })
  185. triggerEvent(vm.$el, 'keyup', e => {
  186. e.keyCode = 13
  187. })
  188. expect(spy).toHaveBeenCalled()
  189. })
  190. it('should support automatic key name inference', () => {
  191. vm = new Vue({
  192. el,
  193. template: `<input @keyup.arrow-right="foo">`,
  194. methods: { foo: spy }
  195. })
  196. triggerEvent(vm.$el, 'keyup', e => {
  197. e.key = 'ArrowRight'
  198. })
  199. expect(spy).toHaveBeenCalled()
  200. })
  201. // ctrl, shift, alt, meta
  202. it('should support system modifers', () => {
  203. vm = new Vue({
  204. el,
  205. template: `
  206. <div>
  207. <input ref="ctrl" @keyup.ctrl="foo">
  208. <input ref="shift" @keyup.shift="foo">
  209. <input ref="alt" @keyup.alt="foo">
  210. <input ref="meta" @keyup.meta="foo">
  211. </div>
  212. `,
  213. methods: { foo: spy }
  214. })
  215. triggerEvent(vm.$refs.ctrl, 'keyup')
  216. expect(spy.calls.count()).toBe(0)
  217. triggerEvent(vm.$refs.ctrl, 'keyup', e => { e.ctrlKey = true })
  218. expect(spy.calls.count()).toBe(1)
  219. triggerEvent(vm.$refs.shift, 'keyup')
  220. expect(spy.calls.count()).toBe(1)
  221. triggerEvent(vm.$refs.shift, 'keyup', e => { e.shiftKey = true })
  222. expect(spy.calls.count()).toBe(2)
  223. triggerEvent(vm.$refs.alt, 'keyup')
  224. expect(spy.calls.count()).toBe(2)
  225. triggerEvent(vm.$refs.alt, 'keyup', e => { e.altKey = true })
  226. expect(spy.calls.count()).toBe(3)
  227. triggerEvent(vm.$refs.meta, 'keyup')
  228. expect(spy.calls.count()).toBe(3)
  229. triggerEvent(vm.$refs.meta, 'keyup', e => { e.metaKey = true })
  230. expect(spy.calls.count()).toBe(4)
  231. })
  232. it('should support exact modifier', () => {
  233. vm = new Vue({
  234. el,
  235. template: `
  236. <div>
  237. <input ref="ctrl" @keyup.exact="foo">
  238. </div>
  239. `,
  240. methods: { foo: spy }
  241. })
  242. triggerEvent(vm.$refs.ctrl, 'keyup')
  243. expect(spy.calls.count()).toBe(1)
  244. triggerEvent(vm.$refs.ctrl, 'keyup', e => {
  245. e.ctrlKey = true
  246. })
  247. expect(spy.calls.count()).toBe(1)
  248. // should not trigger if has other system modifiers
  249. triggerEvent(vm.$refs.ctrl, 'keyup', e => {
  250. e.ctrlKey = true
  251. e.altKey = true
  252. })
  253. expect(spy.calls.count()).toBe(1)
  254. })
  255. it('should support system modifers with exact', () => {
  256. vm = new Vue({
  257. el,
  258. template: `
  259. <div>
  260. <input ref="ctrl" @keyup.ctrl.exact="foo">
  261. </div>
  262. `,
  263. methods: { foo: spy }
  264. })
  265. triggerEvent(vm.$refs.ctrl, 'keyup')
  266. expect(spy.calls.count()).toBe(0)
  267. triggerEvent(vm.$refs.ctrl, 'keyup', e => {
  268. e.ctrlKey = true
  269. })
  270. expect(spy.calls.count()).toBe(1)
  271. // should not trigger if has other system modifiers
  272. triggerEvent(vm.$refs.ctrl, 'keyup', e => {
  273. e.ctrlKey = true
  274. e.altKey = true
  275. })
  276. expect(spy.calls.count()).toBe(1)
  277. })
  278. it('should support number keyCode', () => {
  279. vm = new Vue({
  280. el,
  281. template: `<input @keyup.13="foo">`,
  282. methods: { foo: spy }
  283. })
  284. triggerEvent(vm.$el, 'keyup', e => {
  285. e.keyCode = 13
  286. })
  287. expect(spy).toHaveBeenCalled()
  288. })
  289. it('should support mouse modifier', () => {
  290. const left = 0
  291. const middle = 1
  292. const right = 2
  293. const spyLeft = jasmine.createSpy()
  294. const spyMiddle = jasmine.createSpy()
  295. const spyRight = jasmine.createSpy()
  296. vm = new Vue({
  297. el,
  298. template: `
  299. <div>
  300. <div ref="left" @mousedown.left="foo">left</div>
  301. <div ref="right" @mousedown.right="foo1">right</div>
  302. <div ref="middle" @mousedown.middle="foo2">right</div>
  303. </div>
  304. `,
  305. methods: {
  306. foo: spyLeft,
  307. foo1: spyRight,
  308. foo2: spyMiddle
  309. }
  310. })
  311. triggerEvent(vm.$refs.left, 'mousedown', e => { e.button = right })
  312. triggerEvent(vm.$refs.left, 'mousedown', e => { e.button = middle })
  313. expect(spyLeft).not.toHaveBeenCalled()
  314. triggerEvent(vm.$refs.left, 'mousedown', e => { e.button = left })
  315. expect(spyLeft).toHaveBeenCalled()
  316. triggerEvent(vm.$refs.right, 'mousedown', e => { e.button = left })
  317. triggerEvent(vm.$refs.right, 'mousedown', e => { e.button = middle })
  318. expect(spyRight).not.toHaveBeenCalled()
  319. triggerEvent(vm.$refs.right, 'mousedown', e => { e.button = right })
  320. expect(spyRight).toHaveBeenCalled()
  321. triggerEvent(vm.$refs.middle, 'mousedown', e => { e.button = left })
  322. triggerEvent(vm.$refs.middle, 'mousedown', e => { e.button = right })
  323. expect(spyMiddle).not.toHaveBeenCalled()
  324. triggerEvent(vm.$refs.middle, 'mousedown', e => { e.button = middle })
  325. expect(spyMiddle).toHaveBeenCalled()
  326. })
  327. it('should support custom keyCode', () => {
  328. Vue.config.keyCodes.test = 1
  329. vm = new Vue({
  330. el,
  331. template: `<input @keyup.test="foo">`,
  332. methods: { foo: spy }
  333. })
  334. triggerEvent(vm.$el, 'keyup', e => {
  335. e.keyCode = 1
  336. })
  337. expect(spy).toHaveBeenCalled()
  338. Vue.config.keyCodes = Object.create(null)
  339. })
  340. it('should override build-in keyCode', () => {
  341. Vue.config.keyCodes.up = [1, 87]
  342. vm = new Vue({
  343. el,
  344. template: `<input @keyup.up="foo" @keyup.down="foo">`,
  345. methods: { foo: spy }
  346. })
  347. triggerEvent(vm.$el, 'keyup', e => {
  348. e.keyCode = 87
  349. })
  350. expect(spy).toHaveBeenCalled()
  351. triggerEvent(vm.$el, 'keyup', e => {
  352. e.keyCode = 1
  353. })
  354. expect(spy).toHaveBeenCalledTimes(2)
  355. // should not affect build-in down keycode
  356. triggerEvent(vm.$el, 'keyup', e => {
  357. e.keyCode = 40
  358. })
  359. expect(spy).toHaveBeenCalledTimes(3)
  360. Vue.config.keyCodes = Object.create(null)
  361. })
  362. it('should bind to a child component', () => {
  363. vm = new Vue({
  364. el,
  365. template: '<bar @custom="foo"></bar>',
  366. methods: { foo: spy },
  367. components: {
  368. bar: {
  369. template: '<span>Hello</span>'
  370. }
  371. }
  372. })
  373. vm.$children[0].$emit('custom', 'foo', 'bar')
  374. expect(spy).toHaveBeenCalledWith('foo', 'bar')
  375. })
  376. it('should be able to bind native events for a child component', () => {
  377. vm = new Vue({
  378. el,
  379. template: '<bar @click.native="foo"></bar>',
  380. methods: { foo: spy },
  381. components: {
  382. bar: {
  383. template: '<span>Hello</span>'
  384. }
  385. }
  386. })
  387. vm.$children[0].$emit('click')
  388. expect(spy).not.toHaveBeenCalled()
  389. triggerEvent(vm.$children[0].$el, 'click')
  390. expect(spy).toHaveBeenCalled()
  391. })
  392. it('.once modifier should work with child components', () => {
  393. vm = new Vue({
  394. el,
  395. template: '<bar @custom.once="foo"></bar>',
  396. methods: { foo: spy },
  397. components: {
  398. bar: {
  399. template: '<span>Hello</span>'
  400. }
  401. }
  402. })
  403. vm.$children[0].$emit('custom')
  404. expect(spy.calls.count()).toBe(1)
  405. vm.$children[0].$emit('custom')
  406. expect(spy.calls.count()).toBe(1) // should not be called again
  407. })
  408. it('remove listener', done => {
  409. const spy2 = jasmine.createSpy('remove listener')
  410. vm = new Vue({
  411. el,
  412. methods: { foo: spy, bar: spy2 },
  413. data: {
  414. ok: true
  415. },
  416. render (h) {
  417. return this.ok
  418. ? h('input', { on: { click: this.foo }})
  419. : h('input', { on: { input: this.bar }})
  420. }
  421. })
  422. triggerEvent(vm.$el, 'click')
  423. expect(spy.calls.count()).toBe(1)
  424. expect(spy2.calls.count()).toBe(0)
  425. vm.ok = false
  426. waitForUpdate(() => {
  427. triggerEvent(vm.$el, 'click')
  428. expect(spy.calls.count()).toBe(1) // should no longer trigger
  429. triggerEvent(vm.$el, 'input')
  430. expect(spy2.calls.count()).toBe(1)
  431. }).then(done)
  432. })
  433. it('remove capturing listener', done => {
  434. const spy2 = jasmine.createSpy('remove listener')
  435. vm = new Vue({
  436. el,
  437. methods: { foo: spy, bar: spy2, stopped (ev) { ev.stopPropagation() } },
  438. data: {
  439. ok: true
  440. },
  441. render (h) {
  442. return this.ok
  443. ? h('div', { on: { '!click': this.foo }}, [h('div', { on: { click: this.stopped }})])
  444. : h('div', { on: { mouseOver: this.bar }}, [h('div')])
  445. }
  446. })
  447. triggerEvent(vm.$el.firstChild, 'click')
  448. expect(spy.calls.count()).toBe(1)
  449. expect(spy2.calls.count()).toBe(0)
  450. vm.ok = false
  451. waitForUpdate(() => {
  452. triggerEvent(vm.$el.firstChild, 'click')
  453. expect(spy.calls.count()).toBe(1) // should no longer trigger
  454. triggerEvent(vm.$el, 'mouseOver')
  455. expect(spy2.calls.count()).toBe(1)
  456. }).then(done)
  457. })
  458. it('remove once listener', done => {
  459. const spy2 = jasmine.createSpy('remove listener')
  460. vm = new Vue({
  461. el,
  462. methods: { foo: spy, bar: spy2 },
  463. data: {
  464. ok: true
  465. },
  466. render (h) {
  467. return this.ok
  468. ? h('input', { on: { '~click': this.foo }})
  469. : h('input', { on: { input: this.bar }})
  470. }
  471. })
  472. triggerEvent(vm.$el, 'click')
  473. expect(spy.calls.count()).toBe(1)
  474. triggerEvent(vm.$el, 'click')
  475. expect(spy.calls.count()).toBe(1) // should no longer trigger
  476. expect(spy2.calls.count()).toBe(0)
  477. vm.ok = false
  478. waitForUpdate(() => {
  479. triggerEvent(vm.$el, 'click')
  480. expect(spy.calls.count()).toBe(1) // should no longer trigger
  481. triggerEvent(vm.$el, 'input')
  482. expect(spy2.calls.count()).toBe(1)
  483. }).then(done)
  484. })
  485. it('remove capturing and once listener', done => {
  486. const spy2 = jasmine.createSpy('remove listener')
  487. vm = new Vue({
  488. el,
  489. methods: { foo: spy, bar: spy2, stopped (ev) { ev.stopPropagation() } },
  490. data: {
  491. ok: true
  492. },
  493. render (h) {
  494. return this.ok
  495. ? h('div', { on: { '~!click': this.foo }}, [h('div', { on: { click: this.stopped }})])
  496. : h('div', { on: { mouseOver: this.bar }}, [h('div')])
  497. }
  498. })
  499. triggerEvent(vm.$el.firstChild, 'click')
  500. expect(spy.calls.count()).toBe(1)
  501. triggerEvent(vm.$el.firstChild, 'click')
  502. expect(spy.calls.count()).toBe(1) // should no longer trigger
  503. expect(spy2.calls.count()).toBe(0)
  504. vm.ok = false
  505. waitForUpdate(() => {
  506. triggerEvent(vm.$el.firstChild, 'click')
  507. expect(spy.calls.count()).toBe(1) // should no longer trigger
  508. triggerEvent(vm.$el, 'mouseOver')
  509. expect(spy2.calls.count()).toBe(1)
  510. }).then(done)
  511. })
  512. it('remove listener on child component', done => {
  513. const spy2 = jasmine.createSpy('remove listener')
  514. vm = new Vue({
  515. el,
  516. methods: { foo: spy, bar: spy2 },
  517. data: {
  518. ok: true
  519. },
  520. components: {
  521. test: {
  522. template: '<div></div>'
  523. }
  524. },
  525. render (h) {
  526. return this.ok
  527. ? h('test', { on: { foo: this.foo }})
  528. : h('test', { on: { bar: this.bar }})
  529. }
  530. })
  531. vm.$children[0].$emit('foo')
  532. expect(spy.calls.count()).toBe(1)
  533. expect(spy2.calls.count()).toBe(0)
  534. vm.ok = false
  535. waitForUpdate(() => {
  536. vm.$children[0].$emit('foo')
  537. expect(spy.calls.count()).toBe(1) // should no longer trigger
  538. vm.$children[0].$emit('bar')
  539. expect(spy2.calls.count()).toBe(1)
  540. }).then(done)
  541. })
  542. it('warn missing handlers', () => {
  543. vm = new Vue({
  544. el,
  545. data: { none: null },
  546. template: `<div @click="none"></div>`
  547. })
  548. expect(`Invalid handler for event "click": got null`).toHaveBeenWarned()
  549. expect(() => {
  550. triggerEvent(vm.$el, 'click')
  551. }).not.toThrow()
  552. })
  553. // Github Issue #5046
  554. it('should support keyboard modifier for direction keys', () => {
  555. const spyLeft = jasmine.createSpy()
  556. const spyRight = jasmine.createSpy()
  557. const spyUp = jasmine.createSpy()
  558. const spyDown = jasmine.createSpy()
  559. vm = new Vue({
  560. el,
  561. template: `
  562. <div>
  563. <input ref="left" @keydown.left="foo"></input>
  564. <input ref="right" @keydown.right="foo1"></input>
  565. <input ref="up" @keydown.up="foo2"></input>
  566. <input ref="down" @keydown.down="foo3"></input>
  567. </div>
  568. `,
  569. methods: {
  570. foo: spyLeft,
  571. foo1: spyRight,
  572. foo2: spyUp,
  573. foo3: spyDown
  574. }
  575. })
  576. triggerEvent(vm.$refs.left, 'keydown', e => { e.keyCode = 37 })
  577. triggerEvent(vm.$refs.left, 'keydown', e => { e.keyCode = 39 })
  578. triggerEvent(vm.$refs.right, 'keydown', e => { e.keyCode = 39 })
  579. triggerEvent(vm.$refs.right, 'keydown', e => { e.keyCode = 38 })
  580. triggerEvent(vm.$refs.up, 'keydown', e => { e.keyCode = 38 })
  581. triggerEvent(vm.$refs.up, 'keydown', e => { e.keyCode = 37 })
  582. triggerEvent(vm.$refs.down, 'keydown', e => { e.keyCode = 40 })
  583. triggerEvent(vm.$refs.down, 'keydown', e => { e.keyCode = 39 })
  584. expect(spyLeft.calls.count()).toBe(1)
  585. expect(spyRight.calls.count()).toBe(1)
  586. expect(spyUp.calls.count()).toBe(1)
  587. expect(spyDown.calls.count()).toBe(1)
  588. })
  589. // This test case should only run when the test browser supports passive.
  590. if (supportsPassive) {
  591. it('should support passive', () => {
  592. vm = new Vue({
  593. el,
  594. template: `
  595. <div>
  596. <input type="checkbox" ref="normal" @click="foo"/>
  597. <input type="checkbox" ref="passive" @click.passive="foo"/>
  598. <input type="checkbox" ref="exclusive" @click.prevent.passive/>
  599. </div>
  600. `,
  601. methods: {
  602. foo (e) {
  603. e.preventDefault()
  604. }
  605. }
  606. })
  607. vm.$refs.normal.checked = false
  608. vm.$refs.passive.checked = false
  609. vm.$refs.exclusive.checked = false
  610. vm.$refs.normal.click()
  611. vm.$refs.passive.click()
  612. vm.$refs.exclusive.click()
  613. expect(vm.$refs.normal.checked).toBe(false)
  614. expect(vm.$refs.passive.checked).toBe(true)
  615. expect(vm.$refs.exclusive.checked).toBe(true)
  616. expect('passive and prevent can\'t be used together. Passive handler can\'t prevent default event.').toHaveBeenWarned()
  617. })
  618. }
  619. // GitHub Issues #5146
  620. it('should only prevent when match keycode', () => {
  621. let prevented = false
  622. vm = new Vue({
  623. el,
  624. template: `
  625. <input ref="input" @keydown.enter.prevent="foo">
  626. `,
  627. methods: {
  628. foo ($event) {
  629. prevented = $event.defaultPrevented
  630. }
  631. }
  632. })
  633. triggerEvent(vm.$refs.input, 'keydown', e => { e.keyCode = 32 })
  634. expect(prevented).toBe(false)
  635. triggerEvent(vm.$refs.input, 'keydown', e => { e.keyCode = 13 })
  636. expect(prevented).toBe(true)
  637. })
  638. it('should transform click.right to contextmenu', () => {
  639. const spy = jasmine.createSpy('click.right')
  640. const vm = new Vue({
  641. template: `<div @click.right="foo"></div>`,
  642. methods: { foo: spy }
  643. }).$mount()
  644. triggerEvent(vm.$el, 'contextmenu')
  645. expect(spy).toHaveBeenCalled()
  646. })
  647. it('should transform click.middle to mouseup', () => {
  648. const spy = jasmine.createSpy('click.middle')
  649. const vm = new Vue({
  650. template: `<div @click.middle="foo"></div>`,
  651. methods: { foo: spy }
  652. }).$mount()
  653. triggerEvent(vm.$el, 'mouseup', e => { e.button = 0 })
  654. expect(spy).not.toHaveBeenCalled()
  655. triggerEvent(vm.$el, 'mouseup', e => { e.button = 1 })
  656. expect(spy).toHaveBeenCalled()
  657. })
  658. it('object syntax (no argument)', () => {
  659. const click = jasmine.createSpy('click')
  660. const mouseup = jasmine.createSpy('mouseup')
  661. vm = new Vue({
  662. el,
  663. template: `<button v-on="listeners">foo</button>`,
  664. created () {
  665. this.listeners = {
  666. click,
  667. mouseup
  668. }
  669. }
  670. })
  671. triggerEvent(vm.$el, 'click')
  672. expect(click.calls.count()).toBe(1)
  673. expect(mouseup.calls.count()).toBe(0)
  674. triggerEvent(vm.$el, 'mouseup')
  675. expect(click.calls.count()).toBe(1)
  676. expect(mouseup.calls.count()).toBe(1)
  677. })
  678. it('object syntax (no argument, mixed with normal listeners)', () => {
  679. const click1 = jasmine.createSpy('click1')
  680. const click2 = jasmine.createSpy('click2')
  681. const mouseup = jasmine.createSpy('mouseup')
  682. vm = new Vue({
  683. el,
  684. template: `<button v-on="listeners" @click="click2">foo</button>`,
  685. created () {
  686. this.listeners = {
  687. click: click1,
  688. mouseup
  689. }
  690. },
  691. methods: {
  692. click2
  693. }
  694. })
  695. triggerEvent(vm.$el, 'click')
  696. expect(click1.calls.count()).toBe(1)
  697. expect(click2.calls.count()).toBe(1)
  698. expect(mouseup.calls.count()).toBe(0)
  699. triggerEvent(vm.$el, 'mouseup')
  700. expect(click1.calls.count()).toBe(1)
  701. expect(click2.calls.count()).toBe(1)
  702. expect(mouseup.calls.count()).toBe(1)
  703. })
  704. it('object syntax (usage in HOC, mixed with native listeners)', () => {
  705. const click = jasmine.createSpy('click')
  706. const mouseup = jasmine.createSpy('mouseup')
  707. const mousedown = jasmine.createSpy('mousedown')
  708. vm = new Vue({
  709. el,
  710. template: `
  711. <foo-button
  712. @click="click"
  713. @mousedown="mousedown"
  714. @mouseup.native="mouseup">
  715. </foo-button>
  716. `,
  717. methods: {
  718. click,
  719. mouseup,
  720. mousedown
  721. },
  722. components: {
  723. fooButton: {
  724. template: `
  725. <button v-on="$listeners"></button>
  726. `
  727. }
  728. }
  729. })
  730. triggerEvent(vm.$el, 'click')
  731. expect(click.calls.count()).toBe(1)
  732. expect(mouseup.calls.count()).toBe(0)
  733. expect(mousedown.calls.count()).toBe(0)
  734. triggerEvent(vm.$el, 'mouseup')
  735. expect(click.calls.count()).toBe(1)
  736. expect(mouseup.calls.count()).toBe(1)
  737. expect(mousedown.calls.count()).toBe(0)
  738. triggerEvent(vm.$el, 'mousedown')
  739. expect(click.calls.count()).toBe(1)
  740. expect(mouseup.calls.count()).toBe(1)
  741. expect(mousedown.calls.count()).toBe(1)
  742. })
  743. // #6805 (v-on="object" bind order problem)
  744. it('object syntax (no argument): should fire after high-priority listeners', done => {
  745. const MyCheckbox = {
  746. template: '<input type="checkbox" v-model="model" v-on="$listeners">',
  747. props: {
  748. value: false
  749. },
  750. computed: {
  751. model: {
  752. get () {
  753. return this.value
  754. },
  755. set (val) {
  756. this.$emit('input', val)
  757. }
  758. }
  759. }
  760. }
  761. vm = new Vue({
  762. el,
  763. template: `
  764. <div>
  765. <my-checkbox v-model="check" @change="change"></my-checkbox>
  766. </div>
  767. `,
  768. components: { MyCheckbox },
  769. data: {
  770. check: false
  771. },
  772. methods: {
  773. change () {
  774. expect(this.check).toBe(true)
  775. done()
  776. }
  777. }
  778. })
  779. vm.$el.querySelector('input').click()
  780. })
  781. it('warn object syntax with modifier', () => {
  782. new Vue({
  783. template: `<button v-on.self="{}"></button>`
  784. }).$mount()
  785. expect(`v-on without argument does not support modifiers`).toHaveBeenWarned()
  786. })
  787. it('warn object syntax with non-object value', () => {
  788. new Vue({
  789. template: `<button v-on="123"></button>`
  790. }).$mount()
  791. expect(`v-on without argument expects an Object value`).toHaveBeenWarned()
  792. })
  793. })