Playwright跟踪调试-录像(video)、截图(screenshot)和跟踪(trace)

在 Playwright 的 Python API 中,videoscreenshottrace 是用于调试和记录自动化测试或网页交互的重要工具。这些功能可以帮助捕获页面的视觉状态、录制操作视频以及生成详细的跟踪日志,特别适合调试失败的测试或记录复杂交互。结合你之前的提问(关于 Locatorget_by_textget_by_role、属性和子节点),我将详细介绍这些功能的开启和使用方法,并提供针对性的示例代码,解决你之前提到的问题(如 get_by_text 的换行问题)并与 Locator 结合使用。


1. Screenshot(截图)

概述

  • 功能: Playwright 允许捕获页面、特定元素或整个滚动页面的截图,用于调试、验证 UI 或生成报告。
  • 用途: 测试 UI 状态、验证视觉差异、记录错误时的页面状态。
  • 接口: 主要通过 Page.screenshot()Locator.screenshot() 调用。

主要接口

  • page.screenshot(**kwargs): 捕获整个页面或视口的截图。
  • 参数:
    • path: 保存截图的文件路径(例如 "screenshot.png")。
    • type: 图片格式("png""jpeg",默认 "png")。
    • quality: JPEG 质量(0-100,仅对 JPEG 有效)。
    • full_page: 是否捕获整个滚动页面(默认 False,仅捕获视口)。
    • clip: 裁剪区域(字典,包含 x, y, width, height)。
    • omit_background: 忽略透明背景(默认 False)。
    • timeout: 操作超时(毫秒)。
  • 返回: 如果未指定 path,返回二进制数据(字节流)。
  • locator.screenshot(**kwargs): 捕获特定元素的截图。
  • 参数同上,但只针对 Locator 匹配的元素。
  • 自动截图(Pytest 插件): 使用 --screenshot 命令行参数(on, off, only-on-failure)在测试失败时自动保存截图。

开启和使用

  • 手动截图: 调用 page.screenshot()locator.screenshot()
  • 自动截图: 在 Pytest 中,通过命令行参数启用:
  pytest --screenshot=only-on-failure --full-page-screenshot

这会在测试失败时保存截图,并可选择捕获整个页面。

注意事项

  • 截图保存在文件系统或作为二进制数据返回,适合传递给 API 或进行图像处理。
  • 完整页面截图(full_page=True)会捕获整个滚动区域,可能生成较大的文件。
  • 元素截图需要确保 Locator 匹配的元素可见。

2. Video(视频录制)

概述

  • 功能: Playwright 可以录制页面的操作视频,生成 WebM 格式的视频文件,适合调试用户交互流程。
  • 用途: 记录测试执行过程、调试复杂交互、生成视觉报告。
  • 接口: 通过 BrowserContextrecord_video_dirrecord_video_size 配置。

主要接口

  • browser.new_context(**kwargs):
  • 参数:
    • record_video_dir: 保存视频的目录(例如 "videos/")。
    • record_video_size: 视频分辨率(字典,包含 width, height)。
  • 视频会为每个页面自动生成,保存在指定目录。
  • page.video().path(): 获取页面录制视频的文件路径(异步 API 使用 await page.video.path())。
  • 自动视频录制(Pytest 插件): 使用 --video 命令行参数(on, off, retain-on-failure):
  pytest --video=on

开启和使用

  • 在创建 BrowserContext 时启用视频录制:
  context = await browser.new_context(record_video_dir="videos/")
  • 视频会在页面关闭或上下文关闭时自动保存到指定目录。
  • 文件名通常为页面相关的唯一标识,格式为 .webm

注意事项

  • 视频录制需要指定 record_video_dir,否则不生成视频。
  • 视频文件可能较大,建议仅在调试时启用。
  • 仅在 BrowserContext 级别配置,不支持单个页面或元素级别的视频录制。

3. Trace(跟踪)

概述

  • 功能: Playwright 的 Trace Viewer 记录测试的详细操作日志,包括 DOM 快照、网络请求、动作时间线和截图,生成 .zip 文件,可在 trace.playwright.dev 查看。
  • 用途: 调试测试失败、分析性能、查看操作序列和网络活动。
  • 接口: 通过 BrowserContext.tracing API 控制。

