// test cases for edge cases & bug fixes
var Vue = require('../../../src/vue')
var _ = require('../../../src/util/debug')
describe('Misc', function () {
beforeEach(function () {
spyOn(_, 'warn')
})
it('should handle directive.bind() altering its childNode structure', function () {
var vm = new Vue({
el: document.createElement('div'),
template: '
{{test}}
',
data: {
test: 'hi'
},
directives: {
test: {
bind: function () {
this.el.insertBefore(document.createTextNode('yo '),
this.el.firstChild)
}
}
}
})
expect(vm.$el.textContent).toBe('yo hi')
})
it('attached/detached hooks for transcluded components', function () {
var spy1 = jasmine.createSpy('attached')
var spy2 = jasmine.createSpy('detached')
var el = document.createElement('div')
el.innerHTML = ' '
document.body.appendChild(el)
var vm = new Vue({
el: el,
components: {
outer: {
template: ' '
},
inner: {
template: 'hi',
attached: spy1,
detached: spy2
}
}
})
expect(spy1).toHaveBeenCalled()
vm.$.outter.$remove()
expect(spy2).toHaveBeenCalled()
})
it('v-repeat on component root node with replace:true', function () {
var el = document.createElement('div')
var vm = new Vue({
el: el,
template: ' ',
components: {
test: {
data: function () {
return { list: [1, 2, 3] }
},
template: '{{$value}}
',
replace: true
}
}
})
expect(vm.$el.innerHTML).toBe('1
2
3
')
})
// #922
it('template repeat inside svg', function () {
var el = document.createElement('div')
new Vue({
el: el,
template: '{{$value}} ',
data: {
list: [1, 2, 3]
}
})
// IE inlines svg namespace
var xmlns = /\s?xmlns=".*svg"/
expect(el.innerHTML.replace(xmlns, '')).toBe('1 2 3 ')
})
// #1005
it('call lifecycle hooks for child components', function () {
Vue.options.replace = true
var el = document.createElement('div')
var logs = []
function log (n) {
return function () {
logs.push(n)
}
}
document.body.appendChild(el)
var vm = new Vue({
el: el,
attached: log(0),
ready: log(1),
detached: log(2),
beforeDestroy: log(3),
destroyed: log(4),
template: '
',
components: {
test: {
template: 'hi ',
attached: log(5),
ready: log(6),
detached: log(7),
beforeDestroy: log(8),
destroyed: log(9)
}
}
})
expect(vm.$el.innerHTML).toBe('hi hi ')
expect(logs.join()).toBe('0,5,6,5,6,1')
logs = []
vm.$destroy(true)
expect(logs.join()).toBe('3,8,9,8,9,2,7,7,4')
Vue.options.replace = false
})
// #1006
it('destroyed hook for components inside v-if', function (done) {
var spy = jasmine.createSpy('v-if destroyed hook')
var vm = new Vue({
el: document.createElement('div'),
template: ' ',
data: {
ok: true
},
components: {
test: {
destroyed: spy
}
}
})
vm.ok = false
Vue.nextTick(function () {
expect(spy).toHaveBeenCalled()
done()
})
})
it('frozen model, root', function (done) {
var vm = new Vue({
el: document.createElement('div'),
template: '{{msg}}',
data: Object.freeze({
msg: 'hi!'
})
})
expect(vm.$el.textContent).toBe('hi!')
vm.msg = 'ho!'
Vue.nextTick(function () {
expect(vm.$el.textContent).toBe('hi!')
done()
})
})
it('frozen model, non-root', function (done) {
var vm = new Vue({
el: document.createElement('div'),
template: '{{msg}} {{frozen.msg}}',
data: {
msg: 'hi',
frozen: Object.freeze({
msg: 'frozen'
})
}
})
expect(vm.$el.textContent).toBe('hi frozen')
vm.msg = 'ho'
vm.frozen.msg = 'changed'
Vue.nextTick(function () {
expect(vm.$el.textContent).toBe('ho frozen')
done()
})
})
it('should not trigger deep/Array watchers when digesting', function (done) {
var spy1 = jasmine.createSpy('deep')
var spy2 = jasmine.createSpy('Array')
var spy3 = jasmine.createSpy('test')
var spy4 = jasmine.createSpy('deep-mutated')
var vm = new Vue({
el: 'body',
data: {
obj: {},
arr: [],
obj2: {}
},
watch: {
obj: {
handler: spy1,
deep: true
},
arr: spy2,
// if the watcher is watching the added value,
// it should still trigger properly
test: {
handler: spy3,
deep: true
},
// if the object is in fact mutated, it should
// still trigger.
obj2: {
handler: spy4,
deep: true
}
}
})
var test = []
var obj2 = vm.obj2
vm.$add('test', test)
obj2.$add('test', 123)
Vue.nextTick(function () {
expect(spy1).not.toHaveBeenCalled()
expect(spy2).not.toHaveBeenCalled()
expect(spy3).toHaveBeenCalledWith(test, undefined)
expect(spy4).toHaveBeenCalledWith(obj2, obj2)
done()
})
})
it('strict mode', function () {
Vue.config.strict = true
new Vue({
el: document.createElement('div'),
template: ' ',
components: {
test: {
template: 'hi
'
}
},
directives: {
strict: function () {}
}
})
expect(hasWarned(_, 'Failed to resolve directive: strict')).toBe(true)
Vue.config.strict = false
})
it('strict mode for repeat instances', function () {
Vue.config.strict = true
var vm = new Vue({
el: document.createElement('div'),
template: '
',
data: {
list: [1, 2]
},
components: {
test: {
template: 'hi'
}
}
})
expect(_.warn).not.toHaveBeenCalled()
expect(vm.$el.textContent).toBe('hihi')
Vue.config.strict = false
})
it('class interpolation and v-class should work together', function (done) {
var el = document.createElement('div')
el.setAttribute('class', 'a {{classB}}')
el.setAttribute('v-class', 'c: showC')
var vm = new Vue({
el: el,
data: {
classB: 'b',
showC: true
}
})
assertClasses(['a', 'b', 'c'])
vm.classB = 'bb'
vm.showC = false
Vue.nextTick(function () {
assertClasses(['a', 'bb'])
done()
})
function assertClasses (expectedClasses) {
var classes = el.className.trim().split(/\s+/)
expect(classes.length).toBe(expectedClasses.length)
var has = expectedClasses.every(function (cls) {
return classes.indexOf(cls) > -1
})
expect(has).toBe(true)
}
})
it('handle interpolated textarea', function (done) {
var el = document.createElement('div')
el.innerHTML = ''
var vm = new Vue({
el: el,
data: {
msg: 'test'
}
})
expect(el.innerHTML).toBe('')
vm.msg = 'world'
Vue.nextTick(function () {
expect(el.innerHTML).toBe('')
done()
})
})
it('resolveAsset for repeat instance inside content in strict mode', function () {
Vue.config.strict = true
var el = document.createElement('div')
el.innerHTML =
'' +
'' +
'{{item}} ' +
' ' +
' '
new Vue({
el: el,
data: {
items: [1, 2, 3]
},
components: {
outer: { template: ' ' },
inner: { template: ' ' }
}
})
expect(el.textContent).toBe('123')
Vue.config.strict = false
})
it('nested object $set should trigger parent array notify', function (done) {
var vm = new Vue({
el: document.createElement('div'),
template: '{{items | json}}{{items[0].a}}',
data: {
items: [{}]
}
})
expect(vm.$el.textContent).toBe(JSON.stringify(vm.items, null, 2))
vm.items[0].$set('a', 123)
Vue.nextTick(function () {
expect(vm.$el.textContent).toBe(JSON.stringify(vm.items, null, 2) + '123')
done()
})
})
})