Skip to content

Commit 097bf59

Browse files
committed
fix: parse tb for teardown exception (microsoft#117)
1 parent f139aae commit 097bf59

File tree

1 file changed

+25
-73
lines changed

1 file changed

+25
-73
lines changed

pytest_playwright/pytest_playwright.py

Lines changed: 25 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
import shutil
1717
import os
1818
import sys
19+
20+
import traceback
21+
1922
import warnings
2023
from typing import Any, Callable, Dict, Generator, List, Optional
21-
import logging
24+
2225
import pytest
2326
from playwright.sync_api import (
2427
Browser,
@@ -33,8 +36,6 @@
3336
import tempfile
3437

3538

36-
log = logging.getLogger(__name__)
37-
3839
artifacts_folder = tempfile.TemporaryDirectory(prefix="playwright-pytest-")
3940

4041

@@ -76,34 +77,6 @@ def pytest_configure(config: Any) -> None:
7677
"markers",
7778
"browser_context_args(**kwargs): provide additional arguments to browser.new_context()",
7879
)
79-
log.debug("pytest_configure")
80-
class Teardown:
81-
failed = False
82-
setattr(config, "teardown", Teardown)
83-
84-
85-
def pytest_runtest_teardown(item):
86-
# import faulthandler
87-
# faulthandler.dump_traceback(all_threads=True)
88-
log.debug("pytest_runtest_teardown")
89-
item.config.teardown.failed = True
90-
91-
92-
def pytest_sessionfinish(session, exitstatus):
93-
log.debug("pytest_runtest_teardown")
94-
log.debug(f"{exitstatus=}")
95-
96-
97-
def pytest_exception_interact(node, call, report):
98-
log.debug("1pytest_exception_interact")
99-
log.debug(f"{node.config.teardown.failed=}")
100-
log.debug(f"{node.session.testsfailed=}")
101-
excinfo = call.exc_info if hasattr(call, "exc_info") else None
102-
log.debug(f"{excinfo=}")
103-
104-
if call.when == "teardown":
105-
log.debug("2pytest_exception_interact")
106-
node.config.teardown.failed = True
10780

10881

10982
# Making test result information available in fixtures
@@ -286,52 +259,33 @@ def context(
286259
)
287260

288261
yield context
289-
# import traceback
290-
# log.debug(f"{dir(traceback)=}")
291-
# log.debug(f"{traceback.print_last()=}")
292-
# stack = traceback.extract_stack()
293-
# log.debug(f"{stack=}")
294-
# for frame_summary in stack:
295-
# log.debug(f"{frame_summary.filename=}")
296-
# log.debug(f"{frame_summary.name=}")
297-
# log.debug(f"{frame_summary.colno=}")
298-
299-
300-
# log.debug(f"{traceback.print_stack()=}")
301-
302-
# log.debug(f"{traceback.print_exc()=}")
303-
304-
log.debug(f"{request.session.testscollected=}")
305-
log.debug(f"{request.session.exitstatus=}")
306-
log.debug(f"{request.session.testsfailed=}")
307-
308-
if request.session.testsfailed:
309-
log.debug("Only print if failed")
310-
311-
log.debug("context")
312262
# If request.node is missing rep_call, then some error happened during execution
313263
# that prevented teardown, but should still be counted as a failure
314-
failed_setup = request.node.rep_setup.failed if hasattr(request.node, "rep_setup") else False
315-
failed_call = request.node.rep_call.failed if hasattr(request.node, "rep_call") else False
316-
failed_teardown = request.node.rep_teardown.failed if hasattr(request.node, "rep_teardown") else False
317-
318-
failed_xteardown = request.config.teardown.failed if hasattr(request.config, "teardown") else False
319-
320-
321-
failed = failed_setup or failed_call or failed_xteardown
322-
log.debug(f"{failed=}")
323-
log.debug(f"{failed_setup=}")
324-
log.debug(f"{failed_call=}")
325-
log.debug(f"{failed_teardown=}")
326-
log.debug(f"{failed_xteardown=}")
264+
failed_setup = (
265+
request.node.rep_setup.failed if hasattr(request.node, "rep_setup") else False
266+
)
267+
failed_call = (
268+
request.node.rep_call.failed if hasattr(request.node, "rep_call") else False
269+
)
327270

271+
passed_setup = (
272+
request.node.rep_setup.passed if hasattr(request.node, "rep_setup") else False
273+
)
274+
passed_call = (
275+
request.node.rep_call.passed if hasattr(request.node, "rep_call") else False
276+
)
328277

329-
log.debug(f"{hasattr(request.node, 'rep_setup')=}")
330-
log.debug(f"{hasattr(request.node, 'rep_call')=}")
331-
log.debug(f"{hasattr(request.node, 'rep_teardown')=}")
278+
failed_xteardown = False
332279

333-
log.debug(f"{hasattr(request.config, 'teardown')=}")
280+
if (passed_setup or passed_call) and not (failed_setup or failed_call):
281+
# check tb under stack if any other teardown was failed, False by default
282+
# looks like workaround for https://github.com/pytest-dev/pytest/issues/9909
283+
for trace, _ in traceback.walk_stack(None):
284+
if trace.f_locals.get("these_exceptions"):
285+
failed_xteardown = True
286+
break
334287

288+
failed = failed_setup or failed_call or failed_xteardown
335289

336290
if capture_trace:
337291
retain_trace = tracing_option == "on" or (
@@ -344,11 +298,9 @@ def context(
344298
context.tracing.stop()
345299

346300
screenshot_option = pytestconfig.getoption("--screenshot")
347-
log.debug(f"{screenshot_option=}")
348301
capture_screenshot = screenshot_option == "on" or (
349302
failed and screenshot_option == "only-on-failure"
350303
)
351-
log.debug(f"{capture_screenshot=}")
352304
if capture_screenshot:
353305
for index, page in enumerate(pages):
354306
human_readable_status = "failed" if failed else "finished"

0 commit comments

Comments
 (0)