vue3 测试工具入门使用

332 阅读4分钟

vue/test-utils Vitest

  • 本教程源码已上传github

入门

什么是 Vue 测试工具?

  • Vue Test Utils (VTU) 是一组实用功能,旨在简化 Vue.js 组件的测试。它提供了一些方法来以隔离的方式挂载和与 Vue 组件交互。 让我们看一个例子:

什么是 Vitest

  • Vitest 是一个由 Vite 提供支持的极速单元测试框架。
  • 你可以在 为什么是 为什么是 Vitest 中了解有关该项目背后的基本原理的更多信息。

vitest 优点

  • 重复使用 Vite 的配置、转换器、解析器和插件 - 在您的应用程序和测试中保持一致。
  • 拥有预期、快照、覆盖等 - 从 Jest 迁移很简单。
  • 智能文件监听模式,就像是测试的 HMR!
  • 由 esbuild 提供的开箱即用 ESM、TypeScript 和 JSX 支持。
import { mount } from '@vue/test-utils'
import { describe, it, expect } from 'vitest'
// 这是测试组件
const MessageComponent = {
  template: '<p>{{ msg }}</p>',
  props: ['msg'],
}
// 创建测试用例
describe('displays message', () => {
  it('displays message', () => {
    // 使用 mount函数 挂载组件
    const wrapper = mount(MessageComponent, {
      props: {
        msg: 'Hello world',
      },
    })
    // 断言组件的呈现文本
    expect(wrapper.text()).toContain('Hello world') //可通过
    expect(wrapper.text()).toContain('Hello') //不可通过
  })
})

测试一个 TodoApp

  • 安装组件
  • 查找元素
  • 填写表格
  • 触发事件

入门

TodoApp 我们的一个简单的组件开始: todo 的简单组件

<template>
  <div></div>
</template>

<script setup lang="ts" name="TodoApp">
  import { ref } from 'vue'
  const todos = ref([
    {
      id: 1,
      text: 'Learn Vue.js 3',
      completed: false,
    },
  ])
</script>

第一个测试 - 渲染一个 todo

我们将写出验证来做部分的第一个测试。让我们先看看测试然后讨论:

import { mount } from '@vue/test-utils'
import TodoApp from '../TodoApp/index.vue'
import { describe, it, expect } from 'vitest'
describe('renders a todo', () => {
  it('renders properly', () => {
    const wrapper = mount(TodoApp)
    const todo = wrapper.get('[data-test="todo"]')
    expect(todo.text()).toBe('Learn Vue.js 3')
  })
})
  • 我们从导入 mountVTU 中渲染组件的主要组件。
  • 运行测试会失败,我们通过属性选择器获取元素 [data-test="todo"]

使测试通过

<template>
  <div>
    <div v-for="todo in todos" :key="todo.id" data-test="todo">
      {{ todo.text }}
    </div>
  </div>
</template>

这个改变,测试就通过了。恭喜!您编写了第一个组件测试。

添加新的待办事项

我们将能够让用户的下一个功能是让用户创建一个新的待办事项。我们需要输入一个输入的表格,供用户输入一些文本。当用户提交表单时,我们新的任务被渲染。我们来看看测试:

import { mount } from '@vue/test-utils'
import TodoApp from '../TodoApp/index.vue'
import { describe, it, expect } from 'vitest'
describe('renders a todo', () => {
  it('creates a todo', () => {
    const wrapper = mount(TodoApp)
    // 通过属性选择器获取全部元素 长度为1
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(1)
    // 设置input元素value = New todo
    wrapper.get('[data-test="new-todo"]').setValue('New todo')
    // 触发提交事件
    wrapper.get('[data-test="form"]').trigger('submit')
    // 再次回去长度应为2
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)
  })
})

运行这个程序显然会失败。让我们更新 TodoApp.vue 以拥有<form>并测试我们<input>测试,通过:

<template>
  <div>
    <div v-for="todo in todos" :key="todo.id" data-test="todo">
      {{ todo.text }}
    </div>
    <form data-test="form" @submit.prevent="createTodo">
      <input data-test="new-todo" v-model="newTodo" />
      <button type="submit"></button>
    </form>
  </div>
</template>

<script setup lang="ts" name="TodoApp">
  import { ref } from 'vue'
  const todos = ref([
    {
      id: 1,
      text: 'Learn Vue.js 3',
      completed: false,
    },
  ])
  const newTodo = ref('')
  function createTodo() {
    todos.value.push({
      id: 2,
      text: newTodo.value,
      completed: false,
    })
  }
</script>

我们使用绑定 v-model 到<input>并@submit 监听提交。createTodotodos

这看起来不错,但运行测试显示错误:

待办事项的数量没有。问题是 vitest 以同步方式执行测试, 并可能增加调用最终函数就结束测试。然而,Vue 会异步更新 DOM。我们需要标记测试 async,调用 await 任何导致 DOM 更改的方法。trigger 是这样的方法,所以是 setValue-我们可以按地预先设置并且设置 await 测试应该是一种简单的工作方式:

import { mount } from '@vue/test-utils'
import TodoApp from '../TodoApp/index.vue'
import { describe, it, expect } from 'vitest'
describe('renders a todo', () => {
  // 修改测试用例 添加async await
  it('creates a todo', async () => {
    const wrapper = mount(TodoApp)
    expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(1)

    await wrapper.get('[data-test="new-todo"]').setValue('New todo')
    await wrapper.get('[data-test="form"]').trigger('submit')

    // 异步获取长度
    await expect(wrapper.findAll('[data-test="todo"]')).toHaveLength(2)
  })
})

完成待办事项

现在可以创建待办事项,让我们可以让用户使用如已完成的待办事项为我们/未完成的项目标记。

import { mount } from '@vue/test-utils'
import TodoApp from '../TodoApp/index.vue'
import { describe, it, expect } from 'vitest'
describe('renders a todo', () => {
  // 修改测试用例 添加async await
  it('completes a todo', async () => {
    const wrapper = mount(TodoApp)

    await wrapper.get('[data-test="todo-checkbox"]').setValue(true)

    expect(wrapper.get('[data-test="todo"]').classes()).toContain('completed')
  })
})

本次测试与前两次类似;我们找到一个元素并以相同的方式与之交互(我们 setValue 再次使用,因为我们正在与 a 交互<input>)。

最后,我们做一个断言。我们将为 completed 完成的 todo 应用一个类——然后我们可以使用它来添加一些样式以直观地指示一个 todo 的状态。

我们可以通过更新 todo 元素<template>以包含<input type="checkbox">和类绑定来通过此测试:

<div
  v-for="todo in todos"
  :key="todo.id"
  data-test="todo"
  :class="[todo.completed ? 'completed' : '']"
>
  {{ todo.text }}
  <input type="checkbox" v-model="todo.completed" data-test="todo-checkbox" />
</div>

恭喜!您编写了第一个组件测试。