Playwright的role定位 - 宋马

Playwright的role定位

Playwright的role定位

// Playwright Role定位器示例代码

/**
 * Playwright提供了基于ARIA角色的定位方式,这是一种遵循Web可访问性标准的强大定位策略
 * 以下是role定位器的详细使用方法和示例
 */

const {
             chromium } = require('playwright');

async function demonstrateRoleLocators() {
            
  // 启动浏览器
  const browser = await chromium.launch({
             headless: false });
  const context = await browser.newContext();
  const page = await context.newPage();

  // 导航到测试页面
  await page.goto('https://example.com/');
  
  try {
            
    // =========== 基础角色定位 ===========
    
    // 1. 基本role定位 - 查找按钮
    const submitButton = page.getByRole('button');
    
    // 2. 使用name选项 - 通过按钮文本定位特定按钮
    const loginButton = page.getByRole('button', {
             name: '登录' });
    
    // 3. 使用exact选项 - 精确匹配文本(默认是包含匹配)
    const exactLoginButton = page.getByRole('button', {
             name: '登录', exact: true });
    
    // 4. 使用name正则表达式 - 模糊匹配
    const submitButtonRegex = page.getByRole('button', {
             name: /提交|确认/ });
    
    // =========== 常用角色类型 ===========
    
    // 5. 链接定位
    const homeLink = page.getByRole('link', {
             name: '首页' });
    
    // 6. 标题定位 (h1-h6)
    const mainHeading = page.getByRole('heading', {
             name: '欢迎使用' });
    // 指定标题级别
    const subHeading = page.getByRole('heading', {
             level: 2 });
    
    // 7. 复选框
    const agreeCheckbox = page.getByRole('checkbox', {
             name: '我同意条款' });
    
    // 8. 单选按钮
    const femaleRadio = page.getByRole('radio', {
             name: '女' });
    
    // 9. 文本框
    const usernameInput = page.getByRole('textbox', {
             name: '用户名' });
    
    // 10. 下拉菜单
    const countrySelect = page.getByRole('combobox', {
             name: '国家' });
    
    // 11. 列表
    const menuList = page.getByRole('list');
    const menuItems = page.getByRole('listitem');
    
    // 12. 表格相关
    const userTable = page.getByRole('table', {
             name: '用户列表' });
    const tableRow = page.getByRole('row');
    const tableCell = page.getByRole('cell');
    const columnHeader = page.getByRole('columnheader', {
             name: '姓名' });
    
    // 13. 图像
    const logoImage = page.getByRole('img', {
             name: '公司标志' });
    
    // 14. 警告和提示
    const errorAlert = page.getByRole('alert');
    
    // 15. 对话框
    const confirmDialog = page.getByRole('dialog', {
             name: '确认操作' });
    
    // =========== 高级用法 ===========
    
    // 16. 组合使用 - 在特定区域内查找
    const searchForm = page.getByRole('form', {
             name: '搜索' });
    const searchButton = searchForm.getByRole('button', {
             name: '搜索' });
    
    // 17. 使用checked选项 - 查找已选中的复选框
    const checkedItems = page.getByRole('checkbox', {
             checked: true });
    
    // 18. 使用selected选项 - 查找已选中的选项
    const selectedOption = page.getByRole('option', {
             selected: true });
    
    // 19. 使用disabled选项 - 查找禁用的元素
    const disabledButton = page.getByRole('button', {
             disabled: true });
    
    // 20. 使用expanded选项 - 查找展开的元素
    const expandedMenu = page.getByRole('menu', {
             expanded: true });
    
    // 21. 利用pressed选项 - 查找按下状态的切换按钮
    const toggleButton = page.getByRole('button', {
             pressed: true });
    
    // =========== 常见操作 ===========
    
    // 点击操作
    await loginButton.click();
    
    // 填写表单
    await usernameInput.fill('测试用户');
    
    // 检查元素存在
    const isVisible = await agreeCheckbox.isVisible();
    
    // 获取所有匹配元素的计数
    const buttonCount = await page.getByRole('button').count();
    
    // 获取所有匹配元素
    const allButtons = await page.getByRole('button').all();
    
    // 等待元素可见
    await page.getByRole('alert').waitFor({
             state: 'visible' });
    
    // 处理列表中的所有项目
    const items = await page.getByRole('listitem').all();
    for (const item of items) {
            
      const text = await item.textContent();
      console.log(`列表项内容: ${
            text}`);
    }
    
  } finally {
            
    // 关闭浏览器
    await browser.close();
  }
}

