使用 Jest 與 Puppeteer 來進行界面自動化測試


UI自動化測試 vs. 單元測試

在前面很多文章中,我們都介紹了單元測試。如果你了解單元測試,或者讀過我之前寫的單元測試的文章,那么你一定知道,單元測試的測試對象是單獨的、隔離的小代碼片段或者代碼單元。與單元測試不同,端對端測試的測試對象則是頁面上的用戶交互,我們對底層實現一無所知,也就是說我們的測試是黑盒的。另外,一些跨頁測試,比如鏈接檢查,登陸跳轉等功能必須使用端對端測試才能檢查出來,單元測試是無法測這些功能的。以前我只寫單元測試,不寫端對端測試,結果有一次所負責的頁面上有個鏈接不能點了,還好及時修復,但還是讓我感受到了端對端測試,或者說是自動化端對端測試的重要性。

Puppeteer 默認情況下,所有操作是不可見的,如果你想像我這樣監視發生的一切,需要將 Puppeteer 的 headless 選項設為 false。

使用 Puppeteer 進行瀏覽器自動化

我使用過很多端對端測試的輪子,比如 Selenium、Appium、Protractor、Zombie.js、Cypress、Nightmare、Puppeteer 等。但最終還是選擇了 Puppeteer,因為 Selenium 和 Appium 太難用了,Protractor 則像是專門給 Angular 設計的,Zombie.js 太簡單了,而且使用的瀏覽器內核不是市面上流行的任何一個,而是自定義的。Cypress 有平台依賴,我只是想要個本地運行的工具而已。只剩 Nightmare 和 Puppeteer 了,其實這兩個都是好選擇,但是我是個 star 控,Puppeteer 的 star 比 Nightmare 多,所以我選擇了 Puppeteer。但事實上 Nightmare 更流行,因為我發現螞蟻最新的那個 Antd Pro 就是用的 Nightmare,阿里一些其他端對端測試的工具也有基於 Nightmare 來做的。所以如果你想使用 Nightmare 來進行自動化端對端測試也是完全沒有問題的。

使用 Puppeteer 非常簡單,首先安裝它:

yarn add puppeteer
# or "npm i puppeteer"

const puppeteer = require('puppeteer');然后就可以在 Node 腳本中使用它了!來個簡單的導航並截屏例子吧!這個例子先啟動瀏覽器,導航到 https://baidu.com 頁面,然后截屏並保存為 baidu.png,最后關閉瀏覽器。

 
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://baidu.com');
await page.screenshot({path: 'baidu.png'});
 
await browser.close();
})();

  

image將上述代碼寫進 Node 腳本中,並運行就可以了!看下生成的截圖:

是不是很簡單?短短幾行代碼就做了這么多事。如果你對 asyncawait 這種語法不熟悉,那么我強烈建議你去學習一下,這種語法在 Puppeteer 中使用率簡直不要太高。不過也不要擔心學習成本, asyncawait 語法非常簡單,就是 Promise 的一種新寫法而已,讓你的異步代碼看起來就像是同步的一樣。

使用 Jest 來進行測試

要知道,Puppeteer 是一個瀏覽器自動化工具,它只能進行瀏覽器的自動化,本身並不具有測試功能。我說的測試功能指的是,斷言啊,生成測試報告啊這些功能。如果你不熟悉這些概念,那么請移步:《Jest 單元測試入門》。所以,除了 Puppeteer 外,我們還需要使用一個測試工具,我選擇了 Jest,理由在之前的博文中已經說過很多遍了,這里不再贅述。使用 Jest 非常簡單,只需要

  • 安裝 Jest
  • 編寫測試腳本 *.test.js
  • 最后在終端中輸入 jest 命令運行測試

具體用法看之前的博文:《Jest 單元測試入門》。

將 Jest 與 Puppeteer 結合使用

講完了 Puppeteer 和 Jest 的基本用法,我們來看一下,如何將兩者結合起來使用。其實將 Jest 與 Puppeteer 結合使用非常簡單,因為 Puppeteer 的本質就是個 NPM 模塊而已,所以我們只需要在 Jest 測試腳本中引入它即可使用了。為何如此呢?因為測試腳本的本質其實也是 Node 腳本,既然是 Node 腳本那么當然可以直接引入 NPM 模塊來用了!

需要注意的是,因為 Puppeteer 通常需要使用 asyncawait 這種語法,如果你的 Node 版本在7.6及以上,那么恭喜你,直接大膽使用,否則需要在 Jest 中配置 Babel,來使其支持這種新語法。在 Jest 中配置 Babel 非常簡單,你可以在這里找到具體方法。

讓我們來個小例子吧!首先,我們打開百度頁面,並斷言百度頁面的 title 是 百度一下,你就知道。那么測試腳本應該這么寫:

const puppeteer = require('puppeteer');
 
test('baidu title is correct', async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://baidu.com');
const title = await page.title();
expect(title).toBe('百度一下,你就知道');
await browser.close();
});

$ npm test看到 test 和 expect 兩個全局函數了嗎?這就是 Jest 所賦予的能力,讓你可以編寫測試用例和斷言。最后在命令行輸入 npm test,即 jest(這是在 package.json 中配置好的命令),即可看到生成的測試報告:

 
> fe-test@1.0.0 test /Users/liuyiqi/code/fe-test
> jest
 
PASS puppeteer-demo/baidu-title.test.js
PASS puppeteer-demo/screenshot.test.js
 
Test Suites: 2 passed, 2 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.241s
Ran all test suites.

  

https://github.com/lewis617/fe-test/tree/master/puppeteer-demo其中 screenshot.test.js 是截屏的那個例子,baidu-title.test.js 是斷言百度首頁 title 的例子。你可以在這里找到源碼:

至此,使用 Jest 與 Puppeteer 來進行端對端測試的基本用法就講完了。下篇博文我們將會集中講解常用 Puppeteer 功能,比如模擬用戶輸入、執行 JavaScript 腳本、獲取某個 DOM 節點中的文本等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM