我用豆包多模态模型跑通了 Playwright 脚本报错的自动修复

0 阅读10分钟

标签:Playwright | AI提效 | 自动化测试 | 豆包


1. 开场白

做 UI 自动化的同学一定深有体会:脚本失败、元素失效、超时、定位变更…… 排查一次动辄几十分钟。在快速迭代项目里,维护成本高到让人放弃。

本文分享了:Playwright + AI 视觉分析 + 自动修复,失败自动截图 → AI 分析根因 → 自动生成修复代码 → 自动重试,全流程,欢迎讨论交流!

演示效果:一键跑完40秒,AI分析2.8秒,Token约2000(不到1分钱)。


2. 演示:5分钟闭环,从报错到通过

我把一个故意写错的Playwright脚本跑一遍,pytest失败时自动截图:

测试代码(故意写错定位):

def test_saucedemo_wrong_locator(page):
    page.goto("https://www.saucedemo.com")
    page.fill("#user-name", "standard_user")
    page.fill("#password", "secret_sauce")
    page.click("text=Sign In")  # ← 故意写错,实际应该是 Login

pytest执行结果:

FAILED test_demo_fail.py::test_saucedemo_wrong_locator[chromium]
  playwright._impl._errors.TimeoutError: Page.click: Timeout 30000ms exceeded.
  waiting for locator("text=Sign In")
=========================== 1 failed in 47.94s ============================
❌ 测试失败,已保存截图到:screenshots/test_saucedemo_wrong_locator_20260416_224543.png

截图 + 报错日志,一起发给豆包多模态模型。

发给豆包的Prompt:

你是专业Playwright自动化测试工程师。以下是一个失败的测试用例: 报错日志:TimeoutError: waiting for locator("text=Sign In") 请结合截图分析报错,给出:1.根本原因 2.修复代码

豆包回复:

根本原因:从截图中可以看到登录按钮上的文本是 "Login",而测试代码中使用了错误的文本定位 "text=Sign In",导致找不到元素,最终超时。

修复代码:将 page.click("text=Sign In") 修改为 page.click("text=Login")

AI秒出分析结果,精准定位根因,直接给修复代码。

把豆包给的修复代码自动写入脚本,再次运行——

$ pytest test_saucedemo.py -v
test_saucedemo.py::test_login PASSED  ✅

从截图→分析→修复→重跑→通过,全程5分钟,无需人工介入。


3. 【AI自动化报错修复整体方案】架构设计

ai_fix_error_solution.png

4步完整流程

第1步:执行测试 Playwright + pytest 运行测试用例

第2步:失败自动采集(Hook) 测试失败触发 conftest.py hook,自动生成3件套:

  • 全页截图
  • DOM结构片段(定位失败时的当前页)
  • pytest执行日志

第3步:AI分析(豆包Vision) 自动调用豆包多模态模型,解析3件套,输出结构化结果:

  • 判断失败类型(Flaky/业务Bug/环境问题)
  • 精确定位失败点(具体选择器/等待逻辑)
  • 输出可直接复制的修复代码

第4步:(可选)自动化闭环

  • 提交修复代码到临时分支
  • GitHub Actions自动重跑验证

【AI自动修复 · 调用时序】

call_sequence.png

  1. 测试用例 → pytest:执行 Playwright 自动化测试
  2. pytest → conftest.py Hook:测试失败,触发失败捕获钩子
  3. Hook → 失败文件:自动生成截图、DOM片段、执行日志
  4. 失败文件 → 豆包Vision:上传三套件进行多模态分析
  5. 豆包Vision → 自动修复脚本:返回失败类型、根因、可复制修复代码
  6. 自动修复脚本 → CI/GitHub_Actions:提交代码,触发自动重跑
  7. GitHub Actions → 测试用例:自动重跑验证,完成闭环

4. 三段核心源码(可复制!可修改!可落地!)

思路很多人都懂,怎么做才是关键。 以下是完整可落地的3段源码。

① pytest失败自动截图(conftest.py)

放在项目根目录,pytest自动加载,失败即截图:

import pytest
from playwright.sync_api import Page
from datetime import datetime
import os

SCREENSHOT_DIR = "screenshots"
os.makedirs(SCREENSHOT_DIR, exist_ok=True)

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
    """测试失败时自动截图"""
    outcome = yield
    report = outcome.get_result()
    page = None
    if "page" in item.fixturenames:
        page = item.funcargs["page"]

    if report.when == "call" and report.failed and page:
        test_name = item.name
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3]
        screenshot_path = os.path.join(SCREENSHOT_DIR, f"{test_name}_{timestamp}.png")
        page.screenshot(path=screenshot_path, full_page=True)
        print(f"\n❌ 测试失败,已保存截图到:{screenshot_path}")

踩坑预警:截图路径用相对路径在某些IDE下会找不到,建议用 os.path.join(SCREENSHOT_DIR, ...) 拼接。

② 豆包Vision模型分析截图(doubao_vision_demo.py)

调用豆包多模态模型,截图+报错日志一起分析:

