摘要:在項目中使用測試介紹測試又稱快照測試,可以直觀地反映出組件是否發生了未預見到的變化。結合進行測試生成快照時需要渲染并掛載組件,在中可以使用官方的單元測試實用工具。
在Vue項目中使用snapshot測試 snapshot介紹
snapshot測試又稱快照測試,可以直觀地反映出組件UI是否發生了未預見到的變化。snapshot如字面上所示,直觀描述出組件的樣子。通過對比前后的快照,可以很快找出UI的變化之處。
第一次運行快照測試時會生成一個快照文件。之后每次執行測試的時候,會生成一個快照,然后對比最初生成的快照文件,如果沒有發生改變,則通過測試。否則測試不通過,同時會輸出結果,對比不匹配的地方。
jest中的快照文件以為snap拓展名結尾,格式如下(ps: 在沒有了解之前,我還以為是快照文件是截圖)。一個快照文件中可以包含多個快照,快照的格式其實是HTML字符串,對于UI組件,其HTML會反映出其內部的state。每次測試只需要對比字符串是否符合初始快照即可。
exports[`button 1`] = `"1"`;
snapshot測試不通過的原因有兩個。一個原因是組件發生了未曾預見的變化,此時應檢查代碼。另一個原因是組件更新而快照文件并沒有更新,此時要運行jest -u更新快照。
? 1 snapshot failed from 1 test suite. Inspect your code changes or re-run jest with -u to update them.結合Vue進行snapshot測試
生成快照時需要渲染并掛載組件,在Vue中可以使用官方的單元測試實用工具Vue Test Utils。
Vue Test Utils 提供了mount、shallowMount這兩個方法,用于創建一個包含被掛載和渲染的 Vue 組件的 Wrapper。component是一個vue組件,options是實例化Vue時的配置,包括掛載選項和其他選項(非掛載選項,會將它們通過extend覆寫到其組件選項),結果返回一個包括了一個掛載組件或 vnode,以及測試該組件或 vnode 的方法的Wrapper實例。
mount(component:{Component}, options:{Object})
shallowMount與mount不同的是被存根的子組件,詳細請戳文檔。
Wrapper上的豐富的屬性和方法,足以應付本文中的測試需求。html()方法返回Wrapper DOM 節點的 HTML 字符串。find()和findAll()可以查找Wrapper里的DOM節點或Vue組件,可用于查找監聽事件的元素。trigger可以在DOM節點/組件上觸發一個事件。
結合上述的方法,我們可以完成一個模擬事件觸發的快照測試。
細心的讀者可能會發現,我們平時在使用Vue時,數據更新后視圖并不會立即更新,需要在nextTick回調中處理更新完成后的任務。但在 Vue Test Utils 中,為簡化用法,更新是同步的,所以無需在測試中使用 Vue.nextTick 來等待 DOM 更新。
demo演示Vue Test Utils官方文檔中提供了一個集成VTU和Jest的demo,不過這個demo比較舊,官方推薦用CLI3創建項目。
執行vue create vue-snapshot-demo創建demo項目,創建時要選擇單元測試,提供的庫有Mocha + Chai及Jest,在這里選擇Jest.安裝完成之后運行npm run serve即可運行項目。
本文中將用一個簡單的Todo應用項目來演示。這個Todo應用有簡單的添加、刪除和修改Todo項狀態的功能;Todo項的狀態有已完成和未完成,已完成時不可刪除,未完成時可刪除;已完成的Todo項會用一條線橫貫文本,未完成項會在鼠標懸浮時展示刪除按鈕。
組件簡單地劃分為Todo和TodoItem。TodoItem在Todo項未完成且觸發mouseover事件時會展示刪除按鈕,觸發mouseleave時則隱藏按鈕(這樣可以在快照測試中模擬事件)。TodoItem中有一個checkbox,用于切換Todo項的狀態。Todo項完成時會有一個todo-finished類,用于實現刪除線效果。
為方便這里只介紹TodoItem組件的代碼和測試。
{{item.content}}
進行快照測試時,除了測試數據渲染是否正確外還可以模擬事件。這里只貼快照測試用例的代碼,完整的代碼戳我。
describe("TodoItem snapshot test", () => { it("first render", () => { const wrapper = shallowMount(TodoItem, { propsData: { item: { finished: true, content: "test TodoItem" } } }) expect(wrapper.html()).toMatchSnapshot() }) it("toggle checked", () => { const renderer = createRenderer(); const wrapper = shallowMount(TodoItem, { propsData: { item: { finished: true, content: "test TodoItem" } } }) const checkbox = wrapper.find("input"); checkbox.trigger("click"); renderer.renderToString(wrapper.vm, (err, str) => { expect(str).toMatchSnapshot() }) }) it("mouseover", () => { const renderer = createRenderer(); const wrapper = shallowMount(TodoItem, { propsData: { item: { finished: false, content: "test TodoItem" } } }) wrapper.trigger("mouseover"); renderer.renderToString(wrapper.vm, (err, str) => { expect(str).toMatchSnapshot() }) }) })
這里有三個測試。第二個測試模擬checkbox點擊,將Todo項從已完成切換到未完成,期待類todo-finished會被移除。第三個測試在未完成Todo項上模擬鼠標懸浮,觸發mouseover事件,期待刪除按鈕會展示。
這里使用toMatchSnapshot()來進行匹配快照。這里生成快照文件所需的HTML字符串有wrapper.html()和Renderer.renderToString這兩種方式,區別在于前者是同步獲取,后者是異步獲取。
測試模擬事件時,最好以異步方式獲取HTML字符串。同步方式獲取的字符串并不一定是UI更新后的視圖。
盡管VTU文檔中說所有的更新都是同步,但實際上在第二個快照測試中,如果使用expect(wrapper.html()).toMatchSnapshot(),生成的快照文件中Todo項仍有類todo-finished,期待的結果應該是沒有類todo-finished,結果并非更新后的視圖。而在第三個快照測試中,使用expect(wrapper.html()).toMatchSnapshot()生成的快照,按鈕如期望展示,是UI更新后的視圖。所以才不建議在DOM更新的情況下使用wrapper.html()獲取HTML字符串。
下面是兩種對比的結果,1是使用wrapper.html()生成的快照,2是使用Renderer.renderToString生成的。
exports[`TodoItem snapshot test mouseover 1`] = `
這里使用vue-server-renderer提供的createRenderer來生成一個Renderer實例,實例方法renderToString來獲取HTML字符串。這種是典型的回調風格,斷言語句在回調中執行即可。
// ... wrapper.trigger("mouseover"); renderer.renderToString(wrapper.vm, (err, str) => { expect(str).toMatchSnapshot() })
如果不想使用這個庫,也可以使用VTU中提供的異步案例。由于wrapper.html()是同步獲取,所以獲取操作及斷言語句需要在Vue.nextTick()返回的Promise中執行。
// ... wrapper.trigger("mouseover"); Vue.nextTick().then(()=>{ expect(wrapper.html()).toMatchSnapshot() })觀察測試結果
執行npm run test:unit或yarn test:unit運行測試。
初次執行,終端輸出會有Snapshots: 3 written, 3 total這一行,表示新增三個快照測試,并生成初始快照文件。
? 3 snapshots written. Snapshot Summary ? 3 snapshots written from 1 test suite. Test Suites: 1 passed, 1 total Tests: 7 passed, 7 total Snapshots: 3 written, 3 total Time: 2.012s Ran all test suites. Done in 3.13s.
快照文件如下示:
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`TodoItem snapshot test first render 1`] = `
第二次執行測試后,輸出中有Snapshots: 3 passed, 3 total,表示有三個快照測試成功通過,總共有三個快照測試。
Test Suites: 1 passed, 1 total Tests: 7 passed, 7 total Snapshots: 3 passed, 3 total Time: 2s Ran all test suites. Done in 3.11s.
修改第一個快照中傳入的content,重新運行測試時,終端會輸出不匹配的地方,輸出數據的格式與Git類似,會標明哪一行是新增的,哪一行是被刪除的,并提示不匹配代碼所在行。
- Snapshot + Received -
同時會提醒你檢查代碼是否錯誤或重新運行測試并提供參數-u以更新快照文件。
Snapshot Summary ? 1 snapshot failed from 1 test suite. Inspect your code changes or re-run jest with `-u` to update them.
執行npm run test:unit -- -u或yarn test:unit -u更新快照,輸出如下示,可以發現有一個快照測試的輸出更新了。下次快照測試對照的文件是這個更新后的文件。
Test Suites: 1 passed, 1 total Tests: 7 passed, 7 total Snapshots: 1 updated, 2 passed, 3 total Time: 2.104s, estimated 3s Ran all test suites. Done in 2.93s.其他
除了使用toMatchSnapshot()外,還可以使用toMatchInlineSnapshot()。二者不同之處在于toMatchSnapshot()從快照文件中查找快照,而toMatchInlineSnapshot()則將傳入的參數當成快照文件進行匹配。
配置JestJest配置可以保存在jest.config.js文件里,可以保存在package.json里,用鍵名jest表示,同時也允許行內配置。
介紹幾個常用的配置。
rootDir查找Jest配置的目錄,默認是pwd。
testMatchjest查找測試文件的匹配規則,默認是[ "**/__tests__/**/*.js?(x)", "**/?(*.)+(spec|test).js?(x)" ]。默認查找在__test__文件夾中的js/jsx文件和以.test/.spec結尾的js/jsx文件,同時包括test.js和spec.js。
snapshotSerializers生成的快照文件中HTML文本沒有換行,是否能進行換行美化呢?答案是肯定的。
可以在配置中添加snapshotSerializers,接受一個數組,可以對匹配的快照文件做處理。jest-serializer-vue這個庫做的就是這樣任務。
如果你想要實現這個自己的序列化任務,需要實現的方法有test和print。test用于篩選處理的快照,print返回處理后的結果。
后記在未了解測試之前,我一直以為測試是枯燥無聊的。了解過快照測試后,我發現測試其實蠻有趣且實用,同時由衷地感嘆快照測試的巧妙之處。如果這個簡單的案例能讓你了解快照測試的作用及使用方法,就是我最大的收獲。
如果有問題或錯誤之處,歡迎指出交流。
參考鏈接vue-test-utils-jest-example
Jest - Snapshot Testing
Vue Test Utils
Vue SSR 指南
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100522.html
摘要:年工程化協作開發棧最佳實踐我們將花半小時實戰擼一個包含,的標準的用于工程協作的包開發棧。使用腳手架,秒鐘構建可自由配置的開發棧。分別表示詢問彈窗自動執行任務執行任務后操作。 發起一個github/npm工程協作項目,門檻太高了!! 最基礎的問題,你都要花很久去研究: 如何在項目中全線使用es2017代碼? 答案是babel 如何統一所有協作者的代碼風格? 答案是eslint + pr...
摘要:添加的的依賴,可以從項目的中拷貝使用命令編譯項目。在子模塊中我們可以這樣使用引入父模塊坐標三使用建立項目新建一個項目,選擇,如圖所示在中配置插件可參見官方文檔。部署項目到即可。 一、Maven入門 1.下載maven Maven是基于項目對象模型(Project Object Model),可以通過一小段描述信息來管理項目的構建、報告和文檔的項目管理工具,提供了一個倉庫的概念,統一...
摘要:本項目將使用配合最簡單的邏輯來展示一個基于的微服務全棧快速開發實踐的。提供一系列大型項目常用的非功能性特征,比如內嵌服務器,安全,指標,健康檢測,外部化配置。 SprintBoot-Vue SpringBoot + 前端MVVM 基于Java的微服務全棧快速開發實踐 showImg(https://segmentfault.com/img/remote/1460000010167913...
摘要:本項目將使用配合最簡單的邏輯來展示一個基于的微服務全棧快速開發實踐的。提供一系列大型項目常用的非功能性特征,比如內嵌服務器,安全,指標,健康檢測,外部化配置。 SprintBoot-Vue SpringBoot + 前端MVVM 基于Java的微服務全棧快速開發實踐 showImg(https://segmentfault.com/img/remote/1460000010167913...
摘要:新聞熱點國內國外,前端最新動態發布近日,正式發布新版本中提供了一系列的特性與問題修復。而近日正式發布,其能夠幫助開發者快速構建應用。 前端每周清單第 10 期:Firefox53、React VR發布、JS測試技術概述、Microsoft Edge現代DOM樹構建及性能之道 為InfoQ中文站特供稿件,首發地址為這里;如需轉載,請與InfoQ中文站聯系。從屬于筆者的 Web 前端入門...
閱讀 1438·2021-09-22 15:43
閱讀 2154·2019-08-30 15:54
閱讀 1154·2019-08-30 10:51
閱讀 2082·2019-08-29 18:35
閱讀 426·2019-08-26 11:58
閱讀 2476·2019-08-26 11:38
閱讀 2432·2019-08-23 18:35
閱讀 3627·2019-08-23 18:33