iT邦幫忙

2025 iThome 鐵人賽

DAY 19
1
Software Development

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

Day 19:戰鬥場景轉換|多分頁/視窗處理技巧

  • 分享至 

  • xImage
  •  

我們連續練習了許多操作網站的常見行為,接著,我們要來學習如何處理多分頁/視窗,在網站上點擊一個連結,如果這個連結有 target="_blank" 屬性,會開啟一個新 tab,或者是點擊某個元素,元素標籤有 onclick="openWindow()" 事件,則會開啟新視窗,這些事件在 Playwright 都能夠監聽與處理。

在 Playwright 中,事件的監聽範圍可以分為兩個層級:

  • context - 監聽整個瀏覽器情境(Browser Context),能捕捉所有分頁的事件。
  • page - 僅監聽特定分頁(Page),只會處理該分頁自身觸發的事件。

相信各位玩家對於 page 都不陌生,前面我們練習使用時,必須先在宣告 test 時引入,context 也相同,引入 contextpage 後,我們就可以讓它們來操作整個瀏覽器或特定分頁:

test('context test', async ({ context }) => {
    // 測試內容...
})

test('page test', async ({ page }) => {
    // 測試內容...
})

測試中點擊按鈕開啟新分頁或新視窗,可以用 popup 事件捕捉:

// 先開始監聽 popup 事件
const popupPromise = page.waitForEvent('popup');

// 觸發會開啟新視窗的點擊
await page.locator().click();

// 等待 popup 事件發生,取得新視窗
const newWindow = await popupPromise;

我們已經掌握了多分頁與視窗的處理技巧,接下來,就一起迎接今天的新任務吧!

第 1 關:運用 context 操作多個分頁

難易度 ★★☆☆☆
任務畫面
https://ithelp.ithome.com.tw/upload/images/20250928/201689137EjusMUoge.png
任務解析
必須先開啟 3 個分頁並前往不同網址,接著關閉第 1 個分頁。並且確認最後保留的是第 2 及第 3 個分頁。

要達成這個任務,我們先宣告三個分頁,接著就能輕鬆操作它們啦 ~

test('open new tab', async ({ context }) => {
  // 建立三個分頁
  const pageOne = await context.newPage();
  const pageTwo = await context.newPage();
  const pageThree = await context.newPage();

  const url = ['https://www.youtube.com', 'https://www.google.com', 'https://www.facebook.com'];

  // 各自前往目標頁面
  await pageOne.goto(url[0]);
  await pageTwo.goto(url[1]);
  await pageThree.goto(url[2]);

  // 關閉第 1 個分頁
  await pageOne.close();

  // 驗證目前開啟的分頁數量
  const allPages = context.pages();
  await expect(allPages).toHaveLength(2);

  // 驗證分頁 URL 且 列出所有分頁的 URL
  await allPages.forEach(p => {
    expect(p.url()).toContain(url[allPages.indexOf(p) + 1]);
    console.log(p.url());
  });
});

讓我們看一下執行結果:
https://ithelp.ithome.com.tw/upload/images/20250928/20168913FLufM8CEYS.png

可以看到最後列出的網址是第 2 個分頁與第 3 個分頁前往的目標網址,成功通過任務!

第 2 關:操作新開啟的 tab

難易度 ★★☆☆☆
任務畫面
https://ithelp.ithome.com.tw/upload/images/20250928/20168913hyKM3FrIZS.png
任務解析
這個任務必須在iT邦幫忙點擊具有 target="_blank" 屬性的 「2025 鐵人賽」 連結,開啟新分頁,並在新分頁中從團隊列表找到 「兩貓一犬一條龍小隊」 並進入團隊戰報

因為我們是由特定頁面點擊元素後,開啟新分頁,因此,我們不監聽整個瀏覽器,而是page 監聽特定分頁,接著設置 popup 事件捕捉新的分頁,然後在新分頁操作完成此次任務。

