前兩篇我們解鎖了定位「重複元素」以及「隱形元素」的技能,接著,下一個任務,我們要解鎖的技能是「檔案的上傳與下載」,這也是一個在使用網頁時很常見也很實用的操作行為。這次,我們要在 全家雲端列印 以及 Wormhole 這 2 個網站上實戰操作,看看如何輕鬆完成檔案的上傳與下載!!
全家雲端列印網頁可以讓我們上傳檔案,上傳後可以選擇列印格式,並上傳到雲端,之後可以直接到全家列印檔案,這裡我們只需要練習如何上傳檔案即可。而 Wormhole 這個網站可以讓我們上傳檔案,上傳後會拿到一個網址,輸入網址就會前往下載頁面,從下載頁面我們可以下載剛剛上傳的檔案,我們會在這個網站練習上傳與下載檔案,那就讓我們開始闖關吧!
任務畫面
任務解析
這個頁面中,上傳檔案的區域是一個 的元素,所以我們可以使用 setInputFiles
直接將檔案丟進去即可。
await page.locator().setInputFiles(path.join(__dirname, 'file path'));
所以,我們只需要按照以下步驟,就能完成檔案上傳:
path
,這是用來處理檔案與目錄路徑的模組setInputFiles
上傳檔案import path from 'path';
import { test, expect } from '@playwright/test';
test('upload file', async ({ page }) => {
// 到達上傳檔案頁面
await page.goto('https://print.famiport.com.tw/device-upload');
// 確認上傳檔案頁面正常顯示
await expect(page.getByRole('heading', { name: '上傳檔案' })).toBeVisible();
// 準備上傳的檔案
const fileName = 'findTheTreasure.png';
// 直接對 <input type="file"> 使用 setInputFiles
await page.setInputFiles('input[type="file"]', path.join(__dirname, `./res/${fileName}`));
// 確認檔案已上傳,可在頁面中看見檔名
await expect(page.getByText(fileName)).toBeVisible({ timeout: 5000 });
});
讓我們來看看執行結果:
📌 Did You Know?
上方程式碼使用 Extension 與 cli 執行,結果會有所不同,這是因為 Playwright 執行速度太快,而畫面還沒有準備好的關係,這時候,我們就必須加上 wait,試著在你覺得適當的地方加入await page.waitForLoadState('load');
,再執行看看結果如何吧!
任務畫面
任務解析
我們可以看到這個上傳檔案區域的 html 結構中,沒有 input
欄位,因此無法使用與上一關相同的技巧,這裡,我們要改以下列方法嘗試:
filechooser
事件setFiles()
import path from 'path';
import { test, expect } from '@playwright/test';
test('upload file', async ({ page }) => {
// 到達上傳檔案頁面
await page.goto('https://wormhole.app/');
// 確認上傳檔案頁面正常顯示
await expect(page.getByRole('button', { name: '獲取產品更新通知' })).toBeVisible();
// 準備上傳的檔案
const fileName = 'findTheTreasure.png';
// 點擊上傳檔案按鈕,會跳出選單
await page.getByRole('button', { name: '選擇要傳送的檔案' }).click();
// 點擊選單中的「從電腦選擇檔案」並等待 filechooser 事件
const fileChooserPromise = page.waitForEvent('filechooser');
await page.locator('button[id="menu-list-12-menuitem-9"]').click();
const fileChooser = await fileChooserPromise;
// 呼叫 setFiles 上傳檔案
await fileChooser.setFiles(path.join(__dirname, `./res/${fileName}`));
// 確認檔案已上傳
await expect(page.getByRole('heading', { name: '檔案準備就緒囉!' })).toBeVisible();
});
讓我們來看看執行結果:
📜 Game cheats
Playwright 執行測試時,預設是一個全新且乾淨的瀏覽器,通常顯示語言為en-US
,這時如果想要執行的是中文環境,就必須到playwright.config.ts
設定locale: 'zh-TW'
,這樣執行測試時才會是預期的中文環境。
任務畫面
任務解析
這個任務接續上一關任務,上傳檔案後我們會得到一個網址,在瀏覽器輸入網址後,可以看到我們剛剛上傳的檔案,並且能夠下載,要完成這個任務,我們先將任務拆解成兩段:
一、 直接前往該網址,下載檔案
二、 由上一關取得網址,下載檔案
先來完成第一段任務,在 playwright 中要下載檔案,同樣需要等待 download
事件:
test('download file', async ({ page }) => {
// 到達下載檔案頁面
await page.goto(download URL);
await expect(page.getByRole('heading', { name: '你拿到一個檔案囉!' })).toBeVisible();
// 點擊下載檔案按鈕
const downloadPromise = page.waitForEvent('download');
await page.getByRole('button', { name: '下載檔案' }).click();
const download = await downloadPromise;
// 確認檔案名稱
await expect(download.suggestedFilename()).toBe('findTheTreasure.png');
// 下載路徑
const DownloadPath = './tests/Download/';
const fileName = DownloadPath + download.suggestedFilename();
await download.saveAs(fileName);
});
我們可以看到執行結果成功:
並且,我們還能在專案內看見自動生成一個名稱為 Download
的資料夾,而下載的檔案就在 Download
資料夾內,第一階段完成。
在第二階段,我們需要透過上一階段取得的網址來下載檔案。畢竟,在自動化測試中,我們不可能每次都手動替換 URL,這樣既麻煩又失去「自動化」的意義。要解決這個問題,其實並不複雜──只要善用 describe Hooks 並搭配一個共用變數,就能讓下載測試自動取得網址,輕鬆完成任務!
結構會是這樣:
test.descript('upload and download files', () => {
// 設定共用變數
let link = '';
test('upload file', async ({ page }) => {
// 上傳檔案任務
// ...
// 取得連結並存入變數
link = await page.locator('input[dir="ltr"]').inputValue();
})
test('download file', async ({ page }) => {
// 傳入連結變數
await page.goto(link);
// 繼續下載檔案任務
// ...
});
});
這樣就能一口氣執行上傳與下載檔案的測試,是不是相當簡單呢?
到這裡,我們已經透過兩個網站實際演練了檔案的上傳與下載操作,技能值再次提升!接下來,冒險將邁入下一個初階副本──挑戰神出鬼沒的 dialog 事件!這些突如其來的對話框,就像戰鬥途中冒出的偷襲怪,若不及時應對,很可能導致任務失敗。學會馴服它們,才能讓冒險更加順利!