import Vue from 'vue' describe('Component slot', () => { let vm, child function mount (options) { vm = new Vue({ data: { msg: 'parent message' }, template: `
${options.parentContent || ''}
`, components: { test: { template: options.childTemplate, data () { return { msg: 'child message' } } } } }).$mount() child = vm.$children[0] } it('no content', () => { mount({ childTemplate: '
' }) expect(child.$el.childNodes.length).toBe(0) }) it('default content', done => { mount({ childTemplate: '
', parentContent: '

{{ msg }}

' }) expect(child.$el.tagName).toBe('DIV') expect(child.$el.children[0].tagName).toBe('P') expect(child.$el.children[0].textContent).toBe('parent message') vm.msg = 'changed' waitForUpdate(() => { expect(child.$el.children[0].textContent).toBe('changed') }).then(done) }) it('fallback content', () => { mount({ childTemplate: '

{{msg}}

' }) expect(child.$el.children[0].tagName).toBe('P') expect(child.$el.textContent).toBe('child message') }) it('fallback content with multiple named slots', () => { mount({ childTemplate: `

fallback a

fallback b
`, parentContent: '

slot b

' }) expect(child.$el.childNodes.length).toBe(2) expect(child.$el.firstChild.textContent).toBe('fallback a') expect(child.$el.lastChild.textContent).toBe('slot b') }) it('fallback content with mixed named/unamed slots', () => { mount({ childTemplate: `

fallback a

fallback b
`, parentContent: '

slot b

' }) expect(child.$el.childNodes.length).toBe(2) expect(child.$el.firstChild.textContent).toBe('fallback a') expect(child.$el.lastChild.textContent).toBe('slot b') }) it('selector matching multiple elements', () => { mount({ childTemplate: '
', parentContent: '

1

2

' }) expect(child.$el.innerHTML).toBe('

1

2

') }) it('default content should only render parts not selected', () => { mount({ childTemplate: `
`, parentContent: '
foo

1

2

' }) expect(child.$el.innerHTML).toBe('

1

foo

2

') }) it('name should only match children', function () { mount({ childTemplate: `

fallback a

fallback b fallback c
`, parentContent: ` '

select b

'

nested b

'

nested c

` }) expect(child.$el.childNodes.length).toBe(3) expect(child.$el.firstChild.textContent).toBe('fallback a') expect(child.$el.childNodes[1].textContent).toBe('select b') expect(child.$el.lastChild.textContent).toBe('fallback c') }) it('should accept expressions in slot attribute and slot names', () => { mount({ childTemplate: `
`, parentContent: `

one

two

` }) expect(child.$el.innerHTML).toBe('

two

') }) it('slot inside v-if', done => { const vm = new Vue({ data: { a: 1, b: 2, show: true }, template: '

{{b}}

{{a}}

', components: { test: { props: ['show'], template: '
' } } }).$mount() expect(vm.$el.textContent).toBe('12') vm.a = 2 waitForUpdate(() => { expect(vm.$el.textContent).toBe('22') vm.show = false }).then(() => { expect(vm.$el.textContent).toBe('') vm.show = true vm.a = 3 }).then(() => { expect(vm.$el.textContent).toBe('32') }).then(done) }) it('slot inside v-for', () => { mount({ childTemplate: '
', parentContent: '

{{ i - 1 }}

' }) expect(child.$el.innerHTML).toBe('

0

1

2

') }) it('nested slots', done => { const vm = new Vue({ template: '

{{ msg }}

', data: { msg: 'foo' }, components: { test: { template: '
' }, test2: { template: '
' } } }).$mount() expect(vm.$el.innerHTML).toBe('

foo

') vm.msg = 'bar' waitForUpdate(() => { expect(vm.$el.innerHTML).toBe('

bar

') }).then(done) }) it('v-if on inserted content', done => { const vm = new Vue({ template: '

{{ msg }}

', data: { ok: true, msg: 'hi' }, components: { test: { template: '
fallback
' } } }).$mount() expect(vm.$el.innerHTML).toBe('

hi

') vm.ok = false waitForUpdate(() => { expect(vm.$el.innerHTML).toBe('fallback') vm.ok = true vm.msg = 'bye' }).then(() => { expect(vm.$el.innerHTML).toBe('

bye

') }).then(done) }) it('template slot', function () { const vm = new Vue({ template: '', components: { test: { template: '
world
' } } }).$mount() expect(vm.$el.innerHTML).toBe('hello world') }) it('combined with v-for', () => { const vm = new Vue({ template: '
{{ i }}
', components: { test: { template: '
' } } }).$mount() expect(vm.$el.innerHTML).toBe('
1
2
3
') }) it('inside template v-if', () => { mount({ childTemplate: `
`, parentContent: 'foo' }) expect(child.$el.innerHTML).toBe('foo') }) it('default slot should use fallback content if has only whitespace', () => { Vue.config.preserveWhitespace = true mount({ childTemplate: `

first slot

this is the default slot

second named slot

`, parentContent: `
1
2
` }) expect(child.$el.innerHTML).toBe( '
1

this is the default slot

2
' ) Vue.config.preserveWhitespace = false }) it('programmatic access to $slots', () => { const vm = new Vue({ template: '

A

C

B

', components: { test: { render () { expect(this.$slots.a.length).toBe(1) expect(this.$slots.a[0].tag).toBe('p') expect(this.$slots.a[0].children.length).toBe(1) expect(this.$slots.a[0].children[0].text).toBe('A') expect(this.$slots.b.length).toBe(1) expect(this.$slots.b[0].tag).toBe('p') expect(this.$slots.b[0].children.length).toBe(1) expect(this.$slots.b[0].children[0].text).toBe('B') expect(this.$slots.default.length).toBe(1) expect(this.$slots.default[0].tag).toBe('div') expect(this.$slots.default[0].children.length).toBe(1) expect(this.$slots.default[0].children[0].text).toBe('C') return this.$slots.default[0] } } } }).$mount() expect(vm.$el.tagName).toBe('DIV') expect(vm.$el.textContent).toBe('C') }) it('warn if user directly returns array', () => { new Vue({ template: '
', components: { test: { render () { return this.$slots.default } } } }).$mount() expect('Render function should return a single root node').toHaveBeenWarned() }) })