当前位置: 首页 > news >正文

playwright 最佳实践

playwright 最佳实践

Playwright 是由微软开发的现代化 E2E 自动化测试框架。

🎬 一、Playwright 简介

1. Playwright 是什么?

Playwright 是由微软开发的现代化 E2E 自动化测试框架,支持多浏览器(Chromium、Firefox、WebKit)和多语言(Node.js、Python、Java、C#),特别适合做 UI 自动化测试和爬虫。

示例代码

import { test, expect } from '@playwright/test';test('使用 Google 搜索', async ({ page }) => {// 进入 google 搜索页await page.goto('https://www.google.com');// 模拟手动输入 Playwrightawait page.fill('input[name="q"]', 'Playwright');// 模拟回车确认搜索await page.keyboard.press('Enter');// 校验await expect(page.locator('#search')).toContainText('Playwright');
});

2. Playwright 能做什么?

  • 端到端自动化测试
    • 登录、下单、支付、弹窗、表单交互等全流程模拟
  • 浏览器爬虫
    • 提取页面信息,模拟滚动、点击、登录等
  • 回归测试
    • CI/CD 中检测新版本是否破坏 UI 功能
  • 可视化回归测试
    • 截图、视频、trace,查看测试中实际发生了什么

3. Playwright 特性

特性说明
✅ 多浏览器支持支持 Chromium (Chrome/Edge)FirefoxWebKit (Safari)
✅ 多语言支持支持 JavaScript/TypeScriptPythonJavaC#/.NET
✅ 自动等待机制自动等待元素出现、可点击、导航完成等,不容易出 flaky(随机失败)测试
✅ 原生支持 iframe、多页签轻松处理复杂页面中的 iframe、弹窗、多标签页
✅ 内置测试运行器自带功能完整的 test runner(类似 Jest + Mocha + Chai + Puppeteer)
✅ 网络拦截与 Mock可模拟后端接口,进行无网络依赖测试
✅ 跨平台运行支持 Windows、macOS、Linux、本地/CI 环境运行
✅ 丰富调试工具提供 UI trace viewer、codegen 工具、screenshot/video trace

🚀 二、Playwright 实践

1. Playwright 安装依赖

tests/├── login.spec.ts├── dashboard.spec.ts└── utils/└── auth.ts
playwright.config.ts

官网参考

$ npm init playwright@latest
# 或手动安装
$ npm install -D @playwright/test
$ npx playwright install

2. 测试用例基础结构

如何编写测试用例

import { test, expect } from '@playwright/test';
// test.describe 理解为测试分组
test.describe('用户模块', () => {// test 理解为定义了一个测试用例test('登录', () => {// 登录相关测试});test('注册', () => {// 注册相关测试});
});

3. 常见 API 用法

✅ 页面导航 & 交互

await page.goto('https://example.com');        // 打开页面
await page.click('text=Sign in');              // 点击按钮或链接
await page.fill('#username', 'myname');        // 填写输入框
await page.press('#input', 'Enter');           // 模拟按键
await page.selectOption('select#role', 'admin'); // 选择下拉框选项

✅ 元素等待

await page.waitForSelector('#submit-btn');        // 等待出现并可见
await page.waitForSelector('.modal', { state: 'hidden' });  // 等待消失
await expect(page.locator('h1')).toHaveText('Hello');       // 推荐写法

✅ 截图 / 视频 / Trace

await page.screenshot({ path: 'screenshot.png' });   // 截图
await page.context().tracing.start({ screenshots: true, snapshots: true });
await page.context().tracing.stop({ path: 'trace.zip' });  // 查看 UI 行为

✅ 请求拦截 / mock 接口

await page.route('**/api/**', route =>route.fulfill({ status: 200, body: JSON.stringify({ data: [] }) })
);

4. 模块封装

封装一个登录模块

// login.page.ts
export class LoginPage {constructor(private page: Page) {}async login(username: string, password: string) {await this.page.fill('#user', username);await this.page.fill('#pass', password);await this.page.click('text=Login');}
}

5. 配置项

  • 自定义配置项
// playwright.config.ts
import { defineConfig } from '@playwright/test';export default defineConfig({use: {// Emulates `'prefers-colors-scheme'` media feature.colorScheme: 'dark',// Context geolocation.geolocation: { longitude: 12.492507, latitude: 41.889938 },// Emulates the user locale.locale: 'en-GB',// Grants specified permissions to the browser context.permissions: ['geolocation'],// Emulates the user timezone.timezoneId: 'Europe/Paris',// Viewport used for all pages in the context.viewport: { width: 1280, height: 720 },},
});

5. demo 演示

  • ✅ 示例 1:模拟登录
import { test, expect } from '@playwright/test';test.describe('登录功能', () => {test.beforeEach(async ({ page }) => {await page.goto('https://yourapp.com/login');});test('登录成功跳转到首页', async ({ page }) => {await page.fill('#username', 'robbie');await page.fill('#password', 'correct_password');await page.click('button[type="submit"]');await expect(page).toHaveURL(/dashboard/);await expect(page.locator('text=欢迎回来')).toBeVisible();});test('登录失败提示错误', async ({ page }) => {await page.fill('#username', 'robbie');await page.fill('#password', 'wrong_password');await page.click('button[type="submit"]');await expect(page.locator('.error')).toHaveText('用户名或密码错误');});
});
  • ✅ 示例 2:等待 loading 消失再点击按钮
test('加载后点击按钮', async ({ page }) => {await page.goto('https://yourapp.com/profile');// 等待 loading 动画结束await page.waitForSelector('.loading-spinner', { state: 'hidden' });// 再点击保存按钮await page.click('button.save');await expect(page.locator('.toast')).toHaveText('保存成功');
});
  • ✅ 示例 3:表单验证(空值、错误格式)
test('表单校验错误提示', async ({ page }) => {await page.goto('https://yourapp.com/register');await page.click('button[type="submit"]');await expect(page.locator('#email-error')).toHaveText('邮箱不能为空');await expect(page.locator('#password-error')).toHaveText('密码不能为空');
});
  • ✅ 示例 4:打开弹窗并验证内容
test('打开弹窗并验证内容', async ({ page }) => {await page.goto('https://yourapp.com');await page.click('button.view-detail');await page.waitForSelector('.modal-content');await expect(page.locator('.modal-title')).toHaveText('详情信息');
});
  • ✅ 示例 5:拦截并 Mock 接口返回数据
test('拦截接口并返回自定义数据', async ({ page }) => {await page.route('**/api/user/info', route =>route.fulfill({status: 200,contentType: 'application/json',body: JSON.stringify({ name: '测试用户', id: 1 }),}));await page.goto('https://yourapp.com/user');await expect(page.locator('.username')).toHaveText('测试用户');
});
  • ✅ 示例 6:截图用于 UI 回归测试
test('页面截图', async ({ page }) => {await page.goto('https://yourapp.com/dashboard');await page.screenshot({ path: 'screenshots/dashboard.png', fullPage: true });
});
  • ✅ 示例 7:使用 test.step 添加步骤标记(增强 Trace 可读性)
test('使用步骤结构化流程', async ({ page }) => {await test.step('打开登录页', async () => {await page.goto('https://yourapp.com/login');});await test.step('填写登录表单', async () => {await page.fill('#username', 'robbie');await page.fill('#password', '123456');});await test.step('点击登录按钮并跳转', async () => {await page.click('button[type="submit"]');await expect(page).toHaveURL(/dashboard/);});
});
  • ✅ 示例 8:使用 test.use 指定不同登录状态

Playwright 支持通过 test.use() 给某些 describe 套件设置专属上下文(例如已登录用户):

test.describe.use({ storageState: 'logged-in-state.json' });test('已登录用户访问主页', async ({ page }) => {await page.goto('https://yourapp.com');await expect(page.locator('.username')).toHaveText('robbie');
});

参考文档

  • playwright 官方网站
  • playwright 指引文档
  • playwright API
  • playwright 发布记录
http://www.dtcms.com/a/288814.html

相关文章:

  • PostgreSQL实战:高效SQL技巧
  • 第三章-提示词-中级:进阶技巧与实践指南(12/36)
  • Java什么是原子性
  • 17.TaskExecutor与ResourceManager交互
  • 论文阅读:Instruct BLIP (2023.5)
  • 【Lua】多脚本引用
  • Java反射:打破静态限制的利器
  • 【笔记】Anaconda 重装后虚拟环境写入路径异常的完整排查与解决过程
  • MySQL—表设计和聚合函数以及正则表达式
  • LeetCode 1712.将数组分成三个子数组的方案数
  • ZooKeeper学习专栏(二):深入 Watch 机制与会话管理
  • BST(二叉搜索树)的笔试大题(C语言)
  • [硬件电路-59]:电源:电子存储的仓库,电能的发生地,电场的动力场所
  • 手推OpenGL相机的正交投影矩阵和透视投影矩阵(附源码)
  • 【AI】文生图文生视频
  • 第三章自定义检视面板_创建自定义编辑器类_编辑器操作的撤销与恢复(本章进度3/9)
  • 使用pnpm安装项目的生产依赖dependencies和开发依赖devDependies及pnpm工作空间等简单使用方法说明
  • Function
  • Qwen3-8B 与 ChatGPT-4o Mini 的 TTFT 性能对比与底层原理详解
  • Docker实战:使用Docker部署envlinks极简个人导航页
  • Springboot美食分享平台
  • 【Kafka】深入理解 Kafka MirrorMaker2 - 实战篇
  • Mac m系列 VMware Fusion虚拟机安装ARM contos
  • host.equiv,.rhosts,inetd.conf文件的作用
  • Python应用进阶DAY10--模块化编程概念(模块、包、导入)及常见系统模块总结和第三方模块管理
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘beautifulsoup4’问题
  • 响应式编程入门教程第九节:UniRx 高级特性与自定义
  • python doipclient库
  • 学习C++、QT---30(QT库中如何自定义控件(自定义按钮)讲解)
  • XSS知识总结