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'>
问题原因分析
page.on()的返回值特性:page.on()是事件订阅方法,仅用于注册事件监听器,本身不返回事件触发结果,返回值固定为None——这就是你得到None的直接原因。- 异步事件触发逻辑:Playwright的
pageerror/console事件是异步触发的,页面加载过程中出现的JS错误,会在page.goto()执行后(甚至页面渲染阶段)才触发。而你的代码在注册监听器后立刻打印列表,此时错误还未发生,自然拿不到内容。 - 重复注册监听器:多次调用
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
相关产品推荐
相关产品推荐