/**
 * ============= 完整的ARIA角色列表 =============
 * 
 * Playwright支持以下ARIA角色:
 * 
 * 常用角色:
 * - button: 按钮
 * - link: 链接
 * - checkbox: 复选框
 * - radio: 单选按钮 
 * - textbox: 文本框
 * - img: 图片
 * - heading: 标题
 * 
 * 表单相关:
 * - combobox: 组合框(如下拉菜单)
 * - listbox: 列表框
 * - option: 选项
 * - switch: 开关
 * - searchbox: 搜索框
 * - slider: 滑块
 * - spinbutton: 数字调节器
 * 
 * 内容组织:
 * - table: 表格
 * - grid: 网格
 * - row: 行
 * - cell: 单元格
 * - columnheader: 列标题
 * - rowheader: 行标题
 * - list: 列表
 * - listitem: 列表项
 * - menu: 菜单
 * - menubar: 菜单栏
 * - menuitem: 菜单项
 * - tab: 选项卡
 * - tablist: 选项卡列表
 * - tabpanel: 选项卡面板
 * - tree: 树形结构
 * - treeitem: 树项
 * 
 * 交互组件:
 * - dialog: 对话框
 * - alert: 警告
 * - alertdialog: 警告对话框
 * - tooltip: 工具提示
 * - banner: 横幅
 * - navigation: 导航
 * - complementary: 补充内容
 * - contentinfo: 内容信息(如页脚)
 * - form: 表单
 * - main: 主要内容
 * - region: 区域
 * - search: 搜索区域
 * 
 * 其他角色:
 * - article: 文章
 * - figure: 图表
 * - term: 术语
 * - separator: 分隔符
 * - toolbar: 工具栏
 * - progressbar: 进度条
 * - status: 状态
 * - log: 日志
 * - marquee: 滚动文本
 * - timer: 计时器
 */

// 示例:创建一个简单的测试来演示role定位器的使用
async function runSimpleTest() {
            
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();
  
  // 创建一个包含各种元素的简单HTML页面
  await page.setContent(`
    <h1>登录系统</h1>
    <form role="form" aria-label="登录表单">
      <label for="username">用户名:</label>
      <input id="username" type="text" placeholder="请输入用户名">
      
      <label for="password">密码:</label>
      <input id="password" type="password">
      
      <div>
        <input id="remember" type="checkbox">
        <label for="remember">记住我</label>
      </div>
      
      <button type="submit">登录系统</button>
      <button type="button">取消</button>
    </form>
  `);
  
  // 使用role定位器查找和操作元素
  const loginForm = page.getByRole('form', {
             name: '登录表单' });
  const username = page.getByRole('textbox').first();  // 获取第一个文本框
  const checkbox = page.getByRole('checkbox');
  const loginButton = page.getByRole('button', {
             name: /登录/ });
  
  // 执行操作
  await username.fill('测试用户');
  await checkbox.check();
  
  // 验证复选框是否被选中
  console.log('复选框选中状态:', await checkbox.isChecked());
  
  // 点击登录按钮
  await loginButton.click();
  
  await browser.close();
  console.log('测试完成!');
}

