原文鏈接:http://www.itdecent.cn/p/38a37d5fccb2
視屏鏈接:https://www.bilibili.com/video/av54531291
在《前端進(jìn)階之路: 前端架構(gòu)設(shè)計(jì)(3) - 測(cè)試核心》這邊文章中, 通過分析了"傳統(tǒng)手工測(cè)試的局限性" 去引出了測(cè)試驅(qū)動(dòng)開發(fā)的理念, 并介紹了一些測(cè)試工具. 這篇文章我將通過一個(gè)Vue的項(xiàng)目, 去講解如何使用mocha & karma, 且結(jié)合vue官方推薦的vue-test-utils去進(jìn)行單元測(cè)試的實(shí)戰(zhàn).
一. 安裝
我為本教程寫一個(gè)示例庫, 您可以直接跳過所有安裝過程, 安裝依賴后運(yùn)行該示例項(xiàng)目:
如果想一步步進(jìn)行安裝, 也可以跟著下面的步驟進(jìn)行操作:
(一) 使用腳手架初始化vue項(xiàng)目(使用webpack模板)
//命令行中輸入(默認(rèn)閱讀該文章的讀者已經(jīng)安裝vue-cli和node環(huán)境)vue init webpack vueunittest
注意, 當(dāng)詢問到這一步Pick a test runner(Use arrow keys)時(shí), 請(qǐng)選擇使用Karma and Mocha

選擇Karma ad Mocha
接下來的操作進(jìn)入項(xiàng)目npm install安裝相關(guān)依賴后(該步驟可能更會(huì)出現(xiàn)PhantomJS這個(gè)瀏覽器安裝失敗的報(bào)錯(cuò), 不用理會(huì), 因?yàn)? 之后我們不使用這個(gè)瀏覽器),npm run build即可.
(二) 安裝Karma-chrome-launch
接下來安裝karma-chrome-launcher, 在命令行中輸入
npm install karma-chrome-launcher --save-dev
然后在項(xiàng)目中找到test/unit/karma.conf.js文件, 將PhantomJS瀏覽器修改為Chrome不要問我為什么不使用PhantomJS, 因?yàn)榻?jīng)常莫名的錯(cuò)誤, 改成Chrome就不會(huì)!!!)
//karma.conf.jsvarwebpackConfig=require('../../build/webpack.test.conf')module.exports=function(config){config.set({//browsers: ['PhantomJS'],browsers:['Chrome'],...})}
(三) 安裝Vue-test-utils
安裝Vue.js 官方的單元測(cè)試實(shí)用工具庫, 在命令行輸入:
npm install--save-dev vue-test-utils
(四) 執(zhí)行npm run unit
當(dāng)你完成以上兩步的時(shí)候, 你就可以在命令行執(zhí)行npm run unit嘗鮮你的第一次單元測(cè)試了, Vue腳手架已經(jīng)初始化了一個(gè)HelloWorld.spec.js的測(cè)試文件去測(cè)試HelloWrold.vue, 你可以在test/unit/specs/HelloWorld.spec.js下找到這個(gè)測(cè)試文件.(提示: 將來所有的測(cè)試文件, 都將放specs這個(gè)目錄下, 并以測(cè)試腳本名.spec.js結(jié)尾命名!)
在命令行輸入npm run unit, 當(dāng)你看到下圖所示的一篇綠的時(shí)候, 說明你的單元測(cè)試通過了!

