|
|
@@ -633,131 +633,69 @@ describe('Component scoped slot', () => {
|
|
|
})
|
|
|
|
|
|
// 2.6 new slot syntax
|
|
|
- if (process.env.NEW_SLOT_SYNTAX) {
|
|
|
- describe('v-slot syntax', () => {
|
|
|
- const Foo = {
|
|
|
- render(h) {
|
|
|
- return h('div', [
|
|
|
- this.$scopedSlots.default && this.$scopedSlots.default('from foo default'),
|
|
|
- this.$scopedSlots.one && this.$scopedSlots.one('from foo one'),
|
|
|
- this.$scopedSlots.two && this.$scopedSlots.two('from foo two')
|
|
|
- ])
|
|
|
- }
|
|
|
+ describe('v-slot syntax', () => {
|
|
|
+ const Foo = {
|
|
|
+ render(h) {
|
|
|
+ return h('div', [
|
|
|
+ this.$scopedSlots.default && this.$scopedSlots.default('from foo default'),
|
|
|
+ this.$scopedSlots.one && this.$scopedSlots.one('from foo one'),
|
|
|
+ this.$scopedSlots.two && this.$scopedSlots.two('from foo two')
|
|
|
+ ])
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- const Bar = {
|
|
|
- render(h) {
|
|
|
- return this.$scopedSlots.default && this.$scopedSlots.default('from bar')
|
|
|
- }
|
|
|
+ const Bar = {
|
|
|
+ render(h) {
|
|
|
+ return this.$scopedSlots.default && this.$scopedSlots.default('from bar')
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- const Baz = {
|
|
|
- render(h) {
|
|
|
- return this.$scopedSlots.default && this.$scopedSlots.default('from baz')
|
|
|
- }
|
|
|
+ const Baz = {
|
|
|
+ render(h) {
|
|
|
+ return this.$scopedSlots.default && this.$scopedSlots.default('from baz')
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- const toNamed = (syntax, name) => syntax[0] === '#'
|
|
|
- ? `#${name}` // shorthand
|
|
|
- : `${syntax}:${name}` // full syntax
|
|
|
-
|
|
|
- function runSuite(syntax) {
|
|
|
- it('default slot', () => {
|
|
|
- const vm = new Vue({
|
|
|
- template: `<foo ${syntax}="foo">{{ foo }}<div>{{ foo }}</div></foo>`,
|
|
|
- components: { Foo }
|
|
|
- }).$mount()
|
|
|
- expect(vm.$el.innerHTML).toBe(`from foo default<div>from foo default</div>`)
|
|
|
- })
|
|
|
-
|
|
|
- it('nested default slots', () => {
|
|
|
- const vm = new Vue({
|
|
|
- template: `
|
|
|
- <foo ${syntax}="foo">
|
|
|
- <bar ${syntax}="bar">
|
|
|
- <baz ${syntax}="baz">
|
|
|
- {{ foo }} | {{ bar }} | {{ baz }}
|
|
|
- </baz>
|
|
|
- </bar>
|
|
|
- </foo>
|
|
|
- `,
|
|
|
- components: { Foo, Bar, Baz }
|
|
|
- }).$mount()
|
|
|
- expect(vm.$el.innerHTML.trim()).toBe(`from foo default | from bar | from baz`)
|
|
|
- })
|
|
|
-
|
|
|
- it('named slots', () => {
|
|
|
- const vm = new Vue({
|
|
|
- template: `
|
|
|
- <foo>
|
|
|
- <template ${toNamed(syntax, 'default')}="foo">
|
|
|
- {{ foo }}
|
|
|
- </template>
|
|
|
- <template ${toNamed(syntax, 'one')}="one">
|
|
|
- {{ one }}
|
|
|
- </template>
|
|
|
- <template ${toNamed(syntax, 'two')}="two">
|
|
|
- {{ two }}
|
|
|
- </template>
|
|
|
- </foo>
|
|
|
- `,
|
|
|
- components: { Foo }
|
|
|
- }).$mount()
|
|
|
- expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo default from foo one from foo two`)
|
|
|
- })
|
|
|
-
|
|
|
- it('nested + named + default slots', () => {
|
|
|
- const vm = new Vue({
|
|
|
- template: `
|
|
|
- <foo>
|
|
|
- <template ${toNamed(syntax, 'one')}="one">
|
|
|
- <bar ${syntax}="bar">
|
|
|
- {{ one }} {{ bar }}
|
|
|
- </bar>
|
|
|
- </template>
|
|
|
- <template ${toNamed(syntax, 'two')}="two">
|
|
|
- <baz ${syntax}="baz">
|
|
|
- {{ two }} {{ baz }}
|
|
|
- </baz>
|
|
|
- </template>
|
|
|
- </foo>
|
|
|
- `,
|
|
|
- components: { Foo, Bar, Baz }
|
|
|
- }).$mount()
|
|
|
- expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one from bar from foo two from baz`)
|
|
|
- })
|
|
|
+ const toNamed = (syntax, name) => syntax[0] === '#'
|
|
|
+ ? `#${name}` // shorthand
|
|
|
+ : `${syntax}:${name}` // full syntax
|
|
|
|
|
|
- it('should warn v-slot usage on non-component elements', () => {
|
|
|
- const vm = new Vue({
|
|
|
- template: `<div ${syntax}="foo"/>`
|
|
|
- }).$mount()
|
|
|
- expect(`v-slot can only be used on components or <template>`).toHaveBeenWarned()
|
|
|
- })
|
|
|
-
|
|
|
- it('should warn mixed usage', () => {
|
|
|
- const vm = new Vue({
|
|
|
- template: `<foo><bar slot="one" slot-scope="bar" ${syntax}="bar"></bar></foo>`,
|
|
|
- components: { Foo, Bar }
|
|
|
- }).$mount()
|
|
|
- expect(`Unexpected mixed usage of different slot syntaxes`).toHaveBeenWarned()
|
|
|
- })
|
|
|
- }
|
|
|
+ function runSuite(syntax) {
|
|
|
+ it('default slot', () => {
|
|
|
+ const vm = new Vue({
|
|
|
+ template: `<foo ${syntax}="foo">{{ foo }}<div>{{ foo }}</div></foo>`,
|
|
|
+ components: { Foo }
|
|
|
+ }).$mount()
|
|
|
+ expect(vm.$el.innerHTML).toBe(`from foo default<div>from foo default</div>`)
|
|
|
+ })
|
|
|
|
|
|
- // run tests for both full syntax and shorthand
|
|
|
- runSuite('v-slot')
|
|
|
- runSuite('#default')
|
|
|
+ it('nested default slots', () => {
|
|
|
+ const vm = new Vue({
|
|
|
+ template: `
|
|
|
+ <foo ${syntax}="foo">
|
|
|
+ <bar ${syntax}="bar">
|
|
|
+ <baz ${syntax}="baz">
|
|
|
+ {{ foo }} | {{ bar }} | {{ baz }}
|
|
|
+ </baz>
|
|
|
+ </bar>
|
|
|
+ </foo>
|
|
|
+ `,
|
|
|
+ components: { Foo, Bar, Baz }
|
|
|
+ }).$mount()
|
|
|
+ expect(vm.$el.innerHTML.trim()).toBe(`from foo default | from bar | from baz`)
|
|
|
+ })
|
|
|
|
|
|
- it('shorthand named slots', () => {
|
|
|
+ it('named slots', () => {
|
|
|
const vm = new Vue({
|
|
|
template: `
|
|
|
<foo>
|
|
|
- <template #default="foo">
|
|
|
+ <template ${toNamed(syntax, 'default')}="foo">
|
|
|
{{ foo }}
|
|
|
</template>
|
|
|
- <template #one="one">
|
|
|
+ <template ${toNamed(syntax, 'one')}="one">
|
|
|
{{ one }}
|
|
|
</template>
|
|
|
- <template #two="two">
|
|
|
+ <template ${toNamed(syntax, 'two')}="two">
|
|
|
{{ two }}
|
|
|
</template>
|
|
|
</foo>
|
|
|
@@ -767,62 +705,165 @@ describe('Component scoped slot', () => {
|
|
|
expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo default from foo one from foo two`)
|
|
|
})
|
|
|
|
|
|
- it('should warn mixed root-default and named slots', () => {
|
|
|
+ it('nested + named + default slots', () => {
|
|
|
const vm = new Vue({
|
|
|
template: `
|
|
|
- <foo #default="foo">
|
|
|
- {{ foo }}
|
|
|
- <template #one="one">
|
|
|
- {{ one }}
|
|
|
+ <foo>
|
|
|
+ <template ${toNamed(syntax, 'one')}="one">
|
|
|
+ <bar ${syntax}="bar">
|
|
|
+ {{ one }} {{ bar }}
|
|
|
+ </bar>
|
|
|
+ </template>
|
|
|
+ <template ${toNamed(syntax, 'two')}="two">
|
|
|
+ <baz ${syntax}="baz">
|
|
|
+ {{ two }} {{ baz }}
|
|
|
+ </baz>
|
|
|
</template>
|
|
|
</foo>
|
|
|
`,
|
|
|
- components: { Foo }
|
|
|
+ components: { Foo, Bar, Baz }
|
|
|
}).$mount()
|
|
|
- expect(`default slot should also use <template>`).toHaveBeenWarned()
|
|
|
+ expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one from bar from foo two from baz`)
|
|
|
})
|
|
|
|
|
|
- it('shorthand without scope variable', () => {
|
|
|
+ it('should warn v-slot usage on non-component elements', () => {
|
|
|
const vm = new Vue({
|
|
|
- template: `
|
|
|
- <foo>
|
|
|
- <template #one>one</template>
|
|
|
- <template #two>two</template>
|
|
|
- </foo>
|
|
|
- `,
|
|
|
- components: { Foo }
|
|
|
+ template: `<div ${syntax}="foo"/>`
|
|
|
}).$mount()
|
|
|
- expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`onetwo`)
|
|
|
+ expect(`v-slot can only be used on components or <template>`).toHaveBeenWarned()
|
|
|
})
|
|
|
|
|
|
- it('shorthand named slots on root', () => {
|
|
|
+ it('should warn mixed usage', () => {
|
|
|
const vm = new Vue({
|
|
|
- template: `
|
|
|
- <foo #one="one">
|
|
|
- {{ one }}
|
|
|
- </foo>
|
|
|
- `,
|
|
|
- components: { Foo }
|
|
|
+ template: `<foo><bar slot="one" slot-scope="bar" ${syntax}="bar"></bar></foo>`,
|
|
|
+ components: { Foo, Bar }
|
|
|
}).$mount()
|
|
|
- expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one`)
|
|
|
+ expect(`Unexpected mixed usage of different slot syntaxes`).toHaveBeenWarned()
|
|
|
})
|
|
|
+ }
|
|
|
|
|
|
- it('dynamic slot name', () => {
|
|
|
- const vm = new Vue({
|
|
|
- data: {
|
|
|
- a: 'one',
|
|
|
- b: 'two'
|
|
|
- },
|
|
|
- template: `
|
|
|
- <foo>
|
|
|
- <template #[a]="one">{{ one }} </template>
|
|
|
- <template v-slot:[b]="two">{{ two }}</template>
|
|
|
- </foo>
|
|
|
- `,
|
|
|
- components: { Foo }
|
|
|
- }).$mount()
|
|
|
- expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one from foo two`)
|
|
|
- })
|
|
|
+ // run tests for both full syntax and shorthand
|
|
|
+ runSuite('v-slot')
|
|
|
+ runSuite('#default')
|
|
|
+
|
|
|
+ it('shorthand named slots', () => {
|
|
|
+ const vm = new Vue({
|
|
|
+ template: `
|
|
|
+ <foo>
|
|
|
+ <template #default="foo">
|
|
|
+ {{ foo }}
|
|
|
+ </template>
|
|
|
+ <template #one="one">
|
|
|
+ {{ one }}
|
|
|
+ </template>
|
|
|
+ <template #two="two">
|
|
|
+ {{ two }}
|
|
|
+ </template>
|
|
|
+ </foo>
|
|
|
+ `,
|
|
|
+ components: { Foo }
|
|
|
+ }).$mount()
|
|
|
+ expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo default from foo one from foo two`)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('should warn mixed root-default and named slots', () => {
|
|
|
+ const vm = new Vue({
|
|
|
+ template: `
|
|
|
+ <foo #default="foo">
|
|
|
+ {{ foo }}
|
|
|
+ <template #one="one">
|
|
|
+ {{ one }}
|
|
|
+ </template>
|
|
|
+ </foo>
|
|
|
+ `,
|
|
|
+ components: { Foo }
|
|
|
+ }).$mount()
|
|
|
+ expect(`default slot should also use <template>`).toHaveBeenWarned()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('shorthand without scope variable', () => {
|
|
|
+ const vm = new Vue({
|
|
|
+ template: `
|
|
|
+ <foo>
|
|
|
+ <template #one>one</template>
|
|
|
+ <template #two>two</template>
|
|
|
+ </foo>
|
|
|
+ `,
|
|
|
+ components: { Foo }
|
|
|
+ }).$mount()
|
|
|
+ expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`onetwo`)
|
|
|
+ })
|
|
|
+
|
|
|
+ it('shorthand named slots on root', () => {
|
|
|
+ const vm = new Vue({
|
|
|
+ template: `
|
|
|
+ <foo #one="one">
|
|
|
+ {{ one }}
|
|
|
+ </foo>
|
|
|
+ `,
|
|
|
+ components: { Foo }
|
|
|
+ }).$mount()
|
|
|
+ expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one`)
|
|
|
})
|
|
|
- }
|
|
|
+
|
|
|
+ it('dynamic slot name', done => {
|
|
|
+ const vm = new Vue({
|
|
|
+ data: {
|
|
|
+ a: 'one',
|
|
|
+ b: 'two'
|
|
|
+ },
|
|
|
+ template: `
|
|
|
+ <foo>
|
|
|
+ <template #[a]="one">a {{ one }} </template>
|
|
|
+ <template v-slot:[b]="two">b {{ two }} </template>
|
|
|
+ </foo>
|
|
|
+ `,
|
|
|
+ components: { Foo }
|
|
|
+ }).$mount()
|
|
|
+ expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`a from foo one b from foo two`)
|
|
|
+ vm.a = 'two'
|
|
|
+ vm.b = 'one'
|
|
|
+ waitForUpdate(() => {
|
|
|
+ expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`b from foo one a from foo two `)
|
|
|
+ }).then(done)
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ // 2.6 scoped slot perf optimization
|
|
|
+ it('should have accurate tracking for scoped slots', done => {
|
|
|
+ const parentUpdate = jasmine.createSpy()
|
|
|
+ const childUpdate = jasmine.createSpy()
|
|
|
+ const vm = new Vue({
|
|
|
+ template: `
|
|
|
+ <div>{{ parentCount }}<foo #default>{{ childCount }}</foo></div>
|
|
|
+ `,
|
|
|
+ data: {
|
|
|
+ parentCount: 0,
|
|
|
+ childCount: 0
|
|
|
+ },
|
|
|
+ updated: parentUpdate,
|
|
|
+ components: {
|
|
|
+ foo: {
|
|
|
+ template: `<div><slot/></div>`,
|
|
|
+ updated: childUpdate
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).$mount()
|
|
|
+ expect(vm.$el.innerHTML).toMatch(`0<div>0</div>`)
|
|
|
+
|
|
|
+ vm.parentCount++
|
|
|
+ waitForUpdate(() => {
|
|
|
+ expect(vm.$el.innerHTML).toMatch(`1<div>0</div>`)
|
|
|
+ // should only trigger parent update
|
|
|
+ expect(parentUpdate.calls.count()).toBe(1)
|
|
|
+ expect(childUpdate.calls.count()).toBe(0)
|
|
|
+
|
|
|
+ vm.childCount++
|
|
|
+ }).then(() => {
|
|
|
+ expect(vm.$el.innerHTML).toMatch(`1<div>1</div>`)
|
|
|
+ // should only trigger child update
|
|
|
+ expect(parentUpdate.calls.count()).toBe(1)
|
|
|
+ expect(childUpdate.calls.count()).toBe(1)
|
|
|
+ }).then(done)
|
|
|
+ })
|
|
|
})
|