// 实际使用场景示例
async function realWorldExample() {
            
  const browser = await chromium.launch({
             headless: false });
  const context = await browser.newContext();
  const page = await context.newPage();
  
  try {
            
    // 打开一个示例网站
    await page.goto('https://demo.playwright.dev/todomvc');
    
    // 添加几个待办事项
    const newTodo = page.getByRole('textbox', {
             name: 'What needs to be done?' });
    
    await newTodo.fill('学习 Playwright');
    await page.keyboard.press('Enter');
    
    await newTodo.fill('掌握 role 定位器');
    await page.keyboard.press('Enter');
    
    await newTodo.fill('完成自动化测试');
    await page.keyboard.press('Enter');
    
    // 使用列表项定位并检查第一个待办事项
    const firstTodo = page.getByRole('listitem').first();
    console.log('第一个待办事项:', await firstTodo.textContent());
    
    // 标记第一个待办事项为已完成
    await firstTodo.getByRole('checkbox').check();
    
    // 过滤查看已完成项目
    await page.getByRole('link', {
             name: 'Completed' }).click();
    
    // 计算已完成的项目数量
    const completedCount = await page.getByRole('listitem').count();
    console.log('已完成项目数量:', completedCount);
    
    // 截图保存
    await page.screenshot({
             path: 'todo-app.png' });
    
  } finally {
            
    await browser.close();
  }
}

// 运行示例
// demonstrateRoleLocators().catch(console.error);
// runSimpleTest().catch(console.error);
// realWorldExample().catch(console.error);

module.exports = {
            
  demonstrateRoleLocators,
  runSimpleTest,
  realWorldExample
};

Playwright 的 role 定位详解

Playwright 的 role 定位器是一种基于 ARIA (无障碍富互联网应用) 角色的强大定位方式,它让我们能够以更语义化、更稳定的方式定位网页元素。下面我将详细解释 role 定位器的使用方法、优势以及实际应用场景。

什么是 role 定位器?

role 定位器是基于 Web 可访问性标准中的 ARIA 角色来识别元素的一种方法。它通过元素的语义角色而非 CSS 选择器或 XPath 来定位元素,提供了更稳定且易于维护的自动化脚本。

role 定位器的优势

更稳定的测试 – 基于语义角色定位,不易受到 CSS 类名或 DOM 结构变化的影响
更接近用户体验 – 遵循用户实际交互方式,比如”点击按钮”、“填写文本框”
提高可读性 – 代码更加直观,如 page.getByRole('button', { name: '登录' }) 比 CSS 选择器更容易理解
自动适应无障碍标准 – 鼓励开发人员构建符合可访问性标准的应用

基本语法

// 基本语法
page.getByRole(role, options)

// 例如:
page.getByRole('button', {
             name: '登录' })

常用角色类型及用法

1. 按钮定位

// 定位所有按钮
const allButtons = page.getByRole('button');

// 定位特定文本的按钮
const loginButton = page.getByRole('button', {
             name: '登录' });

// 使用正则表达式匹配按钮文本
const submitButton = page.getByRole('button', {
             name: /提交|确认/ });

// 精确匹配文本(默认是模糊匹配)
const exactButton = page.getByRole('button', {
             name: '登录', exact: true });

2. 文本输入框

// 定位所有文本框
const allTextboxes = page.getByRole('textbox');

// 定位特定标签的文本框
const usernameInput = page.getByRole('textbox', {
             name: '用户名' });

3. 复选框和单选按钮

// 复选框
const agreementCheckbox = page.getByRole('checkbox', {
             name: '我同意条款' });

// 单选按钮
const femaleRadio = page.getByRole('radio', {
             name: '女' });

// 查找已选中的复选框
const checkedItems = page.getByRole('checkbox', {
             checked: true });

4. 链接

// 定位链接
const homeLink = page.getByRole('link', {
             name: '首页' });

5. 标题

// 所有标题
const allHeadings = page.getByRole('heading');

// 特定级别的标题
const mainHeading = page.getByRole('heading', {
             level: 1 });
const subHeading = page.getByRole('heading', {
             level: 2, name: '产品介绍' });

6. 下拉菜单

// 下拉菜单
const dropdown = page.getByRole('combobox', {
             name: '选择国家' });

// 下拉选项
const option = page.getByRole('option', {
             name: '中国' });

7. 表格相关

// 表格
const userTable = page.getByRole('table', {
             name: '用户列表' });

// 表格行
const tableRows = page.getByRole('row');

// 表格单元格
const cells = page.getByRole('cell');

// 表头单元格
const headerCell = page.getByRole('columnheader', {
             name: '姓名' });