主要接口

  • context.tracing.start(**kwargs): 开始跟踪。
  • 参数:
    • screenshots: 是否包含截图(默认 False)。
    • snapshots: 是否包含 DOM 快照(默认 False)。
    • sources: 是否包含源代码(默认 False)。
    • name: 跟踪名称(显示在 Trace Viewer 中)。
  • context.tracing.start_chunk(**kwargs): 开始新的跟踪片段(用于分段记录)。
  • context.tracing.stop(**kwargs): 停止跟踪并保存到文件。
  • 参数: path(保存路径,例如 "trace.zip")。
  • context.tracing.stop_chunk(**kwargs): 停止当前跟踪片段并保存。
  • 自动跟踪(Pytest 插件): 使用 --tracing 命令行参数(on, off, retain-on-failure):
  pytest --tracing=on
  • 查看跟踪: 使用 Playwright CLI 或网页查看:
  playwright show-trace trace.zip

或访问 trace.playwright.dev 并上传 trace.zip

开启和使用

  • BrowserContext 上启动跟踪,执行操作后停止并保存:
  await context.tracing.start(screenshots=True, snapshots=True)
  # 执行操作
  await context.tracing.stop(path="trace.zip")
  • 分段跟踪(多个跟踪文件):
  await context.tracing.start(screenshots=True, snapshots=True)
  await context.tracing.start_chunk()
  # 操作 1
  await context.tracing.stop_chunk(path="trace1.zip")
  await context.tracing.start_chunk()
  # 操作 2
  await context.tracing.stop_chunk(path="trace2.zip")

注意事项

  • 跟踪文件(.zip)包含大量数据(如截图、网络请求、DOM 快照),可能占用较多磁盘空间。
  • 建议启用 screenshotssnapshots 以获得完整的调试信息。
  • Trace Viewer 提供交互式界面,显示动作时间线、DOM 快照和网络请求,适合 CI 环境中调试。

4. 示例代码

以下示例整合了 screenshotvideotrace 的使用,基于你之前的 HTML 和问题(get_by_text 换行、get_by_role、属性和子节点),并使用异步 API(因为你之前使用了 await)。

示例 1: 捕获截图、录制视频和生成跟踪

from playwright.async_api import async_playwright
import asyncio

async def main():
    async with async_playwright() as p:
        # Browser: 启动 Chromium
        browser = await p.chromium.launch(headless=False, slow_mo=500)

        # BrowserContext: 启用视频录制
        context = await browser.new_context(
            record_video_dir="videos/",
            record_video_size={"width": 1280, "height": 720},
            viewport={"width": 1280, "height": 720}
        )

        # 开始跟踪
        await context.tracing.start(screenshots=True, snapshots=True, sources=True)

        # Page: 创建页面并设置内容
        page = await context.new_page()
        html = """
            <div class="first" role="region">Hello <span>world</span></div>
            <button role="button" aria-label="Submit">Click me <span>world</span></button>
            <input type="text" placeholder="Enter text">
        """
        await page.set_content(html)

        # Locator: 使用 get_by_text 精确定位 span(解决换行问题)
        span_locator = page.locator("span:text-is('world')")
        span_text = await span_locator.text_content()
        print("Span text:", span_text)  # 输出: world

        # 捕获 span 的截图
        await span_locator.screenshot(path="span_screenshot.png")
        print("Span screenshot saved to span_screenshot.png")

        # Locator: 使用 get_by_role 定位按钮
        button_locator = page.get_by_role("button", name="Submit")
        await button_locator.click()

        # 捕获整个页面截图
        await page.screenshot(path="full_page_screenshot.png", full_page=True)
        print("Full page screenshot saved to full_page_screenshot.png")

        # 打印按钮属性
        attributes = await button_locator.evaluate(
            """element => {
                const attrs = {};
                for (const attr of element.attributes) {
                    attrs[attr.name] = attr.value;
                }
                return attrs;
            }"""
        )
        print("Button attributes:", attributes)

        # 打印按钮子节点
        children = await button_locator.evaluate(
            """element => {
                const childrenArray = [];
                for (const child of element.children) {
                    childrenArray.push({
                        tagName: child.tagName,
                        textContent: child.textContent.trim(),
                        className: child.className || 'none'
                    });
                }
                return childrenArray;
            }"""
        )
        print("Button children:")
        for i, child in enumerate(children):
            print(f"Child {i + 1}: Tag = {child['tagName']}, Text = {child['textContent']}, Class = {child['className']}")

        # 获取视频路径
        video_path = await page.video.path()
        print("Video saved to:", video_path)

        # 停止跟踪并保存
        await context.tracing.stop(path="trace.zip")
        print("Trace saved to trace.zip")

        await context.close()
        await browser.close()

asyncio.run(main())

输出示例:

