在完成一个组件之后,我们可以看到,想要测试你的组件,需要将他引入你的项目中,然后将你的组件的内容一项一项进行测试,在属性和内容多了以后,这样做是十分没用效率的,所以我们可以选用 vite 环境自带的 vitest 进行自动化测试

引入测试库

首先我们将我们需要的库导入到根目录中,前者是自动化测试的框架,后者是 Vue推荐的测试库,用于进行测试覆盖率的测试

pnpm add vitest happy-dom c8 -D -w

之后我们在我们需要测试的地方,也就是 components 文件夹中创建一个 vite.config.ts 文件,在这个配置文件中我们引入 vue 插件之后导入测试需要的测试插件

/// <reference types="vitest" />
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"
export default defineConfig(
    {
        plugins: [
            vue(),
        ],
        test: {
            environment: "happy-dom"
        },

    }
)

之后我们在 components 文件夹的 package.json 中写入测试的脚本,前者可以运行测试,而后者还可以进行测试覆盖率的测试

"scripts": {
    "test": "vitest",
    "coverage": "vitest run --coverage"
  },

在完成了测试框架的搭建以后,我们来编写我们的测试,在之前的篇章中,我们在 button 组件中预留了 __button__ 文件夹,我们现在在其中写入一个 button.test.ts 文件,vitest 运行之后,它会自动寻找文件夹中以

**.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx} 为格式的文件,运行其中的测试

下面简单讲解一下 vitest 的写法:

  • describe 此函数接受名称和函数,用于将相关测试组合在一起。当您为具有多个测试点(例如逻辑和外观)的组件编写测试时,它会派上用场。
  • it 这个函数代表被测试的实际代码块。它接受一个字符串,该字符串通常是测试用例的名称或描述
  • expect 此函数用于测试值或创建断言,内部包含一个测试的值 ,后接一个判断的条件
  • toBe 表示前面的结果要提供的一致才能通过测试
import { describe, expect, it } from "vitest";

describe("one plus oen is two", () => {
    it("should be 2", () => {
        expect(1 + 1).toBe(2)
    })
}

编写测试

因为我们的项目主要是组件库,所以我们需要在测试的时候先创建一个组件,再对组件的各项内容进行测试,所以这个时候我们就需要用到 @vue/test-utils 这个工具了

pnpm add @vue/test-utils -D -w

这个工具主要提供了一个mount方法,我们通过mount实例化一个组件,传入不同参数来测试组件是否符合我们的预期,例如:

import { describe, expect, it } from 'vitest';
import { mount } from '@vue/test-utils';
import button from '../button.vue';

describe('test Button', () => {
  it('slot test', () => {
    const wrapper = mount( button, {
      slots: {
        default: 'Hello world'
      }
    });
    expect(wrapper.text()).toContain('Hello world');
  });
});

以上的例子中,我们创建了一个 button 组件,然后将我们的传入一个 'Hello world' 的 slot,之后我们测试我们组件的 text 是不是包含 'Hello world' 这个内容我们在文件夹下运行 pnpm run test 可以看到测试成功,输出了以下的内容:

Test Files   1 passed (1)
      Tests  1 passed (1)
   Start at  21:05:23
   Duration  78ms

更多的测试相关的 api 内容可以在: https://cn.vitest.dev/guide/ 查看

关于更多 @vue/test-utils 的使用可以在 https://v1.test-utils.vuejs.org/zh/guides/ 查看

覆盖率测试

我们为我们的组件库编写两个测试,分别测试我们的类和slot :

describe('test Button', () => {
  it('slot test', () => {
    const wrapper = mount(button, {
      slots: {
        default: 'Hello world'
      }
    });
    expect(wrapper.text()).toContain('Hello world');
  });
  it('class test', () => {
    const wrapper = mount(button, {
      props: {
        type: 'primary'
      }
    });
    expect(wrapper.classes()).toContain('ls-button-primary');
  });
});

之后我们运行我们的 pnpm run coverage 脚本,可以看到,运行结果中,它会打印出一张表格

% Coverage report from c8
------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files   |   92.85 |      100 |   28.57 |   92.85 |
 button.vue |   93.54 |      100 |       0 |   93.54 | 24-25
 types.ts   |      92 |      100 |      40 |      92 | 18-19
------------|---------|----------|---------|---------|-------------------

它的含义是:

  • %stmts是语句覆盖率(statement coverage):是不是每个语句都执行了?
  • %Branch分支覆盖率(branch coverage):是不是每个if代码块都执行了?
  • %Funcs函数覆盖率(function coverage):是不是每个函数都调用了?
  • %Lines行覆盖率(line coverage):是不是每一行都执行了?

可以看到,因为我们的测试中没用测试 size 和 click函数的内容,我们的函数覆盖率是不够的,,最后一列也告诉了我们那么并没有被覆盖到,如果之后有需要我会继续补充相关我完整文档。

在根目录运行所有的测试内容

至此我们的组件测试包含了一个在 examples 文件夹内的引入组件的可视化测试,以及一个在 packages/components 文件夹内的自动化测试,如果我们想要运行每个内容需要经常切换文件夹,这是十分复杂的,所以我们在根目录的 package.json 中写入如下的内容:

"scripts": {
    "exm:dev": "pnpm run --filter ./examples dev",
    "test": "pnpm run --filter ./packages/components test",
    "coverage": "pnpm run --filter ./packages/components coverage"
  },

这些脚本可以让我们在根目录运行执行文件夹下方的 package.json 内部的脚本,使用这些脚本,我们就可以在根目录完成我们需要的操作,至此一个包含了测试的组件库框架已经搭建好了