![[Playwright][10]Locator 实战:使用 XPath ancestor 精准定位 Job Card](http://pic.xiahunao.cn/yaotu/[Playwright][10]Locator 实战:使用 XPath ancestor 精准定位 Job Card)
在 HPC Dashboard 的 Job Explorer 模块中页面会展示多个 Job Card每个卡片都有View Details等操作按钮。如果直接定位按钮可能匹配多个元素。因此我采用了先定位 Job Card再定位卡片内部按钮的方式。1. 从 Job ID 定位所属卡片首先找到页面中第一个 Job IDconstjobIdElementpage.getByText(/^Job ID:/).first();awaitexpect(jobIdElement).toBeVisible();constjobIdTextawaitjobIdElement.innerText();constjobIdjobIdText.replace(/^Job ID:\s*/,).trim();接下来通过 XPath 向上查找 Job CardconstjobCardjobIdElement.locator(xpathancestor::div[.//button[normalize-space()View Details]][1]);这里的关键是ancestor::div查找当前元素的祖先div。.//button[...]要求祖先容器内存在文本为View Details的按钮。normalize-space()可以避免这些空白差异影响定位View Details[1]选择满足条件的最近一个祖先div。这样就能从 Job ID 找到对应的卡片容器而不是在整个页面中操作按钮。2. 封装 getFirstJob()为了避免重复定位我将这部分逻辑封装为公共方法asyncfunctiongetFirstJob(page:Page){constjobIdElementpage.getByText(/^Job ID:/).first();awaitexpect(jobIdElement).toBeVisible();constjobIdTextawaitjobIdElement.innerText();constjobIdjobIdText.replace(/^Job ID:\s*/,).trim();constjobCardjobIdElement.locator(xpathancestor::div[.//button[normalize-space()View Details]][1]);constjobName(awaitjobCard.locator(h2, h3, h4).first().innerText()).trim();return{jobCard,jobName,jobId};}该方法返回三个值jobCard、jobName和jobId方便后续测试复用。3. 在真实测试中使用 Locator Scoping在 查看 Job 详情并导出 PDF测试中我这样使用awaitopenJobsPage(page);const{jobCard,jobId}awaitgetFirstJob(page);awaitjobCard.getByRole(button,{name:View Details}).click();awaitexpect(page.getByText(Job ID:${jobId},{exact:true})).toBeVisible();这里的jobCard.getByRole()就是Locator Scoping限定定位范围。它只在当前 Job Card 内查找View Details按钮避免与其他卡片中的同名按钮混淆。随后通过 Job ID 断言验证打开的是对应 Job 的详情。4. 小结这次实践让我认识到复杂页面的元素定位不能只关注单个按钮还需要考虑它所属的业务容器。先定位目标容器再定位内部元素是处理重复列表和卡片组件的一种实用方法。目前getFirstJob()使用.first()获取首个 Job后续如果需要测试指定 Job可以进一步改成按 Job ID 精确查找。