mirror of https://github.com/vuejs/vue.git
392 lines
10 KiB
JavaScript
392 lines
10 KiB
JavaScript
var Vue = require('src')
|
|
var nextTick = Vue.nextTick
|
|
var Watcher = require('src/watcher')
|
|
var _ = Vue.util
|
|
var config = Vue.config
|
|
|
|
describe('Watcher', function () {
|
|
var vm, spy
|
|
beforeEach(function () {
|
|
vm = new Vue({
|
|
filters: {},
|
|
data: {
|
|
a: 1,
|
|
b: {
|
|
c: 2,
|
|
d: 4
|
|
},
|
|
c: 'c',
|
|
msg: 'yo'
|
|
}
|
|
})
|
|
spy = jasmine.createSpy('watcher')
|
|
})
|
|
|
|
it('simple path', function (done) {
|
|
var watcher = new Watcher(vm, 'b.c', spy)
|
|
expect(watcher.value).toBe(2)
|
|
vm.b.c = 3
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(3)
|
|
expect(spy).toHaveBeenCalledWith(3, 2)
|
|
vm.b = { c: 4 } // swapping the object
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(4)
|
|
expect(spy).toHaveBeenCalledWith(4, 3)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('bracket access path', function (done) {
|
|
var watcher = new Watcher(vm, 'b["c"]', spy)
|
|
expect(watcher.value).toBe(2)
|
|
vm.b.c = 3
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(3)
|
|
expect(spy).toHaveBeenCalledWith(3, 2)
|
|
vm.b = { c: 4 } // swapping the object
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(4)
|
|
expect(spy).toHaveBeenCalledWith(4, 3)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('dynamic path', function (done) {
|
|
var watcher = new Watcher(vm, 'b[c]', spy)
|
|
expect(watcher.value).toBe(2)
|
|
vm.b.c = 3
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(3)
|
|
expect(spy).toHaveBeenCalledWith(3, 2)
|
|
vm.c = 'd' // changing the dynamic segment in path
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(4)
|
|
expect(spy).toHaveBeenCalledWith(4, 3)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('simple expression', function (done) {
|
|
var watcher = new Watcher(vm, 'a + b.c', spy)
|
|
expect(watcher.value).toBe(3)
|
|
vm.b.c = 3
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(4)
|
|
expect(spy.calls.count()).toBe(1)
|
|
expect(spy).toHaveBeenCalledWith(4, 3)
|
|
// change two dependencies at once
|
|
vm.a = 2
|
|
vm.b.c = 4
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(6)
|
|
// should trigger only once callback,
|
|
// because it was in the same event loop.
|
|
expect(spy.calls.count()).toBe(2)
|
|
expect(spy).toHaveBeenCalledWith(6, 4)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('ternary expression', function (done) {
|
|
// we're actually testing for the dependency re-calculation here
|
|
var watcher = new Watcher(vm, 'a > 1 ? b.c : b.d', spy)
|
|
expect(watcher.value).toBe(4)
|
|
vm.a = 2
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(2)
|
|
expect(spy).toHaveBeenCalledWith(2, 4)
|
|
vm.b.c = 3
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(3)
|
|
expect(spy).toHaveBeenCalledWith(3, 2)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('meta properties', function (done) {
|
|
_.defineReactive(vm, '$index', 1)
|
|
var watcher = new Watcher(vm, '$index + 1', spy)
|
|
expect(watcher.value).toBe(2)
|
|
vm.$index = 2
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(3)
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('non-existent path, set later', function (done) {
|
|
var watcher = new Watcher(vm, 'd.e', spy)
|
|
var watcher2 = new Watcher(vm, 'b.e', spy)
|
|
expect(watcher.value).toBeUndefined()
|
|
expect(watcher2.value).toBeUndefined()
|
|
// check $add should not affect isolated children
|
|
var child2 = new Vue({ parent: vm })
|
|
var watcher3 = new Watcher(child2, 'd.e', spy)
|
|
expect(watcher3.value).toBeUndefined()
|
|
vm.$set('d', { e: 123 })
|
|
_.set(vm.b, 'e', 234)
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(123)
|
|
expect(watcher2.value).toBe(234)
|
|
expect(watcher3.value).toBeUndefined()
|
|
expect(spy.calls.count()).toBe(2)
|
|
expect(spy).toHaveBeenCalledWith(123, undefined)
|
|
expect(spy).toHaveBeenCalledWith(234, undefined)
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('$delete', function (done) {
|
|
var watcher = new Watcher(vm, 'b.c', spy)
|
|
expect(watcher.value).toBe(2)
|
|
vm.$delete('b')
|
|
nextTick(function () {
|
|
expect(watcher.value).toBeUndefined()
|
|
expect(spy).toHaveBeenCalledWith(undefined, 2)
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('swapping $data', function (done) {
|
|
// existing path
|
|
var watcher = new Watcher(vm, 'b.c', spy)
|
|
var spy2 = jasmine.createSpy()
|
|
// non-existing path
|
|
var watcher2 = new Watcher(vm, 'e', spy2)
|
|
expect(watcher.value).toBe(2)
|
|
expect(watcher2.value).toBeUndefined()
|
|
vm.$data = { b: { c: 3 }, e: 4 }
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(3)
|
|
expect(watcher2.value).toBe(4)
|
|
expect(spy).toHaveBeenCalledWith(3, 2)
|
|
expect(spy2).toHaveBeenCalledWith(4, undefined)
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('path containing $data', function (done) {
|
|
var watcher = new Watcher(vm, '$data.b.c', spy)
|
|
expect(watcher.value).toBe(2)
|
|
vm.b = { c: 3 }
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(3)
|
|
expect(spy).toHaveBeenCalledWith(3, 2)
|
|
vm.$data = { b: { c: 4 }}
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(4)
|
|
expect(spy).toHaveBeenCalledWith(4, 3)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('watching $data', function (done) {
|
|
var oldData = vm.$data
|
|
var watcher = new Watcher(vm, '$data', spy)
|
|
expect(watcher.value).toBe(oldData)
|
|
var newData = {}
|
|
vm.$data = newData
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(newData, oldData)
|
|
expect(watcher.value).toBe(newData)
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('filters', function (done) {
|
|
vm.$options.filters.test = function (val, multi) {
|
|
return val * multi
|
|
}
|
|
vm.$options.filters.test2 = function (val, str) {
|
|
return val + str
|
|
}
|
|
var watcher = new Watcher(vm, 'b.c', spy, {
|
|
filters: [
|
|
{ name: 'test', args: [{ value: 3, dynamic: false }] },
|
|
{ name: 'test2', args: [{ value: 'msg', dynamic: true }] }
|
|
]
|
|
})
|
|
expect(watcher.value).toBe('6yo')
|
|
vm.b.c = 3
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe('9yo')
|
|
expect(spy).toHaveBeenCalledWith('9yo', '6yo')
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('setter', function (done) {
|
|
vm.$options.filters.test = {
|
|
write: function (val, oldVal, arg) {
|
|
return val > arg ? val : oldVal
|
|
}
|
|
}
|
|
var watcher = new Watcher(vm, 'b["c"]', spy, {
|
|
filters: [
|
|
{ name: 'test', args: [{value: 5, dynamic: false}] }
|
|
],
|
|
twoWay: true
|
|
})
|
|
expect(watcher.value).toBe(2)
|
|
watcher.set(4) // shoud not change the value
|
|
nextTick(function () {
|
|
expect(vm.b.c).toBe(2)
|
|
expect(watcher.value).toBe(2)
|
|
expect(spy).not.toHaveBeenCalled()
|
|
watcher.set(6)
|
|
nextTick(function () {
|
|
expect(vm.b.c).toBe(6)
|
|
expect(watcher.value).toBe(6)
|
|
expect(spy).toHaveBeenCalledWith(6, 2)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('set non-existent values', function (done) {
|
|
var watcher = new Watcher(vm, 'd.e.f', spy, {
|
|
twoWay: true
|
|
})
|
|
expect(watcher.value).toBeUndefined()
|
|
watcher.set(123)
|
|
nextTick(function () {
|
|
expect(vm.d.e.f).toBe(123)
|
|
expect(watcher.value).toBe(123)
|
|
expect(spy).toHaveBeenCalledWith(123, undefined)
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('deep watch', function (done) {
|
|
new Watcher(vm, 'b', spy, {
|
|
deep: true
|
|
})
|
|
vm.b.c = { d: 4 }
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
|
|
var oldB = vm.b
|
|
vm.b = { c: [{ a: 1 }]}
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(vm.b, oldB)
|
|
expect(spy.calls.count()).toBe(2)
|
|
vm.b.c[0].a = 2
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
|
|
expect(spy.calls.count()).toBe(3)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
it('deep watch with circular references', function (done) {
|
|
new Watcher(vm, 'b', spy, {
|
|
deep: true
|
|
})
|
|
Vue.set(vm.b, '_', vm.b)
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
|
|
expect(spy.calls.count()).toBe(1)
|
|
vm.b._.c = 1
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
|
|
expect(spy.calls.count()).toBe(2)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('fire change for prop addition/deletion in non-deep mode', function (done) {
|
|
new Watcher(vm, 'b', spy)
|
|
Vue.set(vm.b, 'e', 123)
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(vm.b, vm.b)
|
|
expect(spy.calls.count()).toBe(1)
|
|
Vue.delete(vm.b, 'e')
|
|
nextTick(function () {
|
|
expect(spy.calls.count()).toBe(2)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('watch function', function (done) {
|
|
var watcher = new Watcher(vm, function () {
|
|
return this.a + this.b.d
|
|
}, spy)
|
|
expect(watcher.value).toBe(5)
|
|
vm.a = 2
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(6, 5)
|
|
vm.b = { d: 2 }
|
|
nextTick(function () {
|
|
expect(spy).toHaveBeenCalledWith(4, 6)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
it('lazy mode', function (done) {
|
|
var watcher = new Watcher(vm, function () {
|
|
return this.a + this.b.d
|
|
}, null, { lazy: true })
|
|
expect(watcher.lazy).toBe(true)
|
|
expect(watcher.value).toBeUndefined()
|
|
expect(watcher.dirty).toBe(true)
|
|
watcher.evaluate()
|
|
expect(watcher.value).toBe(5)
|
|
expect(watcher.dirty).toBe(false)
|
|
vm.a = 2
|
|
nextTick(function () {
|
|
expect(watcher.value).toBe(5)
|
|
expect(watcher.dirty).toBe(true)
|
|
watcher.evaluate()
|
|
expect(watcher.value).toBe(6)
|
|
expect(watcher.dirty).toBe(false)
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('teardown', function (done) {
|
|
var watcher = new Watcher(vm, 'b.c', spy)
|
|
watcher.teardown()
|
|
vm.b.c = 3
|
|
nextTick(function () {
|
|
expect(watcher.active).toBe(false)
|
|
expect(watcher.vm).toBe(null)
|
|
expect(watcher.cb).toBe(null)
|
|
expect(spy).not.toHaveBeenCalled()
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('synchronous updates', function () {
|
|
config.async = false
|
|
new Watcher(vm, 'a', spy)
|
|
vm.a = 2
|
|
vm.a = 3
|
|
expect(spy.calls.count()).toBe(2)
|
|
expect(spy).toHaveBeenCalledWith(2, 1)
|
|
expect(spy).toHaveBeenCalledWith(3, 2)
|
|
config.async = true
|
|
})
|
|
|
|
it('warn getter errors', function () {
|
|
new Watcher(vm, 'd.e + c', spy)
|
|
expect('Error when evaluating expression').toHaveBeenWarned()
|
|
})
|
|
|
|
it('warn setter errors', function () {
|
|
var watcher = new Watcher(vm, 'a + b', spy)
|
|
watcher.set(123)
|
|
expect('Error when evaluating setter').toHaveBeenWarned()
|
|
})
|
|
})
|