instance methods tests

This commit is contained in:
Evan You 2016-05-27 21:38:06 -04:00
parent f5bc3e584f
commit 20758d554f
6 changed files with 247 additions and 1 deletions

View File

@ -29,6 +29,7 @@ export function lifecycleMixin (Vue: Class<Component>) {
if (!vm.$options.render) {
vm.$options.render = () => emptyVNode
if (process.env.NODE_ENV !== 'production') {
/* istanbul ignore if */
if (vm.$options.template) {
warn(
'You are using the runtime-only build of Vue where the template ' +
@ -120,7 +121,7 @@ export function lifecycleMixin (Vue: Class<Component>) {
Vue.prototype.$destroy = function () {
const vm: Component = this
if (vm._isDestroyed) {
if (vm._isBeingDestroyed) {
return
}
callHook(vm, 'beforeDestroy')
@ -131,6 +132,9 @@ export function lifecycleMixin (Vue: Class<Component>) {
remove(parent.$children, vm)
}
// teardown watchers
if (vm._watcher) {
vm._watcher.teardown()
}
let i = vm._watchers.length
while (i--) {
vm._watchers[i].teardown()

View File

@ -0,0 +1,59 @@
import Vue from 'vue'
describe('Instance methods events', () => {
let vm, spy
beforeEach(() => {
vm = new Vue()
spy = jasmine.createSpy('emitter')
})
it('$on', () => {
vm.$on('test', function () {
// expect correct context
expect(this).toBe(vm)
spy.apply(this, arguments)
})
vm.$emit('test', 1, 2, 3, 4)
expect(spy.calls.count()).toBe(1)
expect(spy).toHaveBeenCalledWith(1, 2, 3, 4)
})
it('$once', () => {
vm.$once('test', spy)
vm.$emit('test', 1, 2, 3)
vm.$emit('test', 2, 3, 4)
expect(spy.calls.count()).toBe(1)
expect(spy).toHaveBeenCalledWith(1, 2, 3)
})
it('$off', () => {
vm.$on('test1', spy)
vm.$on('test2', spy)
vm.$off()
vm.$emit('test1')
vm.$emit('test2')
expect(spy).not.toHaveBeenCalled()
})
it('$off event', () => {
vm.$on('test1', spy)
vm.$on('test2', spy)
vm.$off('test1')
vm.$off('test1') // test off something that's already off
vm.$emit('test1', 1)
vm.$emit('test2', 2)
expect(spy.calls.count()).toBe(1)
expect(spy).toHaveBeenCalledWith(2)
})
it('$off event + fn', () => {
var spy2 = jasmine.createSpy('emitter')
vm.$on('test', spy)
vm.$on('test', spy2)
vm.$off('test', spy)
vm.$emit('test', 1, 2, 3)
expect(spy).not.toHaveBeenCalled()
expect(spy2.calls.count()).toBe(1)
expect(spy2).toHaveBeenCalledWith(1, 2, 3)
})
})

View File

@ -0,0 +1,113 @@
import Vue from 'vue'
describe('Instance methods lifecycle', () => {
describe('$mount', () => {
it('empty mount', () => {
const vm = new Vue({
data: { msg: 'hi' },
template: '<div>{{ msg }}</div>'
}).$mount()
expect(vm.$el.tagName).toBe('DIV')
expect(vm.$el.textContent).toBe('hi')
})
it('mount to existing element', () => {
const el = document.createElement('div')
el.innerHTML = '{{ msg }}'
const vm = new Vue({
data: { msg: 'hi' }
}).$mount(el)
expect(vm.$el.tagName).toBe('DIV')
expect(vm.$el.textContent).toBe('hi')
})
it('mount to id', () => {
const el = document.createElement('div')
el.id = 'mount-test'
el.innerHTML = '{{ msg }}'
document.body.appendChild(el)
const vm = new Vue({
data: { msg: 'hi' }
}).$mount('#mount-test')
expect(vm.$el.tagName).toBe('DIV')
expect(vm.$el.textContent).toBe('hi')
})
})
describe('$destroy', () => {
it('remove self from parent', () => {
const vm = new Vue({
template: '<test></test>',
components: {
test: { template: '<div></div>' }
}
}).$mount()
vm.$children[0].$destroy()
expect(vm.$children.length).toBe(0)
})
it('teardown watchers', () => {
const vm = new Vue({
data: { a: 123 },
template: '<div></div>'
}).$mount()
vm.$watch('a', () => {})
vm.$destroy()
expect(vm._watcher.active).toBe(false)
expect(vm._watchers.every(w => !w.active)).toBe(true)
})
it('remove self from data observer', () => {
const vm = new Vue({ data: { a: 1 }})
vm.$destroy()
expect(vm.$data.__ob__.vms.length).toBe(0)
})
it('avoid duplicate calls', () => {
const spy = jasmine.createSpy('destroy')
const vm = new Vue({
beforeDestroy: spy
})
vm.$destroy()
vm.$destroy()
expect(spy.calls.count()).toBe(1)
})
})
describe('$forceUpdate', () => {
it('should force update', done => {
const vm = new Vue({
data: {
a: {}
},
template: '<div>{{ a.b }}</div>'
}).$mount()
expect(vm.$el.textContent).toBe('')
vm.a.b = 'foo'
waitForUpdate(() => {
// should not work because adding new property
expect(vm.$el.textContent).toBe('')
vm.$forceUpdate()
}).then(() => {
expect(vm.$el.textContent).toBe('foo')
}).then(done)
})
})
describe('$nextTick', () => {
it('should be called after DOM update in correct context', done => {
const vm = new Vue({
template: '<div>{{ msg }}</div>',
data: {
msg: 'foo'
}
}).$mount()
vm.msg = 'bar'
vm.$nextTick(function () {
expect(this).toBe(vm)
expect(vm.$el.textContent).toBe('bar')
done()
})
})
})
})

View File

@ -0,0 +1,70 @@
import Vue from 'vue'
describe('Instance methods watch', () => {
let vm, spy
beforeEach(() => {
vm = new Vue({
data: {
a: {
b: 1
}
}
})
spy = jasmine.createSpy('watch')
})
it('basic usage', done => {
vm.$watch('a.b', spy)
vm.a.b = 2
waitForUpdate(() => {
expect(spy.calls.count()).toBe(1)
expect(spy).toHaveBeenCalledWith(2, 1)
vm.a = { b: 3 }
}).then(() => {
expect(spy.calls.count()).toBe(2)
expect(spy).toHaveBeenCalledWith(3, 2)
}).then(done)
})
it('immediate', () => {
vm.$watch('a.b', spy, { immediate: true })
expect(spy.calls.count()).toBe(1)
expect(spy).toHaveBeenCalledWith(1)
})
it('unwatch', done => {
const unwatch = vm.$watch('a.b', spy)
unwatch()
vm.a.b = 2
waitForUpdate(() => {
expect(spy.calls.count()).toBe(0)
}).then(done)
})
it('function watch', done => {
vm.$watch(function () {
return this.a.b
}, spy)
vm.a.b = 2
waitForUpdate(() => {
expect(spy).toHaveBeenCalledWith(2, 1)
}).then(done)
})
it('deep watch', done => {
var oldA = vm.a
vm.$watch('a', spy, { deep: true })
vm.a.b = 2
waitForUpdate(() => {
expect(spy).toHaveBeenCalledWith(oldA, oldA)
vm.a = { b: 3 }
}).then(() => {
expect(spy).toHaveBeenCalledWith(vm.a, oldA)
}).then(done)
})
it('warn expresssion', () => {
vm.$watch('a + b', spy)
expect('Watcher only accepts simple dot-delimited paths').toHaveBeenWarned()
})
})