import base64
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ.get("DOUBAO_API_KEY", ""),
    base_url="https://ark.cn-beijing.volces.com/api/v3"
)

def analyze_screenshot_with_text(
    text_prompt: str,
    image_path: str,
    model: str = "doubao-1-5-vision-pro-32k-250115"
) -> str:
    """截图+文本发给豆包多模态模型,分析报错并返回修复建议"""
    with open(image_path, "rb") as f:
        img_data = base64.b64encode(f.read()).decode()

    content = [
        {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_data}"}},
        {"type": "text", "text": text_prompt},
    ]

    response = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": content}],
        temperature=0.1,
        max_tokens=1024
    )
    return response.choices[0].message.content

关键点:图片必须放在content数组的第一个位置,否则模型可能忽略图片。

③ 失败后自动分析脚本(analyze_failures.py)

测试跑完后,自动扫描截图目录,逐个发给AI分析:

import os
import glob
from doubao_vision_demo import analyze_screenshot_with_text

SCREENSHOT_DIR = "screenshots"

PROMPT_TEMPLATE = """你是专业Playwright自动化测试工程师。以下是一个失败的测试用例:

报错日志:{error_log}

请结合截图分析报错,给出:
1. 失败类型(Flaky等待/元素定位失败/业务bug/环境问题)
2. 根本原因(1-2句话)
3. 可直接复制的修复代码(Python Playwright)
4. 预防建议(1-2条)"""

def analyze_all_failures():
    """分析screenshots目录下所有失败截图"""
    screenshots = sorted(glob.glob(os.path.join(SCREENSHOT_DIR, "*.png")))
    if not screenshots:
        print("没有失败用例!🎉")
        return

    for screenshot_path in screenshots:
        test_name = os.path.basename(screenshot_path)
        print(f"\n{'='*60}\n分析:{test_name}\n{'='*60}")

        result = analyze_screenshot_with_text(
            text_prompt=PROMPT_TEMPLATE.format(error_log="请从截图中判断"),
            image_path=screenshot_path
        )
        print(result)

if __name__ == "__main__":
    analyze_all_failures()

真实运行日志

=========================== 1 failed in 47.94s ============================
❌ 测试失败,已保存截图到:screenshots/test_saucedemo_wrong_locator_20260416_224543.png

============================================================
分析:test_saucedemo_wrong_locator
============================================================
### 根本原因分析
从报错日志可以看出,测试用例在等待页面上文本为 `Sign In` 的元素可点击时超时了。
结合提供的截图来看,页面上实际显示的登录按钮文本是 `Login`,而不是 `Sign In`,
这意味着测试代码中定位元素的文本选择器与页面实际内容不匹配。

