不喜勿喷,纯粹是个总结,喜欢就点个赞吧。🎉🎉🎉
What Vitest?
Why Vitest?
GitHub Demo
使用 Vite 快速构建一个初始项目
pnpm create vite share-vitest -- --template vue-ts
pnpm i
pnpm add @types/node -D
将 Vitest 添加到项目中
pnpm add vitest -D
pnpm add @vue/test-utils -D
配置 Vitest
- 增加
vitest.config.ts文件; - 新建
test文件,在其中创建setupFiles/index.ts文件为后续做准备; - 修改
vitest.config.ts文件
import { defineConfig } from "vitest/config";
import path from "path";
const resolveFile = (file: string) => path.resolve(__dirname, file);
export default defineConfig({
test: {
// 运行在每个测试文件前面
setupFiles: [resolveFile("./test/setupFiles/index.ts")],
},
});
- 在
package.json文件中增加test脚本。
配置 MSW
官方推荐使用 Mock Service Worker 来模拟网络请求,同时支持模拟 REST 和 GraphQL 网络请求,并且跟所使用的框架没有任何联系。
安装
pnpm add msw -D
开始
创建 test/mocks/server 文件夹,新建 handlers.ts 和 index.ts 两个文件,其中 handlers.ts 文件用于存模拟 api 请求处理集合。
在 handlers.ts 文件新增一个请求文章列表的接口,并对外暴露,详情见该文件 handlers.ts。
在 index.ts 文件中引入 setupServer ,并将 handlers 传入,详情见该文件 index.ts。
最后在 setupFiles/index.ts 文件中监听该服务,结束用例后关闭该服务。
至此,在 node 端模拟 api 请求配置大致完毕,接下来使用 Express 配置一个小型的接口输出。
配置 Express
安装
pnpm add express -D
开始
创建 index.js 文件,并增加获取文章列表的接口,启动服务,监听端口号为 4430。
使用 node server/index.js 启动服务后,执行 pnpm dev 查看列表是否加载正常。
问题总结
如何设置全局 setup?
-
新建
test/vitest.config.ts文件,在test中设置setupFiles配置;import { defineConfig } from "vitest/config"; export default defineConfig({ test: { // ... setupFiles: ["xxxx/setup.ts"], }, }); -
若在导入
vitest/config时 ts 报错,可以将版本升级至0.5.1+版本,相应的官方修复记录如下:
如何 mock 模块内的方法?
import { vi } from "vitest";
vi.mock("@/my-module", () => {
return {
get: (x: string) => x,
};
});
// mock node_module 模块
vi.mock("js-cookie", () => {
return {
// 使用 default,默认导出
default: {
get: (x: string) => x,
},
};
});
// x.spec.ts 文件
import { get } from "@/my-module";
import Cookies from "js-cookie";
Cookies.get(); // 以替换为 mock 的数据
如何解决 lodash-es 报错?
相关代码:
// ...
import merge from "lodash-es/merge";
// ...
相关的报错信息:
SyntaxError: Unexpected token 'export'
Module D:\xxx\node_modules\.pnpm\lodash-es@4.17.11\node_modules\lodash-es\_freeGlobal.js:4 seems to be an ES Module but shipped in a CommonJS package. You might want to create an issue to the package "D:\xxx\node_modules\.pnpm\lodash-es@4.17.11\node_modules\lodash-es\_freeGlobal.js:4" asking them to ship the file in .mjs extension or add "type": "module" in their package.json.
As a temporary workaround you can try to inline the package by updating your config:
// vitest.config.js
export default {
test: {
deps: {
inline: [
"D:\xxx\node_modules\.pnpm\lodash-es@4.17.11\node_modules\lodash-es\_freeGlobal.js:4"
]
}
}
}
其实提示信息已经给了我们解决问题的思路了,就是在 deps 中配置好 inline ,具体操作如下:
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
// ...
setupFiles: ["xxxx/setup.ts"],
deps: {
inline: ["lodash-es"],
},
},
});
使用 msw mock api 请求报错或请求未被捕获问题
具体错误信息如下:
[MSW] Error: captured a request without a matching request handler:
• GET http://localhost/api/policy
If you still wish to intercept this unhandled request, please create a request handler for it.
Read more: https://mswjs.io/docs/getting-started/mocks
引用官网的一句文案:
Bear in mind that without a DOM-like environment, like the jsdom from Jest, you must use absolute request URLs in NodeJS. This should be reflected in your request handlers:
需要设置具体的请求路径,如果项目中使用的是 axios 库,可以设置 axios.defaults.baseURL = 'https://api.backend.dev' 即可,但使用 rest.get 等方式还是需要将路径写全。如下代码:
const server = setupServer(
// NOT "/user", nothing to be relative to!
rest.get("https://api.backend.dev/user", (req, res, ctx) => {
return res(ctx.json({ firstName: "John" }));
})
);
mock document 问题
happy-dom or jsdom for DOM mocking. 具体的配置方式可以参考官方文档:
mock window.URL 问题
具体报错信息如下:
[error] TypeError: window.URL.createObjectURL is not a function
解决方案:
window.URL.createObjectURL = vi.fn((object: any) => object);
mock 对象某个属性值
实际在写单测场景时,想要修改某个传入对象中的属性值,那么直接使用 vi.mock 去解决显然是不合理的,因为这样会导致全局 mock ,导致影响其他模块的单测。
可以使用 vi.spyOn 解决该问题,而不影响到其他模块单元测试。
// @role
export const user = {
isAdmin: false,
isCustom: true,
};
// xx.spec.ts
import { user } from "@role";
vi.spyOn(user, "isAdmin", "get").mockImplementation(() => true);
若同个模块中其它测试场景下需要修改不同的属性值,可以使用 spyFn.mockRestore 解决。
it("xxx_1", () => {
const spy = vi.spyOn(user, "isAdmin", "get").mockImplementation(() => true);
expect(xxx).xxx();
spy.mockRestore();
});
it("xxx_2", () => {
const spy = vi.spyOn(user, "isAdmin", "get").mockImplementation(() => false);
expect(xxx).xxx();
spy.mockRestore();
});
vscode debugger 测试用例出现 Segmentation fault 问题
考虑降 node 版本
vitest 使用 happy-dom 仍然存在 Element 等内置方法不存在问题
-
执行测试用例,控制台输出如下错误:
[error] TypeError: ele.isEqualNode is not a function可以通过全局 mock 的方式解决:
global.HTMLElement.prototype.isEqualNode = vi.fn();