8. 列表相关

// 列表
const menuList = page.getByRole('list');

// 列表项
const listItems = page.getByRole('listitem');

高级用法

组合使用

// 在特定区域内查找元素
const form = page.getByRole('form', {
             name: '注册表单' });
const submitButton = form.getByRole('button', {
             name: '注册' });

状态相关选项

// 查找禁用的按钮
const disabledButton = page.getByRole('button', {
             disabled: true });

// 查找已展开的菜单
const expandedMenu = page.getByRole('menu', {
             expanded: true });

// 查找处于按下状态的切换按钮
const toggleButton = page.getByRole('button', {
             pressed: true });

常见操作

// 点击操作
await loginButton.click();

// 填写表单
await usernameInput.fill('测试用户');

// 检查元素状态
const isChecked = await checkbox.isChecked();

// 获取所有匹配元素
const allButtons = await page.getByRole('button').all();

// 等待元素可见
await page.getByRole('alert').waitFor({
             state: 'visible' });

完整的 ARIA 角色列表

Playwright 支持所有标准 ARIA 角色,包括但不限于:

常用角色

button: 按钮
link: 链接
checkbox: 复选框
radio: 单选按钮
textbox: 文本框
img: 图片
heading: 标题

表单相关

combobox: 组合框(下拉菜单)
listbox: 列表框
option: 选项
switch: 开关
searchbox: 搜索框
slider: 滑块

内容组织

table: 表格
row: 行
cell: 单元格
columnheader: 列标题
list: 列表
listitem: 列表项
menu: 菜单
menuitem: 菜单项
tab: 选项卡
tabpanel: 选项卡面板

交互组件

dialog: 对话框
alert: 警告
tooltip: 工具提示
form: 表单
navigation: 导航区域
main: 主要内容区域

实际应用场景示例

登录场景

// 登录流程
await page.goto('https://example.com/login');

// 填写用户名和密码
await page.getByRole('textbox', {
             name: '用户名' }).fill('testuser');
await page.getByRole('textbox', {
             name: '密码', exact: true }).fill('password123');

// 勾选"记住我"
await page.getByRole('checkbox', {
             name: '记住我' }).check();

// 点击登录按钮
await page.getByRole('button', {
             name: '登录' }).click();

// 等待登录成功提示
await page.getByRole('alert', {
             name: '登录成功' }).waitFor();

购物车场景

// 添加商品到购物车
await page.getByRole('button', {
             name: '加入购物车' }).click();

// 进入购物车页面
await page.getByRole('link', {
             name: '购物车' }).click();

// 增加商品数量
await page.getByRole('spinbutton', {
             name: '数量' }).fill('2');

// 点击结算按钮
await page.getByRole('button', {
             name: '结算' }).click();

role 定位器的使用建议

优先使用 role 定位器 – 比其他定位方式更可靠
结合 name 选项使用 – 增加定位精确度
避免过于宽泛的定位 – 例如只用 getByRole('button') 可能会匹配多个元素
与其他定位器结合使用 – 在特定情况下可以与 CSS 选择器等结合使用
处理多个匹配元素 – 使用 first(), last(), nth() 等方法处理多个匹配
测试前检查元素角色 – 使用浏览器开发工具查看元素实际的 ARIA 角色

实用调试技巧

当你不确定元素的角色时,可以使用以下方法进行调试:

// 检查页面上所有角色为按钮的元素
const buttons = await page.getByRole('button').all();
console.log(`找到 ${
              buttons.length} 个按钮`);

// 打印每个按钮的文本内容
for (const button of buttons) {
            
  console.log(await button.textContent());
}

总结

Playwright 的 role 定位器提供了一种更加稳定、语义化且符合可访问性标准的元素定位方式。通过使用 role 定位器,你可以创建出更加健壮、易于维护的自动化测试脚本,同时也鼓励开发团队构建更符合可访问性标准的Web应用。

在实际项目中,建议优先考虑使用 role 定位器,这样即使网页的样式和结构发生变化,测试脚本也能保持稳定性。

请登录后发表评论

    没有回复内容