iT邦幫忙

2025 iThome 鐵人賽

DAY 14
2

在真實的測試戰場裡,怪物(元素)很少會乖乖只出現一個。更多時候,你會面對一大群長得一模一樣的敵人:十幾個按鈕、數百個表格列、成群結隊的清單項目。

思考一下,我們在測試時,遇到以下測試情境:

  • 頁面上同時出現十個「加入購物車」,只想點擊第一個
  • 查詢訂單時,有幾十筆資料,只想驗證第三筆
  • 項目往往由新到舊排列,卻想找出最早上架的商品是哪一個
  • 在搜尋結果頁面,只想鎖定「特定品牌」的商品

若只使用 Day 05 介紹的基本元素定位方法,無法瞄準我們想對付的怪物(元素),這時候,使用以下四種方法,可以幫助你更精準鎖定想操作的對象:

  1. first():第一個元素
    await page.locator.first();
    
  2. nth():第 n 個元素
    await page.locator.nth(n);
    
  3. last():最後一個元素
    await page.locator.last();
    
  4. filter():加入參數以篩選元素
    await page.locator.filter();
    
    filter()方法可以使用的參數:
    • has: Locator
    • hasNot: Locator
    • hasNotText: string
    • hasText: string
    • visible: boolean

認識了定位方法後,現在,讓我們以飲料店─可不可熟成紅茶官網的 story 頁面來實際演練這些定位技巧。
https://ithelp.ithome.com.tw/upload/images/20250923/20168913zzreXPgRcR.png

在這個頁面中,可以看到每一間店鋪後方都有一個「店卡故事」連結,我們來點擊連結看看:

// 錯誤示範
test('store story', async ({ page }) => {
  // 前往可不可熟成紅茶官網的門市據點頁面
  await page.goto('https://kebuke.com/store/');

  // 檢查標題
  await expect(page).toHaveTitle('門市據點 | 可不可熟成紅茶 KEBUKE Tea Co.');

  // 點擊「店卡故事」按鈕
  await page.getByText('店卡故事').click();
});

在上面的程式碼中,我們沒有指定要哪一個店卡故事,執行測試,Playwright 會告訴我們找到了 31 個連結,測試失敗:
https://ithelp.ithome.com.tw/upload/images/20250923/20168913cXKsDGwxDI.png

接著我們加入指定條件來執行看看,執行後在 terminal 輸入指令 npx playwright show-report 查看報告 (更詳細的報告產出方式會在後面的文章介紹):

  • 點擊「第一個」店卡故事連結

    test('first store story', async ({ page }) => {
      // 前往可不可熟成紅茶官網的門市據點頁面
      await page.goto('https://kebuke.com/store/');
    
      // 檢查標題
      await expect(page).toHaveTitle('門市據點 | 可不可熟成紅茶 KEBUKE Tea Co.');
    
      // 點擊「第一個」店卡故事按鈕
      await page.getByText('店卡故事').first().click();
      await expect(page.getByText('台北開封 拍板解渴')).toBeVisible();
      await page.getByText('返回列表').click();
    });
    

    執行結果:
    https://ithelp.ithome.com.tw/upload/images/20250923/20168913ZnKVQYCBsH.png

  • 點擊「第五個」店卡故事連結

    test('fifth store story', async ({ page }) => {
      // 前往可不可熟成紅茶官網的門市據點頁面
      await page.goto('https://kebuke.com/store/');
    
      // 檢查標題
      await expect(page).toHaveTitle('門市據點 | 可不可熟成紅茶 KEBUKE Tea Co.');
    
      // 點擊「第五個」店卡故事按鈕
      await page.getByText('店卡故事').nth(4).click();
      await expect(page.getByText('科技大樓 熟成乍現')).toBeVisible();
      await page.getByText('返回列表').click();
    });
    

    執行結果:
    https://ithelp.ithome.com.tw/upload/images/20250923/20168913RV4WC0nmpH.png

  • 點擊「最後一個」店卡故事連結

    test('last store story', async ({ page }) => {
      // 前往可不可熟成紅茶官網的門市據點頁面
      await page.goto('https://kebuke.com/store/');
    
      // 檢查標題
      await expect(page).toHaveTitle('門市據點 | 可不可熟成紅茶 KEBUKE Tea Co.');
    
      // 點擊「最後一個」店卡故事按鈕
      await page.getByText('店卡故事').last().click();
      await expect(page.getByText('台北站前 熟成有志')).toBeVisible();
      await page.getByText('返回列表').click();
    });
    

    執行結果:
    https://ithelp.ithome.com.tw/upload/images/20250923/201689134oYWAFRWv6.png

  • 點擊「指定店鋪」的店卡故事按鈕

    test('specify store story', async ({ page }) => {
      // 前往可不可熟成紅茶官網的門市據點頁面
      await page.goto('https://kebuke.com/store/');
    
      // 檢查標題
      await expect(page).toHaveTitle('門市據點 | 可不可熟成紅茶 KEBUKE Tea Co.');
    
      // 點擊「台北長春店」店卡故事按鈕
      const region = page.locator('div[class="archive-store__list"]');
      const store = region.locator('div[class="archive-store__list-item"]').filter({ hasText: '台北長春店' });
      await store.getByText('店卡故事').click();
      await expect(page.getByText('台北長春 為你寫詩')).toBeVisible();
      await page.getByText('返回列表').click();
    });
    

    執行結果:
    https://ithelp.ithome.com.tw/upload/images/20250923/20168913Rrw4oRObyy.png

以上,我們可以看到都能順利找到想定位的元素,測試通過!

💡Tips:
聰明的 Playwright 報錯時除了告訴我們找到幾個元素,還會告訴我們可以怎麼定位,也就是 aka (also known as) 後面的資訊。如果不曉得如何定位,可以對照 html 結構與 Playwright 報錯提供的資訊來參考!


在這裡,我們學會了面對一群怪物(元素)時,如何精準定位到想攻擊(操作)的目標,接下來,挑戰升級:學習如何定位那些沒有任何屬性、也沒有可辨識文字,就像是隱形怪物一般的無名元素。


上一篇
Day 13:影分身之術|用參數化測試 Parameterized Tests 一次挑戰多個敵人
系列文
Playwright 玩家攻略:從新手村到魔王關14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言