写点什么

Playwright 基础入门篇 (3) | 交互操作深度解析

  • 2025-08-20
    黑龙江
  • 本文字数:3771 字

    阅读完需:约 12 分钟

测试开发全景图:人工智能测试、智能驱动、自动化、测试开发、左移右移与DevOps的持续交付

2025 终极指南:掌握 20+种真实场景交互,解决异步操作难题



一、为什么交互操作失败率高达 60%?

在 Web 自动化中,交互操作失败的主要原因是:


  1. 元素状态不稳定(45%):元素未准备好时进行操作

  2. 异步加载未完成(30%):操作后页面未完全响应

  3. 环境差异(15%):不同设备/网络导致行为不一致

  4. 框架缺陷(10%):操作逻辑不合理


Playwright 通过智能等待系统自动重试机制,将成功率提升至 98%!



二、核心交互操作全景图

graph TD    A[基础操作] --> A1[点击]    A --> A2[输入]    A --> A3[选择]    B[高级操作] --> B1[拖拽]    B --> B2[键盘]    B --> B3[鼠标]    C[特殊场景] --> C1[文件上传]    C --> C2[iframe操作]    C --> C3[阴影DOM]    D[最佳实践] --> D1[等待策略]    D --> D2[错误处理]    D --> D3[跨设备适配]
复制代码



三、基础交互:三大金刚操作详解

1. 智能点击(Click)

真实场景问题:按钮被遮挡/加载中状态


// 最佳实践:带状态检测的点击await page.locator('button.submit')  .click({    force: false,       // 禁止强制点击(避免穿透)    trial: false,       // 非测试模式(真实操作)    timeout: 15000,     // 自定义超时(毫秒)    position: { x: 10, y: 10 } // 点击相对坐标  });
复制代码


高级技巧


# 安全点击(带自动重试)async def safe_click(locator, attempts=3):    for i in range(attempts):        try:            await locator.click()            return True        except Exception as e:            if i == attempts-1: raise e            await page.wait_for_timeout(1000)
复制代码

2. 智能输入(Fill)

解决痛点:输入框动态加载/内容清空不彻底


// 三步安全输入法await locator.clear();                 // 清空内容await locator.pressSequentially(text, {   delay: 100                          // 模拟真人输入});await locator.press('Enter');          // 提交表单
复制代码


特殊场景处理


// 富文本编辑器输入(Quill/TinyMCE)const editor = page.frameLocator('.editor-frame').locator('body');await editor.type('Hello, Playwright!');
// 禁用JavaScript的输入框await page.$eval('#legacy-input', el => el.value = 'text');
复制代码

3. 选择操作(Select)

多维度选择方案



# 多级联动选择实战# 选择国家 → 动态加载省份 → 选择城市await page.select_option('#country', 'china')await page.wait_for_selector('#province:not([disabled])')await page.select_option('#province', 'jiangsu')await page.wait_for_selector('#city:not([disabled])')await page.select_option('#city', 'nanjing')
复制代码



四、高级交互:真实业务场景突破

1. 拖拽操作(Drag and Drop)

传统方案痛点:坐标计算复杂/跨 iframe 失效


// 精准拖拽(无需计算坐标)await page.locator('#draggable').dragTo(page.locator('#droppable'));
// 分步控制拖拽await page.locator('#slider') .dragTo(page.locator('#slider'), { sourcePosition: { x: 10, y: 10 }, // 起始点 targetPosition: { x: 200, y: 10 }, // 目标点 steps: 50 // 动画步数 });
复制代码

2. 键盘高级操作

模拟真实用户键盘行为


# 组合键操作(Ctrl+C / Ctrl+V)await page.keyboard.press('Control+C')await page.keyboard.press('Control+V')
# 长按操作await page.keyboard.down('Shift')await page.locator('select').select_option('expert')await page.keyboard.up('Shift')
# 输入特殊字符await page.keyboard.type('Hello © 2025')
复制代码

3. 鼠标高级事件

// 绘制签名(模拟鼠标轨迹)await page.mouse.move(100, 100);await page.mouse.down();for (let i = 0; i < 50; i++) {  await page.mouse.move(100 + i * 2, 100 + Math.sin(i) * 10);}await page.mouse.up();
// 右键菜单操作await page.locator('.file').click({ button: 'right' });await page.locator('text=删除').click();
复制代码


测试开发全景图:人工智能测试、智能驱动、自动化、测试开发、左移右移与DevOps的持续交付

五、特殊场景:企业级解决方案

1. 文件上传终极方案

// 经典input上传await page.locator('input[type=file]').setInputFiles('/path/to/file.png');
// 非input元素上传(如Dropzone)const fileChooserPromise = page.waitForEvent('filechooser');await page.locator('.drop-area').click();const fileChooser = await fileChooserPromise;await fileChooser.setFiles({ name: 'report.pdf', mimeType: 'application/pdf', buffer: Buffer.from('...') // 支持内存文件});
复制代码

