
1. 项目概述为什么我们需要一个“终极”的自动化测试工具如果你是一名测试工程师、开发人员或者任何需要和网页打交道的人最近一定没少听到“Playwright”这个名字。它就像一阵旋风迅速席卷了自动化测试和网页爬虫的圈子。但你可能也困惑过市面上已经有Selenium和Puppeteer了为什么还要学Playwright这个“终极指南”到底“终极”在哪里简单来说Playwright是微软开源的一个现代化浏览器自动化库。它解决了我们过去用Selenium时最头疼的几个问题等待元素的不确定性、跨浏览器兼容性的繁琐配置、以及处理现代单页应用SPA动态内容的无力感。我最初接触它是因为一个需要同时兼容Chrome、Firefox和Safari的截图项目。用Selenium写一套脚本光是处理不同浏览器的驱动和等待策略就耗掉大半天还经常因为页面加载不完全导致截图失败。换成Playwright后同样的功能代码量减少了三分之一运行稳定性和速度却提升了一倍不止。这份指南的目标就是带你从零开始彻底掌握Playwright Python的核心能力重点聚焦在跨浏览器自动化测试和高保真网页截图这两个最实用、最高频的场景。无论你是想为你的Web应用构建一套健壮的测试体系还是需要批量、精准地捕获网页快照用于归档、监控或数据分析这篇文章都能给你一套可直接复制粘贴的“工业级”解决方案。我们会从环境搭建讲到高级技巧并分享大量我踩过坑后才总结出的实战经验。2. 核心设计思路Playwright凭什么成为“新王”在深入代码之前我们必须理解Playwright的设计哲学。它不是一个简单的“Selenium替代品”而是一次架构上的革新。2.1 架构优势超越WebDriver协议传统的Selenium通过WebDriver协议与浏览器通信这是一个标准但也是瓶颈。每个浏览器厂商提供的WebDriver实现质量参差不齐导致行为不一致且协议本身对现代浏览器的一些高级特性支持滞后。Playwright则采用了更底层的CDPChrome DevTools Protocol或私有协议直接与浏览器内核对话。这意味着Playwright能获得对浏览器更精细、更强大的控制力。例如它可以拦截和修改网络请求在请求发出前或响应返回后注入你的逻辑轻松实现Mock数据或性能测试。模拟丰富的输入设备不仅支持键盘鼠标还能模拟触摸屏、地理定位、设备朝向等。获得更准确的页面生命周期事件知道页面何时“真正”加载完成包括所有异步JavaScript和网络请求这是实现稳定截图和测试的基石。2.2 核心特性拆解自动等待Auto-waiting这是Playwright最“香”的特性。在Selenium里我们不得不写大量的time.sleep()或显式等待WebDriverWait既低效又不稳定。Playwright的绝大多数操作如click,fill,screenshot内部都内置了智能等待。它会等待元素可操作可见、启用、稳定后才执行动作极大减少了因时序问题导致的脚本失败。浏览器上下文Browser Context你可以把它理解为一个独立的、隔离的浏览器会话。每个上下文都有独立的cookie、本地存储和缓存互不干扰。这为并行测试和数据隔离提供了完美支持。一个浏览器进程可以创建多个轻量级的上下文而不是启动多个沉重的浏览器实例。强大的选择器引擎Playwright支持CSS、XPath还提供了非常实用的文本选择器text和React/Vue等框架的组件选择器。特别是文本选择器在编写可读性高的测试用例时非常方便。网络拦截与Mock无需依赖第三方代理工具直接在脚本中拦截请求、修改响应或返回自定义数据对于测试边缘场景和依赖第三方API的应用至关重要。追踪与调试工具内置了playwright trace功能可以录制测试执行过程中的所有操作、网络请求、控制台日志生成一个可视化的ZIP文件用于事后分析失败的测试用例堪称“时光机”。3. 环境搭建与核心API详解理论说再多不如动手搭环境。这里我会给出一个兼顾新手和团队协作的配置方案。3.1 一站式环境配置首先确保你安装了Python3.7。我强烈建议使用虚拟环境来管理依赖。# 1. 创建项目目录并进入 mkdir playwright-project cd playwright-project # 2. 创建虚拟环境以venv为例 python -m venv venv # 3. 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate # 4. 安装Playwright Python库 pip install playwright # 5. 安装Playwright所需的浏览器内核Chromium, Firefox, WebKit playwright install注意playwright install这一步会下载浏览器二进制文件体积较大约1GB请确保网络通畅。它默认会安装所有三个浏览器。如果你只需要其中某一个可以使用playwright install chromium。3.2 同步与异步API的选择Playwright提供了两套API同步和异步。对于大多数自动化测试和截图脚本同步API更直观易懂适合线性任务。如果你的应用本身就是异步的如FastAPI、Sanic或者你需要处理大量并发页面操作异步API能提供更好的性能。本指南主要以同步API为例因为它的学习曲线更平缓。但我会在关键部分指出异步的写法。一个最简单的同步脚本示例打开页面并截图from playwright.sync_api import sync_playwright def run(): with sync_playwright() as p: # 启动Chromium浏览器headlessTrue表示无头模式不显示UI browser p.chromium.launch(headlessTrue) # 创建一个浏览器上下文 context browser.new_context() # 在上下文中打开一个新页面 page context.new_page() # 导航到目标网址 page.goto(https://example.com) # 对页面进行截图并保存 page.screenshot(pathexample.png, full_pageTrue) # 关闭资源 context.close() browser.close() if __name__ __main__: run()3.3 浏览器、上下文与页面的关系理解这三者的层级关系是有效使用Playwright的关键Browser一个浏览器进程实例如Chrome。通过它启动和关闭浏览器。Context一个独立的浏览器会话环境。它比启动一个新浏览器实例要轻量得多并且实现了完美的隔离。你可以在一个Browser下创建多个Context来模拟不同用户同时登录。Page一个标签页。你的绝大部分操作导航、点击、截图都发生在Page对象上。一个Context可以拥有多个Page。这种设计带来了巨大的灵活性。例如在做截图对比时你可以在同一个Browser下为Chrome和Firefox各创建一个Context然后分别打开Page访问同一个URL进行截图效率极高。4. 跨浏览器自动化测试实战让我们构建一个真实的测试场景测试一个登录功能在Chrome、Firefox和WebkitSafari内核上的表现是否一致。4.1 测试用例设计与结构我们不依赖任何测试框架如pytest先用纯Playwright实现这样能更清晰地理解其原理。from playwright.sync_api import sync_playwright import time def test_login_across_browsers(): 跨浏览器登录测试 test_results {} # 定义要测试的浏览器类型 browsers_to_test [chromium, firefox, webkit] # 测试数据 login_url https://your-test-site.com/login username test_user password test_pass123 expected_title_after_login Dashboard for browser_type in browsers_to_test: print(f\n开始测试 {browser_type.upper()}...) with sync_playwright() as p: # 启动对应浏览器headlessFalse便于观察实际运行可设为True browser getattr(p, browser_type).launch(headlessFalse, slow_mo1000) # slow_mo让动作变慢方便观察 context browser.new_context() page context.new_page() try: # 1. 导航到登录页 page.goto(login_url) # 等待页面关键元素出现这里用了选择器实际需替换 page.wait_for_selector(#username) # 2. 填写登录表单 # 使用CSS选择器定位元素并输入 page.fill(#username, username) page.fill(#password, password) # 点击登录按钮 page.click(button[typesubmit]) # 3. 验证登录成功 # 等待导航完成并检查页面标题或某个成功元素 page.wait_for_url(**/dashboard**) # 使用通配符匹配URL actual_title page.title() if expected_title_after_login in actual_title: print(f ✅ {browser_type}: 登录成功) test_results[browser_type] PASS else: print(f ❌ {browser_type}: 登录失败标题为 {actual_title}) test_results[browser_type] FAIL # 4. (可选) 登录后截图存档 page.screenshot(pathflogin_success_{browser_type}.png) except Exception as e: # 捕获任何异常并截图保存错误现场 print(f ⚠️ {browser_type}: 测试执行出错 - {e}) page.screenshot(pathferror_{browser_type}_{int(time.time())}.png) test_results[browser_type] ERROR finally: # 确保资源被关闭 context.close() browser.close() # 输出测试总结 print(\n *30) print(跨浏览器测试结果总结) for browser, result in test_results.items(): print(f {browser.upper()}: {result}) return test_results if __name__ __main__: test_login_across_browsers()4.2 关键操作与最佳实践选择器策略优先使用CSS选择器其次是文本选择器page.click(textLog In)最后才是XPath。Playwright的CSS引擎非常强大且稳定。等待策略page.goto()会等待页面触发load事件。对于单页应用这通常不够。page.wait_for_selector()或page.wait_for_url()是更可靠的选择。page.wait_for_load_state(networkidle)可以等待网络基本空闲适合大多数动态加载页面。slow_mo参数在调试阶段给launch方法加上slow_mo500单位毫秒会让每个Playwright操作都延迟半秒执行你可以清晰地看到脚本是如何运行的极大方便调试。错误处理与截图一定要用try...except包裹核心操作并在异常时截图。截图文件名最好包含时间戳或浏览器类型便于事后追溯。4.3 与Pytest集成实现企业级测试单独脚本适合简单任务但真正的测试项目需要结构化管理、用例发现、夹具fixture和报告。pytest是Python生态的事实标准Playwright官方也提供了pytest-playwright插件。首先安装插件pip install pytest pytest-playwright创建一个测试文件test_login.py:import re import pytest from playwright.sync_api import Page, expect # 定义一个pytest fixture用于为每个测试用例提供配置好的page对象 pytest.fixture(scopefunction) def page(browser): # browser fixture由pytest-playwright插件提供默认是Chromium # 创建一个新的上下文和页面确保测试隔离 context browser.new_context() page context.new_page() yield page # 测试结束后清理上下文 context.close() # 参数化测试用同一套逻辑测试不同浏览器 pytest.mark.parametrize(browser_name, [chromium, firefox, webkit]) def test_login_with_pytest(browser_name, request): 使用pytest运行的登录测试 # 通过request.getfixturevalue动态获取指定浏览器的fixture browser request.getfixturevalue(browser_name) context browser.new_context(record_video_dirvideos/) # 可选录制视频 page context.new_page() page.goto(https://your-test-site.com/login) page.fill(#username, test_user) page.fill(#password, test_pass123) page.click(button[typesubmit]) # 使用Playwright的断言库更语义化 expect(page).to_have_url(re.compile(r.*/dashboard)) expect(page.locator(h1)).to_contain_text(Welcome) context.close() # 使用page fixture的更简洁写法 def test_homepage_title(page: Page): 测试首页标题 page.goto(https://example.com) expect(page).to_have_title(Example Domain)运行测试# 运行所有测试 pytest # 运行特定文件并生成HTML报告 pytest test_login.py --htmlreport.html --self-contained-html与pytest集成的优势自动管理浏览器生命周期通过fixture你无需手动编写launch和close。测试隔离每个测试函数都会获得一个全新的context和page避免测试间状态污染。丰富的断言expectAPI提供了更人性化的断言方式如to_have_title,to_be_visible等失败时错误信息更清晰。强大的参数化与夹具系统轻松实现跨浏览器、多数据驱动的测试。完善的报告结合pytest-html等插件可以生成漂亮的测试报告包含截图、视频如果录制了和日志。5. 高保真网页截图完整教程截图是Playwright的另一项绝活其稳定性和灵活性远超传统工具。我们将从基础截图讲到高级场景。5.1 基础截图元素、页面与全屏from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch(headlessTrue) page browser.new_page() page.goto(https://example.com) page.wait_for_load_state(networkidle) # 等待网络空闲确保资源加载完 # 1. 截取整个可视区域当前窗口大小 page.screenshot(pathviewport.png) # 2. 截取完整页面自动滚动拼接长图 page.screenshot(pathfull_page.png, full_pageTrue) # 3. 截取页面上的某个特定元素 # 首先定位元素 heading_element page.locator(h1) if heading_element.count() 0: # 检查元素是否存在 heading_element.first.screenshot(pathheading_element.png) # 4. 带样式的截图模拟设备视口 # 模拟iPhone 13 Pro iphone_13 p.devices[iPhone 13 Pro] context browser.new_context(**iphone_13) page_mobile context.new_page() page_mobile.goto(https://example.com) page_mobile.screenshot(pathmobile_view.png, full_pageTrue) browser.close()5.2 高级截图技巧与实战场景场景一批量截图与定时监控你需要每天定时对一批重要网页进行截图存档监控其内容变化或外观是否异常。import schedule import time from datetime import datetime from playwright.sync_api import sync_playwright URL_LIST [ https://news.example.com, https://status.example.com, https://blog.example.com ] def capture_screenshots(): 为URL列表中的每个地址截图 timestamp datetime.now().strftime(%Y%m%d_%H%M%S) with sync_playwright() as p: browser p.chromium.launch(headlessTrue) context browser.new_context( viewport{width: 1920, height: 1080}, # 固定视口大小保证一致性 device_scale_factor2 # 视网膜屏高清截图 ) for url in URL_LIST: try: page context.new_page() # 设置超时和重试 page.goto(url, wait_untilnetworkidle, timeout30000) # 生成安全的文件名 domain url.split(//)[1].replace(/, _).replace(:, _) filename fscreenshots/{timestamp}_{domain}.png page.screenshot(pathfilename, full_pageTrue, animationsdisabled) # 禁用动画截图更稳定 print(f✅ 已截图: {filename}) page.close() except Exception as e: print(f❌ 截图失败 {url}: {e}) browser.close() # 每天上午9点执行一次 schedule.every().day.at(09:00).do(capture_screenshots) print(定时截图任务已启动...) while True: schedule.run_pending() time.sleep(60)场景二对比测试与视觉回归开发新功能后需要确保UI没有意外变化。你可以将新版本的截图与基线baseline图片进行像素级对比。from playwright.sync_api import sync_playwright from PIL import Image, ImageChops import os def visual_regression(url, baseline_path, new_path, diff_path, threshold0.01): 视觉回归测试 :param threshold: 容差阈值差异像素占比超过此值则认为失败 # 1. 捕获新版本截图 with sync_playwright() as p: browser p.chromium.launch(headlessTrue) page browser.new_context().new_page() page.goto(url, wait_untilnetworkidle) page.screenshot(pathnew_path, full_pageTrue) browser.close() # 2. 与基线图对比 if not os.path.exists(baseline_path): print(f⚠️ 基线图不存在将当前图保存为基线: {baseline_path}) os.rename(new_path, baseline_path) return True, Baseline created baseline_img Image.open(baseline_path).convert(RGB) new_img Image.open(new_path).convert(RGB) # 计算差异 diff_img ImageChops.difference(baseline_img, new_img) diff_bbox diff_img.getbbox() # 获取有差异的区域边界 if diff_bbox is None: print(✅ 视觉对比通过无差异。) return True, No difference # 计算差异像素比例 diff_pixels sum(diff_img.point(lambda x: 255 if x else 0).convert(L).point(bool).getdata()) total_pixels baseline_img.size[0] * baseline_img.size[1] diff_ratio diff_pixels / total_pixels if diff_ratio threshold: print(f✅ 视觉对比通过差异比例 ({diff_ratio:.4%}) 低于阈值 ({threshold:.2%})。) return True, fDifference within threshold ({diff_ratio:.4%}) else: # 保存高亮显示差异的图片 highlight diff_img.convert(L).point(lambda x: 255 if x 30 else 0) # 阈值化 baseline_img_copy baseline_img.copy() baseline_img_copy.paste(Image.new(RGB, baseline_img.size, (255, 0, 0)), maskhighlight) baseline_img_copy.save(diff_path) print(f❌ 视觉对比失败差异比例: {diff_ratio:.4%}差异图已保存至: {diff_path}) return False, fDifference exceeded threshold ({diff_ratio:.4%}) # 使用示例 result, message visual_regression( urlhttps://your-app.com, baseline_pathbaselines/homepage.png, new_pathcurrent/homepage.png, diff_pathdiffs/homepage_diff.png, threshold0.005 # 0.5%的差异容忍度 )实操心得视觉回归测试的关键在于一致性。必须确保每次截图的环境完全相同相同的浏览器版本、相同的视口大小、相同的系统缩放比例deviceScaleFactor甚至要禁用动画和随机内容。建议在Docker容器中运行此类任务以隔离环境变量。5.3 处理复杂页面的截图挑战现代网页充满了动态内容、懒加载和弹窗直接截图常常不完整。挑战一懒加载Lazy Load页面滚动到下方时图片才加载。full_pageTrue会自动滚动但可能滚动太快图片来不及加载。解决方案在截图前模拟人工滚动并给予足够等待时间。def capture_lazy_load_page(page, url): page.goto(url, wait_untildomcontentloaded) # 获取页面总高度 total_height page.evaluate(document.body.scrollHeight) viewport_height page.viewport_size[height] # 分段滚动 for i in range(0, total_height, viewport_height): page.evaluate(fwindow.scrollTo(0, {i})) page.wait_for_timeout(500) # 每次滚动后等待500ms加载内容 # 滚回顶部再截全图确保顶部状态一致 page.evaluate(window.scrollTo(0, 0)) page.wait_for_timeout(1000) return page.screenshot(pathlazy_loaded.png, full_pageTrue)挑战二悬浮弹窗与固定元素某些弹窗如Cookie提示、订阅框会遮挡主要内容。解决方案一在截图前关闭或隐藏它们。# 方法1通过JavaScript直接移除元素 page.evaluate(() { const popup document.querySelector(.cookie-banner); if (popup) popup.remove(); }) page.screenshot(pathno_popup.png) # 方法2通过Playwright点击关闭按钮更模拟用户行为 close_button page.locator(button:has-text(Accept)) # 或 button:has-text(Close) if close_button.is_visible(): close_button.click() page.wait_for_timeout(300) # 等待弹窗消失动画解决方案二调整截图区域避开固定元素。# 获取某个固定头部的高度 header_height page.evaluate(() { const header document.querySelector(header.fixed); return header ? header.offsetHeight : 0; }) # 截取页面除头部之外的部分 page.screenshot(pathcontent_only.png, clip{ x: 0, y: header_height, width: page.viewport_size[width], height: page.viewport_size[height] - header_height })6. 常见问题排查与性能优化即使工具强大在实际项目中还是会遇到各种“坑”。这里记录了我遇到的一些典型问题及解决方案。6.1 元素定位失败最常见的问题症状page.click(‘button’)报错TimeoutError: Timeout 30000ms exceeded。排查步骤确认元素是否存在立刻打开浏览器开发者工具检查你的选择器是否能唯一匹配到目标元素。Playwright提供了一个超好用的调试命令playwright codegen可以打开一个浏览器并录制你的操作生成代码同时显示它推荐的选择器。检查等待状态页面可能还没加载完。在操作前增加page.wait_for_load_state(‘networkidle’)或page.wait_for_selector(‘your-selector’)。元素是否被遮挡有些元素可能被其他透明层或弹窗覆盖。使用page.locator(‘button’).click(forceTrue)可以强制点击但不推荐因为这不符合真实用户行为。更好的办法是找出并关闭遮挡物。iframe问题如果元素在iframe内部你必须先切换到对应的iframe上下文。# 通过名称或URL定位iframe frame page.frame(namelogin-frame) # 或 page.frame(url‘**/login**) # 然后在frame对象上操作 frame.fill(‘#username’, ‘user’)6.2 截图不完整或颜色异常症状截图缺少部分内容或者颜色与浏览器中看到的不一致。解决方案内容缺失确保使用了full_pageTrue。如果仍有缺失可能是懒加载问题参考5.3节的滚动等待方案。颜色异常深色模式/透明背景默认截图背景是透明的。如果保存为PNG并在白色背景的图片查看器中查看深色文字会显得很奇怪。可以通过omit_background选项设置白色背景。page.screenshot(path‘page.png’, full_pageTrue, omit_backgroundTrue)高清截图需要高DPI截图用于印刷或展示时设置device_scale_factor。context browser.new_context(device_scale_factor2) # 2倍高清 page context.new_page()6.3 性能优化让脚本跑得更快更稳当需要处理成百上千个页面时性能至关重要。复用浏览器实例绝对不要在循环内部launch和close浏览器。始终在外部启动一次浏览器在循环内只创建新的上下文和页面。并行执行使用asyncio或concurrent.futures实现并行截图/测试。每个任务应使用独立的BrowserContext这是线程安全的。import concurrent.futures from playwright.sync_api import sync_playwright def capture_one(url, context): page context.new_page() page.goto(url) # ... 截图逻辑 ... page.close() return url with sync_playwright() as p: browser p.chromium.launch(headlessTrue) # 创建多个上下文供并行使用 contexts [browser.new_context() for _ in range(4)] # 假设并行度为4 urls [‘url1‘, ‘url2‘, ...] with concurrent.futures.ThreadPoolExecutor(max_workers4) as executor: # 将URL和上下文映射到任务 future_to_url {executor.submit(capture_one, url, contexts[i%4]): url for i, url in enumerate(urls)} for future in concurrent.futures.as_completed(future_to_url): url future_to_url[future] try: result future.result() print(f“Done: {result}“) except Exception as exc: print(f“{url} generated an exception: {exc}“) browser.close()合理配置浏览器启动参数禁用不必要的功能可以节省资源。browser p.chromium.launch( headlessTrue, args[ ‘--disable-gpu‘, ‘--disable-dev-shm-usage‘, # 在Docker等受限环境中有用 ‘--no-sandbox‘, ‘--disable-setuid-sandbox‘, ‘--disable-extensions‘, ] )监控与日志对于长时间运行的任务记录详细的日志包括每个页面的开始/结束时间、状态和任何错误。这有助于定位性能瓶颈和失败原因。6.4 在CI/CD环境中运行在GitHub Actions、GitLab CI或Jenkins等无头环境中运行Playwright需要确保系统依赖已安装。使用官方Docker镜像是最简单可靠的方式# Dockerfile FROM mcr.microsoft.com/playwright/python:v1.40.0-noble WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD [“python“, “your_script.py“]在GitHub Actions中的配置示例name: Playwright Tests on: [push] jobs: test: runs-on: ubuntu-latest container: image: mcr.microsoft.com/playwright/python:v1.40.0-noble steps: - uses: actions/checkoutv3 - name: Install dependencies run: pip install -r requirements.txt - name: Run tests run: pytest - uses: actions/upload-artifactv3 if: always() # 即使测试失败也上传 with: name: playwright-report path: test-results/ # 假设pytest输出报告到这里7. 进阶应用场景拓展掌握了基础和问题排查后Playwright还能玩出更多花样。7.1 自动化性能审计结合Playwright的page.metrics和page.evaluate可以自动化收集关键性能指标。def measure_performance(page, url): page.goto(url, wait_untilnetworkidle) # 获取Performance Timing API数据 timing page.evaluate(() { const perf performance.timing; return { dns: perf.domainLookupEnd - perf.domainLookupStart, connect: perf.connectEnd - perf.connectStart, ttfb: perf.responseStart - perf.requestStart, // 首字节时间 domReady: perf.domContentLoadedEventEnd - perf.navigationStart, load: perf.loadEventEnd - perf.navigationStart, }; }) # 获取Lighthouse兼容的指标需在非无头模式下且Chrome DevTools Protocol支持 # 更简单的方式是直接调用 page.evaluate 执行 PerformanceObserver cls, fid, lcp page.evaluate(() { // 这里是一个简化示例实际收集CLS、FID、LCP需要更复杂的代码 return new Promise(resolve { new PerformanceObserver((entryList) { const entries entryList.getEntries(); // ... 处理逻辑 ... resolve([cls, fid, lcp]); }).observe({entryTypes: [layout-shift, first-input, largest-contentful-paint]}); }); }) return {**timing, ‘cls‘: cls, ‘fid‘: fid, ‘lcp‘: lcp}7.2 生成PDF报告Playwright可以直接将网页保存为PDF格式完美支持打印样式。page.goto(‘https://example.com/report‘, wait_until‘networkidle‘) page.pdf( path‘report.pdf‘, format‘A4‘, print_backgroundTrue, # 打印背景色和图片 margin{‘top‘: ‘1cm‘, ‘right‘: ‘1cm‘, ‘bottom‘: ‘1cm‘, ‘left‘: ‘1cm‘} )7.3 模拟复杂用户交互流测试一个多步骤的表单提交或购物流程。# 模拟一个完整的购物流程 def test_checkout_flow(page): page.goto(‘https://shop.example.com‘) # 搜索商品 page.fill(‘[aria-labelSearch]‘, ‘Playwright Book‘) page.press(‘[aria-labelSearch]‘, ‘Enter‘) # 等待结果并点击第一个商品 page.wait_for_selector(‘.product-item‘) page.locator(‘.product-item‘).first.click() # 加入购物车 page.click(‘textAdd to Cart‘) # 去结算 page.click(‘#cart-icon‘) page.click(‘textProceed to Checkout‘) # 填写配送信息 page.fill(‘#shipping-name‘, ‘John Doe‘) # ... 填写更多字段 ... # 选择支付方式并下单 page.click(‘#credit-card-option‘) page.click(‘textPlace Order‘) # 验证订单成功 expect(page.locator(‘h1‘)).to_contain_text(‘Order Confirmed‘)这个流程涵盖了导航、搜索、列表操作、表单填写、多页面跳转和最终断言是一个完整的端到端E2E测试案例。通过合理组织这样的测试用例你可以构建起一个覆盖核心业务流的自动化测试堡垒确保每一次代码提交都不会破坏关键功能。