Span text: world
Span screenshot saved to span_screenshot.png
Full page screenshot saved to full_page_screenshot.png
Button attributes: {'role': 'button', 'aria-label': 'Submit'}
Button children:
Child 1: Tag = SPAN, Text = world, Class = none
Video saved to: videos/<unique_id>.webm
Trace saved to trace.zip

示例 2: Pytest 自动截图和跟踪

使用 Pytest 插件自动捕获截图和跟踪,模拟测试失败场景。

import pytest
from playwright.async_api import async_playwright

@pytest.mark.asyncio
async def test_example(page):
    html = """
        <div class="first" role="region">Hello <span>world</span></div>
        <button role="button" aria-label="Submit">Click me</button>
    """
    await page.set_content(html)

    # Locator: 使用 get_by_role
    button_locator = page.get_by_role("button", name="Submit")
    await button_locator.click()

    # 故意引发失败以触发自动截图和跟踪
    assert await button_locator.text_content() == "Wrong text", "Button text mismatch"

# 运行命令:
# pytest --screenshot=only-on-failure --tracing=retain-on-failure --video=on

说明:

  • 运行上述测试时,失败会触发:
  • 截图保存到 test-results/ 目录(默认)。
  • 跟踪文件保存为 trace.zip
  • 视频保存到 test-results/ 目录(WebM 格式)。
  • 查看跟踪:playwright show-trace test-results/trace.zip

5. 结合你之前的问题

  1. get_by_text 换行问题:
  • 示例中使用 span:text-is('world') 确保精确匹配 <span>,避免父 <div> 的干扰(如 world\n Hello\n)。
  1. get_by_role:
  • 使用 page.get_by_role("button", name="Submit") 定位按钮,结合 Locator 操作(如点击、截图)。
  1. 属性和子节点:
  • 使用 evaluate 提取按钮的属性和子节点,与 screenshottrace 结合,记录调试信息。
  1. Locator 集成:
  • 示例展示了 Locator 的链式定位(span_locator)、截图(span_locator.screenshot())和内容提取(text_content())。

6. Mac上用Quicktime Player录屏并转为mp4

  1. Quicktime Player录屏
  2. ffmpeg转为mp4
ffmpeg -i ubereats_flow.mov -vcodec h264 -acodec mp3 ubereats_flow.mp4

7. 注意事项

  • 文件管理:
  • 截图和视频文件可能占用大量磁盘空间,建议仅在需要时启用。
  • 跟踪文件(trace.zip)包含截图和快照,需合理管理存储。
  • 异步 vs 同步:
  • 示例使用异步 API(async_playwright),同步 API 类似,只需替换为 sync_playwright 并移除 awaitasync
  • 同步示例:
    python from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=False) context = browser.new_context(record_video_dir="videos/") context.tracing.start(screenshots=True, snapshots=True) page = context.new_page() page.set_content('<div>Hello <span>world</span></div>') page.screenshot(path="screenshot.png") context.tracing.stop(path="trace.zip") print("Video saved to:", page.video.path()) context.close() browser.close()
  • 调试:
  • 使用 Trace Viewer(trace.playwright.dev)查看跟踪,检查动作时间线、截图和网络请求。
  • 启用 slow_mo(如 launch(slow_mo=500))减慢操作,便于观察视频。
  • Pytest 集成:
  • 使用 --screenshot=only-on-failure--tracing=retain-on-failure 优化 CI 环境,减少不必要的文件生成。
  • 权限和环境:
  • 确保有权限写入截图、视频和跟踪文件(检查目录权限)。
  • 视频和跟踪需要支持的浏览器(如 Chromium)。

7. 引用

  • 截图和跟踪功能参考 Playwright 官方文档:,,,。
  • 视频录制参考:,。
  • 示例代码基于 Playwright 1.54.0(截至 2025 年 7 月)。

8. 总结

  • Screenshot: 通过 page.screenshot()locator.screenshot() 捕获页面或元素截图,支持视口、完整页面或裁剪区域,适合 UI 验证和调试。
  • Video: 通过 record_video_dir 启用页面操作录制,生成 WebM 视频,适合记录交互流程。
  • Trace: 使用 context.tracing 记录详细操作日志(包括截图和快照),通过 Trace Viewer 分析,适合 CI 调试。
  • 结合 Locator: 示例展示了如何与 get_by_textget_by_roleevaluate 结合,解决你之前的换行问题并提取属性和子节点。

如果你有更具体的场景(例如处理动态页面、特定元素的截图或多片段跟踪),请提供细节,我可以进一步定制代码!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注