Skip to content

Commit 855d661

Browse files
kiebak3rkieranauvipy
authored
Feature - Playwright Support for Trace Zip Mapping (#296)
* support for playwright trace zip mapping * playwright trace zip support * re added accidental removal of session duration * Update pytest_sugar.py * Update pytest_sugar.py * addressed PR comments * updated readme.md with cli args documentation * Update README.md --------- Co-authored-by: kieran <kieran.baker@da-systems.co.uk> Co-authored-by: Asif Saif Uddin {"Auvi":"অভি"} <auvipy@gmail.com>
1 parent 2a5862a commit 855d661

4 files changed

Lines changed: 127 additions & 2 deletions

File tree

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,32 @@ If you would like to run tests without pytest-sugar, use:
2727

2828
pytest -p no:sugar
2929

30+
## Usage
31+
pytest-sugar provides several command-line options to customize its output and behavior. These options enhance test reporting and Playwright trace integration:
32+
33+
34+
Show detailed test failures instead of one-line tracebacks.
35+
Use this if you want to see the full failure information instantly.
36+
37+
--old-summary
38+
39+
Force pytest-sugar output even if pytest doesn’t detect a real terminal.
40+
Useful when running tests in CI systems or other non-interactive environments.
41+
42+
--force-sugar
43+
44+
45+
Specify the directory where Playwright trace files are stored.
46+
Defaults to Playwright default: "test-results"
47+
48+
--sugar-trace-dir <directory>
49+
50+
Disable Playwright trace file detection and output display.
51+
Use this if you want to turn off trace collection or display entirely.
52+
53+
--sugar-no-trace
54+
55+
3056
## How to contribute 👷‍♂️
3157

3258
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=master&repo=10950375)

RELEASE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Release type: minor
2+
3+
Add Playwright trace file detection and display support for failed tests. This enhancement automatically detects and displays Playwright trace.zip files with viewing commands when tests fail, making debugging easier for Playwright users.
4+
![Playwright trace.zip](docs/images/playwright-trace-example.png)
5+
6+
New command-line options:
7+
- `--sugar-trace-dir`: Configure the directory name for Playwright trace files (default: test-results)
8+
- `--sugar-no-trace`: Disable Playwright trace file detection and display
25.3 KB
Loading

pytest_sugar.py

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,20 @@ def pytest_addoption(parser: Parser) -> None:
133133
default=False,
134134
help=("Force pytest-sugar output even when not in real terminal"),
135135
)
136+
group._addoption(
137+
"--sugar-trace-dir",
138+
action="store",
139+
dest="sugar_trace_dir",
140+
default="test-results",
141+
help=("Directory name for Playwright trace files (default: test-results)"),
142+
)
143+
group._addoption(
144+
"--sugar-no-trace",
145+
action="store_true",
146+
dest="sugar_no_trace",
147+
default=False,
148+
help=("Disable Playwright trace file detection and display"),
149+
)
136150

137151

138152
def pytest_sessionstart(session: Session) -> None:
@@ -524,8 +538,8 @@ def count(self, key: str, when: tuple = ("call",)) -> int:
524538

525539
def summary_stats(self) -> None:
526540
session_duration = time.time() - self._sessionstarttime
527-
528541
print(f"\nResults ({format_session_duration(session_duration)}):")
542+
529543
if self.count("passed") > 0:
530544
self.write_line(
531545
colored(" % 5d passed" % self.count("passed"), THEME.success)
@@ -543,9 +557,10 @@ def summary_stats(self) -> None:
543557
THEME.fail,
544558
)
545559
)
546-
for report in self.stats["failed"]:
560+
for i, report in enumerate(self.stats["failed"]):
547561
if report.when != "call":
548562
continue
563+
549564
if self.config.option.tb_summary:
550565
crashline = self._get_decoded_crashline(report)
551566
else:
@@ -559,6 +574,11 @@ def summary_stats(self) -> None:
559574
lineno if lineno else "?",
560575
colored(report.location[2], THEME.fail),
561576
)
577+
578+
# Add trace.zip path if it exists
579+
trace_path = self._find_playwright_trace(report)
580+
if trace_path:
581+
crashline += f"\n - 🎭 {trace_path}"
562582
self.write_line(f" - {crashline}")
563583

564584
if self.count("failed", when=("setup", "teardown")) > 0:
@@ -592,6 +612,77 @@ def summary_stats(self) -> None:
592612
colored(" % 5d deselected" % self.count("deselected"), THEME.warning)
593613
)
594614

615+
def _find_playwright_trace(self, report: TestReport) -> Optional[str]:
616+
"""
617+
Finds the Playwright trace file associated with a specific test report.
618+
619+
Identifies the location of the trace file by using the test report's node ID
620+
and configuration options.
621+
It allows users to locate and optionally view the Playwright trace
622+
for failed tests.
623+
If Playwright trace finding is specifically disabled, or the trace file
624+
does not exist for the given test, no output is returned.
625+
626+
Parameters:
627+
report (TestReport):
628+
The test report containing details about the test execution, including
629+
the node ID.
630+
631+
Returns:
632+
Optional[str]: A string containing command to view the Playwright trace
633+
or
634+
None if trace is not enabled, the file does not exist, or an exception occurs.
635+
"""
636+
# Check if trace finding is disabled
637+
if self.config.option.sugar_no_trace:
638+
return None
639+
640+
try:
641+
# Extract test information from the report
642+
nodeid = report.nodeid
643+
644+
# Handle Node ID conversion to trace name format
645+
trace_dir_name = self._convert_node_to_trace_name(nodeid)
646+
647+
# Construct the expected trace directory path
648+
cwd = os.getcwd()
649+
trace_dir_name_from_config = self.config.option.sugar_trace_dir
650+
test_results_dir = os.path.join(cwd, trace_dir_name_from_config)
651+
trace_dir = os.path.join(test_results_dir, trace_dir_name)
652+
trace_file = os.path.join(trace_dir, "trace.zip")
653+
654+
# Check if the trace file exists
655+
if os.path.exists(trace_file):
656+
# Provide the relative path and a command to view the trace
657+
trace_file_relative = os.path.relpath(trace_file, cwd).replace(
658+
"\\", "/"
659+
)
660+
661+
# Create a command to open the trace with Playwright for Python
662+
view_command = f"playwright show-trace {trace_file_relative}"
663+
664+
# Display unzip command
665+
command_display = colored(view_command, THEME.warning)
666+
return command_display
667+
return None
668+
669+
except (OSError, AttributeError):
670+
return None
671+
672+
@staticmethod
673+
def _convert_node_to_trace_name(nodeid: str) -> str:
674+
# Convert the nodeid to the expected trace directory name
675+
trace_dir_name = (
676+
nodeid.replace("/", "-")
677+
.replace("\\", "-")
678+
.replace("::", "-")
679+
.replace("[", "-")
680+
.replace("]", "")
681+
.replace("_", "-")
682+
.replace(".", "-")
683+
)
684+
return trace_dir_name.lower()
685+
595686
def _get_decoded_crashline(self, report: CollectReport) -> str:
596687
crashline = self._getcrashline(report)
597688

0 commit comments

Comments
 (0)