文章首發原文地址javascript
工欲善其事必先利其器,使用 jest 作 vue 單元測試前,首先的瞭解什麼是 jest。css
Jest 是一個由 Facebook 開發的測試運行器,致力於提供一個「bettery-included」單元測試解決方案。你能夠在其官方文檔學習到更多 Jest 的知識。html
建議使用 vue-cli3 腳手架,搭建 vue 環境,並使用 vue 建立一個 demo 環境vue
npm install -g @vue/cli-service-global
vue create test-demo
//安裝依賴
//插件的方式引入(建議使用此種方式)
vue add @vue/unit-jest
yarn add --dev babel-core@^7.0.0-bridge.0
//或者自定義安裝
yarn add --dev @babel/preset-env jest babel-jest vue-jest @vue/test-utils babel-core@^7.0.0-bridge.0 jest-transform-stub jest-html-reporter jest-serializer-vue jest-environment-jsdom-fifteen
複製代碼
其實使用@vue/unit-jest
的方式安裝 jest 測試環境,也是講上面的babel-jest,vue-jest
等依賴統一安裝。此處我使用的自定義依賴安裝方式以便於更好的介紹。java
依賴說明:node
若是使用自定義安裝方式,請記得將 babel.config.js 修改以下webpack
module.exports = {
presets: ["@vue/app", "@babel/preset-env"]
};
複製代碼
若是你不是使用的vue add @vue/unit-jest
的方式構建 jest 環境,請查看以下配置,不然請忽略!git
此處只是簡單介紹我在項目開發中使用到的配置,若是有興趣請見官方網址。 等上述工程依賴安裝完成以後,請查閱項目根目錄使用有一個jest.config.js
文件,若是不存在建議在根目錄下單首創建一個。es6
jest.config.js說明
github
module.exports = {
//每一個測試腳本都會執行的入口文件,經常咱們在這裏作一些初始化工做,好比可能項目中引用了一些ui庫。
setupFiles: ["<rootDir>/test/setup"],
//告訴jest處理那些文件,須要注意,測試vue文件,確定的加上vue
moduleFileExtensions: ["js", "vue", "jsx", "json"],
//別名,相似於webpack中的alias,可本身定義一些別名,方便引入庫
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
"^@components/(.*)$": "<rootDir>/src/components/$1",
"^@plugins": "<rootDir>/test/utils/plugins",
"^@test": "<rootDir>/test"
},
//代碼轉換配置,此處配置的js/jsx文件使用babel-jest轉換成es5
transform: {
"^.+\\.(js|jsx)$": "babel-jest",
"^.+\\.vue$": "vue-jest", //使用vue-jest轉換vue代碼
".+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$":
"jest-transform-stub"
},
testEnvironment: "jest-environment-jsdom-fifteen",
//快照測試時使用jest-serializer-vue,
snapshotSerializers: ["jest-serializer-vue"],
//jest作單元測試結果展現,通常狀況測試結果會在控制檯展現出來,若是須要以html的方式展現,能夠
//安裝jest-html-reporter,或者 majestic進行結果展現
//如何自定義展現結果,請見第三章
reporters: [
"default",
[
"./node_modules/jest-html-reporter",
{
pageTitle: "DemoTest",
includeFailureMsg: true,
outputPath: "./test-report.html",
includeConsoleLog: true
}
]
],
//此處很重要,見下文介紹
transformIgnorePatterns: ["/node_modules/", "/node_modules/(?!(你的ui庫))"],
//正則匹配那些文件須要測試
testMatch: [
"**/src/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)",
"**/test/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"
],
testURL: "http://localhost/",
//監聽測試文件插件,也能夠自定義哦
watchPlugins: [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname"
],
//是否開啓代碼測試覆蓋率【建議開啓】
collectCoverage: true,
coverageDirectory: "coverage",
coverageReporters: ["json", "lcov", "text", "clover"],
//此處必需要添加進行代碼測試覆蓋率時忽略那些文件
coveragePathIgnorePatterns: ["/node_modules/", "package.json", "yarn.lock"]
};
複製代碼
transformIgnorePatterns 配置說明:
默認狀況下jest不會轉換任何/node_modules中的代碼
,因爲 jest 在 node 中運行,所以咱們也沒必要轉換任何使用現代 ECMAScript 功能的東西,由於 Node> = 8 已經支持這些功能。 可是在一些狀況下,咱們確實須要轉換 node_modules 中的代碼。
import/export
編譯成module.export
針對上述四種狀況,能夠看出,若是你在單元測試文件中有使用到自定義 ui 庫的話,則必須告訴 jest,須要編譯轉換node_modules
中的那些代碼。此處的例子只是介紹了/node_modules/(?!(你的ui庫))
。
默認狀況下 jest 會將展現結果展現在控制檯中,那麼咱們如何自定義 jest 的展現結果呢?請見下文。 其實 jest 在執行完成單元測試以後會將測試結果以對象的方式返回。那麼咱們如何獲取到測試結果,官方文檔提供了一個口子,就是reports
配置。
也許不少朋友會說,jest 單元測試支持直接在構建時使用-json 的方式直接獲取,可是等你使用 reports 方式獲取時,你會發現 Json 結構是不同的。
自定義結果收集
// 自定義報告文件
class MyCustomReporter {
constructor(globalConfig, options) {
this._globalConfig = globalConfig;
this._options = options;
}
/** **咱們能夠在測試完成以後使用results獲取到測試結果 */
onRunComplete(contexts, results) {
console.log("jest配置: ", this._globalConfig);
console.log("額外的慘: ", this._options);
//經過results能夠將對象已html/其餘方式展現,就看你本身 咯。
}
}
module.exports = MyCustomReporter;
複製代碼
前面已經講述了 vue 和 jest 環境配置,若是沒看的朋友建議先看一下。 那麼爲何咱們要使用vue-test-utils
進行單元測試呢?引用官方的一句話Vue Test Utils 是 Vue.js 官方的單元測試實用工具庫。
若是不瞭解 Vue Test Utils 的話,建議先去官網學一下。
此處根據 vue 官方提供的例子,簡單介紹幾個測試用例的編寫,具體的測試用例還得根據業務場景去測試。
import { shallowMount } from "@vue/test-utils";
import MessageToggle from "@/components/MessageToggle.vue";
import Message from "@/components/Message.vue";
describe("MessageToggle.vue", () => {
it("toggles msg passed to Message when button is clicked", () => {
const wrapper = shallowMount(MessageToggle);
const button = wrapper.find("#toggle-message");
button.trigger("click");
const MessageComponent = wrapper.find(Message);
expect(MessageComponent.props()).toEqual({ msg: "message" });
button.trigger("click");
expect(MessageComponent.props()).toEqual({ msg: "toggled message" });
});
});
複製代碼
首先咱們得明白快照測試的意義,快照測試會將上一次運行(若是沒有使用命令更新快照的話)的結果(html)保存一份,以供和下一次單元測試結果進行對比,查看結果(html)是否相同。
注意理解:此處的和前一次對比,並非和前面代碼的toMatchSnapshot
結果對比,而是上一次執行單元測試的結果。
import { shallowMount } from "@vue/test-utils";
import List from "@/components/List.vue";
describe("List.vue", () => {
it("renders li for each item in props.items", () => {
const items = ["1", "2"];
const wrapper = shallowMount(List, {
propsData: { items }
});
expect(wrapper.findAll("li")).toHaveLength(items.length);
});
it("matches snapshot", () => {
const items = ["item 1", "item 2"];
const wrapper = shallowMount(List, {
propsData: { items }
});
//快照測試
expect(wrapper.html()).toMatchSnapshot();
});
});
複製代碼
//源文件child2.vue
<template>
<div>
<span>哈哈哈哈我是child</span>
<slot name="aa"></slot>
</div>
</template>
<script> export default { data() { return { data: { name: "插槽測試-----" } }; } }; </script>
<style></style>
複製代碼
import { mount } from "@vue/test-utils";
import Child from "@/components/child2.vue";
describe("Child", () => {
it("插槽測試", () => {
const wrapper = mount(Child, {
slots: {
//此處aa對應的是插槽的名字
aa: ` <div>啦啦啦,我是插槽的數據</div>`
}
});
expect(wrapper.html()).toMatchSnapshot();
});
});
複製代碼
//源文件child.vue
<template>
<div>
<span>哈哈哈哈我是child</span>
<slot name="ab" :bb="data"></slot>
</div>
</template>
<script> export default { data() { return { data: { name: "測試-----" } }; } }; </script>
<style></style>
複製代碼
//測試用例child.spec.js
import { mount } from "@vue/test-utils";
import Child from "@/components/child.vue";
describe("Child", () => {
it("做用域插槽測試", () => {
const wrapper = mount(Child, {
scopedSlots: {
//此處ab對應的是插槽的名字
ab: ` <div slot-scope="data">{{data.bb.name}}啦啦1</div>`
}
});
expect(wrapper.html()).toMatchSnapshot();
});
});
複製代碼
最後,感謝你們的閱讀,若是對您有幫助,請記得點個贊哦 原文地址