目前的項目已經維護了挺久,由於客戶要求,我們要為項目加上單元測試,挑選一番后選擇了Jest(配置簡便,開箱即用),下面記錄了此次為項目添加Jest作為單元測試的經歷。
安裝Jest
1. 在項目目錄下,執行命令vue add @vue/cli-plugin-unit-jest,這個命令會幫我們把相關的配置都配好,相關的依賴都裝好,還會幫我們生成一個jest.config.js文件,網上說還會生成tests文件夾,我試的沒有,另外還會幫你在eslintr.js文件下配置好jest需要的配置。
一開始的時候,我在編輯器下的控制台輸這個命令,提示錯誤,后來改到系統下的控制台才安裝成功。
用這個命令安裝是最方便的,我嘗試了幾次按照網上說的先安裝unit-jest,再安裝test-util之類的,都不成功。
2. 常用的一些jest配置項,在jest.config.js中配置。如果使用上面的命令,可以少配很多網上說的配置,比如下面標注了 不需要的
module.exports = { "moduleFileExtensions": [ //不需要配置 "js", "json", // 告訴 Jest 處理 `*.vue` 文件 "vue" ], testMatch: [ //test文件所在位置 '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' ], "transform": { //不需要配置 // 用 `vue-jest` 處理 `*.vue` 文件 ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest", // 用 `babel-jest` 處理 js "^.+\\.js$": "babel-jest" }, "moduleNameMapper": { //不需要配置 "^@/(.*)$": "<rootDir>/src/$1" }, "collectCoverage": true, //是否創建報告 "collectCoverageFrom": ["**/*.{js,vue}", "!**/node_modules/**"], //創建報告的文件來源 "coverageReporters": ["html", "text-summary"] //報告的格式
"coveragePathIgnorePatterns":"[]" //生成報告需要忽略的文件,默認值為 node_modules
"globals":{ //配置全局變量,此處我配置了一個全局變量VUE_APP_DATA,也可以在setup file中配置,如下說的lodash
"VUE_APP_DATA": {
siteENV:'DEV'
}
}
setupFiles:['<rootDir>/src/jest-setup.js'] //啟動jest需要的文件
};
3. 如果第一步沒有自動生成tests文件夾,可以自己在項目目錄下創建tests文件夾,再創建units文件夾,並添加example.spec.js文件,類似下面,具體原因可以看上面的配置項,testMatch,指定了test文件在這個目錄下,這個可以自己配置
import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld' describe('HelloWorld.vue', () => { it('renders props.msg when passed', () => { const msg = 'new message' const wrapper = shallowMount(HelloWorld, { propsData: { msg } }) expect(wrapper.text()).toMatch(msg) }) })
4. 在package.json中添加啟動命令,然后在控制台執行 npm run test:unit ,可以看到測試結果
"test:unit": "vue-cli-service test:unit"
Jest 踩坑
一開始的時候jes.config.js,其實沒有配置這么多東西,有些配置是遇到問題后才加的,以下記錄的是遇到的問題,以及解決辦法
1.全局變量報錯,可以配置globals(Object)屬性
2.webpack沒有打包進來的包,報錯,比如lodash,是以cnd形式引入的,項目中直接用_., 像這種需要配置setupFiles,把lodash添加給window對象,在src下的jest-setup.js文件內加上如下代碼,這個jest-setup.js就是jest測試需要的啟動文件,上面有配置
import _ from 'lodash';
if (typeof window !== 'undefined') {
window._ = _;
window.VUE_APP_DATA.resource ={'app':'cfcf'}
}
3. canvas的api報錯,比如CanvasRenderingContext2D,需要安裝jest-canvas-mock,把他引入jest-setup.js文件中
import 'jest-canvas-mock';
4.項目中引入第三方庫報錯,測試時Jest報錯,export default portalCommunication; ^^^^^^ SyntaxError: Unexpected token export > 1
報錯原因是node_modules下的文件默認是不會被transform的(默認配置),所以es6的寫法報錯了。
解決辦法就是在transformIgnorePatterns中把需要transform的文件排除掉,如下代碼,node_modules的文件夾都不會被transform,除了element-ui/src/mixins,
transformIgnorePatterns:["/node_modules/(?!(element-ui/src/mixins)/)"],
5.webpack指定 raw-loader!導入的文件,無法找到模塊
需要將路徑映射添加到我的 jest 配置中,以便讓我的測試識別我設置的路徑映射
"moduleNameMapper": {
"!raw-loader!@/(.*)": "<rootDir>\\src/\\$1",
6. require.context is not a function 報錯,需要添加新的依賴, babel-plugin-transform-require-context
.babelrc中增加
env:{
test:{
plugins:["transform-require-context"] //修復3個jest test報錯
}
}
7. CDN引入的Element UI,Element組件提示沒有注冊,比如HelloWorld組件中使用到了 el-button組件,就會報錯是否
解決辦法就是在jest-setup.js中創建lcoalVue,localVue使用Element組件,這個localVue需要被引入測試文件,測試組件的時候,使用這個localVue就可以了
import { shallowMount } from '@vue/test-utils' import HelloWorld from '@/components/HelloWorld' import {localVue} from '@/jest-setup' describe('HelloWorld.vue', () => { it('renders component', () => { const wrapper = shallowMount(HelloWorld, {localVue}) expect(wrapper.findAll('.hello-world').length).toBe(1) }) })
8.vue i18n國際化報錯:Vue warn]: Error in config.errorHandler: "TypeError: _vm.$t is not a function"
解決辦法就是,把某種國際化語言引入jest-setup.js,使用test-utils的mock api來mock全局對象
參考這篇文章
https://www.cnblogs.com/jiemao/p/12777826.html
在這里貼一下jest-setup.js文件
import _ from 'lodash'; if (typeof window !== 'undefined') { window._ = _; } import 'jest-canvas-mock'; //修復2個報錯 import { config,createLocalVue } from '@vue/test-utils'; import ElementUI from 'element-ui'; import language from '@/i18n/en'; import $store from '@/store'; config.mocks={ //給test-utils設置全局變量,適用於prototype定義的方法 $t:(msg) => language[msg], $store:$store, } const testVue = createLocalVue(); testVue.use(ElementUI); export const localVue = testVue;
如果文章對你有幫助,不妨給我個贊,謝謝~