test/unit/features/directives/on.spec.ts TYPESCRIPT 1,212 lines View on github.com → Search inside
1import Vue from 'vue'2import { supportsPassive } from 'core/util/env'3import { SpyInstanceFn } from 'vitest'45describe('Directive v-on', () => {6  let vm, spy: SpyInstanceFn, el: HTMLElement78  beforeEach(() => {9    vm = null10    spy = vi.fn()11    el = document.createElement('div')12    document.body.appendChild(el)13  })1415  afterEach(() => {16    if (vm) {17      document.body.removeChild(vm.$el)18    }19  })2021  it('should bind event to a method', () => {22    vm = new Vue({23      el,24      template: '<div v-on:click="foo"></div>',25      methods: { foo: spy }26    })27    triggerEvent(vm.$el, 'click')28    expect(spy.mock.calls.length).toBe(1)2930    const args = spy.mock.calls31    const event = (args[0] && args[0][0]) || {}32    expect(event.type).toBe('click')33  })3435  it('should bind event to an inline statement', () => {36    vm = new Vue({37      el,38      template: '<div v-on:click="foo(1,2,3,$event)"></div>',39      methods: { foo: spy }40    })41    triggerEvent(vm.$el, 'click')42    expect(spy.mock.calls.length).toBe(1)4344    const args = spy.mock.calls45    const firstArgs = args[0]46    expect(firstArgs.length).toBe(4)47    expect(firstArgs[0]).toBe(1)48    expect(firstArgs[1]).toBe(2)49    expect(firstArgs[2]).toBe(3)50    expect(firstArgs[3].type).toBe('click')51  })5253  it('should support inline function expression', () => {54    const spy = vi.fn()55    vm = new Vue({56      el,57      template: `<div class="test" @click="function (e) { log(e.target.className) }"></div>`,58      methods: {59        log: spy60      }61    }).$mount()62    triggerEvent(vm.$el, 'click')63    expect(spy).toHaveBeenCalledWith('test')64  })6566  it('should support shorthand', () => {67    vm = new Vue({68      el,69      template: '<a href="#test" @click.prevent="foo"></a>',70      methods: { foo: spy }71    })72    triggerEvent(vm.$el, 'click')73    expect(spy.mock.calls.length).toBe(1)74  })7576  it('should support stop propagation', () => {77    vm = new Vue({78      el,79      template: `80        <div @click.stop="foo"></div>81      `,82      methods: { foo: spy }83    })84    const hash = window.location.hash85    triggerEvent(vm.$el, 'click')86    expect(window.location.hash).toBe(hash)87  })8889  it('should support prevent default', () => {90    vm = new Vue({91      el,92      template: `93        <input type="checkbox" ref="input" @click.prevent="foo">94      `,95      methods: {96        foo($event) {97          spy($event.defaultPrevented)98        }99      }100    })101    vm.$refs.input.checked = false102    triggerEvent(vm.$refs.input, 'click')103    expect(spy).toHaveBeenCalledWith(true)104  })105106  it('should support capture', () => {107    const callOrder: any[] = []108    vm = new Vue({109      el,110      template: `111        <div @click.capture="foo">112          <div @click="bar"></div>113        </div>114      `,115      methods: {116        foo() {117          callOrder.push(1)118        },119        bar() {120          callOrder.push(2)121        }122      }123    })124    triggerEvent(vm.$el.firstChild, 'click')125    expect(callOrder.toString()).toBe('1,2')126  })127128  it('should support once', () => {129    vm = new Vue({130      el,131      template: `132        <div @click.once="foo">133        </div>134      `,135      methods: { foo: spy }136    })137    triggerEvent(vm.$el, 'click')138    expect(spy.mock.calls.length).toBe(1)139    triggerEvent(vm.$el, 'click')140    expect(spy.mock.calls.length).toBe(1) // should no longer trigger141  })142143  // #4655144  it('should handle .once on multiple elements properly', () => {145    vm = new Vue({146      el,147      template: `148        <div>149          <button ref="one" @click.once="foo">one</button>150          <button ref="two" @click.once="foo">two</button>151        </div>152      `,153      methods: { foo: spy }154    })155    triggerEvent(vm.$refs.one, 'click')156    expect(spy.mock.calls.length).toBe(1)157    triggerEvent(vm.$refs.one, 'click')158    expect(spy.mock.calls.length).toBe(1)159    triggerEvent(vm.$refs.two, 'click')160    expect(spy.mock.calls.length).toBe(2)161    triggerEvent(vm.$refs.one, 'click')162    triggerEvent(vm.$refs.two, 'click')163    expect(spy.mock.calls.length).toBe(2)164  })165166  it('should support capture and once', () => {167    const callOrder: any[] = []168    vm = new Vue({169      el,170      template: `171        <div @click.capture.once="foo">172          <div @click="bar"></div>173        </div>174      `,175      methods: {176        foo() {177          callOrder.push(1)178        },179        bar() {180          callOrder.push(2)181        }182      }183    })184    triggerEvent(vm.$el.firstChild, 'click')185    expect(callOrder.toString()).toBe('1,2')186    triggerEvent(vm.$el.firstChild, 'click')187    expect(callOrder.toString()).toBe('1,2,2')188  })189190  // #4846191  it('should support once and other modifiers', () => {192    vm = new Vue({193      el,194      template: `<div @click.once.self="foo"><span/></div>`,195      methods: { foo: spy }196    })197    triggerEvent(vm.$el.firstChild, 'click')198    expect(spy).not.toHaveBeenCalled()199    triggerEvent(vm.$el, 'click')200    expect(spy).toHaveBeenCalled()201    triggerEvent(vm.$el, 'click')202    expect(spy.mock.calls.length).toBe(1)203  })204205  it('should support keyCode', () => {206    vm = new Vue({207      el,208      template: `<input @keyup.enter="foo">`,209      methods: { foo: spy }210    })211    triggerEvent(vm.$el, 'keyup', e => {212      e.keyCode = 13213    })214    expect(spy).toHaveBeenCalled()215  })216217  it('should support automatic key name inference', () => {218    vm = new Vue({219      el,220      template: `<input @keyup.arrow-right="foo">`,221      methods: { foo: spy }222    })223    triggerEvent(vm.$el, 'keyup', e => {224      e.key = 'ArrowRight'225    })226    expect(spy).toHaveBeenCalled()227  })228229  // ctrl, shift, alt, meta230  it('should support system modifiers', () => {231    vm = new Vue({232      el,233      template: `234        <div>235          <input ref="ctrl" @keyup.ctrl="foo">236          <input ref="shift" @keyup.shift="foo">237          <input ref="alt" @keyup.alt="foo">238          <input ref="meta" @keyup.meta="foo">239        </div>240      `,241      methods: { foo: spy }242    })243244    triggerEvent(vm.$refs.ctrl, 'keyup')245    expect(spy.mock.calls.length).toBe(0)246    triggerEvent(vm.$refs.ctrl, 'keyup', e => {247      e.ctrlKey = true248    })249    expect(spy.mock.calls.length).toBe(1)250251    triggerEvent(vm.$refs.shift, 'keyup')252    expect(spy.mock.calls.length).toBe(1)253    triggerEvent(vm.$refs.shift, 'keyup', e => {254      e.shiftKey = true255    })256    expect(spy.mock.calls.length).toBe(2)257258    triggerEvent(vm.$refs.alt, 'keyup')259    expect(spy.mock.calls.length).toBe(2)260    triggerEvent(vm.$refs.alt, 'keyup', e => {261      e.altKey = true262    })263    expect(spy.mock.calls.length).toBe(3)264265    triggerEvent(vm.$refs.meta, 'keyup')266    expect(spy.mock.calls.length).toBe(3)267    triggerEvent(vm.$refs.meta, 'keyup', e => {268      e.metaKey = true269    })270    expect(spy.mock.calls.length).toBe(4)271  })272273  it('should support exact modifier', () => {274    vm = new Vue({275      el,276      template: `277        <div>278          <input ref="ctrl" @keyup.exact="foo">279        </div>280      `,281      methods: { foo: spy }282    })283284    triggerEvent(vm.$refs.ctrl, 'keyup')285    expect(spy.mock.calls.length).toBe(1)286287    triggerEvent(vm.$refs.ctrl, 'keyup', e => {288      e.ctrlKey = true289    })290    expect(spy.mock.calls.length).toBe(1)291292    // should not trigger if has other system modifiers293    triggerEvent(vm.$refs.ctrl, 'keyup', e => {294      e.ctrlKey = true295      e.altKey = true296    })297    expect(spy.mock.calls.length).toBe(1)298  })299300  it('should support system modifiers with exact', () => {301    vm = new Vue({302      el,303      template: `304        <div>305          <input ref="ctrl" @keyup.ctrl.exact="foo">306        </div>307      `,308      methods: { foo: spy }309    })310311    triggerEvent(vm.$refs.ctrl, 'keyup')312    expect(spy.mock.calls.length).toBe(0)313314    triggerEvent(vm.$refs.ctrl, 'keyup', e => {315      e.ctrlKey = true316    })317    expect(spy.mock.calls.length).toBe(1)318319    // should not trigger if has other system modifiers320    triggerEvent(vm.$refs.ctrl, 'keyup', e => {321      e.ctrlKey = true322      e.altKey = true323    })324    expect(spy.mock.calls.length).toBe(1)325  })326327  it('should support number keyCode', () => {328    vm = new Vue({329      el,330      template: `<input @keyup.13="foo">`,331      methods: { foo: spy }332    })333    triggerEvent(vm.$el, 'keyup', e => {334      e.keyCode = 13335    })336    expect(spy).toHaveBeenCalled()337  })338339  it('should support mouse modifier', () => {340    const left = 0341    const middle = 1342    const right = 2343    const spyLeft = vi.fn()344    const spyMiddle = vi.fn()345    const spyRight = vi.fn()346347    vm = new Vue({348      el,349      template: `350        <div>351          <div ref="left" @mousedown.left="foo">left</div>352          <div ref="right" @mousedown.right="foo1">right</div>353          <div ref="middle" @mousedown.middle="foo2">right</div>354        </div>355      `,356      methods: {357        foo: spyLeft,358        foo1: spyRight,359        foo2: spyMiddle360      }361    })362363    triggerEvent(vm.$refs.left, 'mousedown', e => {364      e.button = right365    })366    triggerEvent(vm.$refs.left, 'mousedown', e => {367      e.button = middle368    })369    expect(spyLeft).not.toHaveBeenCalled()370    triggerEvent(vm.$refs.left, 'mousedown', e => {371      e.button = left372    })373    expect(spyLeft).toHaveBeenCalled()374375    triggerEvent(vm.$refs.right, 'mousedown', e => {376      e.button = left377    })378    triggerEvent(vm.$refs.right, 'mousedown', e => {379      e.button = middle380    })381    expect(spyRight).not.toHaveBeenCalled()382    triggerEvent(vm.$refs.right, 'mousedown', e => {383      e.button = right384    })385    expect(spyRight).toHaveBeenCalled()386387    triggerEvent(vm.$refs.middle, 'mousedown', e => {388      e.button = left389    })390    triggerEvent(vm.$refs.middle, 'mousedown', e => {391      e.button = right392    })393    expect(spyMiddle).not.toHaveBeenCalled()394    triggerEvent(vm.$refs.middle, 'mousedown', e => {395      e.button = middle396    })397    expect(spyMiddle).toHaveBeenCalled()398  })399400  it('should support KeyboardEvent.key for built in aliases', () => {401    vm = new Vue({402      el,403      template: `404        <div>405          <input ref="enter" @keyup.enter="foo">406          <input ref="space" @keyup.space="foo">407          <input ref="esc" @keyup.esc="foo">408          <input ref="left" @keyup.left="foo">409          <input ref="delete" @keyup.delete="foo">410        </div>411      `,412      methods: { foo: spy }413    })414415    triggerEvent(vm.$refs.enter, 'keyup', e => {416      e.key = 'Enter'417    })418    expect(spy.mock.calls.length).toBe(1)419    triggerEvent(vm.$refs.space, 'keyup', e => {420      e.key = ' '421    })422    expect(spy.mock.calls.length).toBe(2)423    triggerEvent(vm.$refs.esc, 'keyup', e => {424      e.key = 'Escape'425    })426    expect(spy.mock.calls.length).toBe(3)427    triggerEvent(vm.$refs.left, 'keyup', e => {428      e.key = 'ArrowLeft'429    })430    expect(spy.mock.calls.length).toBe(4)431    triggerEvent(vm.$refs.delete, 'keyup', e => {432      e.key = 'Backspace'433    })434    expect(spy.mock.calls.length).toBe(5)435    triggerEvent(vm.$refs.delete, 'keyup', e => {436      e.key = 'Delete'437    })438    expect(spy.mock.calls.length).toBe(6)439  })440441  it('should support custom keyCode', () => {442    Vue.config.keyCodes.test = 1443    vm = new Vue({444      el,445      template: `<input @keyup.test="foo">`,446      methods: { foo: spy }447    })448    triggerEvent(vm.$el, 'keyup', e => {449      e.keyCode = 1450    })451    expect(spy).toHaveBeenCalled()452    Vue.config.keyCodes = Object.create(null)453  })454455  it('should override built-in keyCode', () => {456    Vue.config.keyCodes.up = [1, 87]457    vm = new Vue({458      el,459      template: `<input @keyup.up="foo" @keyup.down="foo">`,460      methods: { foo: spy }461    })462    triggerEvent(vm.$el, 'keyup', e => {463      e.keyCode = 87464    })465    expect(spy).toHaveBeenCalled()466    triggerEvent(vm.$el, 'keyup', e => {467      e.keyCode = 1468    })469    expect(spy).toHaveBeenCalledTimes(2)470    // should not affect built-in down keycode471    triggerEvent(vm.$el, 'keyup', e => {472      e.keyCode = 40473    })474    expect(spy).toHaveBeenCalledTimes(3)475    Vue.config.keyCodes = Object.create(null)476  })477478  it('should bind to a child component', () => {479    vm = new Vue({480      el,481      template: '<bar @custom="foo"></bar>',482      methods: { foo: spy },483      components: {484        bar: {485          template: '<span>Hello</span>'486        }487      }488    })489    vm.$children[0].$emit('custom', 'foo', 'bar')490    expect(spy).toHaveBeenCalledWith('foo', 'bar')491  })492493  it('should be able to bind native events for a child component', () => {494    vm = new Vue({495      el,496      template: '<bar @click.native="foo"></bar>',497      methods: { foo: spy },498      components: {499        bar: {500          template: '<span>Hello</span>'501        }502      }503    })504    vm.$children[0].$emit('click')505    expect(spy).not.toHaveBeenCalled()506    triggerEvent(vm.$children[0].$el, 'click')507    expect(spy).toHaveBeenCalled()508  })509510  it('should throw a warning if native modifier is used on native HTML element', () => {511    vm = new Vue({512      el,513      template: `514        <button @click.native="foo"></button>515      `,516      methods: { foo: spy }517    })518519    triggerEvent(vm.$el, 'click')520    expect(521      `The .native modifier for v-on is only valid on components but it was used on <button>.`522    ).toHaveBeenWarned()523    expect(spy.mock.calls.length).toBe(0)524  })525526  it('should not throw a warning if native modifier is used on a dynamic component', () => {527    vm = new Vue({528      el,529      template: `530        <component is="div" @click.native="foo('native')" @click="foo('regular')"/>531      `,532      methods: { foo: spy }533    })534535    triggerEvent(vm.$el, 'click')536    expect(537      `The .native modifier for v-on is only valid on components but it was used on <div>.`538    ).not.toHaveBeenWarned()539    expect(spy.mock.calls).toEqual([['regular']]) // Regular @click should work for dynamic components resolved to native HTML elements.540  })541542  it('.once modifier should work with child components', () => {543    vm = new Vue({544      el,545      template: '<bar @custom.once="foo"></bar>',546      methods: { foo: spy },547      components: {548        bar: {549          template: '<span>Hello</span>'550        }551      }552    })553    vm.$children[0].$emit('custom')554    expect(spy.mock.calls.length).toBe(1)555    vm.$children[0].$emit('custom')556    expect(spy.mock.calls.length).toBe(1) // should not be called again557  })558559  it('remove listener', done => {560    const spy2 = vi.fn()561    vm = new Vue({562      el,563      methods: { foo: spy, bar: spy2 },564      data: {565        ok: true566      },567      render(h) {568        return this.ok569          ? h('input', { on: { click: this.foo } })570          : h('input', { on: { input: this.bar } })571      }572    })573    triggerEvent(vm.$el, 'click')574    expect(spy.mock.calls.length).toBe(1)575    expect(spy2.mock.calls.length).toBe(0)576    vm.ok = false577    waitForUpdate(() => {578      triggerEvent(vm.$el, 'click')579      expect(spy.mock.calls.length).toBe(1) // should no longer trigger580      triggerEvent(vm.$el, 'input')581      expect(spy2.mock.calls.length).toBe(1)582    }).then(done)583  })584585  it('remove capturing listener', done => {586    const spy2 = vi.fn()587    vm = new Vue({588      el,589      methods: {590        foo: spy,591        bar: spy2,592        stopped(ev) {593          ev.stopPropagation()594        }595      },596      data: {597        ok: true598      },599      render(h) {600        return this.ok601          ? h('div', { on: { '!click': this.foo } }, [602              h('div', { on: { click: this.stopped } })603            ])604          : h('div', { on: { mouseOver: this.bar } }, [h('div')])605      }606    })607    triggerEvent(vm.$el.firstChild, 'click')608    expect(spy.mock.calls.length).toBe(1)609    expect(spy2.mock.calls.length).toBe(0)610    vm.ok = false611    waitForUpdate(() => {612      triggerEvent(vm.$el.firstChild, 'click')613      expect(spy.mock.calls.length).toBe(1) // should no longer trigger614      triggerEvent(vm.$el, 'mouseOver')615      expect(spy2.mock.calls.length).toBe(1)616    }).then(done)617  })618619  it('remove once listener', done => {620    const spy2 = vi.fn()621    vm = new Vue({622      el,623      methods: { foo: spy, bar: spy2 },624      data: {625        ok: true626      },627      render(h) {628        return this.ok629          ? h('input', { on: { '~click': this.foo } })630          : h('input', { on: { input: this.bar } })631      }632    })633    triggerEvent(vm.$el, 'click')634    expect(spy.mock.calls.length).toBe(1)635    triggerEvent(vm.$el, 'click')636    expect(spy.mock.calls.length).toBe(1) // should no longer trigger637    expect(spy2.mock.calls.length).toBe(0)638    vm.ok = false639    waitForUpdate(() => {640      triggerEvent(vm.$el, 'click')641      expect(spy.mock.calls.length).toBe(1) // should no longer trigger642      triggerEvent(vm.$el, 'input')643      expect(spy2.mock.calls.length).toBe(1)644    }).then(done)645  })646647  it('remove capturing and once listener', done => {648    const spy2 = vi.fn()649    vm = new Vue({650      el,651      methods: {652        foo: spy,653        bar: spy2,654        stopped(ev) {655          ev.stopPropagation()656        }657      },658      data: {659        ok: true660      },661      render(h) {662        return this.ok663          ? h('div', { on: { '~!click': this.foo } }, [664              h('div', { on: { click: this.stopped } })665            ])666          : h('div', { on: { mouseOver: this.bar } }, [h('div')])667      }668    })669    triggerEvent(vm.$el.firstChild, 'click')670    expect(spy.mock.calls.length).toBe(1)671    triggerEvent(vm.$el.firstChild, 'click')672    expect(spy.mock.calls.length).toBe(1) // should no longer trigger673    expect(spy2.mock.calls.length).toBe(0)674    vm.ok = false675    waitForUpdate(() => {676      triggerEvent(vm.$el.firstChild, 'click')677      expect(spy.mock.calls.length).toBe(1) // should no longer trigger678      triggerEvent(vm.$el, 'mouseOver')679      expect(spy2.mock.calls.length).toBe(1)680    }).then(done)681  })682683  it('remove listener on child component', done => {684    const spy2 = vi.fn()685    vm = new Vue({686      el,687      methods: { foo: spy, bar: spy2 },688      data: {689        ok: true690      },691      components: {692        test: {693          template: '<div></div>'694        }695      },696      render(h) {697        return this.ok698          ? h('test', { on: { foo: this.foo } })699          : h('test', { on: { bar: this.bar } })700      }701    })702    vm.$children[0].$emit('foo')703    expect(spy.mock.calls.length).toBe(1)704    expect(spy2.mock.calls.length).toBe(0)705    vm.ok = false706    waitForUpdate(() => {707      vm.$children[0].$emit('foo')708      expect(spy.mock.calls.length).toBe(1) // should no longer trigger709      vm.$children[0].$emit('bar')710      expect(spy2.mock.calls.length).toBe(1)711    }).then(done)712  })713714  it('warn missing handlers', () => {715    vm = new Vue({716      el,717      data: { none: null },718      template: `<div @click="none"></div>`719    })720    expect(`Invalid handler for event "click": got null`).toHaveBeenWarned()721    expect(() => {722      triggerEvent(vm.$el, 'click')723    }).not.toThrow()724  })725726  // Github Issue #5046727  it('should support keyboard modifier for direction keys', () => {728    const spyLeft = vi.fn()729    const spyRight = vi.fn()730    const spyUp = vi.fn()731    const spyDown = vi.fn()732    vm = new Vue({733      el,734      template: `735        <div>736          <input ref="left" @keydown.left="foo"></input>737          <input ref="right" @keydown.right="foo1"></input>738          <input ref="up" @keydown.up="foo2"></input>739          <input ref="down" @keydown.down="foo3"></input>740        </div>741      `,742      methods: {743        foo: spyLeft,744        foo1: spyRight,745        foo2: spyUp,746        foo3: spyDown747      }748    })749    triggerEvent(vm.$refs.left, 'keydown', e => {750      e.keyCode = 37751    })752    triggerEvent(vm.$refs.left, 'keydown', e => {753      e.keyCode = 39754    })755756    triggerEvent(vm.$refs.right, 'keydown', e => {757      e.keyCode = 39758    })759    triggerEvent(vm.$refs.right, 'keydown', e => {760      e.keyCode = 38761    })762763    triggerEvent(vm.$refs.up, 'keydown', e => {764      e.keyCode = 38765    })766    triggerEvent(vm.$refs.up, 'keydown', e => {767      e.keyCode = 37768    })769770    triggerEvent(vm.$refs.down, 'keydown', e => {771      e.keyCode = 40772    })773    triggerEvent(vm.$refs.down, 'keydown', e => {774      e.keyCode = 39775    })776777    expect(spyLeft.mock.calls.length).toBe(1)778    expect(spyRight.mock.calls.length).toBe(1)779    expect(spyUp.mock.calls.length).toBe(1)780    expect(spyDown.mock.calls.length).toBe(1)781  })782783  // This test case should only run when the test browser supports passive.784  if (supportsPassive) {785    it('should support passive', () => {786      vm = new Vue({787        el,788        template: `789          <div>790            <input type="checkbox" ref="normal" @click="foo"/>791            <input type="checkbox" ref="passive" @click.passive="foo"/>792            <input type="checkbox" ref="exclusive" @click.prevent.passive/>793          </div>794        `,795        methods: {796          foo(e) {797            e.preventDefault()798          }799        }800      })801802      vm.$refs.normal.checked = false803      vm.$refs.passive.checked = false804      vm.$refs.exclusive.checked = false805      vm.$refs.normal.click()806      vm.$refs.passive.click()807      vm.$refs.exclusive.click()808      expect(vm.$refs.normal.checked).toBe(false)809      expect(vm.$refs.passive.checked).toBe(true)810      expect(vm.$refs.exclusive.checked).toBe(true)811      expect(812        "passive and prevent can't be used together. Passive handler can't prevent default event."813      ).toHaveBeenWarned()814    })815  }816817  // GitHub Issues #5146818  it('should only prevent when match keycode', () => {819    let prevented = false820    vm = new Vue({821      el,822      template: `823        <input ref="input" @keydown.enter.prevent="foo">824      `,825      methods: {826        foo($event) {827          prevented = $event.defaultPrevented828        }829      }830    })831832    triggerEvent(vm.$refs.input, 'keydown', e => {833      e.keyCode = 32834    })835    expect(prevented).toBe(false)836    triggerEvent(vm.$refs.input, 'keydown', e => {837      e.keyCode = 13838    })839    expect(prevented).toBe(true)840  })841842  it('should transform click.right to contextmenu', () => {843    const spy = vi.fn()844    const vm = new Vue({845      template: `<div @click.right="foo"></div>`,846      methods: { foo: spy }847    }).$mount()848849    triggerEvent(vm.$el, 'contextmenu')850    expect(spy).toHaveBeenCalled()851  })852853  it('should transform click.middle to mouseup', () => {854    const spy = vi.fn()855    vm = new Vue({856      el,857      template: `<div @click.middle="foo"></div>`,858      methods: { foo: spy }859    })860    triggerEvent(vm.$el, 'mouseup', e => {861      e.button = 0862    })863    expect(spy).not.toHaveBeenCalled()864    triggerEvent(vm.$el, 'mouseup', e => {865      e.button = 1866    })867    expect(spy).toHaveBeenCalled()868  })869870  it('object syntax (no argument)', () => {871    const click = vi.fn()872    const mouseup = vi.fn()873    vm = new Vue({874      el,875      template: `<button v-on="listeners">foo</button>`,876      created() {877        this.listeners = {878          click,879          mouseup880        }881      }882    })883884    triggerEvent(vm.$el, 'click')885    expect(click.mock.calls.length).toBe(1)886    expect(mouseup.mock.calls.length).toBe(0)887888    triggerEvent(vm.$el, 'mouseup')889    expect(click.mock.calls.length).toBe(1)890    expect(mouseup.mock.calls.length).toBe(1)891  })892893  it('object syntax (no argument, mixed with normal listeners)', () => {894    const click1 = vi.fn()895    const click2 = vi.fn()896    const mouseup = vi.fn()897    vm = new Vue({898      el,899      template: `<button v-on="listeners" @click="click2">foo</button>`,900      created() {901        this.listeners = {902          click: click1,903          mouseup904        }905      },906      methods: {907        click2908      }909    })910911    triggerEvent(vm.$el, 'click')912    expect(click1.mock.calls.length).toBe(1)913    expect(click2.mock.calls.length).toBe(1)914    expect(mouseup.mock.calls.length).toBe(0)915916    triggerEvent(vm.$el, 'mouseup')917    expect(click1.mock.calls.length).toBe(1)918    expect(click2.mock.calls.length).toBe(1)919    expect(mouseup.mock.calls.length).toBe(1)920  })921922  it('object syntax (usage in HOC, mixed with native listeners)', () => {923    const click = vi.fn()924    const mouseup = vi.fn()925    const mousedown = vi.fn()926927    vm = new Vue({928      el,929      template: `930        <foo-button931          @click="click"932          @mousedown="mousedown"933          @mouseup.native="mouseup">934        </foo-button>935      `,936      methods: {937        click,938        mouseup,939        mousedown940      },941      components: {942        fooButton: {943          template: `944            <button v-on="$listeners"></button>945          `946        }947      }948    })949950    triggerEvent(vm.$el, 'click')951    expect(click.mock.calls.length).toBe(1)952    expect(mouseup.mock.calls.length).toBe(0)953    expect(mousedown.mock.calls.length).toBe(0)954955    triggerEvent(vm.$el, 'mouseup')956    expect(click.mock.calls.length).toBe(1)957    expect(mouseup.mock.calls.length).toBe(1)958    expect(mousedown.mock.calls.length).toBe(0)959960    triggerEvent(vm.$el, 'mousedown')961    expect(click.mock.calls.length).toBe(1)962    expect(mouseup.mock.calls.length).toBe(1)963    expect(mousedown.mock.calls.length).toBe(1)964  })965966  // #6805 (v-on="object" bind order problem)967  it('object syntax (no argument): should fire after high-priority listeners', done => {968    const MyCheckbox = {969      template: '<input type="checkbox" v-model="model" v-on="$listeners">',970      props: {971        value: false972      },973      computed: {974        model: {975          get() {976            return this.value977          },978          set(val) {979            this.$emit('input', val)980          }981        }982      }983    }984985    vm = new Vue({986      el,987      template: `988        <div>989          <my-checkbox v-model="check" @change="change"></my-checkbox>990        </div>991      `,992      components: { MyCheckbox },993      data: {994        check: false995      },996      methods: {997        change() {998          expect(this.check).toBe(true)999          done()1000        }1001      }1002    })10031004    vm.$el.querySelector('input').click()1005  })10061007  it('warn object syntax with modifier', () => {1008    new Vue({1009      template: `<button v-on.self="{}"></button>`1010    }).$mount()1011    expect(1012      `v-on without argument does not support modifiers`1013    ).toHaveBeenWarned()1014  })10151016  it('warn object syntax with non-object value', () => {1017    new Vue({1018      template: `<button v-on="123"></button>`1019    }).$mount()1020    expect(`v-on without argument expects an Object value`).toHaveBeenWarned()1021  })10221023  it('should correctly remove once listener', done => {1024    const vm = new Vue({1025      template: `1026        <div>1027          <span v-if="ok" @click.once="foo">1028            a1029          </span>1030          <span v-else a="a">1031            b1032          </span>1033        </div>1034      `,1035      data: {1036        ok: true1037      },1038      methods: {1039        foo: spy1040      }1041    }).$mount()10421043    vm.ok = false1044    waitForUpdate(() => {1045      triggerEvent(vm.$el.childNodes[0], 'click')1046      expect(spy.mock.calls.length).toBe(0)1047    }).then(done)1048  })10491050  // #76281051  it('handler should return the return value of inline function invocation', () => {1052    let value1053    new Vue({1054      template: `<test @foo="bar()"></test>`,1055      methods: {1056        bar() {1057          return 11058        }1059      },1060      components: {1061        test: {1062          created() {1063            value = this.$listeners.foo()1064          },1065          render(h) {1066            return h('div')1067          }1068        }1069      }1070    }).$mount()1071    expect(value).toBe(1)1072  })10731074  it('should not execute callback if modifiers are present', () => {1075    vm = new Vue({1076      el,1077      template: '<input @keyup.?="foo">',1078      methods: { foo: spy }1079    })1080    // simulating autocomplete event (Event object with type keyup but without keyCode)1081    triggerEvent(vm.$el, 'keyup')1082    expect(spy.mock.calls.length).toBe(0)1083  })10841085  describe('dynamic arguments', () => {1086    it('basic', done => {1087      const spy = vi.fn()1088      const vm = new Vue({1089        template: `<div v-on:[key]="spy"></div>`,1090        data: {1091          key: 'click'1092        },1093        methods: {1094          spy1095        }1096      }).$mount()1097      triggerEvent(vm.$el, 'click')1098      expect(spy.mock.calls.length).toBe(1)1099      vm.key = 'mouseup'1100      waitForUpdate(() => {1101        triggerEvent(vm.$el, 'click')1102        expect(spy.mock.calls.length).toBe(1)1103        triggerEvent(vm.$el, 'mouseup')1104        expect(spy.mock.calls.length).toBe(2)1105        // explicit null value1106        vm.key = null1107      })1108        .then(() => {1109          triggerEvent(vm.$el, 'click')1110          expect(spy.mock.calls.length).toBe(2)1111          triggerEvent(vm.$el, 'mouseup')1112          expect(spy.mock.calls.length).toBe(2)1113        })1114        .then(done)1115    })11161117    it('shorthand', done => {1118      const spy = vi.fn()1119      const vm = new Vue({1120        template: `<div @[key]="spy"></div>`,1121        data: {1122          key: 'click'1123        },1124        methods: {1125          spy1126        }1127      }).$mount()1128      triggerEvent(vm.$el, 'click')1129      expect(spy.mock.calls.length).toBe(1)1130      vm.key = 'mouseup'1131      waitForUpdate(() => {1132        triggerEvent(vm.$el, 'click')1133        expect(spy.mock.calls.length).toBe(1)1134        triggerEvent(vm.$el, 'mouseup')1135        expect(spy.mock.calls.length).toBe(2)1136      }).then(done)1137    })11381139    it('with .middle modifier', () => {1140      const spy = vi.fn()1141      const vm = new Vue({1142        template: `<div @[key].middle="spy"></div>`,1143        data: {1144          key: 'click'1145        },1146        methods: {1147          spy1148        }1149      }).$mount()1150      triggerEvent(vm.$el, 'mouseup', e => {1151        e.button = 01152      })1153      expect(spy).not.toHaveBeenCalled()1154      triggerEvent(vm.$el, 'mouseup', e => {1155        e.button = 11156      })1157      expect(spy).toHaveBeenCalled()1158    })11591160    it('with .right modifier', () => {1161      const spy = vi.fn()1162      const vm = new Vue({1163        template: `<div @[key].right="spy"></div>`,1164        data: {1165          key: 'click'1166        },1167        methods: {1168          spy1169        }1170      }).$mount()1171      triggerEvent(vm.$el, 'contextmenu')1172      expect(spy).toHaveBeenCalled()1173    })11741175    it('with .capture modifier', () => {1176      const callOrder: any[] = []1177      const vm = new Vue({1178        template: `1179          <div @[key].capture="foo">1180            <div @[key]="bar"></div>1181          </div>1182        `,1183        data: {1184          key: 'click'1185        },1186        methods: {1187          foo() {1188            callOrder.push(1)1189          },1190          bar() {1191            callOrder.push(2)1192          }1193        }1194      }).$mount()1195      triggerEvent(vm.$el.firstChild, 'click')1196      expect(callOrder.toString()).toBe('1,2')1197    })11981199    it('with .once modifier', () => {1200      const vm = new Vue({1201        template: `<div @[key].once="foo"></div>`,1202        data: { key: 'click' },1203        methods: { foo: spy }1204      }).$mount()1205      triggerEvent(vm.$el, 'click')1206      expect(spy.mock.calls.length).toBe(1)1207      triggerEvent(vm.$el, 'click')1208      expect(spy.mock.calls.length).toBe(1) // should no longer trigger1209    })1210  })1211})

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.