Playwright自动化测试:从核心原理到工程实践全解析

📅 2026/7/2 22:23:45 👁️ 阅读次数 📝 编程学习
Playwright自动化测试:从核心原理到工程实践全解析

1. 项目概述:为什么是Playwright?

如果你正在寻找一个能搞定现代Web应用自动化测试的工具,无论是做UI测试、爬虫、还是RPA,Playwright绝对值得你花时间深入了解。它不是一个简单的“Selenium替代品”,而是一个为当下复杂Web环境量身定制的解决方案。我最初接触它是因为一个项目:需要测试一个重度使用React、动态加载、且有大量Shadow DOM组件的单页应用。用传统的工具,光是处理元素等待和定位就让人头疼不已,而Playwright几乎是以一种“理解”页面的方式解决了这些问题。

简单来说,Playwright是一个由微软开源的浏览器自动化库。它支持Chromium、Firefox和WebKit三大浏览器引擎,这意味着你可以用一套脚本测试你的网站在Chrome、Firefox和Safari上的表现是否一致。它的核心优势在于其“智能”和“健壮性”。它内置了自动等待机制,能智能地等待元素可操作、网络请求完成,大大减少了编写显式等待(time.sleep)的需要。同时,它对现代Web技术的原生支持,如单页应用(SPA)、文件上传下载、网络拦截、地理位置模拟等,让它从一众工具中脱颖而出。

它适合谁?前端开发者、测试工程师、需要做数据抓取或流程自动化的任何人。无论你是想验证一个新功能,还是需要每天自动执行一些重复的网页操作,Playwright都能提供稳定、高效的脚本支持。接下来,我会从一个实际使用者的角度,拆解它的核心设计、手把手带你实操,并分享那些官方文档里不会写的“踩坑”经验。

2. 核心设计理念与架构优势

2.1 多浏览器引擎支持与无头模式

Playwright最显著的特点之一就是其跨浏览器引擎的支持。它不像某些工具只绑定一个浏览器,而是通过统一的API同时驱动Chromium、Firefox和WebKit。这背后的设计考量是测试的真实性与一致性。WebKit是Safari的渲染引擎,确保你的网站在苹果生态下的兼容性;Firefox代表了Gecko引擎;Chromium则是Chrome、Edge等浏览器的基础。Playwright团队与这些浏览器引擎的维护者紧密合作,确保API的稳定性和行为的一致性。

在实际使用中,你只需要在启动浏览器时指定一个引擎类型即可。例如,在Python中,你可以这样写:

from playwright.sync_api import sync_playwright with sync_playwright() as p: # 启动Chromium browser = p.chromium.launch(headless=False) # 启动Firefox # browser = p.firefox.launch(headless=False) # 启动WebKit # browser = p.webkit.launch(headless=False) page = browser.new_page() page.goto("https://example.com")

headless=False参数会让浏览器以有界面的模式运行,方便调试。而在生产环境的持续集成(CI)流水线中,通常使用无头模式(headless=True),不启动GUI以节省资源。

注意:首次运行playwright install命令时,它会下载所有三大浏览器的二进制文件。如果你只需要其中某一个,可以使用playwright install chromium来仅安装Chromium,以节省磁盘空间和下载时间。国内用户可能会遇到下载慢的问题,可以通过设置环境变量PLAYWRIGHT_DOWNLOAD_HOST来配置镜像源,例如设置为https://npmmirror.com/mirrors/playwright/可以显著提升下载速度。

2.2 自动等待与执行上下文

这是Playwright解决“脆性测试”(Flaky Tests)的杀手锏。传统脚本失败的一个主要原因是元素尚未加载完成就尝试进行操作。Playwright的绝大多数操作(如click,fill,type)都内置了智能等待。

