咲奈 2022-05-14 14:35:31 阅读数:620
開門見山,首先 vitest 是一個 esm first 的測試工具,所以他的定比特應該是 純 esm
/ 純 cjs
的場景,不像 jest 可以通過一些 transform
插件支持混雜場景。
什麼是混雜場景,比如我們使用 typescript 編寫 esm 格式的 source ,但是把產物編譯為 commonjs 格式,最後給 node 調用,這在 Native ESM 普及之前是 node 庫的基本操作。
當然現在有 type: "module"
帶來了 typescript 編譯的 esm 格式包和真正的 Native ESM 包。
我們這裏不就 esm 話題展開聊,關鍵在於這種源碼 esm 產物 cjs 是一種 混雜 場景。
這就違背了 vitest 的設計,不在 vitest 的概念內,所以自然無法使用 vitest 。
在混雜場景下,我不建議使用 vitest ,而使用 jest ,但如果非要使用 vitest 怎麼辦呢?我們有一種 workaround 的方法。
該方法的靈感和現在社區熱導入 ts 文件的做法一致,也是 esno
/ swno
/ esbuild-jest
等庫的底層原理。
在了解解法前,我們先簡單剖析一下 vitest 不支持的底層邏輯。
由於 vitest 在底層使用 vite 的 esbuild 能力 transform ts 文件,所以關鍵在 esbuild 的配置。
// vitest.config.ts
import {
defineConfig } from 'vitest/config'
export default defineConfig({
esbuild: {
target: 'node14',
format: 'cjs'
},
})
當我們把所有 transform 的 format 都定為 cjs
時,這將導致 *.test.ts
轉換為 cjs 格式,這就意味著最終 *.test.ts
內會出現 ts 文件的導入:
// before: test file
// example.test.ts
import {
method } from './some-file'
// after: transformed result
// example.test.js
const {
method } = require('./some-file')
注:以上轉換為偽代碼描述,並非真實結果。
其中 method
是 some-file.ts
文件的一個變量,關鍵在於 require()
是無法正常導入一個 .ts
文件的,由此將引發:
Error: Cannot find module ‘./some-file’
Require stack:
- …
// vitest.config.ts
import {
defineConfig } from 'vitest/config'
export default defineConfig({
esbuild: {
target: 'node14',
},
})
默認情况 vitest 是 esm 優先,所以我們的 test file *.test.ts
和相關導入的 .ts
文件會原模原樣使用 esm 格式來處理,但別忘了我們使用 typescript 的產物是 cjs 格式,最終運行時是 cjs 而不是 esm ,這就導致了兩者的概念發生沖突,將導致測試不符合預期,最終失敗。
關於此處的錯誤可能是千人千面的,大多可能和 cjs 的導入報錯相關,比如 TypeError: default is not a function
等。
剖析完底層邏輯,我們來看解法。
在上文的剖析中,既然 require()
不能導入 .ts
文件,那麼我們讓他支持就好了。
在每次啟動測試前人為 hook require.extensions
來支持 .ts
文件導入:
// hook.ts
import {
EsbuildPhoenix } from '@xn-sakina/phoenix'
// 這個類實現了 hook 對 .ts 文件的 require 導入並進行熱轉換
new EsbuildPhoenix({
target: 'es2019'
})
vitest 配置:
// vitest.config.ts
import {
defineConfig } from https://github.com/vitest-dev/vitest
export default defineConfig({
test: {
setupFiles: ['./hook']
},
esbuild: {
target: 'node14',
format: 'cjs'
},
})
由此,我們便可以 workaround 掉這個問題。
進一步思考,還有什麼沒考慮到的?
性能和 ts-jest
/ esbuild-jest
等 jest transform 插件實現思路一致,那麼速度和 vitest 誰快?
hook require
的一個邊緣情况是存在 require.cache
,如何應對?
如何應對 .tsx
的 jsx element 場景?
其他 edge case 是否都能無傷應對?
在此解法下,我順利跑通了兩大組非 jsx 測試,還是比較滿意的。
但綜合來看,仍然存在一些謎點待驗證,我們還不能認為他是萬能的解法。
雖然 vitest 在混合場景可圈可點,但在這一切之前,我們還需要注意 migrating from jest 的方法,關於這一點,官方文檔 有所描述,可以看到需要應對的點還是有不少的。
值得注意的是,我還是建議在業務 React Project 場景使用 RTL ,因為更成熟,但簡單的 libs jsx 場景可以使用 react-test-renderer
,這也是 vitest 推薦的做法。
同時,當你准備好擁抱 native esm 時,vitest 將是你不二的選擇,你也可以在官方倉庫 examples 找到更多的用例和打開姿勢。
版权声明:本文为[咲奈]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/134/202205141432588203.html