寫在前面
隨着業務的增加,復雜性的增加,我們更需要保證頁面不能出錯,之前需要每次上線之前需要每次人工測試,如果有好多改動,為保證業務不出錯,需要耗費更多的時間來測試,所以我們需要寫一些測試來保證業務的邏輯。
端到端測試
測試有很多種,只是當前我們的業務對單元測試不太友好(之前寫過redux的單元測試,例子在點我),代碼耦合性略高,函數也非pure function。所以需要端到端的測試(End to End Testing)。端到端的測試可以確保一堆組件能夠按照預先設想的方式整合起來運行的時候使用。
testcafe
之前調研了一些框架,選擇了testcafe這個框架,之前是收費的,現在開源沒多久,所以生態不是很好。之所以選中testcafe,很主要的原因是它的api簡單和不需要任何依賴。
testcafe只需要全局安裝這個庫,並不需要安裝lite chrome等等。還有一點就是它很具有前瞻性的支持了ts和眾多es6,es7的特性。這是比較爽的。
我們開始編寫一個測試試一下。
安裝testcafe環境
sudo npm i -g testcafe
開始編寫case
import { Selector } from 'testcafe';
引入選擇器
fixture `open.toutiao.com test case`
.page `http://open.toutiao.com/`;
打開需要測試的網站(api比較簡潔)。
test('should open.toutiao work as expected', async t => {
//some code there
});
這是一個測試的case
test('should open.toutiao work as expected', async t => {
const newsList = Selector('section');
await t.expect(newsList.exists).eql(true, 'should display news list');
})
這是一個最簡單的例子,我們選擇新聞列表,這個列表需要存在。
ok,我們運行一個命令來執行這個測試。
文件保存為index.js
testcafe chrome index.js
官網例子
import { Selector } from 'testcafe';
fixture `Github Search`
.page `https://github.com`;
test('should github search work as expected', async t => {
const searchInput = Selector('.js-site-search-focus');
const searchList = Selector('.repo-list-item');
const resultItem = Selector('.repo-list-item h3 a');
const repoContent = Selector('.repository-content');
await t.setTestSpeed(0.8);
await t.expect(searchInput.exists).eql(true, 'should search input visible');
await t.typeText(searchInput, 'testcafe');
await t.pressKey('enter');
await t.expect(searchList.count).eql(10, 'should show 10 results');
await t.click(resultItem);
await t.expect(repoContent.exists).eql(true, 'should repo detail visible');
const location = await t.eval(() => window.location);
await t.expect(location.pathname).eql('/DevExpress/testcafe', 'should testcafe repo found');
});
這個測試做的工作為打開github,期望github的搜索框存在,輸入框輸入testcafe,點擊回車,期望搜索列表搜索結果多於10條,點擊第一條結果,期望跳轉的頁面中存在返回的內容。
最后期望網址的域名搜索位置為/DevExpress/testcafe。返回。
可以運行測試
testcafe chrome index.js
我們的測試
我們的測試也挺簡單的,再給個例子吧~
import { Selector, ClientFunction } from 'testcafe';
fixture `open.toutiao.com test case`
.page `http://open.toutiao.com/`;
test('should open.toutiao work as expected', async t => {
const newsList = Selector('section');
const detailItem = Selector('.list_content section a');
const getWindowLocation = ClientFunction(() => document.body.scrollTop);
let random = Math.floor(Math.random()*10);
await t.expect(newsList.exists).eql(true, 'should display news list');
await t.expect(newsList.count).gt(5,'news more than 5 ');//需要新聞列表頁大於5條新聞
let a = detailItem.nth(random);
await t.click(a);//進入任意一條詳情頁
await t.debug();
await t.eval(() => {
document.body.scrollTop =$('.box-title')[0].offsetTop;//滾動到推薦
});
await t.expect(getWindowLocation()).gt(0,'should be scroll');//保證頁面滾動
await t.expect(Selector('#pageletArticleContent').exists).eql(true, 'should display news and it is open.toutiao ');//文章是open下的文章
});
測試做的工作是打開open.toutiao.com,期望新聞列表頁存在,期望多於5條新聞,隨機點開一條新聞,文章滾動到“精彩推薦區域”,保證頁面已經滾動,保證文章內容存在,且不是廣告頁。
具體的工作已經寫在注釋就不多說了。
測試效果
執行命令,自動打開瀏覽器。輸入網址:
我們可以通過await debug
來進行調試,點擊上圖的step可以每步進行調試。
運行成功如圖
如果點擊到廣告頁,搜索不到新聞內容就會報錯,我們也可以很容易的debug,如圖:
我們可以看到哪一步出錯,報什么錯,來進行業務代碼的快速debug,也可以配合插件進行log上報。
屏幕快照功能
await t
.click('#change-avatar')
.setFilesToUpload('#upload-input', 'img/portrait.jpg')
.click('#submit')
.takeScreenshot();
點擊文件上傳,上傳文件,點擊提交,然后拍一下照,保存。可以在命令行里加-s來指定文件位置。就不展示了。
注意
- testcafe不提供瀏覽器環境,所以如果我們需要什么瀏覽器就自行下載。只需要在命令行修改瀏覽器名稱。比如 testcafe safari index.js。
- testcafe不支持function spy。
- testcafe支持異步,不需要為lazyload的dom特殊處理。可以直接選擇。
- 在eval里不支持await
- ...具體參見其官網好了。