iT邦幫忙

2025 iThome 鐵人賽

DAY 16
1
Software Development

Playwright 玩家攻略:從新手村到魔王關系列 第 16

Day 16:獻上素材與獲取秘方|處理檔案的上傳與下載

  • 分享至 

  • xImage
  •  

前兩篇我們解鎖了定位「重複元素」以及「隱形元素」的技能,接著,下一個任務,我們要解鎖的技能是「檔案的上傳與下載」,這也是一個在使用網頁時很常見也很實用的操作行為。這次,我們要在 全家雲端列印 以及 Wormhole 這 2 個網站上實戰操作,看看如何輕鬆完成檔案的上傳與下載!!

全家雲端列印網頁可以讓我們上傳檔案,上傳後可以選擇列印格式,並上傳到雲端,之後可以直接到全家列印檔案,這裡我們只需要練習如何上傳檔案即可。而 Wormhole 這個網站可以讓我們上傳檔案,上傳後會拿到一個網址,輸入網址就會前往下載頁面,從下載頁面我們可以下載剛剛上傳的檔案,我們會在這個網站練習上傳與下載檔案,那就讓我們開始闖關吧!

第 1 關:全家雲端列印 檔案上傳

難易度 ★★☆☆☆

任務畫面
https://ithelp.ithome.com.tw/upload/images/20250925/201689136w7HLVZ9ij.png

任務解析
這個頁面中,上傳檔案的區域是一個 的元素,所以我們可以使用 setInputFiles 直接將檔案丟進去即可。

await page.locator().setInputFiles(path.join(__dirname, 'file path'));

所以,我們只需要按照以下步驟,就能完成檔案上傳:

  1. 在 Playwright 處理檔案上傳時,參數如果是給一個檔案路徑,就必須 import Node.js 內建的模組 path,這是用來處理檔案與目錄路徑的模組
  2. 前往目標頁面並確認頁面已完成
  3. 準備好上傳的檔案,直接對 使用 setInputFiles 上傳檔案
  4. 確認檔案已上傳
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 });
});

讓我們來看看執行結果:
https://ithelp.ithome.com.tw/upload/images/20250925/20168913aK8lrA0dg8.png

📌 Did You Know?
上方程式碼使用 Extension 與 cli 執行,結果會有所不同,這是因為 Playwright 執行速度太快,而畫面還沒有準備好的關係,這時候,我們就必須加上 wait,試著在你覺得適當的地方加入 await page.waitForLoadState('load'); ,再執行看看結果如何吧!

第 2 關:Wormhole 檔案上傳

難易度 ★★★☆☆

任務畫面
https://ithelp.ithome.com.tw/upload/images/20250925/20168913rUMjOwJsbU.png
任務解析
我們可以看到這個上傳檔案區域的 html 結構中,沒有 input 欄位,因此無法使用與上一關相同的技巧,這裡,我們要改以下列方法嘗試:

  1. 等待 filechooser 事件
  2. 點擊打開檔案選擇器的按鈕
  3. 呼叫 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();
});

讓我們來看看執行結果:
https://ithelp.ithome.com.tw/upload/images/20250925/20168913UtZHJPn8Vc.png

📜 Game cheats
Playwright 執行測試時,預設是一個全新且乾淨的瀏覽器,通常顯示語言為 en-US,這時如果想要執行的是中文環境,就必須到 playwright.config.ts 設定locale: 'zh-TW',這樣執行測試時才會是預期的中文環境。

第 3 關:Wormhole 下載剛剛上傳的檔案

難易度 ★★★★☆

任務畫面
https://ithelp.ithome.com.tw/upload/images/20250925/20168913idH7eb3NU4.png

任務解析
這個任務接續上一關任務,上傳檔案後我們會得到一個網址,在瀏覽器輸入網址後,可以看到我們剛剛上傳的檔案,並且能夠下載,要完成這個任務,我們先將任務拆解成兩段:
一、 直接前往該網址,下載檔案
二、 由上一關取得網址,下載檔案

先來完成第一段任務,在 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);
});

我們可以看到執行結果成功:
https://ithelp.ithome.com.tw/upload/images/20250925/20168913tw6XfO0vsh.png

並且,我們還能在專案內看見自動生成一個名稱為 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 事件!這些突如其來的對話框,就像戰鬥途中冒出的偷襲怪,若不及時應對,很可能導致任務失敗。學會馴服它們,才能讓冒險更加順利!


上一篇
Day 15:破解隱形敵人與敵軍陣列|如何鎖定沒有「真名」的怪物
下一篇
Day 17:擊退偷襲怪|Dialog Handler 技能演練
系列文
Playwright 玩家攻略:從新手村到魔王關17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言