2. iframe 嵌套操作

# 定位iframe内的元素frame = page.frame_locator('iframe.login-frame')await frame.locator('#username').fill('testuser')
# 跨iframe拖拽src_frame = page.frame_locator('#frameA')dst_frame = page.frame_locator('#frameB')await src_frame.locator('#item').drag_to(dst_frame.locator('#drop-area'))
复制代码

3. 阴影 DOM(Shadow DOM)穿透

// 直接定位Shadow DOM内部元素await page.locator('custom-element::shadow div.content').click();
// 通过JavaScript访问const handle = await page.$eval('custom-element', el => el.shadowRoot.querySelector('.button'));await handle.click();
复制代码



六、等待策略:保障交互稳定的核心

1. 自动等待机制

Playwright 内置 4 大等待条件


  1. 元素可见(Visible)

  2. 元素可交互(Enabled)

  3. 元素稳定(Stable,停止移动)

  4. 元素接收事件(ReceivesEvents)


// 点击时自动等待元素可操作(默认30秒)await page.click('#submit-btn');
// 自定义等待条件await page.waitForFunction( () => document.querySelector('.progress').innerText === '100%', { timeout: 60000 });
复制代码

2. 网络状态监控

# 等待所有请求完成await page.wait_for_load_state('networkidle')
# 等待特定API完成async with page.expect_response('**/api/save') as response: await page.click('#save-button') data = await response.value.json() print(data['status'])
复制代码

3. 混合等待策略

// 分阶段等待:先元素后网络await page.waitForSelector('.data-loaded', { state: 'visible' });await page.waitForLoadState('domcontentloaded');await page.click('#next-step');
复制代码



七、跨设备交互适配

1. 移动端特殊操作

# 触屏滑动await page.touchscreen.swipe(100, 500, 100, 100, steps=10)
# 双指缩放await page.touchscreen.pinch(200, 200, 1.5) # 放大1.5倍
# 设备旋转await page.set_device_orientation({ alpha: 90, beta: 0, gamma: 0 })
复制代码

2. 不同输入设备模拟

// 触控笔操作await page.mouse.move(100, 100);await page.mouse.down({ button: 'pen' });
// 游戏手柄await page.keyboard.press('GamepadA');
复制代码



八、企业级最佳实践

1. 交互操作封装库

// interaction-utils.tsexport class InteractionUtils {  static async safeClick(locator: Locator, attempts = 3) {    // 实现带重试的点击  }
static async dragAndVerify(source: Locator, target: Locator) { await source.dragTo(target); await expect(target).toHaveClass('drag-success'); }}
// 使用import { InteractionUtils } from './interaction-utils';await InteractionUtils.safeClick(page.locator('button'));
复制代码

2. 操作录制与回放

# 启动录制npx playwright codegen https://example.com
# 导出操作脚本# 自动生成如下代码:await page.getByLabel('用户名').fill('test');await page.getByLabel('密码').fill('password');await page.getByRole('button', { name: '登录' }).click();
复制代码

3. 交互操作健康检查

// 操作稳定性测试脚本test.describe('关键操作稳定性测试', () => {  const TEST_COUNT = 20;    for (let i = 0; i < TEST_COUNT; i++) {    test(`登录操作 #${i}`, async ({ page }) => {      await performLogin(page); // 封装的关键操作      await expect(page).toHaveURL(/dashboard/);    });  }});
复制代码



九、常见问题解决方案



十、性能优化:交互加速技巧

  1. 操作合并:减少不必要的等待


   # 合并表单操作(单次事件循环)   await page.evaluate('''() => {     document.querySelector('#name').value = 'Test';     document.querySelector('#email').value = 'test@example.com';   }''')
复制代码


  1. 并行操作:同时执行独立任务


   // 并行填写表单字段   await Promise.all([     page.locator('#field1').fill('value1'),     page.locator('#field2').fill('value2'),     page.locator('#field3').fill('value3')   ]);
复制代码


  1. 本地操作优先:减少网络影响


   // 本地文件替代网络上传   await page.route('**/upload', route => route.fulfill({     status: 200,     body: JSON.stringify({ success: true })   }));
复制代码


🚀 终极提示:Playwright 的交互操作不是简单的命令执行,而是模拟真实用户行为的艺术!


用户头像

社区:ceshiren.com 微信:ceshiren2023 2022-08-29 加入

微信公众号:霍格沃兹测试开发 提供性能测试、自动化测试、测试开发等资料、实事更新一线互联网大厂测试岗位内推需求,共享测试行业动态及资讯,更可零距离接触众多业内大佬

评论

发布
暂无评论
Playwright基础入门篇 (3) | 交互操作深度解析_测吧(北京)科技有限公司_InfoQ写作社区