Skip to content

Commit 7149c05

Browse files
wthoeddyerburgh
authored andcommitted
fix: event capturing in beforeCreate lifecycle hook (#243)
* Fix event capture by installing captor via mixin The event capture was not working when events were emitted in methods during the component creation, like in the lifecycle hook beforeCreate. This fix installs the captor using a mixin before the beforeCreate event gets emitted. The captor is available to the wrapper, when the wrapper accesses the vue component. Two tests were written, in emitted.spec, and emittedByOrder, respectively. * Adjust emitted tests to pass tested Vue versions * Use component field for event capturing Instead of using an external object, this.__emitted and this.__emittedByOrder is now used to capture events. This allows the wrapper to access the event logger of the component. The installed event logger is never removed and therefore will exist even after the wrapper was created.
1 parent 790a949 commit 7149c05

File tree

5 files changed

+106
-11
lines changed

5 files changed

+106
-11
lines changed

src/lib/create-instance.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import addMocks from './add-mocks'
55
import addAttrs from './add-attrs'
66
import addListeners from './add-listeners'
77
import addProvide from './add-provide'
8+
import { addEventLogger } from './log-events'
89
import { stubComponents } from './stub-components'
910
import { throwError } from './util'
1011
import { compileTemplate } from './compile-template'
@@ -45,6 +46,8 @@ export default function createConstructor (
4546
compileTemplate(component)
4647
}
4748

49+
addEventLogger(vue)
50+
4851
const Constructor = vue.extend(component)
4952

5053
const instanceOptions = { ...options }

src/lib/log-events.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1-
export function logEvents (vm, emitted, emittedByOrder) {
1+
// @flow
2+
3+
export function logEvents (vm: Component, emitted: Object, emittedByOrder: Array<any>) {
24
const emit = vm.$emit
35
vm.$emit = (name, ...args) => {
46
(emitted[name] || (emitted[name] = [])).push(args)
57
emittedByOrder.push({ name, args })
68
return emit.call(vm, name, ...args)
79
}
810
}
11+
12+
export function addEventLogger (vue: Component) {
13+
vue.mixin({
14+
beforeCreate: function () {
15+
this.__emitted = Object.create(null)
16+
this.__emittedByOrder = []
17+
logEvents(this, this.__emitted, this.__emittedByOrder)
18+
}
19+
})
20+
}

src/wrappers/vue-wrapper.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// @flow
22

33
import Wrapper from './wrapper'
4-
import { logEvents } from '../lib/log-events'
54

65
function update () {
76
this._update(this._render())
@@ -24,9 +23,7 @@ export default class VueWrapper extends Wrapper implements BaseWrapper {
2423
}))
2524
this.vm = vm
2625
this.isVueComponent = true
27-
this._emitted = Object.create(null)
28-
this._emittedByOrder = []
29-
30-
logEvents(vm, this._emitted, this._emittedByOrder)
26+
this._emitted = vm.__emitted
27+
this._emittedByOrder = vm.__emittedByOrder
3128
}
3229
}

test/unit/specs/mount/Wrapper/emitted.spec.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import mount from '~src/mount'
2+
import createLocalVue from '~src/create-local-vue'
23

