vue3 + tsx 项目搭配 jest 进行单元测试

660 阅读2分钟

1. 为什么要进行单元测试?

  1. 测试的目的为了确保代码执行达到预期效果
  2. 可测试的代码可读性相对高一些,提高开发者写代码的质量
  3. 减少 Bug 率

2. 开发环境

node 14.17.0
vue 3.x

3. 在项目中集成

3.1 安装以及配置 jest

首先安装 Jest 和 @vue/test-utils

pnpm install --save-dev jest@26 ts-jest @types/jest

接下来,package.json中我们配置脚本

// package.json
{
    "scripts": {
        "test": "jest"
    }
}

tsconfig.json 配置

{
  // ...
  "types": ["webpack-env", "jest"],
  // ...
}

3.2 在 Jest 中处理 vue 文件

要告诉 Jest 处理 .vue以及 .ts|.tsx 文件,需要安装和配置预处理器。

pnpm install --save-dev vue-jest ts-jest@26 @testing-library/vue@next

然后修改/新增 jest.config.js 文件

// jest.config.js
module.exports = {
  // ...
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
    '\\.(vue)$': 'vue-jest',
  },
  // ...
}

3.3 处理别名

如果想要使用别名,需要增加 Jest 配置 moduleNameMapper

// jest.config.js
module.exports = {
  // ...
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1"
  },
  // ...
}

3.4 babel 设定

安装 @babel/preset-env

pnpm install --save-dev @babel/preset-env

babel.config.js 配置

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        targets: {
          node: "current",
        },
      },
    ],
  ],
};

3.5 生成报导文件

"test": "jest --coverage" 在 package.json 的执行命令增加 --coverage 告诉 Jest 生存测试报导,约定生成报道的地址可以通过设置coverageDirectory

// jest.config.js
module.exports = {
  // ...
   coverageDirectory: './__test__/coverage',
  // ...
}

默认情况下 Jest 会获取项目中所有的 .test.js 文件,但是为了测试文件方便管理可以新建一个专门用于测试的目录。通过在 jest.config.js 中 testMatch 配置,去实现,例如 testMatch: ["/tests/**/*.spec.[jt]s?(x)"]

4. 写一个简单的 Demo 示例

新建文件 Counter.vue

// src/components/Counter.vue
<template>
  <div>
    <p>Times clicked: {{ count }}</p>
    <button @click="increment">increment</button>
  </div>
</template>

<script>
import { defineComponent } from "vue";
export default defineComponent({
  name: "Counter",
  data: () => ({
    count: 0,
  }),

  methods: {
    increment() {
      this.count++;
    },
  },
});
</script>

测试用例代码 counter.test.ts

// src/__tests__/counter.test.ts
import { render, fireEvent } from "@testing-library/vue";
import Counter from "@/components/Counter.vue";

test("increments value on click", async () => {
  // The render method returns a collection of utilities to query your component.
  const { getByText } = render(Counter);

  // getByText returns the first matching node for the provided text, and
  // throws an error if no elements match or if more than one match is found.
  getByText("Times clicked: 0");

  const button = getByText("increment");

  // Dispatch a native click event to our button element.
  await fireEvent.click(button);
  await fireEvent.click(button);

  getByText("Times clicked: 2");
});

运行测试用例 npm run test

image.png
打开报导文件

image.png