2013-09-10 06:04:33 +08:00
|
|
|
describe('UNIT: ViewModel', function () {
|
2013-09-11 06:57:47 +08:00
|
|
|
|
2013-12-25 04:34:22 +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],
|
2013-12-08 06:29:17 +08:00
|
|
|
vm = new Vue({
|
2013-10-03 06:14:29 +08:00
|
|
|
el: '#vm-test',
|
2013-12-24 03:47:51 +08:00
|
|
|
data: {
|
2013-09-11 06:57:47 +08:00
|
|
|
a: data,
|
|
|
|
b: arr
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('.$set()', function () {
|
|
|
|
vm.$set('a.b.c', 54321)
|
|
|
|
it('should set correct value', function () {
|
|
|
|
assert.strictEqual(data.b.c, 54321)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('.$watch()', function () {
|
|
|
|
|
|
|
|
it('should trigger callback when a plain value changes', function () {
|
|
|
|
var val
|
|
|
|
vm.$watch('a.b.c', function (newVal) {
|
2013-10-08 13:14:40 +08:00
|
|
|
val = newVal
|
2013-09-11 06:57:47 +08:00
|
|
|
})
|
|
|
|
data.b.c = 'new value!'
|
|
|
|
assert.strictEqual(val, data.b.c)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should trigger callback when an object value changes', function () {
|
|
|
|
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
|
|
|
|
})
|
|
|
|
data.b = target
|
|
|
|
assert.strictEqual(val, target)
|
|
|
|
assert.strictEqual(subVal, target.c)
|
|
|
|
vm.a = 'hehehe'
|
|
|
|
assert.strictEqual(rootVal, 'hehehe')
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should trigger callback when an array mutates', function () {
|
|
|
|
var val, mut
|
|
|
|
vm.$watch('b', function (array, mutation) {
|
|
|
|
val = array
|
|
|
|
mut = mutation
|
|
|
|
})
|
|
|
|
arr.push(4)
|
|
|
|
assert.strictEqual(val, arr)
|
|
|
|
assert.strictEqual(mut.method, 'push')
|
|
|
|
assert.strictEqual(mut.args.length, 1)
|
|
|
|
assert.strictEqual(mut.args[0], 4)
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('.$unwatch()', function () {
|
|
|
|
|
|
|
|
it('should unwatch the stuff', function () {
|
|
|
|
var triggered = false
|
2013-10-08 13:14:40 +08:00
|
|
|
vm.$watch('a.b.c', function () {
|
2013-09-11 06:57:47 +08:00
|
|
|
triggered = true
|
|
|
|
})
|
2013-10-08 13:14:40 +08:00
|
|
|
vm.$watch('a', function () {
|
2013-09-11 06:57:47 +08:00
|
|
|
triggered = true
|
|
|
|
})
|
2013-10-08 13:14:40 +08:00
|
|
|
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)
|
|
|
|
assert.notOk(triggered)
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
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-09 10:26:25 +08:00
|
|
|
})
|
|
|
|
|
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)
|
|
|
|
})
|
|
|
|
|
2013-10-09 10:26:25 +08:00
|
|
|
})
|
|
|
|
|
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>',
|
2013-11-14 10:51:51 +08:00
|
|
|
components: {
|
2013-10-09 11:19:12 +08:00
|
|
|
test: Child
|
|
|
|
}
|
|
|
|
})
|
|
|
|
var t = new Test()
|
|
|
|
t.$broadcast('hello', msg)
|
|
|
|
assert.strictEqual(triggered, 2)
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('.$emit', function () {
|
|
|
|
|
|
|
|
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
|
2013-12-25 04:34:22 +08:00
|
|
|
nextTick(function () {
|
2013-10-09 11:19:12 +08:00
|
|
|
self.$emit('hello', msg)
|
|
|
|
assert.ok(topTriggered)
|
|
|
|
assert.ok(midTriggered)
|
|
|
|
done()
|
2013-12-25 04:34:22 +08:00
|
|
|
})
|
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>',
|
2013-11-14 10:51:51 +08:00
|
|
|
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>',
|
2013-11-14 10:51:51 +08:00
|
|
|
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
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2013-10-12 05:40:39 +08:00
|
|
|
new Top()
|
2013-10-09 11:19:12 +08:00
|
|
|
})
|
|
|
|
|
2013-10-09 10:26:25 +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: {
|
|
|
|
'v-transition': 'test'
|
|
|
|
},
|
|
|
|
transitions: {
|
|
|
|
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)
|
2013-12-25 04:34:22 +08:00
|
|
|
nextTick(function () {
|
2013-12-21 00:57:46 +08:00
|
|
|
assert.ok(callbackCalled)
|
|
|
|
done()
|
2013-12-25 04:34:22 +08:00
|
|
|
})
|
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)
|
2013-12-25 04:34:22 +08:00
|
|
|
nextTick(function () {
|
2013-12-21 00:57:46 +08:00
|
|
|
assert.ok(callbackCalled)
|
|
|
|
done()
|
2013-12-25 04:34:22 +08:00
|
|
|
})
|
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)
|
2013-12-25 04:34:22 +08:00
|
|
|
nextTick(function () {
|
2013-12-21 00:57:46 +08:00
|
|
|
assert.ok(callbackCalled)
|
|
|
|
next()
|
2013-12-25 04:34:22 +08:00
|
|
|
})
|
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)
|
2013-12-25 04:34:22 +08:00
|
|
|
nextTick(function () {
|
2013-12-21 00:57:46 +08:00
|
|
|
assert.ok(callbackCalled)
|
|
|
|
done()
|
2013-12-25 04:34:22 +08:00
|
|
|
})
|
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)
|
2013-12-25 04:34:22 +08:00
|
|
|
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
|
|
|
})
|
|
|
|
|
2013-11-03 10:19:52 +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-11-03 10:19:52 +08:00
|
|
|
|
2013-12-17 14:38:01 +08:00
|
|
|
var beforeDestroyCalled = false,
|
|
|
|
afterDestroyCalled = false,
|
2013-11-03 10:19:52 +08:00
|
|
|
observerOffCalled = false,
|
|
|
|
emitterOffCalled = false,
|
|
|
|
dirUnbindCalled = false,
|
|
|
|
expUnbindCalled = false,
|
|
|
|
bindingUnbindCalled = false,
|
|
|
|
unobserveCalled = 0,
|
|
|
|
elRemoved = false,
|
|
|
|
externalBindingUnbindCalled = false
|
|
|
|
|
|
|
|
var dirMock = {
|
|
|
|
binding: {
|
|
|
|
compiler: null,
|
|
|
|
instances: []
|
|
|
|
},
|
|
|
|
unbind: function () {
|
|
|
|
dirUnbindCalled = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dirMock.binding.instances.push(dirMock)
|
|
|
|
|
|
|
|
var bindingsMock = Object.create({
|
|
|
|
'test2': {
|
|
|
|
unbind: function () {
|
|
|
|
externalBindingUnbindCalled = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
bindingsMock.test = {
|
|
|
|
root: true,
|
|
|
|
key: 'test',
|
|
|
|
value: {
|
|
|
|
__observer__: {
|
|
|
|
off: function () {
|
|
|
|
unobserveCalled++
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
unbind: function () {
|
|
|
|
bindingUnbindCalled = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var compilerMock = {
|
|
|
|
options: {
|
2013-12-17 14:38:01 +08:00
|
|
|
beforeDestroy: function () {
|
|
|
|
beforeDestroyCalled = true
|
|
|
|
},
|
|
|
|
afterDestroy: function () {
|
|
|
|
afterDestroyCalled = true
|
2013-11-03 10:19:52 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
observer: {
|
|
|
|
off: function () {
|
|
|
|
observerOffCalled = true
|
|
|
|
},
|
|
|
|
proxies: {
|
|
|
|
'test.': {}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
emitter: {
|
|
|
|
off: function () {
|
|
|
|
emitterOffCalled = true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
dirs: [dirMock],
|
|
|
|
exps: [{
|
|
|
|
unbind: function () {
|
|
|
|
expUnbindCalled = true
|
|
|
|
}
|
|
|
|
}],
|
|
|
|
bindings: bindingsMock,
|
|
|
|
childId: 'test',
|
|
|
|
parentCompiler: {
|
|
|
|
childCompilers: [],
|
|
|
|
vm: {
|
|
|
|
$: {
|
|
|
|
'test': true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2013-12-18 14:36:58 +08:00
|
|
|
vm: {
|
|
|
|
$remove: function () {
|
|
|
|
elRemoved = true
|
2013-11-03 10:19:52 +08:00
|
|
|
}
|
2013-12-18 23:04:55 +08:00
|
|
|
},
|
|
|
|
execHook: function (id) {
|
|
|
|
this.options[id].call(this)
|
2013-11-03 10:19:52 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
compilerMock.parentCompiler.childCompilers.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)
|
2013-11-03 10:19:52 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should turn observer and emitter off', function () {
|
|
|
|
assert.ok(observerOffCalled)
|
|
|
|
assert.ok(emitterOffCalled)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should unbind all directives', function () {
|
|
|
|
assert.ok(dirUnbindCalled)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should remove directives from external bindings', function () {
|
|
|
|
assert.strictEqual(dirMock.binding.instances.indexOf(dirMock), -1)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should unbind all expressions', function () {
|
|
|
|
assert.ok(expUnbindCalled)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should unbind and unobserve own bindings', function () {
|
|
|
|
assert.ok(bindingUnbindCalled)
|
|
|
|
assert.strictEqual(unobserveCalled, 3)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should not unbind external bindings', function () {
|
|
|
|
assert.notOk(externalBindingUnbindCalled)
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should remove self from parentCompiler', function () {
|
|
|
|
var parent = compilerMock.parentCompiler
|
|
|
|
assert.ok(parent.childCompilers.indexOf(compilerMock), -1)
|
|
|
|
assert.strictEqual(parent.vm.$[compilerMock.childId], undefined)
|
|
|
|
})
|
|
|
|
|
|
|
|
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 () {
|
|
|
|
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)
|
|
|
|
assert.ok(emittedChange)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2013-09-10 06:04:33 +08:00
|
|
|
})
|