TDesign在vitest的實踐示例詳解

起源

tdesign-vue-nextCI 流程中,單元測試模塊的執行效率太低,每次在單元測試這個環節都需要花費 6m 以上。加上依賴按照,lint 檢查等環節,需要花費 8m 以上。

加上之前在單元測試這一塊隻是簡單的處理瞭一下,對開發者提交的組件也沒有相應的要求,隻是讓它能跑起來就好。另一方面單元測試目前是 TD 發佈正式版的一個卡點,所以準備對其進行一次梳理和重構,為後續的重點工作做準備。

痛點與現狀

  • 單元測試執行效率太低,上面已經講到瞭,這個速度是無法忍受。
  • 單元測試規范不明確,開發者沒有對應的單測規范可以遵循,不知道怎麼寫。
  • 單元測試中 snapshot 占據瞭大多數,每個組件的單元測試中其所有 demo 都做瞭一次 snapshot。這部分的代碼由腳本輸出。在一定程度上屬於集成測試,但執行過程融合在人工寫的單元測試當中,需要做集成測試的整合。

vitest

最開始註意到 vitest 是在 evan you 的分享裡面。vitest 的特性如下:

  • Vite 的配置、轉換器、解析器和插件通用,免去瞭額外對 jest 的配置
  • TypeScript / JSX 支持開箱即用的,像寫組件一樣寫測試
  • 多線程通過 tinypool 使用 Worker 線程盡可能多地並發運行測試。隔離瞭每個測試文件的運行環境,因此一個文件中的運行環境改變不會影響其他文件。
  • watch 模式下極速熱更,在單元測試開發時更友好
  • Jest 幾乎相同的 API,極少量的差異
  • 更清晰的 C8 生成測試覆蓋率
  • 源碼內聯測試
  • 非常酷的 GUI

遷移

配置文件改造

依賴,上面說到,vitest 的配置文件和 vite 的配置文件共用,且插件也是共用,所以不需要像配置 jest 一樣去配置 babel-jest, vue-jest, jest-serializer-vue 這些插件。

開發環境

vitest 中開發環境的執行命令

vitest --config site/vite.config.js 

單測開發的過程中,需要過濾對應的測試文件,則隻需要加上對應的文件路徑即可,具體如下:

#執行button組件的單測
vitest --config site/vite.config.js button
#執行button的index.test.jsx測試文件
vitest --config site/vite.config.js button/index.test.jsx 

另外還有 GUI 的選項

vitest --config site/vite.config.js --ui

集成測試

之前我們繼承測試環境有兩套 ssr 環境和 csr 環境。

ssr 環境

ssr 環境的測試需要做一個 setup 用來做組件 render,此部分和之前保持一致。

ssr-setup

import { config } from '@vue/test-utils';
import { createApp } from 'vue';
import { renderToString } from '@vue/server-renderer';
import TDesign from '@/src/index';
config.global.plugins = [TDesign];
// global掛載createSSRApp方法,掛載render環境的配置
config.global.createSSRApp = (comp) => {
  const app = createApp(comp);
  app.config.globalProperties.$route = {};
  app.use(TDesign);
  const html = renderToString(app);
  return html;
};

之前的執行環境是 commonjs 引入組件使用的是 require, 在 vite 中需要替換為 es 規范的 import

const demo = require(`../.${file}`);

ssr.test.js

import glob from 'glob';
import MockDate from 'mockdate';
import { config } from '@vue/test-utils';
MockDate.set('2020-12-28 00:00:00');
function runTest() {
  const files = glob.sync('./examples/**/demos/*.vue');
  const { createSSRApp } = config.global;
  describe('ssr snapshot test', () => {
    files.forEach((file) => {
      it(`ssr test ${file}`, async () => {
        const demo = await import(`../.${file}`); //此部分
        const realDemoComp = demo.default ? demo.default : demo;
        const html = await createSSRApp(realDemoComp);
        expect(html).toMatchSnapshot();
      });
    });
  });
}
runTest();

csr 環境

csr 環境的集成測試在之前使用的是腳本輸出一個如下的標準文件,分散在每個組件的單元測試裡面。這樣做影響單元測試的執行效率,對每個組件都開一個 describe, 這些代碼會影響單元測試的代碼結構。所以合並在一個文件執行是最合理的。其實現思路與ssr基本一致,隻是 render 不一樣而已。

/**
 * 該文件為由腳本 `npm run test:demo` 自動生成,如需修改,執行腳本命令即可。請勿手寫直接修改,否則會被覆蓋
 */
import { mount } from '@vue/test-utils';
import baseVue from '@/examples/affix/demos/base.vue';
import containerVue from '@/examples/affix/demos/container.vue';
const mapper = {
  baseVue,
  containerVue,
};
describe('Affix', () => {
  Object.keys(mapper).forEach((demoName) => {
    it(`Affix ${demoName} demo works fine`, () => {
      const wrapper = mount(mapper[demoName]);
      expect(wrapper.element).toMatchSnapshot();
    });
  });
});

csr.test.js

import glob from 'glob';
import MockDate from 'mockdate';
import { mount } from '@vue/test-utils';
MockDate.set('2020-12-28 00:00:00');
function runTest() {
  const files = glob.sync('./examples/**/demos/*.vue');
  describe('csr snapshot test', () => {
    files.forEach((file) => {
      it(`csr test ${file}`, async () => {
        const demo = await import(`../.${file}`);
        const realDemoComp = demo.default ? demo.default : demo;
        realDemoComp.name = `test-csr-${realDemoComp.name}`;
        const wrapper = mount(realDemoComp);
        expect(wrapper.element).toMatchSnapshot();
      });
    });
  });
}
runTest();

配置文件

vitest 的配置文件如下,下面這一段 config 隻需要掛在 vite.config.jstest 選項即可.

const testConfig = {
  include:
    process.env.NODE_ENV === 'test-snap'
      ? ['test/snap/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}']
      : ['test/unit/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
  globals: true,
  environment: 'jsdom',
  testTimeout: 5000,
  setupFiles: process.env.NODE_ENV === 'test-snap' ? path.resolve(__dirname, '../script/test/test-setup.js') : '',
  transformMode: {
    web: [/\.[jt]sx$/],
  },
  coverage: {
    reporter: ['text', 'json', 'html'],
  },
};

兼容性

因為我們老的測試方案基於 jest,相應的 API 都有。所以在遷移過程中,兼容性問題基隻有一些從 jest 中的函數,切換到 vi,其他問題沒有遇到。

before

const fn = jest.fn();

after

import { vi } from 'vitest';
const fn = vi.fn();

結果

CI測試速度提升

CI 中從原來的 6m 提升到 2m30, 執行效率提升百分之 60%,在開發機的執行效率更高(不同配置的機器執行效率不同,用 ci 中的標準執行做對比測試)。

更清爽的日志信息

jest 這一部分的 log 隻是單個組件的日志,而整個 log 記下來是非常長的,導致我們在開發中會忽略掉很多日志的告警。本地的 terminal 輸出的長度是有限制的。而 vitestlog 則非常清爽。

源碼傳送門

以上就是TDesign在vitest的實踐示例詳解的詳細內容,更多關於TDesign在vitest實踐的資料請關註WalkonNet其它相關文章!

推薦閱讀: