把 puppeteer 融入調(diào)試流程,調(diào)試體驗(yàn)爽翻了!
最近一直在做業(yè)務(wù)需求,表單類的,每次調(diào)試都要填一堆東西,而且項(xiàng)目需要登錄,經(jīng)常需要來一遍登錄流程,再填寫表單來調(diào)試。這個(gè)流程還是比較繁瑣的。
于是我在想,自動化測試工具 puppeteer 是可以通過腳本來自動執(zhí)行瀏覽器操作的,能不能調(diào)試的時(shí)候讓 puppeteer 幫我自動做了頁面操作的一些流程呢?
我試了一下還真可以,用 puppeteer 來自動執(zhí)行腳本,并且過程中還可以打斷點(diǎn)調(diào)試,調(diào)試體驗(yàn)簡直不要太爽。
這篇文章就來分享下。
首先,react 項(xiàng)目我是通過 vscode debugger 來調(diào)試的:

在 .vscode > launch.json 的調(diào)試配置文件里新增一個(gè) chrome 類型的調(diào)試配置,輸入調(diào)試的 url。
然后點(diǎn)擊 debug 啟動:

執(zhí)行到代碼中的斷點(diǎn)就會在 vscode 里斷住:

這樣就可以在 vscode 里斷點(diǎn)調(diào)試 react 項(xiàng)目了。
但登錄還是比較麻煩的,用戶名密碼我經(jīng)常忘,而且登錄之后還要填一些表單,也很麻煩。
這時(shí)候我想到了 puppeteer。
它是可以自動執(zhí)行腳本的。
比如這樣一段腳本:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: false
});
const page = await browser.newPage();
await page.goto('http://localhost:8000/login');
await page.waitForSelector('#username');
const $username = await page.$('#username');
await $username.type('1111111', {
delay: 100
});
const $password = await page.$('#password');
await $password.type('testtest', {
delay: 100
});
const $button = await page.$('button[type="submit"]');
await $button.click();
})();
用 puppeteer 啟動一個(gè)瀏覽器,headless 設(shè)為 false 就是需要界面。
打開新頁面,加載 login 的 url,等出現(xiàn) #username 的元素之后之后,輸入用戶名和密碼,然后點(diǎn)擊提交。
這個(gè)腳本還是很容易理解的。
跑下試試:

流程倒是對了,只是顯示的不對,加個(gè) viewport 的設(shè)置就好了:

width、height 為 0 會自適應(yīng)。

自動跑登錄腳本成功了。
那問題來了,斷點(diǎn)調(diào)試和自動化測試能不能一起跑呢?
看起來這倆都是跑了一個(gè)瀏覽器,應(yīng)該能融合才對。
這個(gè)就要從 puppeteer 和調(diào)試的實(shí)現(xiàn)原理來看了。
調(diào)試是基于調(diào)試協(xié)議的,比如網(wǎng)頁調(diào)試是 Chrome DevTools Protocol。
Chrome DevTools 對接了 CDP 可以調(diào)試網(wǎng)頁,我們用 VSCode Debugger 能調(diào)試網(wǎng)頁同樣也是對接了 CDP。

puppeteer 能控制瀏覽器執(zhí)行一些腳本,也是基于 CDP。
這倆都需要瀏覽器在調(diào)試模式啟動,也就是指定 remote-debugging-port。
我們前面跑 react 項(xiàng)目的調(diào)試是用的 launch 的方式,它會自動跑一個(gè)調(diào)試瀏覽器,然后連接上 ws 調(diào)試服務(wù)。
其實(shí)它還有 attach 的方式:

attach 的方式不單獨(dú)跑調(diào)試瀏覽器,而是連接上已有的瀏覽器來調(diào)試。所以需要指定調(diào)試服務(wù)的端口。
既然 puppeteer 和調(diào)試都要以調(diào)試模式跑瀏覽器,那我們就等 puppeteer 跑起 chrome 之后,vscode debugger 再 attach 上它來調(diào)試。
這樣不就既能自動化測試,又能斷點(diǎn)調(diào)試了么?
我們來試一下:

puppeteer 啟動 chrome 的時(shí)候,我指定了調(diào)試端口為 9999。
然后跑下 puppeteer 腳本,把 chrome 跑起來:

之后,去 react 項(xiàng)目里啟動調(diào)試,只不過這次是 attach:

依然是能正常斷點(diǎn)調(diào)試的:

而且現(xiàn)在還可以跑自動化腳本了!
我們改造下 puppeteer 腳本,改成每次輸入內(nèi)容的時(shí)候才跑對應(yīng)的腳本。
const puppeteer = require('puppeteer');
const readline = require('readline');
(async () => {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: {
width: 0,
height: 0
},
debuggingPort: 9999
});
const page = await browser.newPage();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('line', async (str) => {
if (str === 'login') {
await login(page);
} else if (str === 'baidu') {
await baidu(page);
}
});
})();
async function baidu(page) {
await page.goto('http://www.baidu.com');
}
async function login(page) {
await page.goto('http://localhost:8000/login');
await page.waitForSelector('#username');
const $username = await page.$('#username');
await $username.type('1111111', {
delay: 100
});
const $password = await page.$('#password');
await $password.type('testtest', {
delay: 100
});
const $button = await page.$('button[type="submit"]');
await $button.click();
}
主要是加了 readline 模塊,這是 node 內(nèi)置模塊,用于一行行讀取流的輸入用的。

我指定了輸入 baidu 的時(shí)候打開 baidu,輸入 login 的時(shí)候打開 localhost:8000,然后執(zhí)行登錄腳本。
試一下:

然后我們把 vscode debugger 也 attach 上。
之后再跑 puppeteer 的腳本。
猜下這時(shí)候會發(fā)生什么?

執(zhí)行了自動化測試腳本,并且還在斷點(diǎn)處斷住了!
這樣我們就不用再手動點(diǎn)點(diǎn)點(diǎn),可以用腳本自動跑一些流程,而且還可以斷點(diǎn)調(diào)試這個(gè)流程。
我們再改一下腳本:

click 之后,又輸入了密碼,然后再 click:

斷住的時(shí)候?yàn)g覽器不會執(zhí)行代碼,這時(shí)候自動化腳本也就執(zhí)行不了,可以專心根據(jù)調(diào)用棧作用域等調(diào)試代碼,調(diào)試完之后,釋放斷點(diǎn),自動化腳本才會繼續(xù)執(zhí)行。
這樣我們就完美的把 puppeteer 的自動化測試和 VSCode Debugger 的網(wǎng)頁斷點(diǎn)調(diào)試結(jié)合在了一起。
總結(jié)
我們會用 VSCode Debugger 斷點(diǎn)調(diào)試網(wǎng)頁,會用 puppeteer 寫自動化測試的腳本來測試某條流程。
這倆其實(shí)完全可以結(jié)合在一起用,因?yàn)樗麄兌际腔?CDP,會啟動一個(gè)調(diào)試模式的瀏覽器。只要 VSCode Debugger attach 到 puppeteer 啟動的瀏覽器就好了。
融合在一起之后,你可以寫 puppeteer 腳本來自動化一些流程,比如自動登錄、自動填寫表單等,這個(gè)過程還可以斷點(diǎn)調(diào)試,斷點(diǎn)釋放之后再執(zhí)行后續(xù)自動化腳本。
兩者簡直是完美的配合。
把 puppeteer 融入調(diào)試流程,調(diào)試體驗(yàn)爽翻了!
