vue2/test/unit/specs/viewmodel.js

561 lines
16 KiB
JavaScript
Raw Permalink Normal View History

describe('ViewModel', function () {
2013-09-11 06:57:47 +08:00
var nextTick = require('vue/src/utils').nextTick
2013-09-11 06:57:47 +08:00
mock('vm-test', '{{a.b.c}}')
var data = {
b: {
c: 12345
}
},
arr = [1, 2, 3],
2014-03-21 03:29:32 +08:00
parentVM = new Vue({
data: { fromParent: 'hello' }
}),
2013-12-08 06:29:17 +08:00
vm = new Vue({
2013-10-03 06:14:29 +08:00
el: '#vm-test',
2014-03-21 03:29:32 +08:00
parent: parentVM,
data: {
2013-09-11 06:57:47 +08:00
a: data,
b: arr
}
})
2014-03-07 03:05:21 +08:00
describe('.$get()', function () {
2014-03-21 03:29:32 +08:00
it('should get correct value', function () {
2014-03-07 03:05:21 +08:00
var v = vm.$get('a.b.c')
assert.strictEqual(v, 12345)
})
2014-03-21 03:29:32 +08:00
it('should recursively get value from parents', function () {
var v = vm.$get('fromParent')
assert.strictEqual(v, 'hello')
})
2014-03-07 03:05:21 +08:00
})
2013-09-11 06:57:47 +08:00
describe('.$set()', function () {
it('should set correct value', function () {
2014-03-07 03:05:21 +08:00
vm.$set('a.b.c', 54321)
2013-09-11 06:57:47 +08:00
assert.strictEqual(data.b.c, 54321)
})
})
describe('.$watch()', function () {
it('should trigger callback when a plain value changes', function (done) {
2013-09-11 06:57:47 +08:00
var val
vm.$watch('a.b.c', function (newVal) {
val = newVal
2013-09-11 06:57:47 +08:00
})
data.b.c = 'new value!'
nextTick(function () {
assert.strictEqual(val, data.b.c)
done()
})
2013-09-11 06:57:47 +08:00
})
it('should trigger callback when an object value changes', function (done) {
2013-09-11 06:57:47 +08:00
var val, subVal, rootVal,
target = { c: 'hohoho' }
vm.$watch('a.b', function (newVal) {
val = newVal
})
vm.$watch('a.b.c', function (newVal) {
subVal = newVal
})
vm.$watch('a', function (newVal) {
rootVal = newVal
})
2013-09-11 06:57:47 +08:00
data.b = target
nextTick(function () {
assert.strictEqual(val, target)
assert.strictEqual(subVal, target.c)
next()
})
function next () {
vm.a = 'hehehe'
nextTick(function () {
assert.strictEqual(rootVal, 'hehehe')
done()
})
}
2013-09-11 06:57:47 +08:00
})
it('should trigger callback when an array mutates', function (done) {
2013-09-11 06:57:47 +08:00
var val, mut
vm.$watch('b', function (array, mutation) {
val = array
mut = mutation
})
arr.push(4)
nextTick(function () {
assert.strictEqual(val, arr)
assert.strictEqual(mut.method, 'push')
assert.strictEqual(mut.args.length, 1)
assert.strictEqual(mut.args[0], 4)
done()
})
2013-09-11 06:57:47 +08:00
})
it('should batch mutiple changes in a single event loop', function (done) {
var callbackCount = 0,
gotVal,
finalValue = { b: { c: 3} },
vm = new Vue({
data: {
a: { b: { c: 0 }}
}
})
vm.$watch('a', function (newVal) {
callbackCount++
gotVal = newVal
})
vm.a.b.c = 1
vm.a.b = { c: 2 }
vm.a = finalValue
nextTick(function () {
assert.strictEqual(callbackCount, 1)
assert.strictEqual(gotVal, finalValue)
done()
})
})
2013-09-11 06:57:47 +08:00
})
describe('.$unwatch()', function () {
it('should unwatch the stuff', function (done) {
2013-09-11 06:57:47 +08:00
var triggered = false
vm.$watch('a.b.c', function () {
2013-09-11 06:57:47 +08:00
triggered = true
})
vm.$watch('a', function () {
2013-09-11 06:57:47 +08:00
triggered = true
})
vm.$watch('b', function () {
2013-09-11 06:57:47 +08:00
triggered = true
})
vm.$unwatch('a')
vm.$unwatch('b')
vm.$unwatch('a.b.c')
vm.a = { b: { c:123123 }}
vm.b.push(5)
nextTick(function () {
assert.notOk(triggered)
done()
})
2013-09-11 06:57:47 +08:00
})
})
2013-10-09 11:19:12 +08:00
describe('.$on', function () {
it('should register listener on vm\'s compiler\'s emitter', function () {
2013-12-08 06:29:17 +08:00
var t = new Vue(),
2013-10-09 11:19:12 +08:00
triggered = false,
msg = 'on test'
t.$on('test', function (m) {
assert.strictEqual(m, msg)
triggered = true
})
t.$compiler.emitter.emit('test', msg)
assert.ok(triggered)
})
})
2013-10-18 00:19:58 +08:00
describe('.$once', function () {
it('should invoke the listener only once', function () {
2013-12-08 06:29:17 +08:00
var t = new Vue(),
2013-10-18 00:19:58 +08:00
triggered = 0,
msg = 'on once'
t.$once('test', function (m) {
assert.strictEqual(m, msg)
triggered++
})
t.$compiler.emitter.emit('test', msg)
t.$compiler.emitter.emit('test', msg)
assert.strictEqual(triggered, 1)
})
})
2013-10-09 11:19:12 +08:00
describe('$off', function () {
it('should turn off the listener', function () {
2013-12-08 06:29:17 +08:00
var t = new Vue(),
2013-10-09 11:19:12 +08:00
triggered1 = false,
triggered2 = false,
f1 = function () {
triggered1 = true
},
f2 = function () {
triggered2 = true
}
t.$on('test', f1)
t.$on('test', f2)
t.$off('test', f1)
t.$compiler.emitter.emit('test')
assert.notOk(triggered1)
assert.ok(triggered2)
})
})
describe('$emit', function () {
it('should trigger the event', function () {
var t = new Vue(),
triggered = false
t.$compiler.emitter.on('test', function (m) {
triggered = m
})
t.$emit('test', 'hi')
assert.strictEqual(triggered, 'hi')
})
})
2013-10-09 11:19:12 +08:00
describe('.$broadcast()', function () {
it('should notify all child VMs', function () {
var triggered = 0,
msg = 'broadcast test'
2013-12-08 06:29:17 +08:00
var Child = Vue.extend({
2013-12-17 14:38:01 +08:00
ready: function () {
2013-10-09 11:19:12 +08:00
this.$on('hello', function (m) {
assert.strictEqual(m, msg)
triggered++
})
}
})
2013-12-08 06:29:17 +08:00
var Test = Vue.extend({
template: '<div v-component="test"></div><div v-component="test"></div>',
components: {
2013-10-09 11:19:12 +08:00
test: Child
}
})
var t = new Test()
t.$broadcast('hello', msg)
assert.strictEqual(triggered, 2)
})
})
describe('.$dispatch', function () {
2013-10-09 11:19:12 +08:00
it('should notify all ancestor VMs', function (done) {
var topTriggered = false,
midTriggered = false,
msg = 'emit test'
2013-12-08 06:29:17 +08:00
var Bottom = Vue.extend({
2013-12-17 14:38:01 +08:00
ready: function () {
2013-10-09 11:19:12 +08:00
var self = this
nextTick(function () {
self.$dispatch('hello', msg)
2013-10-09 11:19:12 +08:00
assert.ok(topTriggered)
assert.ok(midTriggered)
done()
})
2013-10-09 11:19:12 +08:00
}
})
2013-12-08 06:29:17 +08:00
var Middle = Vue.extend({
template: '<div v-component="bottom"></div>',
components: { bottom: Bottom },
2013-12-17 14:38:01 +08:00
ready: function () {
2013-10-09 11:19:12 +08:00
this.$on('hello', function (m) {
assert.strictEqual(m, msg)
midTriggered = true
})
}
})
2013-12-08 06:29:17 +08:00
var Top = Vue.extend({
template: '<div v-component="middle"></div>',
components: { middle: Middle },
2013-12-17 14:38:01 +08:00
ready: function () {
2013-10-09 11:19:12 +08:00
this.$on('hello', function (m) {
assert.strictEqual(m, msg)
topTriggered = true
})
}
})
new Top()
2013-10-09 11:19:12 +08:00
})
})
2013-12-19 13:34:59 +08:00
describe('DOM methods', function () {
var enterCalled,
2013-12-21 00:33:48 +08:00
leaveCalled,
2013-12-24 15:03:01 +08:00
callbackCalled
2013-12-19 13:34:59 +08:00
var v = new Vue({
attributes: {
2014-02-25 03:57:27 +08:00
'v-effect': 'test'
2013-12-19 13:34:59 +08:00
},
2014-02-25 03:57:27 +08:00
effects: {
2013-12-19 13:34:59 +08:00
test: {
enter: function (el, change) {
enterCalled = true
change()
},
leave: function (el, change) {
leaveCalled = true
change()
}
}
}
2013-12-18 23:36:24 +08:00
})
2013-12-19 13:34:59 +08:00
function reset () {
enterCalled = false
leaveCalled = false
2013-12-21 00:33:48 +08:00
callbackCalled = false
}
function cb () {
callbackCalled = true
2013-12-19 13:34:59 +08:00
}
2013-12-21 00:57:46 +08:00
it('$appendTo', function (done) {
2013-12-19 13:34:59 +08:00
reset()
var parent = document.createElement('div')
2013-12-21 00:33:48 +08:00
v.$appendTo(parent, cb)
2013-12-19 13:34:59 +08:00
assert.strictEqual(v.$el.parentNode, parent)
assert.ok(enterCalled)
nextTick(function () {
2013-12-21 00:57:46 +08:00
assert.ok(callbackCalled)
done()
})
2013-12-18 23:36:24 +08:00
})
2013-12-21 00:57:46 +08:00
it('$before', function (done) {
2013-12-19 13:34:59 +08:00
reset()
var parent = document.createElement('div'),
ref = document.createElement('div')
parent.appendChild(ref)
2013-12-21 00:33:48 +08:00
v.$before(ref, cb)
2013-12-19 13:34:59 +08:00
assert.strictEqual(v.$el.parentNode, parent)
assert.strictEqual(v.$el.nextSibling, ref)
assert.ok(enterCalled)
nextTick(function () {
2013-12-21 00:57:46 +08:00
assert.ok(callbackCalled)
done()
})
2013-12-18 23:36:24 +08:00
})
2013-12-21 00:57:46 +08:00
it('$after', function (done) {
2013-12-19 13:34:59 +08:00
reset()
var parent = document.createElement('div'),
ref1 = document.createElement('div'),
ref2 = document.createElement('div')
parent.appendChild(ref1)
parent.appendChild(ref2)
2013-12-21 00:33:48 +08:00
v.$after(ref1, cb)
2013-12-19 13:34:59 +08:00
assert.strictEqual(v.$el.parentNode, parent)
assert.strictEqual(v.$el.nextSibling, ref2)
assert.strictEqual(ref1.nextSibling, v.$el)
assert.ok(enterCalled)
nextTick(function () {
2013-12-21 00:57:46 +08:00
assert.ok(callbackCalled)
next()
})
2013-12-21 00:57:46 +08:00
function next () {
reset()
v.$after(ref2, cb)
assert.strictEqual(v.$el.parentNode, parent)
assert.notOk(v.$el.nextSibling)
assert.strictEqual(ref2.nextSibling, v.$el)
assert.ok(enterCalled)
nextTick(function () {
2013-12-21 00:57:46 +08:00
assert.ok(callbackCalled)
done()
})
2013-12-21 00:57:46 +08:00
}
2013-12-18 23:36:24 +08:00
})
2013-12-19 13:34:59 +08:00
2013-12-21 00:57:46 +08:00
it('$remove', function (done) {
2013-12-19 13:34:59 +08:00
reset()
var parent = document.createElement('div')
v.$appendTo(parent)
2013-12-21 00:33:48 +08:00
v.$remove(cb)
2013-12-19 13:34:59 +08:00
assert.notOk(v.$el.parentNode)
assert.ok(enterCalled)
assert.ok(leaveCalled)
nextTick(function () {
2013-12-21 00:57:46 +08:00
assert.ok(callbackCalled)
done()
})
2013-12-19 13:34:59 +08:00
})
2013-12-18 23:36:24 +08:00
})
describe('.$destroy', function () {
// since this simply delegates to Compiler.prototype.destroy(),
// that's what we are actually testing here.
2013-12-08 06:29:17 +08:00
var destroy = require('vue/src/compiler').prototype.destroy
2013-12-17 14:38:01 +08:00
var beforeDestroyCalled = false,
afterDestroyCalled = false,
observerOffCalled = false,
emitterOffCalled = false,
dirUnbindCalled = false,
expUnbindCalled = false,
bindingUnbindCalled = false,
unobserveCalled = false,
2014-03-22 08:35:39 +08:00
elRemoved = false
var dirMock = {
binding: {
compiler: null,
dirs: []
},
$unbind: function () {
dirUnbindCalled = true
}
}
dirMock.binding.dirs.push(dirMock)
var bindingsMock = {
test: {
root: true,
key: 'test',
unbind: function () {
bindingUnbindCalled = true
}
}
}
var compilerMock = {
2014-03-22 08:35:39 +08:00
el: document.createElement('div'),
options: {
2013-12-17 14:38:01 +08:00
beforeDestroy: function () {
beforeDestroyCalled = true
},
afterDestroy: function () {
afterDestroyCalled = true
}
},
data: {
__emitter__: {
off: function () {
unobserveCalled = true
return this
}
}
},
observer: {
off: function () {
observerOffCalled = true
},
proxies: {
'test.': {},
'': {}
}
},
emitter: {
off: function () {
emitterOffCalled = true
}
},
dirs: [dirMock],
2014-03-13 05:45:33 +08:00
computed: [{
unbind: function () {
expUnbindCalled = true
}
}],
bindings: bindingsMock,
childId: 'test',
2014-03-01 00:12:23 +08:00
children: [],
2014-02-28 22:41:26 +08:00
parent: {
children: []
},
2013-12-18 14:36:58 +08:00
vm: {
$remove: function () {
elRemoved = true
}
2013-12-18 23:04:55 +08:00
},
execHook: function (id) {
this.options[id].call(this)
}
}
2014-03-01 00:12:23 +08:00
compilerMock.parent.children.push(compilerMock)
destroy.call(compilerMock)
2013-12-17 14:38:01 +08:00
it('should call the pre and post destroy hooks', function () {
assert.ok(beforeDestroyCalled)
assert.ok(afterDestroyCalled)
})
it('should turn observer and emitter off', function () {
assert.ok(observerOffCalled)
assert.ok(emitterOffCalled)
})
it('should unobserve the data', function () {
assert.ok(unobserveCalled)
})
it('should unbind all directives', function () {
assert.ok(dirUnbindCalled)
})
it('should remove directives from external bindings', function () {
assert.strictEqual(dirMock.binding.dirs.indexOf(dirMock), -1)
})
it('should unbind all expressions', function () {
assert.ok(expUnbindCalled)
})
it('should unbind and unobserve own bindings', function () {
assert.ok(bindingUnbindCalled)
})
2014-02-28 22:41:26 +08:00
it('should remove self from parent', function () {
var parent = compilerMock.parent
2014-03-01 00:12:23 +08:00
assert.ok(parent.children.indexOf(compilerMock), -1)
})
it('should remove the dom element', function () {
assert.ok(elRemoved)
})
})
2013-12-31 01:04:55 +08:00
describe('$data', function () {
it('should be the same data', function () {
var data = {},
vm = new Vue({data:data})
assert.strictEqual(vm.$data, data)
})
it('should be able to be swapped', function (done) {
2013-12-31 01:04:55 +08:00
var data1 = { a: 1 },
data2 = { a: 2 },
vm = new Vue({data: data1}),
emittedChange = false
vm.$watch('a', function (v) {
assert.equal(v, 2)
emittedChange = true
})
vm.$data = data2
assert.equal(vm.a, 2)
nextTick(function () {
assert.ok(emittedChange)
done()
})
2013-12-31 01:04:55 +08:00
})
})
2013-09-10 06:04:33 +08:00
})