其工作原理是:当执行一个操作时,Playwright会进行一系列可操作性检查(Actionability Checks)。例如,对于page.click(‘button#submit’),它会自动等待,直到:

  1. 元素被附加到DOM中。
  2. 元素是可见的(非隐藏、非display:none、非visibility:hidden)。
  3. 元素是启用的(非disabled)。
  4. 元素稳定(例如,没有正在进行的动画或样式变化)。
  5. 元素滚动到视图中。

只有所有这些条件都满足,它才会执行点击。这几乎消除了因时机问题导致的随机失败。你不再需要到处写WebDriverWaitexpected_conditions

另一个核心概念是执行上下文。Playwright的API设计围绕BrowserBrowserContextPage展开。

  • Browser: 对应一个浏览器进程实例。
  • BrowserContext: 这是一个独立的“会话”环境,类似于一个隐身模式窗口。每个Context拥有独立的cookie、缓存和本地存储,彼此隔离。这在测试中非常有用,例如,你可以创建一个已登录用户的Context和一个未登录用户的Context,并行执行测试,而无需清理状态。
  • Page: 对应一个标签页。

这种层级结构让状态管理和并行测试变得清晰。例如,你可以轻松模拟多用户场景:

context1 = browser.new_context() page1 = context1.new_page() # 在page1上登录用户A context2 = browser.new_context() page2 = context2.new_page() # page2是全新的会话,用户B未登录

2.3 网络拦截与模拟

现代Web应用高度依赖API通信。Playwright允许你监听和修改页面发出的任何网络请求和响应,这为测试提供了极大的灵活性。

  • 路由(Route)与拦截:你可以拦截特定请求,并返回一个自定义的响应,或者修改请求/响应内容。这在以下场景非常有用:
    • 测试边缘情况:模拟API返回错误码(如500)、超时或空数据。
    • 屏蔽第三方资源:屏蔽广告、分析脚本,让测试跑得更快。
    • 准备测试数据:直接向页面“注入”API响应数据,绕过后端依赖。
# 拦截所有图片请求并中止,加速页面加载 page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort()) # 拦截一个API请求并返回模拟数据 def handle_route(route): if "/api/user" in route.request.url: route.fulfill( status=200, content_type="application/json", body=json.dumps({"name": "Mock User", "id": 123}) ) else: route.continue_() page.route("**/api/**", handle_route)
  • 模拟网络条件:可以模拟慢速3G、离线等网络环境,测试应用在弱网下的表现。

    context = browser.new_context(**playwright.devices["iPhone 12"]) # 进一步模拟网络 context.set_default_timeout(60000) # 设置长超时 # 或者使用更精确的网络模拟(需浏览器支持特定标志)
  • 监听请求/响应:简单地记录所有网络活动,用于调试。

    page.on("request", lambda request: print(f">> {request.method} {request.url}")) page.on("response", lambda response: print(f"<< {response.status} {response.url}"))

3. 环境搭建与核心API详解

3.1 多语言绑定安装与初始化

Playwright提供了Python、Node.js、Java和.NET的API,其核心是相同的。这里以最常用的Python和Node.js为例。

Python环境:

  1. 安装Playwright库:pip install playwright
  2. 安装浏览器二进制文件:playwright install(或指定playwright install chromium
  3. 验证安装:创建一个简单的脚本test.py
    from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=False) # 首次调试建议用有头模式 page = browser.new_page() page.goto("https://www.baidu.com") print(page.title()) page.screenshot(path="baidu.png") browser.close()
    运行python test.py,你应该能看到浏览器打开百度首页,控制台打印标题,并截图保存。

Node.js环境:

  1. 初始化项目并安装:npm init -y && npm i playwright
  2. 安装浏览器:npx playwright install
  3. 创建测试文件example.js
    const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch({ headless: false }); const page = await browser.newPage(); await page.goto('https://www.baidu.com'); console.log(await page.title()); await page.screenshot({ path: 'baidu.png' }); await browser.close(); })();
    运行node example.js

实操心得:对于团队项目,强烈建议将playwright的安装和浏览器安装步骤写入项目的package.jsonrequirements.txt以及CI配置中。对于Node.js项目,可以在package.jsonscripts里添加"postinstall": "playwright install",这样在npm install后会自动安装浏览器。国内团队可以搭建内部镜像,统一配置下载源,避免因网络问题导致CI失败。

3.2 元素定位与操作:超越CSS和XPath

稳定地定位元素是自动化的基石。Playwright提供了丰富且强大的定位器(Locator)API。