test('open new tab', async ({ page }) => {
  // 前往 iT邦幫忙 首頁
  await page.goto('https://ithelp.ithome.com.tw/');
  
  // 監聽新分頁事件,並點擊「2025 鐵人賽」連結
  const newTabPromise = page.waitForEvent('popup');
  await page.getByRole('link', { name: '2025 鐵人賽' }).click();
  const newTab = await newTabPromise;

  // 在新分頁中進行操作
  await newTab.getByRole('link', { name: '團隊列表' }).click();
  await newTab.waitForLoadState('load');

  // 點擊「兩貓一犬一條龍小隊」連結,並驗證頁面內容
  await newTab.getByRole('link', { name: '兩貓一犬一條龍小隊' }).click();
  await expect(newTab.locator('div[class="kv-content"]')).toHaveText('團隊戰報');
});

執行一下看看結果:
https://ithelp.ithome.com.tw/upload/images/20250928/20168913KM3zj7NI8b.png

我們可以看到 Playwright 成功地操作新分頁,並且順利找到了目標元素,而在 report 當中可以看見,如果在 playwright.config.ts 裡設定 screenshot: 'on'video: 'on',會分別記錄下兩個分頁的執行狀況,方便觀察實際執行結果畫面與流程。

第 3 關:操作新開啟的 window

難易度 ★★☆☆☆
任務畫面
https://ithelp.ithome.com.tw/upload/images/20250928/20168913VUFmHi0wff.png

任務解析
前往 Rahul Shetty’s Automation Practice Page 這個頁面,點擊有 onclick="openWindow()" 事件的「open window」按鈕,會開啟一個新的視窗,並在新視窗中找到黃色的「Access all our Courses」。

test('open new window', async ({ page }) => {
  // 前往目標頁面
  await page.goto('https://rahulshettyacademy.com/AutomationPractice/');

  // 開始監聽 popup 事件,點擊會觸發事件的按鈕,取得新視窗
  const popupPromise = page.waitForEvent('popup');
  await page.getByRole('button', { name: 'Open Window' }).click();
  const newWindow = await popupPromise;

  // 等待新視窗載入完成
  await newWindow.waitForLoadState('load');

  // 在新視窗中找到目標元素
  await expect(newWindow.getByRole('button', { name: 'Access all our Courses' })).toBeVisible();
});

執行上面的程式碼,結果 failed 了,Playwright Error Message 顯示找不到元素:
https://ithelp.ithome.com.tw/upload/images/20250928/20168913crsmKhQh7K.png

讓我們打開 devtool 確認一下元素:
https://ithelp.ithome.com.tw/upload/images/20250928/201689139KaVWlHNUc.png
原來這個元素不是 <button>,而是 <a> 標籤,讓我們把最後一行替換一下:

await expect(newWindow.getByRole('link', { name: 'Access all our Courses' })).toBeVisible();

再次執行,就能在新頁面順利找到元素啦!
https://ithelp.ithome.com.tw/upload/images/20250928/20168913ffaqpWb8qL.png

💡 Tips:
眼見不一定為實!有時候畫面上看似「按鈕」的元素,其實在程式碼裡是一個連結。若在測試前沒有確認清楚元素的標籤與屬性,往往就會踩到坑。唯有先確定元素的真實結構,才能讓測試如預期順利執行。


到這裡,我們已經能夠自如地操作新分頁與新視窗。無論是透過 context 管理多個分頁,或是利用 popup 事件監聽 page 開啟的新分頁/視窗,都能在多變的測試情境中靈活應對,並累積更多實用技巧。接下來,我們將進一步學習如何導入 POM(Page Object Model),透過結構化設計減少重複程式碼,不僅讓測試流程更輕鬆高效,也能大幅提升可讀性與維護性。


上一篇
Day 18:拆除不定時炸彈|用 expect.poll() 精準等待時機
下一篇
Day 20:撰寫你自己的魔導書|Page Object Models 設計模式
系列文
Playwright 玩家攻略:從新手村到魔王關24
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言