Jest迁移到Vitest指南

3,069 阅读3分钟

Vitest是啥?

Vitest是去年由Vue团队出品的最新的测试框架,由于有Vite的支持,开发体验上几乎是顶级的,开发使用上面,Vitest几乎复制了一份Jest的API,支持了Jest拥有的功能且支持在浏览器运行,因此迁移起来成本不大。

在Vite项目中可以直接公用原有的项目配置(vite.config.js),在React中使用的配置也不麻烦。

缺点是目前还只是0.x.x版本,部分功能还有一些小bug,社区使用度还很低,迁移过程中的报错信息也不太友好,不过相信解决都只是时间的问题。

迁移后的效果

迁移到vitest主要是为了快,快就是王道,具体效果有多快?

Vitest跑全部测试:1.96s

image.png

Jest跑全部测试:9.415s

image.png

Jest跑单个测试:3.141s

image.png

Vite跑单个测试:1.64s

image.png

我的配置(太长不看?直接抄配置)

笔者的项目是React + Vitest + Testing Library技术栈,省时间可以直接抄配置。

// src/setupTests.ts
import '@testing-library/jest-dom'; //用来import RTL扩展的断言api 
// vite.config.js 
/// <reference types="vitest" /> 
/// <reference types="vite/client" /> 
import { defineConfig } from 'vitest/config'; 
import react from '@vitejs/plugin-react' 
import svgrPlugin from 'vite-plugin-svgr' 
export default defineConfig({ 
    plugins: [ 
        react(), 
        svgrPlugin({ svgrOptions: { icon: true } }) 
    ], 
    test: { 
        globals: true, 
        setupFiles: 'src/setupTests.tsx', 
        environment: "jsdom", 
        exclude: ["src/__visual_tests__", '**/node_modules/**', '**/dist/**', '**/cypress/**', '**/.{idea,git,cache,output,temp}/**'] 
    }, 
})

官方指南

自己踩的坑

1. Typescript对全局API的支持

Jest默认使用全局API(describe,jest,it等),通过配置,vite也能支持全局api,但是在TS项目中我们还需要配置一下tsconfig.json来确保静态检查不会报错:

// tsconfig.json 
{ "compilerOptions": { "types": ["vitest/globals"] } }

2. document is not defined

download.png

vite的默认运行环境的node,对于UI的dom测试,我们需要手动配置运行环境为jsdom,才能正常使用浏览器的api:

import { defineConfig } from 'vitest/config'; 
export default defineConfig({ test: { environment: "jsdom", }, })

3. Invalid Chai property

download (1).png toBeInTheDocument并非Chai的api,这个报错信息着实是有些迷惑,实际上toBeInTheDocument是RTL的api,这里报错是因为没有在setupTests中import RTL的jest-dom:

// vite.config.js 
// ... 
export default defineConfig({ test: { setupFiles: 'src/setupTests.tsx', }, })
// src/setupTests.tsx 
import '@testing-library/jest-dom';

4. jest is not defined

image.png

如果项目中原本有使用到全局对象jest的方法,比如jest.fn()jest.mock()等,运行测试时会报错,这个很自然,毕竟你已经迁移到jest了,jest全局对象当然是不能用了,这块其实vitest基本都兼容了jest用到的api了,你仅需把jest.批量替换为vi.,并确保全局api配置已经开启即可:

// vite.config.js // ... 
export default defineConfig({ test: { globals: true, }, })
// xxx.test.tsx 
// jest.mock(...) 
// 修改为 
vi.mock(...) 
// jest.fn(...) 
// 修改为 
vi.fn(...)

5. react is not defined;Unable to fire a "click" event - please provide a DOM element.

image.png

image.png

image.png 如果你测试的是react组件,使用了svgr等,你可能还需要配置一些vite plugins来支持运行时不报错:

// vite.config.js // ... import { defineConfig } from 'vitest/config'; 
import react from '@vitejs/plugin-react' 
import svgrPlugin from 'vite-plugin-svgr' 
export default defineConfig({ 
    plugins: [ 
        react(), 
        svgrPlugin({ svgrOptions: { icon: true } }) 
    ], 
});

6. mock es模块

使用jesk.mock来mock es模块时,默认能mock模块里面的default返回。

// setupTests.ts 
vi.mock('@scope/icon', () => { 
    return function Icon(props: IconProps) { 
        return <div data-testid="testIcon">{props.type}</div>; 
    }; 
}); 

然而直接把jest改成vi之后,就会出现一些奇怪的react报错:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

image.png

表示你import了一个undefined用来当成react组件来渲染。

解决办法:需要手动mock esm的 default export

// setupTests.ts 
vi.mock('@mail/ui.icon', () => {
  return {
    default: function Icon(props: IconProps) {
      return <div data-testid="testIcon">{props.type}</div>;
    },
  };
});