跳至内容

插槽

Vue 测试工具提供了一些有用的功能,用于使用slots测试组件。

一个简单的例子

您可能有一个通用的<layout>组件,它使用默认插槽来渲染一些内容。例如

js
const Layout = {
  template: `
    <div>
      <h1>Welcome!</h1>
      <main>
        <slot />
      </main>
      <footer>
        Thanks for visiting.
      </footer>
    </div>
  `
}

您可能想编写一个测试来确保默认插槽内容被渲染。VTU 提供了slots挂载选项来实现此目的

js
test('layout default slot', () => {
  const wrapper = mount(Layout, {
    slots: {
      default: 'Main Content'
    }
  })

  expect(wrapper.html()).toContain('Main Content')
})

它通过了!在这个例子中,我们向默认插槽传递了一些文本内容。如果您想更具体,并验证默认插槽内容在<main>内部渲染,您可以更改断言

js
test('layout default slot', () => {
  const wrapper = mount(Layout, {
    slots: {
      default: 'Main Content'
    }
  })

  expect(wrapper.find('main').text()).toContain('Main Content')
})

命名插槽

您可能拥有更复杂的<layout>组件,它包含一些命名插槽。例如

js
const Layout = {
  template: `
    <div>
      <header>
        <slot name="header" />
      </header>

      <main>
        <slot name="main" />
      </main>
      <footer>
        <slot name="footer" />
      </footer>
    </div>
  `
}

VTU 也支持这一点。您可以编写如下测试。请注意,在这个例子中,我们向插槽传递了 HTML 而不是文本内容。

js
test('layout full page layout', () => {
  const wrapper = mount(Layout, {
    slots: {
      header: '<div>Header</div>',
      main: '<div>Main Content</div>',
      footer: '<div>Footer</div>'
    }
  })

  expect(wrapper.html()).toContain('<div>Header</div>')
  expect(wrapper.html()).toContain('<div>Main Content</div>')
  expect(wrapper.html()).toContain('<div>Footer</div>')
})

多个插槽

您也可以传递一个插槽数组

js
test('layout full page layout', () => {
  const wrapper = mount(Layout, {
    slots: {
      default: [
        '<div id="one">One</div>',
        '<div id="two">Two</div>'
      ]
    }
  })

  expect(wrapper.find('#one').exists()).toBe(true)
  expect(wrapper.find('#two').exists()).toBe(true)
})

高级用法

您还可以向插槽挂载选项传递一个渲染函数、一个包含模板的对象,甚至是从vue文件导入的 SFC

js
import { h } from 'vue'
import Header from './Header.vue'

test('layout full page layout', () => {
  const wrapper = mount(Layout, {
    slots: {
      header: Header,
      main: h('div', 'Main Content'),
      sidebar: { template: '<div>Sidebar</div>' },
      footer: '<div>Footer</div>'
    }
  })

  expect(wrapper.html()).toContain('<div>Header</div>')
  expect(wrapper.html()).toContain('<div>Main Content</div>')
  expect(wrapper.html()).toContain('<div>Footer</div>')
})

参考测试以获取更多示例和用例。

作用域插槽

作用域插槽和绑定也受支持。

js
const ComponentWithSlots = {
  template: `
    <div class="scoped">
      <slot name="scoped" v-bind="{ msg }" />
    </div>
  `,
  data() {
    return {
      msg: 'world'
    }
  }
}

test('scoped slots', () => {
  const wrapper = mount(ComponentWithSlots, {
    slots: {
      scoped: `<template #scoped="scope">
        Hello {{ scope.msg }}
        </template>
      `
    }
  })

  expect(wrapper.html()).toContain('Hello world')
})

当使用字符串模板作为插槽内容时,如果未明确使用包装的<template #scoped="scopeVar">标签定义,插槽作用域将作为params对象在插槽评估时可用。

js
test('scoped slots', () => {
  const wrapper = mount(ComponentWithSlots, {
    slots: {
      scoped: `Hello {{ params.msg }}` // no wrapping template tag provided, slot scope exposed as "params"
    }
  })

  expect(wrapper.html()).toContain('Hello world')
})

结论

  • 使用slots挂载选项来测试使用<slot>的组件是否正确渲染内容。
  • 内容可以是字符串、渲染函数或导入的 SFC。
  • 对于默认插槽使用default,对于命名插槽使用正确的名称。
  • 作用域插槽和#简写也受支持。