You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

342 lines
8.9 KiB

import Vue from 'vue'
describe('Directive v-once', () => {
it('should not rerender component', done => {
const vm = new Vue({
template: '<div v-once>{{ a }}</div>',
data: { a: 'hello' }
}).$mount()
expect(vm.$el.innerHTML).toBe('hello')
vm.a = 'world'
waitForUpdate(() => {
expect(vm.$el.innerHTML).toBe('hello')
}).then(done)
})
it('should not rerender self and child component', done => {
const vm = new Vue({
template: `
<div v-once>
<span>{{ a }}</span>
<item :b="a"></item>
</div>`,
data: { a: 'hello' },
components: {
item: {
template: '<div>{{ b }}</div>',
props: ['b']
}
}
}).$mount()
expect(vm.$children.length).toBe(1)
expect(vm.$el.innerHTML)
.toBe('<span>hello</span> <div>hello</div>')
vm.a = 'world'
waitForUpdate(() => {
expect(vm.$el.innerHTML)
.toBe('<span>hello</span> <div>hello</div>')
}).then(done)
})
it('should rerender parent but not self', done => {
const vm = new Vue({
template: `
<div>
<span>{{ a }}</span>
<item v-once :b="a"></item>
</div>`,
data: { a: 'hello' },
components: {
item: {
template: '<div>{{ b }}</div>',
props: ['b']
}
}
}).$mount()
expect(vm.$children.length).toBe(1)
expect(vm.$el.innerHTML)
.toBe('<span>hello</span> <div>hello</div>')
vm.a = 'world'
waitForUpdate(() => {
expect(vm.$el.innerHTML)
.toBe('<span>world</span> <div>hello</div>')
}).then(done)
})
it('should not rerender static sub nodes', done => {
const vm = new Vue({
template: `
<div>
<span v-once>{{ a }}</span>
<item :b="a"></item>
<span>{{ suffix }}</span>
</div>`,
data: {
a: 'hello',
suffix: '?'
},
components: {
item: {
template: '<div>{{ b }}</div>',
props: ['b']
}
}
}).$mount()
expect(vm.$el.innerHTML)
.toBe('<span>hello</span> <div>hello</div> <span>?</span>')
vm.a = 'world'
waitForUpdate(() => {
expect(vm.$el.innerHTML)
.toBe('<span>hello</span> <div>world</div> <span>?</span>')
vm.suffix = '!'
}).then(() => {
expect(vm.$el.innerHTML)
.toBe('<span>hello</span> <div>world</div> <span>!</span>')
}).then(done)
})
it('should work with v-if', done => {
const vm = new Vue({
data: {
tester: true,
yes: 'y',
no: 'n'
},
template: `
<div>
<div v-if="tester">{{ yes }}</div>
<div v-else>{{ no }}</div>
<div v-if="tester" v-once>{{ yes }}</div>
<div v-else>{{ no }}</div>
<div v-if="tester">{{ yes }}</div>
<div v-else v-once>{{ no }}</div>
<div v-if="tester" v-once>{{ yes }}</div>
<div v-else v-once>{{ no }}</div>
</div>
`
}).$mount()
expectTextContent(vm, 'yyyy')
vm.yes = 'yes'
waitForUpdate(() => {
expectTextContent(vm, 'yesyyesy')
vm.tester = false
}).then(() => {
expectTextContent(vm, 'nnnn')
vm.no = 'no'
}).then(() => {
expectTextContent(vm, 'nononn')
}).then(done)
})
it('should work with v-for', done => {
const vm = new Vue({
data: {
list: [1, 2, 3]
},
template: `<div><div v-for="i in list" v-once>{{i}}</div></div>`
}).$mount()
expect(vm.$el.textContent).toBe('123')
vm.list.reverse()
waitForUpdate(() => {
expect(vm.$el.textContent).toBe('123')
}).then(done)
})
it('should work inside v-for', done => {
const vm = new Vue({
data: {
list: [
{ id: 0, text: 'a' },
{ id: 1, text: 'b' },
{ id: 2, text: 'c' }
]
},
template: `
<div>
<div v-for="i in list" :key="i.id">
<div>
<span v-once>{{ i.text }}</span><span>{{ i.text }}</span>
</div>
</div>
</div>
`
}).$mount()
expect(vm.$el.textContent).toBe('aabbcc')
vm.list[0].text = 'd'
waitForUpdate(() => {
expect(vm.$el.textContent).toBe('adbbcc')
vm.list[1].text = 'e'
}).then(() => {
expect(vm.$el.textContent).toBe('adbecc')
vm.list.reverse()
}).then(() => {
expect(vm.$el.textContent).toBe('ccbead')
}).then(done)
})
it('should work inside v-for with v-if', done => {
const vm = new Vue({
data: {
list: [
{ id: 0, text: 'a', tester: true, truthy: 'y' }
]
},
template: `
<div>
<div v-for="i in list" :key="i.id">
<span v-if="i.tester" v-once>{{ i.truthy }}</span>
<span v-else v-once>{{ i.text }}</span>
<span v-if="i.tester" v-once>{{ i.truthy }}</span>
<span v-else>{{ i.text }}</span>
<span v-if="i.tester">{{ i.truthy }}</span>
<span v-else v-once>{{ i.text }}</span>
<span v-if="i.tester">{{ i.truthy }}</span>
<span v-else>{{ i.text }}</span>
</div>
</div>
`
}).$mount()
expectTextContent(vm, 'yyyy')
vm.list[0].truthy = 'yy'
waitForUpdate(() => {
expectTextContent(vm, 'yyyyyy')
vm.list[0].tester = false
}).then(() => {
expectTextContent(vm, 'aaaa')
vm.list[0].text = 'nn'
}).then(() => {
expectTextContent(vm, 'annann')
}).then(done)
})
it('should work inside v-for with nested v-else', done => {
const vm = new Vue({
data: {
list: [{ id: 0, text: 'a', tester: true, truthy: 'y' }]
},
template: `
<div v-if="0"></div>
<div v-else>
<div v-for="i in list" :key="i.id">
<span v-if="i.tester" v-once>{{ i.truthy }}</span>
<span v-else v-once>{{ i.text }}</span>
</div>
</div>
`
}).$mount()
expectTextContent(vm, 'y')
vm.list[0].truthy = 'yy'
waitForUpdate(() => {
expectTextContent(vm, 'y')
vm.list[0].tester = false
}).then(() => {
expectTextContent(vm, 'a')
vm.list[0].text = 'nn'
}).then(() => {
expectTextContent(vm, 'a')
}).then(done)
})
it('should work inside v-for with nested v-else-if and v-else', done => {
const vm = new Vue({
data: {
tester: false,
list: [{ id: 0, text: 'a', tester: true, truthy: 'y' }]
},
template: `
<div v-if="0"></div>
<div v-else-if="tester">
<div v-for="i in list" :key="i.id">
<span v-if="i.tester" v-once>{{ i.truthy }}</span>
<span v-else-if="tester" v-once>{{ i.text }}elseif</span>
<span v-else v-once>{{ i.text }}</span>
</div>
</div>
<div v-else>
<div v-for="i in list" :key="i.id">
<span v-if="i.tester" v-once>{{ i.truthy }}</span>
<span v-else-if="tester">{{ i.text }}elseif</span>
<span v-else v-once>{{ i.text }}</span>
</div>
</div>
`
}).$mount()
expectTextContent(vm, 'y')
vm.list[0].truthy = 'yy'
waitForUpdate(() => {
expectTextContent(vm, 'y')
vm.list[0].tester = false
}).then(() => {
expectTextContent(vm, 'a')
vm.list[0].text = 'nn'
}).then(() => {
expectTextContent(vm, 'a')
vm.tester = true
}).then(() => {
expectTextContent(vm, 'nnelseif')
vm.list[0].text = 'xx'
}).then(() => {
expectTextContent(vm, 'nnelseif')
vm.list[0].tester = true
}).then(() => {
expectTextContent(vm, 'yy')
vm.list[0].truthy = 'nn'
}).then(() => {
expectTextContent(vm, 'yy')
}).then(done)
})
it('should warn inside non-keyed v-for', () => {
const vm = new Vue({
data: {
list: [
{ id: 0, text: 'a' },
{ id: 1, text: 'b' },
{ id: 2, text: 'c' }
]
},
template: `
<div>
<div v-for="i in list">
<span v-once>{{ i.text }}</span><span>{{ i.text }}</span>
</div>
</div>
`
}).$mount()
expect(vm.$el.textContent).toBe('aabbcc')
expect(`v-once can only be used inside v-for that is keyed.`).toHaveBeenWarned()
})
// #4288
it('should inherit child reference for v-once', done => {
const vm = new Vue({
template: `<div>{{a}}<test v-if="ok" v-once></test></div>`,
data: {
a: 0,
ok: true
},
components: {
test: {
template: '<div>foo</div>'
}
}
}).$mount()
vm.a++ // first update to force a patch
waitForUpdate(() => {
expect(vm.$el.textContent).toBe('1foo')
}).then(() => {
vm.ok = false // teardown component with v-once
}).then(done) // should not throw
})
})
function expectTextContent (vm, text) {
expect(vm.$el.textContent.replace(/\r?\n|\r|\s/g, '')).toBe(text)
}