基本定位器:

  • page.locator(‘text=登录’): 通过文本内容定位。这是Playwright非常推荐的方式,因为它最接近用户感知。
  • page.locator(‘#username’): 通过CSS选择器定位。
  • page.locator(‘xpath=//button[@type=”submit”]’): 通过XPath定位。
  • page.locator(‘role=button[name=”确认”]’): 通过ARIA角色定位,这是面向可访问性测试的强大功能。
  • page.get_by_role(‘button’, name=‘Submit’): 这是更语义化的API(Node.js v1.27+, Python v1.31+),优先推荐使用。

组合与过滤:定位器可以链式调用和过滤,非常灵活。

# 找到表格中第一行,状态为“活跃”的“编辑”按钮 row = page.locator(‘tr’).first edit_btn = row.get_by_role(‘button’, name=‘编辑’).filter(has=page.locator(‘.status-active’)) # 等待这个按钮可见并点击 edit_btn.click()

操作元素:定位到元素后,可以进行各种操作:

# 输入文本 page.locator(‘#search’).fill(‘Playwright’) # 点击 page.locator(‘button:has-text(“搜索”)’).click() # 勾选复选框 page.locator(‘#agree-terms’).check() # 选择下拉框选项 page.locator(‘#country’).select_option(‘CN’) # 上传文件(非常方便,无需模拟input点击) page.locator(‘input[type=”file”]’).set_input_files(‘./myfile.pdf’) # 获取文本、属性、内部HTML text = page.locator(‘.title’).inner_text() href = page.locator(‘a’).get_attribute(‘href’)

注意事项:尽量避免使用纯索引定位,如page.locator(‘button’).nth(2),因为页面结构一旦微调,脚本就很容易失效。优先使用具有语义的文本、角色或稳定的ID/数据测试属性(如># 在触发弹窗的操作之前,先监听dialog事件 page.on(‘dialog’, lambda dialog: dialog.accept(“输入的文字”)) page.locator(‘#btn-show-prompt’).click() # 点击触发prompt弹窗 # 监听后,当弹窗出现时,会自动用“输入的文字”接受它

框架(Frame)和内嵌页面(iframe):对于iframe中的元素,需要先获取frame对象。

# 通过名称或URL定位frame frame = page.frame(name=‘login-frame’) # 或 page.frame(url=‘**/login.html’) # 然后在frame上使用locator frame.locator(‘#username’).fill(‘user’) # 更通用的方式:使用FrameLocator frame_locator = page.frame_locator(‘iframe[name=”login-frame”]’) frame_locator.locator(‘#username’).fill(‘user’)

Shadow DOM:对于Web Components和Shadow DOM,Playwright可以穿透影子根(Shadow Root)直接定位内部元素,无需复杂的JavaScript注入。

# 假设有一个自定义组件 <my-component> # 直接使用 `::part()` 或 `::shadow` 选择器(取决于组件实现) # Playwright的定位器通常能自动处理深度嵌套的Shadow DOM page.locator(‘my-component’).locator(‘.internal-button’).click() # 或者如果组件暴露了part page.locator(‘my-component::part(button)’).click()

这是Playwright对比旧工具的一个巨大优势,对现代UI库(如Lit, Stencil)构建的应用支持非常好。

4. 高级功能与实战场景

4.1 录制与生成脚本:Codegen工具

Playwright提供了一个强大的命令行工具playwright codegen,可以录制你的浏览器操作并生成对应语言的脚本。这是快速入门和编写简单脚本的神器。

使用方法:

# 启动录制工具,并打开浏览器 playwright codegen https://your-test-site.com

随后,你在浏览器中的所有点击、输入、导航操作都会被实时转换成代码,显示在旁边的窗口中。你可以选择生成Python、JavaScript、Java等语言的代码。

实操心得:Codegen生成的代码是一个很好的起点,但绝不能直接用于生产环境。它生成的定位器可能不够健壮(例如过度依赖文本或索引),且缺乏必要的等待和断言。正确的做法是:用Codegen快速生成操作流骨架,然后手动优化定位器策略、添加断言、重构代码结构(如使用Page Object模式)、并加入错误处理。把它当作一个“代码助手”而非“代码生成器”。

4.2 文件下载与上传处理

文件下载:处理文件下载时,你需要监听download事件,并等待下载完成。

# 启动下载前,先设置下载路径并监听事件 download_path = ‘/path/to/downloads’ context = browser.new_context(accept_downloads=True) # 必须启用 page = context.new_page() # 开始监听下载 with page.expect_download() as download_info: page.locator(‘#download-csv’).click() # 触发下载的按钮 download = download_info.value # 等待下载完成并保存到指定路径 save_path = f”{download_path}/{download.suggested_filename}” download.save_as(save_path) print(f”文件已下载到: {save_path}”)

文件上传:如前所述,Playwright的文件上传极其简单,使用set_input_files方法即可,无需触发文件选择对话框。

# 单文件上传 page.locator(‘input[type=”file”]’).set_input_files(‘./resume.pdf’) # 多文件上传 page.locator(‘input[type=”file”]’).set_input_files([‘./file1.pdf’, ‘./file2.jpg’]) # 清除已选文件 page.locator(‘input[type=”file”]’).set_input_files([])

4.3 模拟设备、地理位置与权限

Playwright可以模拟移动设备、地理位置、语言时区、以及权限(如摄像头、麦克风、通知)。

模拟移动设备:Playwright内置了众多流行设备(如iPhone, Pixel)的配置。

from playwright.sync_api import sync_playwright with sync_playwright() as p: # 获取iPhone 13的设备描述符 iphone_13 = p.devices[‘iPhone 13’] # 创建上下文时应用设备模拟 browser = p.chromium.launch() context = browser.new_context(**iphone_13) # 应用用户代理、视口大小、设备比例因子等 page = context.new_page() page.goto(‘https://mobile.example.com’) # 此时页面看到的将是移动端视图和对应的User-Agent

模拟地理位置和语言:

context = browser.new_context( locale=‘zh-CN’, # 模拟中文环境 timezone_id=‘Asia/Shanghai’, # 上海时区 geolocation={‘longitude’: 121.4737, ‘latitude’: 31.2304}, # 上海坐标 permissions=[‘geolocation’] # 授予地理位置权限 ) page = context.new_page() page.goto(‘https://maps.example.com’) # 页面将获得地理位置权限,并获取到模拟的坐标

4.4 集成测试框架:Playwright Test

虽然你可以单独使用Playwright库写脚本,但对于严肃的测试项目,强烈推荐使用其官方测试框架@playwright/test(Node.js) 或pytest-playwright(Python)。它提供了测试运行器、断言库、夹具(Fixtures)和HTML报告等一站式解决方案。

Node.js (@playwright/test) 示例:

  1. 安装:npm init playwright@latest(按照引导完成)
  2. 编写测试example.spec.js
    const { test, expect } = require(‘@playwright/test’); test(‘basic test’, async ({ page }) => { // `page` fixture 自动注入 await page.goto(‘https://playwright.dev/’); await expect(page).toHaveTitle(/Playwright/); const getStarted = page.locator(‘text=Get Started’); await expect(getStarted).toHaveAttribute(‘href’, ‘/docs/intro’); await getStarted.click(); await expect(page).toHaveURL(/.*intro/); });
  3. 运行测试:npx playwright test, 查看报告:npx playwright show-report

Python (pytest) 示例:

  1. 安装:pip install pytest-playwright
  2. 安装浏览器:playwright install
  3. 编写测试test_example.py
    import re from playwright.sync_api import Page, expect def test_homepage_has_playwright_in_title(page: Page): # `page` fixture 自动注入 page.goto(“https://playwright.dev/”) expect(page).to_have_title(re.compile(“Playwright”)) def test_get_started_link(page: Page): page.goto(“https://playwright.dev/”) link = page.locator(“text=Get Started”) expect(link).to_have_attribute(“href”, “/docs/intro”) link.click() expect(page).to_have_url(re.compile(“.*intro”))
  4. 运行测试:pytest

框架核心优势:

  • 自动并行化:测试默认在隔离的BrowserContext中并行运行,速度快。
  • 强大的断言:专为动态Web设计,如to_have_title,to_have_url,to_be_visible,to_have_text等,都内置了智能等待。
  • 丰富的夹具:开箱即用的page,context,browser夹具,管理生命周期。
  • 可视化报告:自动生成带截图、视频、追踪时间线的HTML报告,失败时一目了然。
  • 追踪(Trace):可以记录测试执行的详细追踪文件,包含每一步的DOM快照、网络请求、控制台日志,是调试复杂失败的终极武器。通过--trace on参数启用。

5. 工程化实践与性能优化

5.1 测试组织模式:Page Object Model (POM)

对于任何稍具规模的测试项目,使用Page Object模式是必须的。它将页面的元素定位和操作封装成类,使测试脚本更清晰、更易维护、减少重复代码。

Python POM示例:

# pages/login_page.py from playwright.sync_api import Page class LoginPage: def __init__(self, page: Page): self.page = page self.username_input = page.locator(‘#username’) self.password_input = page.locator(‘#password’) self.submit_button = page.locator(‘button[type=”submit”]’) self.error_message = page.locator(‘.alert-error’) def navigate(self): self.page.goto(“/login”) def login(self, username: str, password: str): self.username_input.fill(username) self.password_input.fill(password) self.submit_button.click() def get_error(self) -> str: return self.error_message.inner_text() # test_login.py import pytest from pages.login_page import LoginPage def test_successful_login(page): login_page = LoginPage(page) login_page.navigate() login_page.login(“valid_user”, “valid_pass”) # 断言跳转或成功元素出现 assert page.url == “/dashboard” def test_failed_login(page): login_page = LoginPage(page) login_page.navigate() login_page.login(“wrong”, “wrong”) assert “Invalid credentials” in login_page.get_error()

5.2 配置管理与CI/CD集成

配置文件:Playwright Test框架支持配置文件来定义全局设置,如浏览器类型、基础URL、超时时间、截图/视频选项等。

  • Node.js:playwright.config.ts
  • Python:pytest.iniplaywright.config.py

一个典型的Node.js配置示例:

// playwright.config.ts import { defineConfig, devices } from ‘@playwright/test’; export default defineConfig({ testDir: ‘./tests’, // 测试目录 fullyParallel: true, // 完全并行 forbidOnly: !!process.env.CI, // CI环境下禁止使用test.only retries: process.env.CI ? 2 : 0, // CI下失败重试2次 workers: process.env.CI ? 4 : undefined, // CI下使用4个worker并行 reporter: ‘html’, // 生成HTML报告 use: { baseURL: ‘https://my-app.staging.com’, // 基础URL trace: ‘on-first-retry’, // 首次重试时记录追踪 screenshot: ‘only-on-failure’, // 仅失败时截图 video: ‘retain-on-failure’, // 仅失败时保留视频 }, projects: [ // 定义多个项目,如不同浏览器测试 { name: ‘chromium’, use: { …devices[‘Desktop Chrome’] } }, { name: ‘firefox’, use: { …devices[‘Desktop Firefox’] } }, { name: ‘webkit’, use: { …devices[‘Desktop Safari’] } }, { name: ‘Mobile Chrome’, use: { …devices[‘Pixel 5’] } }, ], });

CI/CD集成:在GitHub Actions、GitLab CI、Jenkins等CI环境中运行Playwright测试非常普遍。关键步骤包括:

  1. 缓存浏览器二进制文件:避免每次运行都下载,加速构建。
  2. 安装依赖npm cipip install -r requirements.txt
  3. 安装系统依赖:Playwright可能需要一些系统库(如字体)。使用npx playwright install-depsplaywright install-deps来安装。
  4. 运行测试npx playwright testpytest
  5. 上传产物:将测试报告、截图、视频等作为构建产物上传,便于查看。

一个简化的GitHub Actions配置示例:

name: Playwright Tests on: [push] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: { node-version: ‘18’ } - name: Cache playwright browsers uses: actions/cache@v3 with: path: ~/.cache/ms-playwright key: ${{ runner.os }}-playwright-${{ hashFiles(‘package-lock.json’) }} - run: npm ci - run: npx playwright install –with-deps chromium # 只安装Chromium及其依赖 - run: npx playwright test - uses: actions/upload-artifact@v3 if: always() with: name: playwright-report path: playwright-report/ retention-days: 7

5.3 性能考量与最佳实践

  1. 浏览器启动与复用:启动浏览器是昂贵的操作。在测试套件级别复用浏览器实例,通过不同的BrowserContext来隔离测试,可以极大提升速度。Playwright Test框架的夹具系统已经很好地处理了这一点。
  2. 并行执行:充分利用Playwright Test的并行能力。通过配置workers数量(通常等于CPU核心数),让测试并行运行。
  3. 选择性安装浏览器:在CI环境中,如果不需要测试所有浏览器,只安装必要的(如playwright install chromium)。
  4. 禁用不必要的功能:对于不需要的功能,可以在启动上下文时关闭,如java_script_enabled=False,ignore_https_errors=True(仅测试环境),或拦截不必要的资源(如图片、样式表)。
  5. 合理设置超时:为不同的操作设置合理的超时。全局超时在配置中设置,也可以为特定操作设置单独的超时:page.click(‘button’, timeout=10000)
  6. 使用追踪(Trace)进行调试,而非视频:记录视频对性能影响较大。优先使用trace: ‘on-first-retry’,它只在失败时记录,且信息量远大于视频,更利于调试。
  7. 清理资源:确保在测试结束后正确关闭浏览器和上下文,避免内存泄漏。

6. 常见问题排查与调试技巧

6.1 元素定位失败:动态内容与等待策略

这是自动化测试中最常见的问题。现代Web应用大量使用动态内容,元素可能异步加载、状态频繁变化。

症状:脚本报错TimeoutError: Timeout 30000ms exceeded.Error: Element not found.

排查与解决:

  1. 优先使用语义化定位器:使用get_by_role,get_by_text,get_by_test_id。避免使用脆弱的CSS选择器,如依赖于DOM结构顺序的:nth-child(3)
  2. 检查元素是否在iframe或Shadow DOM中:如果是,需要使用frame_locator或确保定位器能穿透Shadow DOM。
  3. 利用Playwright的调试工具
    • Playwright Inspector:通过设置环境变量PWDEBUG=1运行脚本,或使用playwright codegen–debug模式。它会打开一个带调试信息的UI,可以逐步执行、查看定位器、检查页面快照。
    • 生成选择器:在浏览器开发者工具中选中元素,在Playwright的Console面板(或使用浏览器扩展)中可以直接生成推荐的选择器。
  4. 显式等待与重试:虽然Playwright操作内置等待,但有时你需要等待特定条件。使用page.wait_for_selector(‘.loading’, state=‘hidden’)等待加载动画消失,或page.wait_for_function()等待自定义JavaScript条件。
  5. 处理动态ID/类名:如果元素的ID或类名是动态生成的(如button-abc123),不要依赖完整字符串。使用CSS属性选择器匹配部分内容:page.locator(‘[id^=”button-“]’)(匹配id以”button-“开头的元素),或直接使用更稳定的文本或角色定位。

6.2 异步操作与竞态条件

症状:脚本执行顺序不符合预期,比如在数据加载完之前就进行了断言。

解决:

  • 等待导航:在点击可能引发页面跳转的链接后,使用page.wait_for_url()page.wait_for_navigation()来等待新页面就绪。
    with page.expect_navigation(): page.locator(‘#submit’).click() # 或者 page.locator(‘#submit’).click() page.wait_for_url(‘**/success’)
  • 等待网络请求:如果操作会触发一个特定的API调用,可以等待该请求完成。
    # 在点击“保存”按钮前,先准备监听请求 with page.expect_response(‘**/api/save’) as response_info: page.locator(‘#save-btn’).click() response = response_info.value assert response.ok
  • 使用expect断言:Playwright Test框架的expect断言(如to_have_text,to_be_visible)内置了重试和等待逻辑,比手动写assert语句更可靠。

6.3 跨域与iframe安全限制

症状:无法操作跨域iframe中的元素,或出现安全错误。

解决:

  • Playwright默认遵循同源策略。要操作跨域iframe,你需要获取对该iframe的引用,但操作可能受限。
  • 在测试环境中,如果可能,最好让开发人员提供非跨域的iframe或使用测试专用的构建,以避免复杂性问题。
  • 对于某些操作(如截图),如果iframe是跨域的,可能无法捕获其完整内容。这是浏览器安全限制,Playwright无法绕过。

6.4 资源加载与超时处理

症状:页面加载慢,脚本因超时而失败。

解决:

  1. 增加超时时间:在page.goto()或配置中设置更长的超时:page.goto(url, timeout=60000)
  2. 忽略某些资源错误:对于测试非关键的资源(如第三方分析、广告),可以监听请求失败事件并忽略。
    page.on(‘requestfailed’, lambda request: print(f”请求失败: {request.url} {request.failure}”)) # 或者直接拦截并中止不重要的请求 page.route(“**/*.gif”, lambda route: route.abort())
  3. 使用wait_for_load_statepage.goto()默认等待load事件。对于单页应用,可能domcontentloaded就足够了,或者需要等待networkidle
    page.goto(url, wait_until=”domcontentloaded”) # 等待DOM加载完成 # 或者 page.goto(url) page.wait_for_load_state(‘networkidle’) # 等待网络基本空闲

6.5 调试利器:追踪(Trace Viewer)

当测试在CI中失败,而本地又无法复现时,追踪文件是你的救命稻草。在配置中启用trace: ‘on-first-retry’trace: ‘on’

运行测试后,会生成一个trace.zip文件。使用以下命令查看:

npx playwright show-trace trace.zip

Trace Viewer会展示一个时间线,你可以看到:

  • 每一步操作(点击、输入)的精确时刻。
  • 操作前后的DOM快照。
  • 发生的所有网络请求及其响应。
  • 控制台输出的所有日志和错误。
  • 页面的截图。

通过回放时间线,你可以像看录像一样逐步分析测试失败的原因,精准定位到是哪个元素没找到、哪个请求失败了、或者页面状态在哪个时刻出现了问题。这是我解决复杂、偶发性问题最依赖的工具。