You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python+Playwright+pytest测试中无法捕获浏览器错误日志

Playwright + pytest 捕获浏览器日志错误的问题

问题背景

用Python结合Playwright与pytest编写功能测试,目标是识别浏览器日志中的错误,但当前存在两个核心问题:

  • 无法正确捕获日志内容,获取的结果为None
  • 代码执行顺序异常——明明页面存在JS错误,却先输出None,之后才打印错误信息

现有代码

测试用例代码

@pytest.mark.django_db(transaction=True)
def test_can_load_pages_without_error(login_to_myscore):
    # login
    page = login_to_myscore
    # Retrieve testing objects
    testing_objects = get_testing_objects('all')
    # load up the page for each object
    for object in tqdm(testing_objects):
        url = page.goto(f'http://localhost:{local_port}/production/{str(object.slug)}')
        # check for errors
        can_load_page_without_errors(url, page)

错误检查函数代码

def can_load_page_without_errors(url, page):

    print("THE URL: ", url)

    # page.on("console", lambda msg: print(f"A1: {msg.text}") if msg.type == "error" else None)
    # page.on("console", lambda msg: print(f"A2:{msg.text}"))

    page.on("pageerror", lambda exc: print(f"1: {exc}"))

    page.on("pageerror", lambda err: print(f"2: {err.message}"))

    # check for any uncaught errors logged to browser console
    uncaught_errors = []
    # uncaught_error = page.on("pageerror", lambda error: error)

    # Define a function to handle the pageerror event
    def handle_pageerror(error):
        print("3", error)
        print("4", type(error))
        error = str(error)
        print("5", type(error))
        return error

    # Attach the function to the pageerror event
    uncaught_error = page.on("pageerror", handle_pageerror)
    uncaught_errors.append(uncaught_error)
    print("6", uncaught_error)
    print("7", uncaught_errors)
    # assert len(uncaught_errors) == 0, f"The following uncaught JavaScript errors were reported for {url}:\n{uncaught_error}"

现有打印输出

URL:  http://localhost:8080/production/1538
6 None
7 [None]
1: overflows is not defined
2: overflows is not defined
3 overflows is not defined
4 <class 'playwright._impl._errors.Error'>
5 <class 'str'>

问题原因分析

  1. page.on()的返回值特性:page.on()是事件订阅方法,仅用于注册事件监听器,本身不返回事件触发结果,返回值固定为None——这就是你得到None的直接原因。
  2. 异步事件触发逻辑:Playwright的pageerror/console事件是异步触发的,页面加载过程中出现的JS错误,会在page.goto()执行后(甚至页面渲染阶段)才触发。而你的代码在注册监听器后立刻打印列表,此时错误还未发生,自然拿不到内容。
  3. 重复注册监听器:多次调用page.on("pageerror")会添加多个独立监听器,导致同一错误被多次处理,属于冗余操作。

解决方案

正确捕获pageerror(未捕获JS错误)

核心思路:用列表收集错误,等待页面稳定后检查列表,测试完成后清理监听器。

def can_load_page_without_errors(url, page):
    uncaught_errors = []

    # 定义回调:将错误转为字符串后追加到列表
    def handle_pageerror(error):
        uncaught_errors.append(str(error))

    # 注册事件监听器,保存引用用于后续移除
    listener = page.on("pageerror", handle_pageerror)

    try:
        # 等待页面完全稳定(networkidle表示无网络请求,适合单页应用)
        # 也可根据需求选择"load"(DOM加载完成)或"domcontentloaded"
        page.wait_for_load_state("networkidle")
        # 极端情况可加短延迟,确保异步错误全部触发(不推荐,仅作备选)
        # page.wait_for_timeout(1000)

        # 断言无错误
        assert len(uncaught_errors) == 0, \
            f"页面 {url} 存在未捕获JS错误:\n{chr(10).join(uncaught_errors)}"
    finally:
        # 移除监听器,避免影响后续测试用例
        page.remove_listener("pageerror", listener)

正确捕获console日志(含错误级日志)

如果需要捕获控制台输出的错误(比如console.error()),可使用类似逻辑:

def can_load_page_without_console_errors(url, page):
    console_errors = []

    # 仅捕获error类型的控制台日志
    def handle_console(msg):
        if msg.type == "error":
            console_errors.append(f"[{msg.type}] {msg.text}")

    listener = page.on("console", handle_console)

    try:
        page.wait_for_load_state("networkidle")
        assert len(console_errors) == 0, \
            f"页面 {url} 控制台存在错误日志:\n{chr(10).join(console_errors)}"
    finally:
        page.remove_listener("console", listener)

修正测试用例的错误

page.goto()返回的是Response对象,不是URL,需修正赋值逻辑:

@pytest.mark.django_db(transaction=True)
def test_can_load_pages_without_error(login_to_myscore):
    page = login_to_myscore
    testing_objects = get_testing_objects('all')
    for obj in tqdm(testing_objects):
        # 先构造URL
        url = f'http://localhost:{local_port}/production/{obj.slug}'
        # goto时指定等待条件,确保页面加载完成
        page.goto(url, wait_until="networkidle")
        # 传入正确的URL参数
        can_load_page_without_errors(url, page)

关键注意事项

  • 事件监听器建议在页面加载前注册,确保不会遗漏加载过程中的错误;若在page.goto()后注册,也能捕获后续渲染阶段的错误。
  • 必须等待页面稳定后再检查错误列表,否则异步错误还未触发就会误判。
  • 测试完成后务必移除监听器,避免不同测试用例之间的干扰。

内容的提问来源于stack exchange,提问作者Matt S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 17:52:33