在真實的測試戰場裡,怪物(元素)很少會乖乖只出現一個。更多時候,你會面對一大群長得一模一樣的敵人:十幾個按鈕、數百個表格列、成群結隊的清單項目。
思考一下,我們在測試時,遇到以下測試情境:
若只使用 Day 05 介紹的基本元素定位方法,無法瞄準我們想對付的怪物(元素),這時候,使用以下四種方法,可以幫助你更精準鎖定想操作的對象:
await page.locator.first();
await page.locator.nth(n);
await page.locator.last();
await page.locator.filter();
filter()方法可以使用的參數:
has: Locator
hasNot: Locator
hasNotText: string
hasText: string
visible: boolean
認識了定位方法後,現在,讓我們以飲料店─可不可熟成紅茶官網的 story 頁面來實際演練這些定位技巧。
在這個頁面中,可以看到每一間店鋪後方都有一個「店卡故事」連結,我們來點擊連結看看:
// 錯誤示範
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 個連結,測試失敗:
接著我們加入指定條件來執行看看,執行後在 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();
});
執行結果:
點擊「第五個」店卡故事連結
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();
});
執行結果:
點擊「最後一個」店卡故事連結
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();
});
執行結果:
點擊「指定店鋪」的店卡故事按鈕
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();
});
執行結果:
以上,我們可以看到都能順利找到想定位的元素,測試通過!
💡Tips:
聰明的 Playwright 報錯時除了告訴我們找到幾個元素,還會告訴我們可以怎麼定位,也就是aka (also known as)
後面的資訊。如果不曉得如何定位,可以對照 html 結構與 Playwright 報錯提供的資訊來參考!
在這裡,我們學會了面對一群怪物(元素)時,如何精準定位到想攻擊(操作)的目標,接下來,挑戰升級:學習如何定位那些沒有任何屬性、也沒有可辨識文字,就像是隱形怪物一般的無名元素。