第一次單元測(cè)試測(cè)試通過
二. 測(cè)試工具的使用方法
下面是一個(gè)Counter.vue文件, 我將以該文件為基礎(chǔ)講解項(xiàng)目中測(cè)試工具的使用方法.
//Counter.vue<template><div><h3>Counter.vue</h3>{{count}}<button @click="increment">自增</button></div></template><script>exportdefault{data(){return{count:0}},methods:{increment(){this.count++}}}</script>
(一) Mocha框架
1. Mocha測(cè)試腳本的寫法
Mocha的作用是運(yùn)行測(cè)試腳本, 要對(duì)上面Counter.vue進(jìn)行測(cè)試, 我們就要寫測(cè)試腳本, 通常測(cè)試腳本應(yīng)該與Vue組件名相同, 后綴為spec.js. 比如,Counter.vue組件的測(cè)試腳本名字就應(yīng)該為Counter.spec.js
//Counter.spec.jsimportVuefrom'vue'importCounterfrom'@/components/Counter'describe('Counter.vue',()=>{it('點(diǎn)擊按鈕后, count的值應(yīng)該為1',()=>{//獲取組件實(shí)例constConstructor=Vue.extend(Counter);//掛載組件constvm=newConstructor().$mount();//獲取buttonconstbutton=vm.$el.querySelector('button');//新建點(diǎn)擊事件constclickEvent=newwindow.Event('click');//觸發(fā)點(diǎn)擊事件button.dispatchEvent(clickEvent);//監(jiān)聽點(diǎn)擊事件vm._watcher.run();// 斷言:count的值應(yīng)該是數(shù)字1expect(Number(vm.$el.querySelector('.num').textContent)).to.equal(1);})})
上面這段代碼就是一個(gè)測(cè)試腳本.測(cè)試腳本應(yīng)該包含一個(gè)或多個(gè)describe, 每個(gè)describe塊應(yīng)該包括一個(gè)或多個(gè)it塊
describe塊稱為"測(cè)試套件"(test suite), 表示一組相關(guān)的測(cè)試. 它是一個(gè)函數(shù), 第一個(gè)參數(shù)是測(cè)試套件的名稱(通常寫測(cè)試組件的名稱, 這里即為Counter.js), 第二個(gè)參數(shù)是一個(gè)實(shí)際執(zhí)行的函數(shù).
it塊稱為"測(cè)試用例"(test case), 表示一個(gè)單獨(dú)的測(cè)試, 是測(cè)試的最小單位. 它也是一個(gè)函數(shù), 第一個(gè)參數(shù)是測(cè)試用例的名稱(通常描述你的斷言結(jié)果, 這里即為"點(diǎn)擊按鈕后, count的值應(yīng)該為1"), 第二個(gè)參數(shù)是一個(gè)實(shí)際執(zhí)行的函數(shù).
2. Mocha進(jìn)行異步測(cè)試
我們?cè)贑ounter.vue組件中添加一個(gè)按鈕, 并添加一個(gè)異步自增的方法為incrementByAsync, 該函數(shù)設(shè)置一個(gè)延時(shí)器, 1000ms后count自增1.
<template>...<button @click="increment">自增</button><button @click="incrementByAsync">異步自增</button>...<template><script>...methods:{...incrementByAsync(){window.setTimeout(()=>{this.count++;},1000)}}</script>
給測(cè)試腳本中新增一個(gè)測(cè)試用例, 也就是it()
it('count異步更新, count的值應(yīng)該為1',(done)=>{///獲取組件實(shí)例constConstructor=Vue.extend(Counter);//掛載組件constvm=newConstructor().$mount();//獲取buttonconstbutton=vm.$el.querySelectorAll('button')[1];//新建點(diǎn)擊事件constclickEvent=newwindow.Event('click');//觸發(fā)點(diǎn)擊事件button.dispatchEvent(clickEvent);//監(jiān)聽點(diǎn)擊事件vm._watcher.run();//1s后進(jìn)行斷言window.setTimeout(()=>{// 斷言:count的值應(yīng)該是數(shù)字1expect(Number(vm.$el.querySelector('.num').textContent)).to.equal(1);done();},1000);})
Mocha中的異步測(cè)試, 需要給it()內(nèi)函數(shù)的參數(shù)中添加一個(gè)done, 并在異步執(zhí)行完后必須調(diào)用done(), 如果不調(diào)用done(), 那么Mocha會(huì)在2000ms后報(bào)錯(cuò)且本次單元測(cè)試測(cè)試失敗(mocha默認(rèn)的異步測(cè)試超時(shí)上線為2000ms), 錯(cuò)誤信息如下:

未調(diào)用done()的報(bào)錯(cuò)
3. Mocha的測(cè)試鉤子
如果大家對(duì)于vue的mounted(),created()鉤子能夠理解的話, 對(duì)Mocha的鉤子也很容易理解, Mocha在describe塊中提供了四個(gè)鉤子:before(),after(),beforeEach(),afterEach(). 它們會(huì)在以下時(shí)間執(zhí)行
describe('鉤子說明',function(){before(function(){// 在本區(qū)塊的所有測(cè)試用例之前執(zhí)行});after(function(){// 在本區(qū)塊的所有測(cè)試用例之后執(zhí)行});beforeEach(function(){// 在本區(qū)塊的每個(gè)測(cè)試用例之前執(zhí)行});afterEach(function(){// 在本區(qū)塊的每個(gè)測(cè)試用例之后執(zhí)行});});
上述就是Mocha的基本使用介紹, 如果想了解Mocha的更多使用方法, 可以查看下面的文檔和一篇阮一峰的Mocha教程:
Mocha官方文檔 :https://mochajs.org/
Mocha官方文檔翻譯 :http://www.itdecent.cn/p/9c78548caffa
阮一峰 - 測(cè)試框架 Mocha 實(shí)例教程 :http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
(二) Chai斷言庫
上面的測(cè)試用例中, 以expect()方法開頭的就是斷言.
expect(Number(vm.$el.querySelector('.num').textContent)).to.equal(1);
所謂斷言, 就是判斷源碼的實(shí)際執(zhí)行結(jié)果與預(yù)期結(jié)果是否一致, 如果不一致, 就會(huì)拋出錯(cuò)誤. 上面的斷言的意思是指: 有.num這類名的節(jié)點(diǎn)的內(nèi)容應(yīng)該為數(shù)字1. 斷言庫庫有很多種, Mocha并不限制你需要使用哪一種斷言庫,? Vue的腳手架提供的斷言庫是sino-chai, 是一個(gè)基于Chai的斷言庫, 并且我們指定使用的是它的expect斷言風(fēng)格.
expect斷言風(fēng)格的優(yōu)點(diǎn)很接近于自然語言, 下面是一些例子
// 相等或不相等expect(1+1).to.be.equal(2);expect(1+1).to.be.not.equal(3);// 布爾值為trueexpect('hello').to.be.ok;expect(false).to.not.be.ok;// typeofexpect('test').to.be.a('string');expect({foo:'bar'}).to.be.an('object');expect(foo).to.be.an.instanceof(Foo);// includeexpect([1,2,3]).to.include(2);expect('foobar').to.contain('foo');expect({foo:'bar',hello:'universe'}).to.include.keys('foo');// emptyexpect([]).to.be.empty;expect('').to.be.empty;expect({}).to.be.empty;// matchexpect('foobar').to.match(/^foo/);
每一個(gè)it()所包裹的測(cè)試用例都應(yīng)該有一句或多句斷言,上面只是介紹了一部分的斷言語法, 如果想要知道更多Chai的斷言語法, 請(qǐng)查看以下的官方文檔.
Chai官方文檔:http://chaijs.com/
Chai官方文檔翻譯:http://www.itdecent.cn/p/f200a75a15d2
(三) Vue-test-utils測(cè)試庫
1. 在測(cè)試腳本中引入vue-test-utils
//Counter.spec.jsimportVuefrom'vue'importCounterfrom'@/components/Counter'//引入vue-test-utilsimport{mount}from'vue-test-utils'
2. 測(cè)試文本內(nèi)容
下面我將在Counter.spec.js測(cè)試腳本中對(duì)Counter.vue中<h3>的文本內(nèi)容進(jìn)行測(cè)試, 大家可以直觀的感受一下使用了Vue-test-utils后對(duì).vue單文件組件的測(cè)試變得多么簡單.
未使用vue-test-utils的測(cè)試用例:
it('未使用Vue-test-utils: 正確渲染h3的文字為Counter.vue',()=>{constConstructor=Vue.extend(Counter);constvm=newConstructor().$mount();constH3=vm.$el.querySelector('h3').textContent;expect(H3).to.equal('Counter.vue');})
使用了vue-test-utils的測(cè)試用例:
it('使用Vue-test-Utils: 正確渲染h3的文字為Counter.vue',()=>{constwrapper=mount(Counter);expect(wrapper.find('h3').text()).to.equal('Counter.vue');})
從上面的代碼可以看出, vue-test-utils工具將該測(cè)試用例的代碼量減少了一半, 如果是更復(fù)雜的測(cè)試用例, 那么代碼量的減少將更為突出.? 它可以讓我們更專注于去寫文件的測(cè)試邏輯, 將獲取組件實(shí)例和掛載的繁瑣的操作交由vue-test-utils去完成.
3. vue-test-utils的常用API
find(): 返回匹配選擇器的第一個(gè)DOM節(jié)點(diǎn)或Vue組件的wrapper, 可以使用任何有效的選擇器
text(): 返回wrapper的文本內(nèi)容
html(): 返回wrapper DOM的HTML字符串
it('find()/text()/html()方法',()=>{constwrapper=mount(Counter);consth3=wrapper.find('h3');expect(h3.text()).to.equal('Counter.vue');expect(h3.html()).to.equal('<h3>Counter.vue</h3>');})
trigger(): 在該wrapper DOM節(jié)點(diǎn)上觸發(fā)一個(gè)事件。
it('trigger()方法',()=>{constwrapper=mount(Counter);constbuttonOfSync=wrapper.find('.sync-button');buttonOfSync.trigger('click');buttonOfSync.trigger('click');constcount=Number(wrapper.find('.num').text());expect(count).to.equal(2);})
setData(): 設(shè)置data的屬性并強(qiáng)制更新
it('setData()方法',()=>{constwrapper=mount(Counter);wrapper.setData({foo:'bar'});expect(wrapper.vm.foo).to.equal('bar');})
上面介紹了幾個(gè)vue-test-utils提供的方法, 如果想深入學(xué)習(xí)vue-test-utils, 請(qǐng)閱讀下面的官方文檔:
vue-test-utils官方文檔:https://vue-test-utils.vuejs.org/zh-cn/
三. 項(xiàng)目說明
該項(xiàng)目模仿了一個(gè)簡單的微博, 在代碼倉庫下載后, 可直接通過npm run dev運(yùn)行.
(一) 項(xiàng)目效果圖

項(xiàng)目展示
(二) 項(xiàng)目中的交互邏輯和需求
在文本框中輸入內(nèi)容后點(diǎn)擊"發(fā)布"按鈕(1), 會(huì)新發(fā)布內(nèi)容到微博列表中, 且個(gè)人頭像等下的微博數(shù)量(6)會(huì)增加1個(gè)
當(dāng)文本框中無內(nèi)容時(shí), 不能發(fā)布空微博到微博列表, 且彈出提示框, 叫用戶輸入內(nèi)容
當(dāng)點(diǎn)擊"關(guān)注"(2), 個(gè)人頭像下關(guān)注的數(shù)量(5)會(huì)增加1個(gè), 且按鈕內(nèi)字體變成"取消關(guān)注"; 當(dāng)點(diǎn)擊"取消關(guān)注"(2), 個(gè)人頭像下的數(shù)量(5)會(huì)減少1個(gè), 且按鈕內(nèi)字體變成"關(guān)注"
當(dāng)點(diǎn)擊"收藏"(3)時(shí), 我的收藏(7)會(huì)增加1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"已收藏"; 點(diǎn)擊"已收藏"(3)時(shí), 我的收藏(7)會(huì)減少1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"收藏"
當(dāng)點(diǎn)擊"贊"(4), 我的贊(8)會(huì)增加1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"取消贊"; 點(diǎn)擊"取消贊"(3)時(shí), 我的贊(8)會(huì)減少1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"贊"
(三) 項(xiàng)目源碼
//SinaWeibo.vue<template><divclass="weibo-page"><nav><spanclass="weibo-logo"></span><divclass="search-wrapper"><input type="text"placeholder="大家正在搜: 李棠輝的文章好贊!"><img v-if="!iconActive"@mouseover="mouseOverToIcon"src="../../static/image/search.png"alt="搜索icon"><img v-if="iconActive"@mouseout="mouseOutToIcon"src="../../static/image/search-active.png"alt="搜索icon"></div></nav><divclass="main-container"><asideclass="aside-nav"><ul><li:class="{ active: isActives[indexOfContent] }"v-for="(content, indexOfContent) in asideTab":key="indexOfContent"@click="tabChange(indexOfContent)"><span>{{content}}</span><spanclass="count"><span v-if="indexOfContent === 1">({{collectNum}})</span><span v-if="indexOfContent === 2">({{likeNum}})</span></span></li></ul></aside><mainclass="weibo-content"><divclass="weibo-publish-wrapper"><img src="../../static/image/tell-people.png"></img><textarea v-model="newWeiboContent.content"></textarea><button @click="publishNewWeiboContent">發(fā)布</button></div><divclass="weibo-news"v-for="(news, indexOfNews) in weiboNews":key="indexOfNews"><divclass="content-wrapper"><divclass="news-title"><divclass="news-title__left"><img:src="news.imgUrl"><divclass="title-text"><divclass="title-name">{{news.name}}</div><divclass="title-time">{{news.resource}}</div></div></div><buttonclass="news-title__right add"v-if="news.attention === false"@click="attention(indexOfNews)"><iclass="fa fa-plus"></i>關(guān)注</button><buttonclass="news-title__right cancel"v-if="news.attention === true"@click="unAttention(indexOfNews)"><iclass="fa fa-close"></i>取消關(guān)注</button></div><divclass="news-content">{{news.content}}</div><divclass="news-image"v-if="news.images.length"><img? ? ? ? ? ? v-for="(img, indexOfImg) in news.images":key="indexOfImg":src="img"></div></div><ulclass="news-panel"><li @click="handleCollect(indexOfNews)"><iclass="fa fa-star-o":class="{collected: news.collect }"></i>{{news.collect?"已收藏":'收藏'}}</li><li><iclass="fa fa-external-link"></i>轉(zhuǎn)發(fā)</li><li><iclass="fa fa-commenting-o"></i>評(píng)論</li><li @click="handleLike(indexOfNews)"><iclass="fa fa-thumbs-o-up":class="{liked: news.like}"></i>{{news.like?'取消贊':'贊'}}</li></ul></div></main><asideclass="aside-right"><divclass="profile-wrapper"><divclass="profile-top"><img src="../../static/image/profile.jpg"></div><divclass="profile-bottom"><divclass="profile-name">Lee_tanghui</div><ulclass="profile-info"><li? ? ? ? ? ? ? ? v-for="(profile, indexOfProfile) in profileData":key="indexOfProfile"><divclass="number">{{profile.num}}</div><divclass="text">{{profile.text}}</div></li></ul></div></div></aside></div><footer>Wish you like my blog!---LITANGHUI</footer></div></template><script>//引入假數(shù)據(jù)import*asmockDatafrom'../mock-data.js'exportdefault{mounted(){//模擬獲取數(shù)據(jù)this.profileData=mockData.profileData;this.weiboNews=mockData.weiboNews;this.collectNum=mockData.collectNum;this.likeNum=mockData.likeNum;},data(){return{iconActive:false,asideTab:["首頁","我的收藏","我的贊"],isActives:[true,false,false],profileData:[],weiboNews:[],collectNum:0,likeNum:0,newWeiboContent:{imgUrl:'../../static/image/profile.jpg',name:'Lee_tanghui',resource:'剛剛 來自 網(wǎng)頁版微博',content:'',images:[]},}},methods:{mouseOverToIcon(){this.iconActive=true;},mouseOutToIcon(){this.iconActive=false;},tabChange(indexOfContent){this.isActives.forEach((item,index)=>{index===indexOfContent?this.$set(this.isActives,index,true):this.$set(this.isActives,index,false);})},publishNewWeiboContent(){if(!this.newWeiboContent.content){alert('請(qǐng)輸入內(nèi)容!')return;}constnewWeibo=JSON.parse(JSON.stringify(this.newWeiboContent));this.weiboNews.unshift(newWeibo);this.newWeiboContent.content='';this.profileData[2].num++;},attention(index){this.weiboNews[index].attention=true;this.profileData[0].num++;},unAttention(index){this.weiboNews[index].attention=false;this.profileData[0].num--;},handleCollect(index){this.weiboNews[index].collect=!this.weiboNews[index].collect;this.weiboNews[index].collect?this.collectNum++:this.collectNum--;},handleLike(index){this.weiboNews[index].like=!this.weiboNews[index].like;this.weiboNews[index].like?this.likeNum++:this.likeNum--;}}}</script><style lang="less">//css部分略</style>
四. 項(xiàng)目單元測(cè)試腳本實(shí)戰(zhàn)
我們將以上文提到的"項(xiàng)目中的交互邏輯和需求"為基礎(chǔ), 為SinaWeibo.vue編寫測(cè)試腳本, 下面我將展示測(cè)試用例編寫過程:
1.在文本框中輸入內(nèi)容后點(diǎn)擊"發(fā)布"按鈕(1), 會(huì)新發(fā)布內(nèi)容到微博列表中, 且個(gè)人頭像等下的微博數(shù)量(6)會(huì)增加1個(gè)
it('點(diǎn)擊發(fā)布按鈕,發(fā)布新內(nèi)容&個(gè)人微博數(shù)量增加1個(gè)',()=>{constwrapper=mount(SinaWeibo);consttextArea=wrapper.find('.weibo-publish-wrapper textarea');constbuttonOfPublish=wrapper.find('.weibo-publish-wrapper button');constlengthOfWeiboNews=wrapper.vm.weiboNews.length;constcountOfMyWeibo=wrapper.vm.profileData[2].num;//設(shè)置textArea的綁定數(shù)據(jù)wrapper.setData({newWeiboContent:{imgUrl:'../../static/image/profile.jpg',name:'Lee_tanghui',resource:'剛剛 來自 網(wǎng)頁版微博',content:'歡迎來到我的微博',images:[]}});//觸發(fā)點(diǎn)擊事件buttonOfPublish.trigger('click');constlengthOfWeiboNewsAfterPublish=wrapper.vm.weiboNews.length;constcountOfMyWeiboAfterPublish=wrapper.vm.profileData[2].num;//斷言: 發(fā)布新內(nèi)容expect(lengthOfWeiboNewsAfterPublish).to.equal(lengthOfWeiboNews+1);//斷言: 個(gè)人微博數(shù)量增加1個(gè)expect(countOfMyWeiboAfterPublish).to.equal(countOfMyWeibo+1);})
測(cè)試結(jié)果:

通過測(cè)試
2.當(dāng)文本框中無內(nèi)容時(shí), 不能發(fā)布空微博到微博列表, 且彈出提示框, 叫用戶輸入內(nèi)容
it('當(dāng)文本框中無內(nèi)容時(shí), 不能發(fā)布空微博到微博列表, 且彈出提示框',()=>{constwrapper=mount(SinaWeibo);consttextArea=wrapper.find('.weibo-publish-wrapper textarea');constbuttonOfPublish=wrapper.find('.weibo-publish-wrapper button');constlengthOfWeiboNews=wrapper.vm.weiboNews.length;constcountOfMyWeibo=wrapper.vm.profileData[2].num;//設(shè)置textArea的綁定數(shù)據(jù)為空wrapper.setData({newWeiboContent:{imgUrl:'../../static/image/profile.jpg',name:'Lee_tanghui',resource:'剛剛 來自 網(wǎng)頁版微博',content:'',images:[]}});//觸發(fā)點(diǎn)擊事件buttonOfPublish.trigger('click');constlengthOfWeiboNewsAfterPublish=wrapper.vm.weiboNews.length;constcountOfMyWeiboAfterPublish=wrapper.vm.profileData[2].num;//斷言: 沒有發(fā)布新內(nèi)容expect(lengthOfWeiboNewsAfterPublish).to.equal(lengthOfWeiboNews);//斷言: 個(gè)人微博數(shù)量不變expect(countOfMyWeiboAfterPublish).to.equal(countOfMyWeibo);})
測(cè)試結(jié)果:

image_1c2l52h0i11e51fjqm9o8751m7hm.png-32.4kB
3.當(dāng)點(diǎn)擊"關(guān)注"(2), 個(gè)人頭像下關(guān)注的數(shù)量(5)會(huì)增加1個(gè), 且按鈕內(nèi)字體變成"取消關(guān)注"; 當(dāng)點(diǎn)擊"取消關(guān)注"(2), 個(gè)人頭像下的數(shù)量(5)會(huì)減少1個(gè), 且按鈕內(nèi)字體變成"關(guān)注"
it('當(dāng)點(diǎn)擊"關(guān)注", 個(gè)人頭像下關(guān)注的數(shù)量會(huì)增加1個(gè), 且按鈕內(nèi)字體變成"取消關(guān)注"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfAddAttendion=wrapper.find('.add');constcountOfMyAttention=wrapper.vm.profileData[0].num;//觸發(fā)事件buttonOfAddAttendion.trigger('click');constcountOfMyAttentionAfterClick=wrapper.vm.profileData[0].num;//斷言: 個(gè)人頭像下關(guān)注的數(shù)量會(huì)增加1個(gè)expect(countOfMyAttentionAfterClick).to.equal(countOfMyAttention+1);//斷言: 按鈕內(nèi)字體變成"取消關(guān)注expect(buttonOfAddAttendion.text()).to.equal('取消關(guān)注');})
it('當(dāng)點(diǎn)擊"取消關(guān)注", 個(gè)人頭像下關(guān)注的數(shù)量會(huì)減少1個(gè), 且按鈕內(nèi)字體變成"關(guān)注"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfUnAttendion=wrapper.find('.cancel');constcountOfMyAttention=wrapper.vm.profileData[0].num;//觸發(fā)事件buttonOfUnAttendion.trigger('click');constcountOfMyAttentionAfterClick=wrapper.vm.profileData[0].num;//斷言: 個(gè)人頭像下關(guān)注的數(shù)量會(huì)增加1個(gè)expect(countOfMyAttentionAfterClick).to.equal(countOfMyAttention-1);//斷言: 按鈕內(nèi)字體變成"取消關(guān)注expect(buttonOfUnAttendion.text()).to.equal('關(guān)注');})
測(cè)試結(jié)果:

image_1c2lbcvod1d7ton71mod1i6b1bt13.png-62.3kB
4.當(dāng)點(diǎn)擊"收藏"(3)時(shí), 我的收藏(7)會(huì)增加1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"已收藏"; 點(diǎn)擊"已收藏"(3)時(shí), 我的收藏(7)會(huì)減少1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"收藏"
it('當(dāng)點(diǎn)擊"收藏"時(shí), 我的收藏會(huì)增加1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"已收藏"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfCollect=wrapper.find('.collectWeibo');constcountOfMyCollect=Number(wrapper.find('.collect-num span').text());//觸發(fā)點(diǎn)擊事件buttonOfCollect.trigger('click');constcountOfMyCollectAfterClick=Number(wrapper.find('.collect-num span').text());//斷言: 我的收藏?cái)?shù)量會(huì)加1expect(countOfMyCollectAfterClick).to.equal(countOfMyCollect+1);//斷言: 按鈕內(nèi)文字變成已收藏expect(buttonOfCollect.text()).to.equal('已收藏');})
it('當(dāng)點(diǎn)擊"已收藏"時(shí), 我的收藏會(huì)減少1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"收藏"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfUnCollect=wrapper.find('.uncollectWeibo');constcountOfMyCollect=Number(wrapper.find('.collect-num span').text());//觸發(fā)點(diǎn)擊事件buttonOfUnCollect.trigger('click');constcountOfMyCollectAfterClick=Number(wrapper.find('.collect-num span').text());//斷言: 我的收藏?cái)?shù)量會(huì)減1expect(countOfMyCollectAfterClick).to.equal(countOfMyCollect-1);//斷言: 按鈕內(nèi)文字變成已收藏expect(buttonOfUnCollect.text()).to.equal('收藏');})
測(cè)試結(jié)果:

image_1c2lbdfe9i5jrja10cc447rgj1g.png-88.6kB
5.當(dāng)點(diǎn)擊"贊"(4), 我的贊(8)會(huì)增加1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"取消贊"; 點(diǎn)擊"取消贊"(3)時(shí), 我的贊(8)會(huì)減少1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"贊"
it('當(dāng)點(diǎn)擊"贊", 我的贊會(huì)增加1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"取消贊"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfLike=wrapper.find('.dislikedWeibo');constcountOfMyLike=Number(wrapper.find('.like-num span').text());//觸發(fā)點(diǎn)擊事件buttonOfLike.trigger('click');constcountOfMyLikeAfterClick=Number(wrapper.find('.like-num span').text());//斷言: 我的贊會(huì)增加1個(gè)數(shù)量expect(countOfMyLikeAfterClick).to.equal(countOfMyLike+1);//斷言: 按鈕內(nèi)文字變成取消贊expect(buttonOfLike.text()).to.equal('取消贊');});
it('當(dāng)點(diǎn)擊"取消贊", 我的贊會(huì)減少1個(gè)數(shù)量, 且按鈕內(nèi)文字變成"贊"',()=>{constwrapper=mount(SinaWeibo);constbuttonOfDislike=wrapper.find('.likedWeibo');constcountOfMyLike=Number(wrapper.find('.like-num span').text());//觸發(fā)點(diǎn)擊事件buttonOfDislike.trigger('click');constcountOfMyLikeAfterClick=Number(wrapper.find('.like-num span').text());//斷言: 我的贊會(huì)增加1個(gè)數(shù)量expect(countOfMyLikeAfterClick).to.equal(countOfMyLike-1);//斷言: 按鈕內(nèi)文字變成取消贊expect(buttonOfDislike.text()).to.equal('贊');});
測(cè)試結(jié)果

作者:李棠輝
鏈接:http://www.itdecent.cn/p/38a37d5fccb2
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。