Introduction
Chrome DevTools 於 VER.97 隆重推出 Recorder Panel,讓 user 可以透過該功能來做些使用行為的紀錄甚至是自動化流程。User 可以憑藉頁面的操作行為讓 Chrome 將之轉換成 end to end testing 的 JavaScript code,以利日後再利用。除此之外,更可以將之匯出,分享給其他人~
玩過之後,發現它背後實際上是透過 Puppeteer 來加持並且完成這樣的 automation,也因為這樣,讓筆者想知道 Puppeteer 的點點滴滴,與 selenium 間的差異又是什麼?
經過簡單的 survey 之後,Puppeteer 可以跟 Chrome 做緊密的結合,並且透過 headless 的參數設置讓部署更加容易外,語法上亦包裝得更細緻,也因此撰寫起來更加的直覺,可以很快撰寫出我們所需要的 flow 出來。語法使用主要是透過 front-end 所熟悉的 CSS Selector 來快速找到 element 後,便可以透過一些操作,比方說:type、select、click、waitFor* …etc,便可以有效的模擬出一些操作出來。
由於非常直覺,所以筆者便能在很短的時間內便對自家服務 TW Yahoo 奇摩拍賣撰寫出簡單的一條龍測試(GitHub)。
相關的 step 如下所示:
- As a seller, I could submit a new merchandise.
- As a buyer, I could purchase merchandise.
- As a buyer, I could cancel an order.
- As a seller, I could terminate merchandise.
Useful API
透過 Puppeteer API 文件中可以發現它支援的 method 非常非常多,對於初學者來說可能會有點亂,所以筆者將透過上述的 automation 將幾個會用到的使用情境與大家分享~
Puppeteer 的起手式非常的容易,在安裝完 Puppeteer 後,只要透過下列的 code 便可以開啟一個新的瀏覽器頁籤出來。Developers 可以設置 launch 時所需要的條件來打造出所需要的測試環境出來。
測試不外乎就是「做了什麼樣的操作」、「期待什麼樣的結果」所組成的集合,即便 Pupeteer 提供這麼多樣的 Class 供 developer 操作,但大多均可以在 Page 以及 ElementHandle 間完成。只要熟悉這兩個 Class 所提供的 method,便可以輕鬆玩轉 80% 以上的操作行為了~
page.goto
前往特定頁面進行測試一直都是測試的第一步驟,Developer 可以透過 page.goto 進行前往特定網址的操作。
page.waitForSelector
由於有越來越多 client side render 的 web page,所以在進行任何操作之前,可以先透過 page.waitForSelector 來進行 element 是否已經 ready 的試探,default timeout 為 30 秒,可以藉由參數設置調整所需要的 timeout。
如上所示,適時的搭配 CSS Selector > :not(:empty) 亦可用來偵測部分 module 是否已經 ready。
page.waitForFunction
友善的 developer 總會讓頁面元素留下一些線索,方便我們知道特定操作的前後變化,它可能 classname、attribute 或者是 data-*,但是總是有例外的時候會發生,好比 TW Yahoo 拍賣 IM 的 text message,發送後就很單純只會 append 一個 message element 上去,也因為這樣,便無法直接透過 page.waitForSelector 來進行偵測了。
這時候可以搭配 page.waitForFunction 來自行定義我們所想監聽的變化,可以說彈性非常。
page.click、page.tap
確認 element ready 後,便可以開始進行一些操作,可以依照一開始設置的環境來搭配不同的點擊行為,page.click 基本上就是 mouse 的延伸,page.tap 則是 touchscreen 的延伸。早期比較嚴謹,這種 click 的行為僅能被用在那些可供點擊的 element 上,比方說 <a />、<button />、<input type=submit />上,不過 Puppeteer 打破這樣的限制,所以即使指定的是不可點擊 element,一樣可以正常運作不受影響。
page.waitForNavigation
當點擊了連結或者是會轉導頁面的行為時,通常都會偵測頁面是否已經完成轉導?便可以透過這個 page.waitNavigation 這個 method 來完成這樣的需求。
page.type
很多時候均需要進行一些 form elements 的操作,比方說 input[type=text] 內容的輸入等,便可以透過 page.type 來完成內容的輸入,不過要特別注意的是它是 append 的行為,並不會先做 clear 再 input,所以使用上要特別注意。
page.select
<select /> 也是 form element 操作的一員,透過 page.select 便可以針對特定的 element 進行賦值的行為。
elementHandle.uploadFile
上傳檔案亦是一門學問,比方說新增商品的時候總是免不了需要上傳商品圖片,要如何在 Puppeteer 中完成這樣的行為呢?這些 Puppeteer 通通都幫我們想好了,亦包裝了非常方便的 method 可以使用。
如下方的 code 所示,我們先透過 page.$ 找出 input[type=file] 這個 element 後(可取得 elementHandle),這時候再透過 elementHandle.uploadFile 來完成選取檔案的行為。
page.$eval、page.$$eval
雖然說 Puppeteer 已經封裝了很多實用的 methods,不過總是會有不堪用的情境出現,這時候 developers 可以透過 page.$eval、page.$$eval 直接掃出所需要的 elements 後,透過 callBack function 直接對 DOM 進行操作,便可以完成各式奇巧的行為了,可以說是終極的 methods。
Clear cookie
由於筆者需要在不同的登入身份進行切換,雖然說可以透過 cookie 的注入與清除來達到身份切換,但總是沒有直接清除 cookie 來的優雅與確實。所以可以透過清除 cookie 後再來完成 Yahoo login process,便可以輕易地完成身份切換。
透過上述的這些 method 交錯組合,便可以輕輕鬆鬆完成 80% 以上的 user interaction,是不是非常簡單且直覺?彈指之間便可以為服務打造出簡單的一條龍測試,趕快試試看吧~
#Puppeteer #EndToEndTesting #automation
Reference
- Record, replay and measure user flows
- GitHub > Puppeteer
- GitHub > Yahoo Auction Automation (Puppeteer exercise)
- page.goto(url[, options])
- page.waitForSelector(selector[, options])
- page.waitForFunction(pageFunction[, options[, …args]])
- page.click(selector[, options])
- page.tap(selector)
- page.waitForNavigation([options])
- page.type(selector, text[, options])
- page.select(selector, …values)
- elementHandle.uploadFile(…filePaths)
- page.$eval(selector, pageFunction[, …args])
- page.$$eval(selector, pageFunction[, …args])