### 修复代码(Python Playwright)
```python
# 将
test_saucedemo_wrong_locator(page)
page.click("text=Sign In")

# 修改为
test_saucedemo_wrong_locator(page)
page.click("text=Login")

### 全链路汇总报告(实测数据)

一键运行后,自动输出完整闭环报告:


\============================================================
🔧 Step1: 模拟运行失败的Playwright测试...
================================

📸 正在执行用例(故意让它失败),请稍候...
(这一步要等Playwright找'Sign In'找不到,最长30秒,不是卡住!)
❌ 测试失败,已保存截图到:screenshots/test\_saucedemo\_wrong\_locator\_20260417\_114558.png
⏱️  失败用例耗时:31.82秒

\============================================================
🤖 Step2: 豆包视觉模型正在分析失败场景...
===========================

📸 正在上传截图并调用API,请稍等...
💡 豆包回复:
根本原因:按钮文本是 "Login",而代码写的是 "Sign In"
修复代码:page.click("text=Login")
⏱️  分析耗时:2.82秒
💰 Token消耗:输入1200,输出800,总计2000

\============================================================
🔧 Step3: 自动生成修复后的v2测试脚本...
===========================

✅ 修复脚本已生成:test\_demo\_fail\_v2.py

\============================================================
✅ Step4: 自动运行v2脚本验证修复效果...
==========================

test\_demo\_fail\_v2.py .  ✅ 1 passed in 2.0s
✅ v2测试用例全部通过!修复成功!

🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉
📊 全链路截图诊断修复汇总报告 📊
🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉

🔹 第一次运行(失败场景):⏱️ 31.82秒
🔹 豆包视觉分析:⏱️ 2.82秒  💰 2000 Token
🔹 自动生成v2脚本:✅ 成功
🔹 v2验证通过:✅ 1 passed in 2.0s

🔹 整体数据:
⏱️  全链路总耗时:36.62秒
🕒 手动修复预估耗时:1800秒(30分钟)
⏳ 节省时间:1763.38秒(约29.4分钟)
🚀 效率提升:98.0%!

💡 可给领导汇报的话:
'我们用豆包视觉模型+Playwright做了自动化测试的自修复演示,
一个经典的定位器错误场景,原来手动修复要30分钟,
现在一键运行,36.62秒就搞定了,效率大幅度提升!'


从截图诊断到自动修复,全程自动化。

Token耗费

{
  "model": "doubao-1-5-vision-pro-32k-250115",
  "usage": {
    "prompt_tokens": 1247,
    "completion_tokens": 89,
    "total_tokens": 1336
  }
}

整个闭环只需消耗约 1336 Token,目前大模型50w免费额度,不花钱。


5. 豆包视觉模型:为什么选它?替代方案?

为什么选豆包Vision?

优势说明
多模态能力强同时理解截图+报错日志,定位准确率高
性价比高火山引擎定价,比GPT-4V便宜一半以上
国内访问快无墙,延迟低,企业内网可用
Token上限够用32k文本Token,完整DOM+日志都存得下

有替代方案吗?

方案适合场景成本
豆包-1.5-Vision-Pro-32k(推荐)国内企业项目中等,性价比最高
豆包Lite-Vision新手试用、小项目免费额度
GPT-4V / Claude 3国外项目、追求最高准确率较高
Qwen-VL-Max / InternVL2.5有GPU资源、自建服务运维成本高

怎么开通?

image.png

操作步骤:火山引擎控制台 → 方舟 → 创建API Key → 开通Vision模型


6. 兜底:万一AI也修不好怎么办?

加一个安全阈值兜底:

MAX_FIX_ATTEMPTS = 3

fix_attempt = 0
while fix_attempt < MAX_FIX_ATTEMPTS:
    result = subprocess.run(["pytest", "-v"], ...)
    if result.returncode == 0:
        print("✅ 测试通过!")
        break

    # 截图发给AI
    ai_response = analyze_screenshot_with_text(...)
    fix_code = extract_fix_code(ai_response)

    # 应用修复
    apply_fix(fix_code)
    fix_attempt += 1
else:
    # AI尝试3次仍未修好,人工介入
    raise RuntimeError(
        f"⚠️ AI尝试{MAX_FIX_ATTEMPTS}次修复未通过。"
        "可能是复杂Bug,需人工介入定位。"
    )

3次兜底逻辑:普通定位错误通常1次修好;复杂场景3次修不好,说明需要人工介入,避免AI无意义循环。


7. 这套方案怎么用到我的项目?

最小改动原则(改这5个地方就能用!)

改动点具体操作难易度
替换被测URL环境变量里改 BASE_URL⭐ 简单
替换fixture名称如果你的fixture叫 browser_page,在 conftest.py 里改⭐ 简单
替换API Keyexport DOUBAO_API_KEY=你的火山引擎Key⭐ 简单
调整提示词模板根据业务规范修改分析维度⭐⭐ 中等
调整Token限制DOM/日志超过50KB时,适当压缩⭐⭐ 中等

通用化扩展思路

  • 多项目复用:每个项目单独建 conftest.py + config.py,共享 doubao_vision_demo.py
  • 多模型切换:换模型名+换prompt即可,一键切换豆包/DeepSeek/GPT
  • CI/CD集成:把 analyze_failures.py 放到GitHub Actions/Jenkins流水线,失败自动发分析结果到企业微信/钉钉群
  • 自动提交修复:用GitPython库,把AI生成的修复代码提交到临时分支,并发PR

8. 进阶预告:恭候高手共建

这套方案可以做成一个可扩展的测试Skill,支持:

  • ✅ 自定义AI模型(豆包/DeepSeek/GPT/开源模型)
  • ✅ 自定义报错处理逻辑(特定Flaky超时直接重试,不用AI分析)
  • ✅ 自定义报告格式(Markdown/HTML/Excel/企业微信卡片)
  • ✅ 自动Jira bug创建、测试文档生成等插件扩展

恭候各位高手来 星球 「欢乐马自动化测试实战」一起讨论共建!


9. 适用场景

场景AI修复价值
定位失效(超时/找不到元素)看图判断,秒出正确定位
UI改版导致用例失败AI识别变化点,自动更新定位
回归测试批量失败排查截图+AI批量分析,省时省力
学习阶段调试脚本新手用AI辅助定位,少走弯路

不管是文本定位错、ID被改、弹窗遮挡——这套方案都能用。


10. 源码包

完整可运行的源码包分两个版本:

🟢 入门版(适合演示/领导/新手)

  • conftest.py — pytest失败自动截图钩子
  • doubao_vision_demo.py — 豆包Vision API调用封装
  • screenshot_feedback_demo_v2.py一键闭环主脚本
  • analyze_failures.py — 批量分析失败截图脚本
  • screenshots/ — 失败截图示例
  • README.md + Q&A.md — 4步跑通说明

👉 想给领导演示"AI自动修复测试"?不用录视频,一键运行就够了。 改URL和Key就能用,全程36秒,Token不到1分钱。

🟡 高级版

6模块,3用例(登录/浏览/结账),POM设计模式 + MCP多Agent并发执行,适合接入CI/CD流水线。


本文源码包配套:pytest截图Hook + 豆包Vision API调用 + 批量分析脚本,改URL和Key就能用到你的项目