34
describe('emitted', () => {
45
it('captures emitted events with a different api', () => {
@@ -54,4 +55,39 @@ describe('emitted', () => {
5455
const fn = () => wrapper.find('p').emitted()
5556
expect(fn).to.throw().with.property('message', message)
5657
})
58+
59+
it('captures all events thrown after beforeCreate lifecycle hook', () => {
60+
const wrapper = mount({
61+
beforeCreate () {
62+
this.$emit('foo')
63+
},
64+
mounted () {
65+
this.$emit('bar', 1, 2)
66+
}
67+
})
68+
69+
expect(wrapper.emitted().foo).to.eql([[]])
70+
expect(wrapper.emitted().bar).to.eql([[1, 2]])
71+
})
72+
73+
it('captures only events from its component without side effects on localVue', () => {
74+
const localVue = createLocalVue()
75+
76+
const wrapper1 = mount({
77+
beforeCreate () {
78+
this.$emit('foo')
79+
}
80+
}, { localVue })
81+
82+
const wrapper2 = mount({
83+
mounted () {
84+
this.$emit('bar')
85+
}
86+
}, { localVue })
87+
88+
expect(wrapper1.emitted().foo).to.eql([[]])
89+
expect(wrapper1.emitted().bar).to.eql(undefined)
90+
expect(wrapper2.emitted().foo).to.eql(undefined)
91+
expect(wrapper2.emitted().bar).to.eql([[]])
92+
})
5793
})

test/unit/specs/mount/Wrapper/emittedByOrder.spec.js

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import mount from '~src/mount'
2+
import Vue from 'vue'
23

34
describe('emittedByOrder', () => {
45
it('captures emitted events in order', () => {
@@ -9,11 +10,24 @@ describe('emittedByOrder', () => {
910
wrapper.vm.$emit('foo')
1011
wrapper.vm.$emit('bar', 1, 2, 3)
1112
wrapper.vm.$emit('foo', 2, 3, 4)
12-
expect(wrapper.emittedByOrder()).to.eql([
13-
{ name: 'foo', args: [] },
14-
{ name: 'bar', args: [1, 2, 3] },
15-
{ name: 'foo', args: [2, 3, 4] }
16-
])
13+
14+
if (Vue.version === '2.0.8') {
15+
expect(wrapper.emittedByOrder()).to.eql([
16+
{ name: 'hook:beforeCreate', args: [] },
17+
{ name: 'hook:created', args: [] },
18+
{ name: 'hook:beforeMount', args: [] },
19+
{ name: 'hook:mounted', args: [] },
20+
{ name: 'foo', args: [] },
21+
{ name: 'bar', args: [1, 2, 3] },
22+
{ name: 'foo', args: [2, 3, 4] }
23+
])
24+
} else {
25+
expect(wrapper.emittedByOrder()).to.eql([
26+
{ name: 'foo', args: [] },
27+
{ name: 'bar', args: [1, 2, 3] },
28+
{ name: 'foo', args: [2, 3, 4] }
29+
])
30+
}
1731
})
1832

1933
it('throws error when called on non VueWrapper', () => {
@@ -25,4 +39,37 @@ describe('emittedByOrder', () => {
2539
const fn = () => wrapper.find('p').emittedByOrder()
2640
expect(fn).to.throw().with.property('message', message)
2741
})
42+
43+
it('captures in lifecycle hooks emitted events in order', () => {
44+
const wrapper = mount({
45+
render: h => h('div'),
46+
beforeCreate: function () {
47+
this.$emit('foo')
48+
},
49+
created: function () {
50+
this.$emit('bar', 1, 2, 3)
51+
},
52+
mounted: function () {
53+
this.$emit('foo', 2, 3, 4)
54+
}
55+
})
56+
57+
if (Vue.version === '2.0.8') {
58+
expect(wrapper.emittedByOrder()).to.eql([
59+
{ name: 'foo', args: [] },
60+
{ name: 'hook:beforeCreate', args: [] },
61+
{ name: 'bar', args: [1, 2, 3] },
62+
{ name: 'hook:created', args: [] },
63+
{ name: 'hook:beforeMount', args: [] },
64+
{ name: 'foo', args: [2, 3, 4] },
65+
{ name: 'hook:mounted', args: [] }
66+
])
67+
} else {
68+
expect(wrapper.emittedByOrder()).to.eql([
69+
{ name: 'foo', args: [] },
70+
{ name: 'bar', args: [1, 2, 3] },
71+
{ name: 'foo', args: [2, 3, 4] }
72+
])
73+
}
74+
})
2875
})

0 commit comments

Comments
 (0)