Previous
Day 06 · Locators Fundamentals
Next
Day 08 · Assertions
定位断言
Day 0760-120 minutesPlaywright QA hands-on drill

Day 07 - Advanced Locators: Filtering and Chaining

今日目标

  • 掌握 locator 组合能力。
  • 能处理列表、表格、重复元素。

学习时间安排(60–120 分钟)

时间模块做什么
0-20 分钟核心概念与词汇读概念表,重点理解 filter、nth、链式定位的语义。
20-45 分钟官方文档阅读读 Locators 的 filtering 和 lists 部分。
45-75 分钟实操练习在列表页完成 5 个定位任务。
75-105 分钟示例代码改写把 nth/长链式写法改写成容器 + filter 的写法。
105-120 分钟复盘与作业完成链式定位示例表,完成今日问题。

核心概念与词汇

English中文场景用法
chaining链式定位Use it when you narrow a search from a container to its children.
filter()过滤Use it when you keep only elements matching text, another locator, or a predicate.
hasText按包含文本过滤Use it when you filter a list by the text it contains.
has按子元素过滤Use it when you keep rows that contain a specific status or button.
nth()按序号取元素Use it when order itself is the business rule, otherwise avoid it.
first() / last()第一个/最后一个Use it for the first or last item of a collection.
count()元素数量Use it when you assert how many items a list renders.
strict mode violation严格模式冲突Use it when multiple elements match and Playwright refuses to act.
list / row列表 / 行Use it when you locate a repeated UI unit like a product card or table row.
container容器Use it when you first locate the region that groups related elements.

学习材料

  • 必读:[Locators - Lists](https://playwright.dev/docs/locators#lists)
  • 必读:[Locators - Filtering](https://playwright.dev/docs/locators#filtering-locators)
  • 选读:[Other locators](https://playwright.dev/docs/other-locators)

重点理解

常用写法:

page.getByRole('listitem').filter({ hasText: 'Product 1' })
page.getByRole('row').filter({ has: page.getByText('Pending') })
page.locator('.item').nth(0)
page.locator('.item').first()
page.locator('.item').last()

注意:

  • 优先让 locator 唯一。
  • 不要随意使用 .nth(),除非顺序本身就是业务规则。
  • 使用 filter({ hasText }) 缩小范围。
  • 对表格、卡片、列表先定位容器,再定位内部元素。

实操步骤

找一个列表页面,例如商品列表、文章列表、用户表格:

  1. 定位包含指定文本的行。
  2. 在该行内点击按钮。
  3. 断言行状态变化。
  4. 统计列表数量。
  5. 验证某个 item 可见。

示例代码

import { test, expect } from '@playwright/test';

test('approve a pending order', async ({ page }) => {
  await page.goto('/orders');

  // 先定位容器行,再在行内操作,避免 nth
  const row = page.getByRole('row').filter({ hasText: 'Order #42' });
  await row.getByRole('button', { name: 'Approve' }).click();

  // 断言行状态变化
  await expect(row).toContainText('Approved');
  await expect(page.getByRole('row').filter({ hasText: 'Pending' })).toHaveCount(2);
});

常见坑

  • 列表元素文本相同就用 nth(0),需求一变顺序就 flaky。
  • filter({ hasText }) 写不完整文本导致匹配到多条。
  • getByRole('row') 上直接用 toHaveCount 把表头也数进去。
  • 链式定位写成长 CSS 的等价物(.panel > .list > li:nth-child(2)),失去语义。
  • count() 手动循环遍历元素,而不是用 filter + 断言。

今日产出

  • 一个列表/表格测试。
  • 一份 “locator 链式定位示例表”。

今日问题

  1. filter({ hasText }) 解决什么问题?
  2. .nth() 的风险是什么?
  3. 如何定位某一行里的按钮?
  4. locator 链式定位和长 CSS 选择器有什么区别?
  5. 多个元素匹配时 Playwright 为什么可能报错?

复盘要点

  • “先容器、后内部”是列表类页面的万能套路:找到唯一容器 → filter 缩小 → 在容器内操作。
  • nth 是最后的武器而不是首选:能用 filter 解决的顺序问题就不要用 nth。
  • 严格模式报错不是 bug,是 Playwright 在提醒你 locator 不够唯一。

AI 时代扩展:AI 辅助 Playwright 测试

新增概念

English中文
element disambiguation元素消歧
collection filtering集合过滤
locator chain review定位链审查

适用场景

让 AI 把你写的 nth() 代码重构成 filter 写法,或让 AI 判断一条 locator 链在什么情况下会失效。列表类页面的消歧问题很适合让 AI 给多种方案。

可复用表达 / 提示词

这个页面有 10 个订单行,我想定位「包含 Order #42 的行内的 Approve 按钮」,请给出 2 种写法并比较稳定性。
下面这条 locator 链有哪些失效场景?page.locator('.list > li').nth(2).getByRole('button')

追问加练

  • AI 给的 filter 方案你如何确认它只匹配一行?
  • 顺序是业务规则时(如最新订单),nth 是否就安全了?
  • 让 AI 重构定位代码,你最需要它保留什么?

今日作业

  • 完成“链式定位示例表”:至少 5 组场景(列表行内按钮、卡片内文本、表格状态过滤等)。
  • 找一个真实列表页写 3 条测试,其中至少 1 条使用容器 + filter。
  • 让 AI 审查你的测试,找出可以用 filter 替代 nth 的地方。

自检清单

Previous
Day 06 · Locators Fundamentals
Next
Day 08 · Assertions