pytest-html-plus 1.2.0__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: pytest-html-plus
3
+ Version: 1.3.0
4
+ Summary: Generate Actionable, automatic screenshots, unified Mobile friendly Pytest HTML report in less than 3 seconds — no hooks, merge plugins, no config, xdist-ready.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: pytest,pytest-plugin,html-report,test-report,screenshot,mobile-report,xdist,allure-alternative,playwright,selenium
8
+ Author: reporterplus
9
+ Maintainer: reporterplus
10
+ Requires-Python: >=3.10,<4.0
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Framework :: Pytest
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Programming Language :: Python :: 3.15
23
+ Classifier: Topic :: Software Development :: Quality Assurance
24
+ Classifier: Topic :: Software Development :: Testing
25
+ Requires-Dist: keyring (>=25.6.0,<26.0.0)
26
+ Requires-Dist: tomli (>=2.0.1,<3.0.0) ; python_version < "3.11"
27
+ Requires-Dist: yagmail (>=0.15.293,<0.16.0)
28
+ Project-URL: Changelog, https://github.com/reporterplus/pytest-html-plus/blob/main/CHANGELOG.md
29
+ Project-URL: Documentation, https://pytest-html-plus.readthedocs.io
30
+ Project-URL: Homepage, https://github.com/reporterplus/pytest-html-plus
31
+ Project-URL: Source, https://github.com/reporterplus/pytest-html-plus
32
+ Project-URL: Tracker, https://github.com/reporterplus/pytest-html-plus/issues
33
+ Description-Content-Type: text/markdown
34
+
35
+ ⚡ **Test your code, not your reporting setup.**
36
+
37
+ > A pytest report built for fast debugging, with parallel execution support, automatic screenshots, and shareable failure context.
38
+
39
+ `pytest-html-plus` turns pytest results into portable debugging artifacts for CI, collaboration, and integrations, without a reporting platform.
40
+
41
+ ➡️ [View Demo Report](https://reporterplus.github.io/pytest-html-plus/)
42
+
43
+ [![Docs](https://img.shields.io/badge/docs-online-blue)](https://pytest-html-plus.readthedocs.io/en/main/) [![PyPI Downloads](https://img.shields.io/pypi/dm/pytest-html-plus?label=downloads%2Fmonth)](https://pypistats.org/packages/pytest-html-plus) ![PyPI](https://img.shields.io/pypi/v/pytest-html-plus) ![Python Versions](https://img.shields.io/pypi/pyversions/pytest-html-plus) ![License](https://img.shields.io/pypi/l/pytest-html-plus) [![Unit Tests](https://github.com/reporterplus/pytest-html-plus/actions/workflows/unit-test.yml/badge.svg)](https://github.com/reporterplus/pytest-html-plus/actions/workflows/unit-test.yml) [![codecov](https://codecov.io/gh/reporterplus/pytest-html-plus/branch/main/graph/badge.svg)](https://codecov.io/gh/reporterplus/pytest-html-plus) [![GitHub Action](https://img.shields.io/badge/GitHub_Action-Pytest_HTML_Plus-2088FF?logo=githubactions&logoColor=white)](https://github.com/marketplace/actions/pytest-html-plus-action) [![VS Code](https://img.shields.io/badge/VS_Code-Pytest_HTML_Plus-007ACC?logo=visualstudiocode&logoColor=white)](https://marketplace.visualstudio.com/items?itemName=reporterplus.pytest-html-plus-vscode)
44
+
45
+ ---
46
+
47
+ ## 🚀 Quick Start
48
+
49
+ ```bash
50
+ pip install pytest-html-plus
51
+ # or
52
+ poetry add pytest-html-plus
53
+
54
+ pytest
55
+ ```
56
+
57
+ By default, that generates a portable HTML report and structured JSON output. No hooks, decorators, or reporting server are required.
58
+
59
+ ## Why pytest-html-plus?
60
+
61
+ - ⚡ Produce one unified report with or without `pytest-xdist`.
62
+ - 📸 Capture failure screenshots automatically for Selenium and Playwright tests.
63
+ - 📋 Keep errors, traces, logs, stdout, and stderr together in one report.
64
+ - 🔄 Understand flaky tests with complete retry history.
65
+ - 🔗 Share a direct link to an individual test result.
66
+ - 🔍 Find tests, failures, traces, issue references, and documentation links from the same report.
67
+
68
+ ## ✨ Features
69
+
70
+ #### ⚡ One Unified Report with xdist
71
+
72
+ Run tests in parallel and receive one merged HTML and JSON report without an additional merge plugin or post-processing step.
73
+
74
+ #### 📸 See What Failed Automatically
75
+
76
+ Capture Selenium and Playwright screenshots automatically and view them alongside the relevant failure context, with no custom hooks or decorators required.
77
+
78
+ #### 📋 Everything You Need to Investigate a Failure
79
+
80
+ Review errors, traces, logs, stdout, stderr, and screenshots together. Copy the context you need in one click and use `--plus-output=failed-only` to keep passing-test output compact.
81
+
82
+ ![Configurable output capture](https://github.com/user-attachments/assets/209cd2c0-d33b-48ec-b58b-8c8991ce35be)
83
+
84
+ ![Copy failure context](https://github.com/user-attachments/assets/396e8cf6-862b-4619-82bf-81a8eae8e7b6)
85
+
86
+ #### 🔄 Understand Flaky Tests Across Every Retry
87
+
88
+ See how a test behaves across retries, from initial failure to recovery. Spot patterns such as cache issues, race conditions, and intermittent crashes without guesswork.
89
+
90
+ ![Flaky test retry history](https://github.com/user-attachments/assets/1f7e0cd8-d2f9-47fd-8909-6f12adf8a800)
91
+
92
+ #### 🔗 Share Any Test with a Direct Link
93
+
94
+ Copy a direct link to any test result and share it with your team. The report opens at the linked test, reveals it, expands its details, and highlights it, so teammates can jump straight to the relevant context without searching through the report.
95
+
96
+ <img width="3024" height="1778" alt="ScreenRecording2026-10-03at8 55 26AM-ezgif com-cut" src="https://github.com/user-attachments/assets/0c44a38f-7898-4a4d-8241-4f1d1c57ccfb" />
97
+
98
+ #### 🔍 Find the Context You Need
99
+
100
+ Search tests, errors, traces, issue references, documentation links, and custom references from the same report.
101
+
102
+ <img width="800" height="421" alt="Universal test search" src="https://github.com/user-attachments/assets/54858747-ab16-4d4f-baa9-0d651a1d8bac" />
103
+
104
+ ---
105
+
106
+ ## Try It Without Changing Your Test Suite
107
+
108
+ `pytest-html-plus` works alongside existing pytest tooling, so you can evaluate it with your current test suite without adopting a reporting server, rewriting tests, or maintaining reporting infrastructure.
109
+
110
+ ## More Built In
111
+
112
+ Also includes merged JUnit XML export, run metadata, slow-test visibility, reusable profiles, traceability helpers, email delivery, dynamic markers, and configurable output capture.
113
+
114
+ **[See all features and configuration options →](https://pytest-html-plus.readthedocs.io/en/main/)**
115
+
116
+ ## Project Status
117
+
118
+ pytest-html-plus is stable and actively maintained, with its core reporting experience now well established. Future development will focus on compatibility, reliability, and carefully selected improvements that strengthen the core reporting experience.
119
+
120
+ We're also looking for co-maintainers to help review pull requests, triage issues, and keep the project healthy across future Python and pytest releases.
121
+
122
+ If you're interested in becoming a long-term contributor, we'd love to hear from you. Please open an issue or start a discussion.
123
+
124
+ ## Contributing
125
+
126
+ We welcome pull requests, issues, and feature suggestions from the community.
127
+
128
+ See the [contribution guide](CONTRIBUTING.md) for setup instructions.
129
+
130
+ ## 📜 License
131
+
132
+ MIT
133
+
@@ -0,0 +1,98 @@
1
+ ⚡ **Test your code, not your reporting setup.**
2
+
3
+ > A pytest report built for fast debugging, with parallel execution support, automatic screenshots, and shareable failure context.
4
+
5
+ `pytest-html-plus` turns pytest results into portable debugging artifacts for CI, collaboration, and integrations, without a reporting platform.
6
+
7
+ ➡️ [View Demo Report](https://reporterplus.github.io/pytest-html-plus/)
8
+
9
+ [![Docs](https://img.shields.io/badge/docs-online-blue)](https://pytest-html-plus.readthedocs.io/en/main/) [![PyPI Downloads](https://img.shields.io/pypi/dm/pytest-html-plus?label=downloads%2Fmonth)](https://pypistats.org/packages/pytest-html-plus) ![PyPI](https://img.shields.io/pypi/v/pytest-html-plus) ![Python Versions](https://img.shields.io/pypi/pyversions/pytest-html-plus) ![License](https://img.shields.io/pypi/l/pytest-html-plus) [![Unit Tests](https://github.com/reporterplus/pytest-html-plus/actions/workflows/unit-test.yml/badge.svg)](https://github.com/reporterplus/pytest-html-plus/actions/workflows/unit-test.yml) [![codecov](https://codecov.io/gh/reporterplus/pytest-html-plus/branch/main/graph/badge.svg)](https://codecov.io/gh/reporterplus/pytest-html-plus) [![GitHub Action](https://img.shields.io/badge/GitHub_Action-Pytest_HTML_Plus-2088FF?logo=githubactions&logoColor=white)](https://github.com/marketplace/actions/pytest-html-plus-action) [![VS Code](https://img.shields.io/badge/VS_Code-Pytest_HTML_Plus-007ACC?logo=visualstudiocode&logoColor=white)](https://marketplace.visualstudio.com/items?itemName=reporterplus.pytest-html-plus-vscode)
10
+
11
+ ---
12
+
13
+ ## 🚀 Quick Start
14
+
15
+ ```bash
16
+ pip install pytest-html-plus
17
+ # or
18
+ poetry add pytest-html-plus
19
+
20
+ pytest
21
+ ```
22
+
23
+ By default, that generates a portable HTML report and structured JSON output. No hooks, decorators, or reporting server are required.
24
+
25
+ ## Why pytest-html-plus?
26
+
27
+ - ⚡ Produce one unified report with or without `pytest-xdist`.
28
+ - 📸 Capture failure screenshots automatically for Selenium and Playwright tests.
29
+ - 📋 Keep errors, traces, logs, stdout, and stderr together in one report.
30
+ - 🔄 Understand flaky tests with complete retry history.
31
+ - 🔗 Share a direct link to an individual test result.
32
+ - 🔍 Find tests, failures, traces, issue references, and documentation links from the same report.
33
+
34
+ ## ✨ Features
35
+
36
+ #### ⚡ One Unified Report with xdist
37
+
38
+ Run tests in parallel and receive one merged HTML and JSON report without an additional merge plugin or post-processing step.
39
+
40
+ #### 📸 See What Failed Automatically
41
+
42
+ Capture Selenium and Playwright screenshots automatically and view them alongside the relevant failure context, with no custom hooks or decorators required.
43
+
44
+ #### 📋 Everything You Need to Investigate a Failure
45
+
46
+ Review errors, traces, logs, stdout, stderr, and screenshots together. Copy the context you need in one click and use `--plus-output=failed-only` to keep passing-test output compact.
47
+
48
+ ![Configurable output capture](https://github.com/user-attachments/assets/209cd2c0-d33b-48ec-b58b-8c8991ce35be)
49
+
50
+ ![Copy failure context](https://github.com/user-attachments/assets/396e8cf6-862b-4619-82bf-81a8eae8e7b6)
51
+
52
+ #### 🔄 Understand Flaky Tests Across Every Retry
53
+
54
+ See how a test behaves across retries, from initial failure to recovery. Spot patterns such as cache issues, race conditions, and intermittent crashes without guesswork.
55
+
56
+ ![Flaky test retry history](https://github.com/user-attachments/assets/1f7e0cd8-d2f9-47fd-8909-6f12adf8a800)
57
+
58
+ #### 🔗 Share Any Test with a Direct Link
59
+
60
+ Copy a direct link to any test result and share it with your team. The report opens at the linked test, reveals it, expands its details, and highlights it, so teammates can jump straight to the relevant context without searching through the report.
61
+
62
+ <img width="3024" height="1778" alt="ScreenRecording2026-10-03at8 55 26AM-ezgif com-cut" src="https://github.com/user-attachments/assets/0c44a38f-7898-4a4d-8241-4f1d1c57ccfb" />
63
+
64
+ #### 🔍 Find the Context You Need
65
+
66
+ Search tests, errors, traces, issue references, documentation links, and custom references from the same report.
67
+
68
+ <img width="800" height="421" alt="Universal test search" src="https://github.com/user-attachments/assets/54858747-ab16-4d4f-baa9-0d651a1d8bac" />
69
+
70
+ ---
71
+
72
+ ## Try It Without Changing Your Test Suite
73
+
74
+ `pytest-html-plus` works alongside existing pytest tooling, so you can evaluate it with your current test suite without adopting a reporting server, rewriting tests, or maintaining reporting infrastructure.
75
+
76
+ ## More Built In
77
+
78
+ Also includes merged JUnit XML export, run metadata, slow-test visibility, reusable profiles, traceability helpers, email delivery, dynamic markers, and configurable output capture.
79
+
80
+ **[See all features and configuration options →](https://pytest-html-plus.readthedocs.io/en/main/)**
81
+
82
+ ## Project Status
83
+
84
+ pytest-html-plus is stable and actively maintained, with its core reporting experience now well established. Future development will focus on compatibility, reliability, and carefully selected improvements that strengthen the core reporting experience.
85
+
86
+ We're also looking for co-maintainers to help review pull requests, triage issues, and keep the project healthy across future Python and pytest releases.
87
+
88
+ If you're interested in becoming a long-term contributor, we'd love to hear from you. Please open an issue or start a discussion.
89
+
90
+ ## Contributing
91
+
92
+ We welcome pull requests, issues, and feature suggestions from the community.
93
+
94
+ See the [contribution guide](CONTRIBUTING.md) for setup instructions.
95
+
96
+ ## 📜 License
97
+
98
+ MIT
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pytest-html-plus"
3
- version = "1.2.0"
3
+ version = "1.3.0"
4
4
  description = "Generate Actionable, automatic screenshots, unified Mobile friendly Pytest HTML report in less than 3 seconds — no hooks, merge plugins, no config, xdist-ready."
5
5
  readme = "README.md"
6
6
  authors = ["reporterplus"]
@@ -78,13 +78,7 @@ html-output = "report_output_warnings"
78
78
  [tool.ruff]
79
79
  line-length = 88
80
80
  target-version = "py39"
81
- ignore = [
82
- "E501", # line too long — let black handle
83
- "W291", # trailing whitespace — let black handle
84
- "W293", # blank line whitespace — let black handle
85
- ]
86
81
  exclude = [
87
- "pytest_html_plus/generate_html_report.py",
88
82
  ".git"
89
83
  ]
90
84
 
@@ -96,4 +90,8 @@ select = [
96
90
  "I", # isort
97
91
  "UP", # pyupgrade
98
92
  ]
99
- ignore = []
93
+ ignore = [
94
+ "E501", # line too long — let black handle
95
+ "W291", # trailing whitespace — let black handle
96
+ "W293", # blank line whitespace — let black handle
97
+ ]
@@ -1,14 +1,23 @@
1
1
  import argparse
2
2
  import base64
3
+ import hashlib
3
4
  import json
4
5
  import os
5
6
  import shutil
6
7
  from datetime import datetime, timezone
7
8
  from html import escape
9
+
8
10
  from pytest_html_plus.compute_filter_counts import compute_filter_count
11
+ from pytest_html_plus.resolver_driver import sanitize_filename
9
12
  from pytest_html_plus.utils import extract_error_block, extract_trace_block
10
13
 
11
14
 
15
+ def stable_test_anchor(nodeid):
16
+ """Return a deterministic, URL-safe HTML anchor for a pytest nodeid."""
17
+ digest = hashlib.sha256(str(nodeid).encode("utf-8")).hexdigest()[:32]
18
+ return f"test-{digest}"
19
+
20
+
12
21
  def main():
13
22
  parser = argparse.ArgumentParser(
14
23
  description="Generate HTML report from Playwright JSON report"
@@ -342,6 +351,13 @@ class JSONReporter:
342
351
 
343
352
  .inline-copy-btn {{ cursor: pointer; background: none; border: 1px solid #ddd; border-radius: 3px; padding: 2px 4px; font-size: 0.8em; margin-left: 8px; color: #666; transition: all 0.2s ease; line-height: 1; }}
344
353
  .inline-copy-btn:hover {{ border-color: #999; background: #f5f5f5; color: #333; }}
354
+ .test:target, .test.deep-link-target {{
355
+ outline: 2px solid rgba(160, 130, 90, 0.4);
356
+ outline-offset: 1px;
357
+ box-shadow: 0 2px 8px rgba(80, 65, 45, 0.1);
358
+ }}
359
+ .test:focus-visible {{ outline: 2px solid #2563eb; outline-offset: 2px; }}
360
+ .test {{ scroll-margin-top: 1rem; }}
345
361
  .error-content pre {{ background: #fef2f2; border-left: 4px solid #dc2626; padding: 12px; border-radius: 4px; color: #7f1d1d; margin: 8px 0; }}
346
362
  .trace-content pre {{ background: #fef7ed; border-left: 4px solid #ea580c; padding: 12px; border-radius: 4px; color: #9a3412; margin: 8px 0; }}
347
363
  .details-text div pre {{ background: #f8fafc; border: 1px solid #e2e8f0; padding: 12px; border-radius: 4px; margin: 8px 0; font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; font-size: 0.85em; line-height: 1.4; }}
@@ -416,6 +432,68 @@ class JSONReporter:
416
432
  }}
417
433
  }}
418
434
 
435
+ function copyTestLink(anchorId, button) {{
436
+ try {{
437
+ const url = new URL(window.location.href);
438
+ url.hash = anchorId;
439
+ const originalContent = button.innerHTML;
440
+ navigator.clipboard.writeText(url.href).then(() => {{
441
+ button.innerHTML = '<span style="color: #2f7a33;">✓</span>';
442
+ setTimeout(() => {{ button.innerHTML = originalContent; }}, 1000);
443
+ }}).catch(err => {{
444
+ console.error("Copy link failed:", err);
445
+ button.innerHTML = '<span style="color: #d32f2f;">✗</span>';
446
+ setTimeout(() => {{ button.innerHTML = originalContent; }}, 1000);
447
+ }});
448
+ }} catch (error) {{
449
+ console.error("Copy link error:", error);
450
+ }}
451
+ }}
452
+
453
+ function clearFiltersForDeepLink() {{
454
+ const filterIds = [
455
+ 'failedOnlyCheckbox', 'errorOnlyCheckbox', 'skippedOnlyCheckbox',
456
+ 'longestOnlyCheckbox', 'untrackedOnlyCheckbox', 'flakyOnlyCheckbox'
457
+ ];
458
+ filterIds.forEach(id => {{
459
+ const checkbox = document.getElementById(id);
460
+ if (checkbox) checkbox.checked = false;
461
+ }});
462
+ document.querySelectorAll('.marker-filter input[type="checkbox"]')
463
+ .forEach(checkbox => checkbox.checked = false);
464
+ const searchInput = document.getElementById('universal-search');
465
+ if (searchInput) searchInput.value = '';
466
+ document.querySelectorAll('.test').forEach(test => test.style.display = 'block');
467
+ }}
468
+
469
+ function revealTestFromFragment() {{
470
+ if (!window.location.hash) return;
471
+ let anchorId;
472
+ try {{
473
+ anchorId = decodeURIComponent(window.location.hash.slice(1));
474
+ }} catch (error) {{
475
+ return;
476
+ }}
477
+ if (!anchorId.startsWith('test-')) return;
478
+ const testCard = document.getElementById(anchorId);
479
+ if (!testCard || !testCard.classList.contains('test')) return;
480
+
481
+ clearFiltersForDeepLink();
482
+ document.querySelectorAll('.test.deep-link-target')
483
+ .forEach(test => test.classList.remove('deep-link-target'));
484
+ testCard.classList.add('deep-link-target');
485
+
486
+ const header = testCard.querySelector('.header');
487
+ const details = testCard.querySelector('.details');
488
+ if (header && details) {{
489
+ header.classList.add('expanded');
490
+ details.style.display = 'block';
491
+ }}
492
+
493
+ testCard.scrollIntoView({{ behavior: 'smooth', block: 'center' }});
494
+ testCard.focus({{ preventScroll: true }});
495
+ }}
496
+
419
497
  function toggleFullscreen(img) {{
420
498
  const overlay = document.getElementById('fullscreen-overlay');
421
499
  if (img.classList.contains('fullscreen')) {{
@@ -664,6 +742,8 @@ class JSONReporter:
664
742
  flakyCheckbox.addEventListener('change', () => toggleFlakyOnly(flakyCheckbox));
665
743
  const markerCheckboxes = document.querySelectorAll('.marker-filter input[type="checkbox"]');
666
744
  markerCheckboxes.forEach(cb => cb.addEventListener('change', filterByMarkers));
745
+ revealTestFromFragment();
746
+ window.addEventListener('hashchange', revealTestFromFragment);
667
747
  }};
668
748
  </script>
669
749
  </head>
@@ -792,7 +872,14 @@ class JSONReporter:
792
872
  else "error" if test["status"] == "error" else "skipped"
793
873
  )
794
874
  )
795
- screenshot_path = self.find_screenshot_and_copy(test["test"])
875
+ # NOTE: Parammetrized test name may contains unsupport filesystem-safe chars
876
+ # Use test_name will not match the screenshot.
877
+ # 1. use test["screenshot"] which is the the screenshot path will lost the wild pattern
878
+ # *2. use sanitize_filename which replace non-alphanumeric will match the screenshot filename pattern
879
+ # 3. try to split parametrized will be hard
880
+ screenshot_path = self.find_screenshot_and_copy(
881
+ sanitize_filename(test["test"])
882
+ )
796
883
  screenshot_html = (
797
884
  f'<div class="details-screenshot"><img src="{screenshot_path}" alt="Screenshot" onclick="toggleFullscreen(this)"></div>'
798
885
  if screenshot_path
@@ -847,7 +934,7 @@ class JSONReporter:
847
934
 
848
935
  error_block = (
849
936
  f'<div class="error-content"><strong>Error:</strong> '
850
- f'{self.generate_copy_button(error, "error")}'
937
+ f"{self.generate_copy_button(error, 'error')}"
851
938
  f"<pre>{error}</pre></div>"
852
939
  if error
853
940
  else ""
@@ -855,7 +942,7 @@ class JSONReporter:
855
942
 
856
943
  trace_block = (
857
944
  f'<div class="trace-content"><strong>Trace:</strong> '
858
- f'{self.generate_copy_button(trace, "trace")}'
945
+ f"{self.generate_copy_button(trace, 'trace')}"
859
946
  f"<pre>{trace}</pre></div>"
860
947
  if trace
861
948
  else ""
@@ -874,7 +961,7 @@ class JSONReporter:
874
961
  """
875
962
 
876
963
  attempts_html += "</div>"
877
-
964
+
878
965
  search_error = ""
879
966
 
880
967
  if test.get("error"):
@@ -895,10 +982,8 @@ class JSONReporter:
895
982
  <pre>{error_content}</pre></div>
896
983
  """
897
984
  search_error = (
898
- error_content.replace("\n", " ")
899
- .replace("\r", " ")
985
+ error_content.replace("\n", " ").replace("\r", " ")
900
986
  )[:1000]
901
-
902
987
 
903
988
  flaky_badge = ""
904
989
  if test.get("flaky"):
@@ -935,18 +1020,26 @@ class JSONReporter:
935
1020
  '<span style="display:inline-block; min-width:45px;"></span>'
936
1021
  )
937
1022
 
1023
+ escaped_test_name = escape(test["test"])
1024
+ test_anchor = stable_test_anchor(test["nodeid"])
938
1025
  html += f"""
939
- <div class="test test-card" data-name="{test["test"]}" data-link="{",".join(test.get("links") or [])}" data-markers="{marker_str}" data-error="{escape(search_error)}">
1026
+ <div id="{test_anchor}" class="test test-card" data-nodeid="{escape(test["nodeid"], quote=True)}" tabindex="-1" data-name="{escaped_test_name}" data-link="{",".join(test.get("links") or [])}" data-markers="{marker_str}" data-error="{escape(search_error)}">
940
1027
  <div class="header {status_class}" onclick="toggleDetails(this)">
941
1028
  <div class="header-section test-info">
942
1029
  <span class="toggle"></span>
943
- <strong>{test["test"]}</strong>
1030
+ <strong>{escaped_test_name}</strong>
944
1031
  <span>— {test["status"].upper()}</span>
945
1032
  </div>
946
1033
  <div class="header-section meta">
947
1034
  <span class="nodeid-badge" style="display: flex; align-items: center; gap: 6px;">
948
- <code style="font-size: 0.6em; color: #555;">{test["nodeid"]}</code>
1035
+ <code style="font-size: 0.6em; color: #555;">{escape(test["nodeid"], quote=True)}</code>
949
1036
  {self.generate_copy_button(test["nodeid"], "nodeid")}
1037
+ <button class="inline-copy-btn test-link-btn" onclick="event.stopPropagation(); copyTestLink('{test_anchor}', this)" title="Copy link to test">
1038
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1039
+ <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
1040
+ <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
1041
+ </svg>
1042
+ </button>
950
1043
  </span>
951
1044
  <span class="worker-id" style="background: #ddd; border-radius: 3px; padding: 2px 5px; font-size: 0.85em; font-weight: bold;">{test["worker"]}</span>
952
1045
  </div>
@@ -990,20 +1083,21 @@ class JSONReporter:
990
1083
  "#e6f4ea" if failed_tests == 0 and error_tests == 0 else "#fdecea"
991
1084
  };
992
1085
  border: 1px solid {
993
- "#2f7a33" if failed_tests == 0 and
994
- error_tests == 0
995
- else "#a83232"
1086
+ "#2f7a33" if failed_tests == 0 and error_tests == 0 else "#a83232"
996
1087
  };
997
1088
  border-radius: 5px; margin-bottom: 1rem;">
998
1089
  {
999
1090
  "<strong>Bingo!</strong> All your tests passed!"
1000
1091
  if failed_tests == 0 and error_tests == 0
1001
- else (f"Total tests: {total_tests}, "
1002
- f"Failures: {failed_tests}, "
1003
- f"Errors: {error_tests}.")
1092
+ else (
1093
+ f"Total tests: {total_tests}, "
1094
+ f"Failures: {failed_tests}, "
1095
+ f"Errors: {error_tests}."
1096
+ )
1004
1097
  }
1005
- The slowest test was <strong>{slowest_test_name}</strong> at {
1006
- slowest_test_duration:.2f}s.
1098
+ The slowest test was <strong>{
1099
+ escape(slowest_test_name, quote=True)
1100
+ }</strong> at {slowest_test_duration:.2f}s.
1007
1101
  </div>
1008
1102
  """
1009
1103
 
@@ -247,7 +247,6 @@ def pytest_runtest_makereport(item, call):
247
247
  screenshot_path = take_screenshot_generic(screenshot_path, item, driver)
248
248
 
249
249
  worker_id = os.getenv("PYTEST_XDIST_WORKER") or "main"
250
- test_name = "".join(c if c.isalnum() else "_" for c in item.name)
251
250
 
252
251
  status = report.outcome
253
252
  if report.when in ("setup", "teardown") and report.failed:
@@ -256,14 +255,13 @@ def pytest_runtest_makereport(item, call):
256
255
  output_policy = config.getoption(OUTPUT_OPTION)
257
256
  is_expected_failure = report.skipped and hasattr(report, "wasxfail")
258
257
  include_output = output_policy == "all" or (
259
- output_policy == "failed-only"
260
- and (report.failed or is_expected_failure)
258
+ output_policy == "failed-only" and (report.failed or is_expected_failure)
261
259
  )
262
260
  stdout = getattr(report, "capstdout", "") if include_output else ""
263
261
  stderr = getattr(report, "capstderr", "") if include_output else ""
264
262
 
265
263
  reporter.log_result(
266
- test_name=test_name,
264
+ test_name=item.name,
267
265
  nodeid=item.nodeid,
268
266
  status=status,
269
267
  duration=report.duration,
@@ -1,219 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: pytest-html-plus
3
- Version: 1.2.0
4
- Summary: Generate Actionable, automatic screenshots, unified Mobile friendly Pytest HTML report in less than 3 seconds — no hooks, merge plugins, no config, xdist-ready.
5
- License: MIT
6
- License-File: LICENSE
7
- Keywords: pytest,pytest-plugin,html-report,test-report,screenshot,mobile-report,xdist,allure-alternative,playwright,selenium
8
- Author: reporterplus
9
- Maintainer: reporterplus
10
- Requires-Python: >=3.10,<4.0
11
- Classifier: Development Status :: 5 - Production/Stable
12
- Classifier: Framework :: Pytest
13
- Classifier: Intended Audience :: Developers
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Operating System :: OS Independent
16
- Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.10
18
- Classifier: Programming Language :: Python :: 3.11
19
- Classifier: Programming Language :: Python :: 3.12
20
- Classifier: Programming Language :: Python :: 3.13
21
- Classifier: Programming Language :: Python :: 3.14
22
- Classifier: Topic :: Software Development :: Quality Assurance
23
- Classifier: Topic :: Software Development :: Testing
24
- Requires-Dist: keyring (>=25.6.0,<26.0.0)
25
- Requires-Dist: tomli (>=2.0.1,<3.0.0) ; python_version < "3.11"
26
- Requires-Dist: yagmail (>=0.15.293,<0.16.0)
27
- Project-URL: Changelog, https://github.com/reporterplus/pytest-html-plus/blob/main/CHANGELOG.md
28
- Project-URL: Documentation, https://pytest-html-plus.readthedocs.io
29
- Project-URL: Homepage, https://github.com/reporterplus/pytest-html-plus
30
- Project-URL: Source, https://github.com/reporterplus/pytest-html-plus
31
- Project-URL: Tracker, https://github.com/reporterplus/pytest-html-plus/issues
32
- Description-Content-Type: text/markdown
33
-
34
- ⚡ **Test your code, not your reporting setup.**
35
- > _Get started with rich pytest reports in under 3 seconds. Just install — no setup required. The simplest, fastest reporter for pytest._
36
-
37
- ## Get a self-contained, actionable, easy-to-read single page HTML unified reports summarizing all your test results — no hassle, just clarity. Detect **flaky tests**, **attach screenshots** automatically without hooks and optionally send reports via email**. Works beautifully with or without `xdist`.
38
-
39
- ➡️ [View Demo Report](https://reporterplus.github.io/pytest-html-plus/)
40
-
41
- [![Docs](https://img.shields.io/badge/docs-online-blue)](https://pytest-html-plus.readthedocs.io/en/main/) [![PyPI Downloads](https://static.pepy.tech/badge/pytest-html-plus)](https://pepy.tech/projects/pytest-html-plus) ![PyPI](https://img.shields.io/pypi/v/pytest-html-plus) ![Python Versions](https://img.shields.io/pypi/pyversions/pytest-html-plus) ![License](https://img.shields.io/pypi/l/pytest-html-plus) [![Unit Tests](https://github.com/reporterplus/pytest-html-plus/actions/workflows/unit-test.yml/badge.svg)](https://github.com/reporterplus/pytest-html-plus/actions/workflows/unit-test.yml) [![codecov](https://codecov.io/gh/reporterplus/pytest-html-plus/branch/main/graph/badge.svg)](https://codecov.io/gh/reporterplus/pytest-html-plus)
42
-
43
- ---
44
-
45
- ## Already using pytest-html or Allure?
46
-
47
- No uninstall needed — `pytest-html-plus` works alongside `pytest-html`. Install it, run your suite, and see what you've been missing. Most teams uninstall `pytest-html` within the same day.
48
-
49
- ```bash
50
- pip install pytest-html-plus
51
- ```
52
-
53
- Your existing `pytest --html=report.html` commands keep working unchanged.
54
-
55
- | Feature | pytest-html | Allure | pytest-html-plus |
56
- |---|:---:|:---:|:---:|
57
- | Self-contained single HTML file | ✅ | ❌ | ✅ |
58
- | No server or CLI tool needed | ✅ | ❌ | ✅ |
59
- | Zero config — works out of the box | ✅ | ❌ | ✅ |
60
- | xdist parallel run support | ⚠️ extra plugin | ✅ | ✅ built-in |
61
- | Screenshots (no hooks or decorators) | ❌ | ❌ requires decorators | ✅ |
62
- | Automatic log & print() capture | ❌ | ✅ | ✅ |
63
- | Flaky test detection + retry history | ❌ | ✅ | ✅ |
64
- | Slow test highlighting | ❌ | ❌ | ✅ |
65
- | Traceability links (Jira, Testmo, etc.) | ❌ | ✅ | ✅ |
66
- | JUnit XML export (merged, one flag) | ❌ extra steps | ✅ | ✅ |
67
- | Run metadata (branch, commit, env) | ❌ | ✅ | ✅ |
68
- | Reusable config profiles | ❌ | ❌ | ✅ |
69
- | Unlinked test detection | ❌ | ❌ | ✅ |
70
- | Copy logs & traces to clipboard | ❌ | ❌ | ✅ |
71
- | Email reports | ❌ | ❌ | ✅ |
72
- | Mobile-friendly layout | ❌ | ✅ | ✅ |
73
- | Report size | 🟢 single file | 🔴 many files | 🟢 single file |
74
-
75
- ---
76
-
77
- ## 🚀 Installation
78
-
79
- ```bash
80
- pip install pytest-html-plus
81
- # or with Poetry
82
- poetry add pytest-html-plus
83
- ```
84
-
85
- ## Pytest HTML Plus Action
86
-
87
- If you don't want the burden of installing pytest-html-plus manually and your project already manages dependencies with `requirements.txt` or Poetry, use this GitHub Action to generate rich pytest reports automatically.
88
-
89
- [![🚀 Checkout on GitHub Marketplace](https://img.shields.io/badge/Marketplace-Pytest%20HTML%20Plus-blue?logo=github)](https://github.com/marketplace/actions/pytest-html-plus-action)
90
- [![Documentation](https://img.shields.io/badge/docs-readthedocs.io-brightgreen)](https://pytest-html-plus.readthedocs.io/en/main/marketplace/usage.html)
91
-
92
- ## Pytest HTML Plus VSCode
93
-
94
- [![VS Code Marketplace](https://img.shields.io/visual-studio-marketplace/v/reporterplus.pytest-html-plus-vscode?label=VS%20Code%20Marketplace&logo=visualstudiocode&logoColor=white&color=0078d7)](https://marketplace.visualstudio.com/items?itemName=reporterplus.pytest-html-plus-vscode)
95
- [![Installs](https://img.shields.io/visual-studio-marketplace/i/reporterplus.pytest-html-plus-vscode)]
96
- [![Docs](https://img.shields.io/badge/docs-online-blue)](https://pytest-html-plus.readthedocs.io/en/main/extensions/vscode/usage.html)
97
-
98
- ## ✨ Features
99
-
100
- #### 🧩 Seamless Combined XML Export to your favourite test management tools — No Plugins Needed
101
- Export a fully merged JUnit XML report effortlessly — no external tools or plugins required. (No More merge html additional plugins or steps in your YAML to feed xml reports)
102
-
103
- ✔ Links, logs, stdout/stderr, and even flaky history — all included
104
- ✔ Works out-of-the-box with your test management tools (like TestRail, XRay, Zephyr)
105
- ✔ Just one flag. No extra lines of code. Total traceability.
106
-
107
- ![ScreenRecording2025-07-06at11 38 21PM-ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/02da5cc9-7ef5-4a3a-a475-88907964a9c6)
108
-
109
- #### 🔄 Stop Guessing — See What's Breaking Your Flaky Tests
110
- Instantly see how your tests behave across retries — from failure to recovery. Spot patterns like cache issues, race conditions, and random crashes without the guesswork.
111
-
112
- ![ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/1f7e0cd8-d2f9-47fd-8909-6f12adf8a800)
113
-
114
- #### 🏷️ Tag your tests on the fly!
115
- With dynamic markers, you can assign tags like `api`, `critical`, or `slow` — or any custom label — at runtime using standard `pytest.mark.*`.
116
- No need for custom marker definitions. Perfect for smarter filtering, reporting, and analysis.
117
-
118
- ![ScreenRecording2025-07-12at10 15 33PM-ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/f000388f-cdbc-418d-829b-a54309b8ffc4)
119
-
120
- #### 📦 Ship reports with provenance 📜 — full run metadata included 📋 and copy-ready.
121
-
122
- ![ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/fa397d22-e40b-4e4a-9321-a2e88aea1c08)
123
-
124
- #### 📋⚡ Turn failure context into a single click — copy logs, traces, and errors instantly for your team.
125
-
126
- ![ezgif com-video-to-gif-converter (1)](https://github.com/user-attachments/assets/396e8cf6-862b-4619-82bf-81a8eae8e7b6)
127
-
128
- #### Easily track Untracked test scenarios
129
-
130
- ![ScreenRecording2025-06-29at1 06 02AM-ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/af40622f-f548-44a5-982b-344c74a65e13)
131
-
132
- #### 🔍 Universal Test Search + Smart Traceability
133
-
134
- Whether you're tracing coverage, investigating failures, or tracking unlinked test cases — this search has your back!
135
-
136
- Just start typing, and the dashboard will instantly filter tests by:
137
-
138
- ✅ Test names
139
-
140
- ✅ Linked issue or documentation IDs (JIRA, Testmo, Notion, etc.)
141
-
142
- ✅ Custom URLs or keywords present in linked references
143
-
144
- ✅ Error messages and trace snippets to quickly group related failures
145
-
146
- <img width="800" height="421" alt="new_search" src="https://github.com/user-attachments/assets/54858747-ab16-4d4f-baa9-0d651a1d8bac" />
147
-
148
-
149
- #### 📸 Screenshot Support: View screenshots directly in the report to understand failures faster.
150
-
151
- #### 📧 Email Test Reports: Send your reports via email effortlessly using SendGrid integration.
152
-
153
- ![Screenshot 2025-05-28 at 4 38 49 PM](https://github.com/user-attachments/assets/3f40e206-5dfd-45e9-a511-4dd206cf3318)
154
-
155
- #### 🐢 Spot Slow Tests: Highlights the slowest tests so you know where to optimize your suite.
156
-
157
- ![ScreenRecording2025-06-21at2 52 49PM-ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/b9760927-7c67-4bbf-b03d-e13964c727ee)
158
-
159
- #### 📝 Configurable output capture: Test logs, print() statements, stdout/stderr, and screenshots are automatically captured and embedded in the report. Use `--plus-output=failed-only` to omit captured stdout/stderr from passing tests and reduce report size; logger and screenshot behavior is unchanged.
160
-
161
- ![ezgif-744a5d34a4c46d](https://github.com/user-attachments/assets/209cd2c0-d33b-48ec-b58b-8c8991ce35be)
162
-
163
- ### Complete Feature List
164
-
165
- | Feature | Details |
166
- |---|---|
167
- | 📊 **Single-file HTML report** | Fully self-contained — no external CSS, JS, or image folders to archive |
168
- | 🔄 **Flaky test detection** | Detects tests that fail then pass on retry; shows full retry history |
169
- | 📸 **Automatic screenshots** | Selenium & Playwright screenshots captured and embedded with no conftest hooks |
170
- | 🧩 **JUnit XML export** | Merged XML output compatible with TestRail, Xray, and Zephyr (`--generate-xml`) |
171
- | 🔗 **Traceability links** | Attach Jira, Testmo, Notion, or any URL to a test; rendered and searchable in the report |
172
- | 🏷️ **Dynamic markers** | Tag tests at runtime with `pytest.mark.*` — no marker pre-registration needed |
173
- | 🔍 **Universal search** | Filter tests by name, issue ID, or any URL keyword in real time |
174
- | 🐢 **Slow test highlighting** | Slowest tests in the run automatically flagged |
175
- | 📋 **Copy-to-clipboard** | Copy test path, logs, trace, and errors in one click |
176
- | 📦 **Run metadata** | Branch, commit SHA, environment, and custom metadata embedded in the report header |
177
- | 📝 **Configurable stream capture** | Control captured stdout/stderr with `--plus-output`; logger and screenshot behavior remains unchanged |
178
- | ⚡ **xdist support** | Parallel runs with `pytest-xdist` produce a single merged report, no extra steps |
179
- | 🌐 **Auto-open report** | `--should-open-report` opens the report in your browser after a run (always / failed / never) |
180
- | 📄 **JSON report** | Raw JSON output (`--json-report`) for custom dashboards or post-processing |
181
- | 🔎 **Unlinked test detection** | Instantly filter tests that have no associated issue or documentation link |
182
- | ⚙️ **Reusable config profiles** | Define named profiles in `pyproject.toml` (`--profile=ci`) — no more repeated CLI flags |
183
- | 📱 **Mobile-friendly layout** | Report renders cleanly on any screen size |
184
- | 📧 **Email reports** | Send reports via SendGrid integration (`--send-email`) |
185
-
186
- ## Target Audience
187
-
188
- This plugin is aimed at those who are:
189
-
190
- - Tired of writing extra code just to generate reports or capture screenshots
191
-
192
- - Manually attaching logs or outputs to test results
193
-
194
- - Are frustrated with archiving folders full of assets, CSS, JS, and dashboards just to share test results.
195
-
196
- - Don't want to refactor existing test suites or tag everything with new decorators just to integrate with a reporting tool.
197
-
198
- - Prefer simplicity — a zero-config, zero code, lightweight report that still looks clean, useful, and polished.
199
-
200
- - Want "just enough" — not bare-bones plain text, not a full dashboard with database setup — just a portable HTML report that STILL supports features like links, screenshots, and markers.
201
-
202
- ## Project Status
203
-
204
- pytest-html-plus is stable and actively maintained, with its core reporting experience now well established. Future development will prioritize compatibility, reliability, bug fixes, and thoughtfully selected enhancements.
205
-
206
- We're also looking for co-maintainers to help review pull requests, triage issues, and keep the project healthy across future Python and pytest releases.
207
-
208
- If you're interested in becoming a long-term contributor, we'd love to hear from you. Please open an issue or start a discussion.
209
-
210
- ## Contributing
211
-
212
- We welcome pull requests, issues, and feature suggestions from the community.
213
-
214
- See the [contribution guide](CONTRIBUTING.md) for setup instructions.
215
-
216
- ## 📜 License
217
-
218
- MIT
219
-
@@ -1,185 +0,0 @@
1
- ⚡ **Test your code, not your reporting setup.**
2
- > _Get started with rich pytest reports in under 3 seconds. Just install — no setup required. The simplest, fastest reporter for pytest._
3
-
4
- ## Get a self-contained, actionable, easy-to-read single page HTML unified reports summarizing all your test results — no hassle, just clarity. Detect **flaky tests**, **attach screenshots** automatically without hooks and optionally send reports via email**. Works beautifully with or without `xdist`.
5
-
6
- ➡️ [View Demo Report](https://reporterplus.github.io/pytest-html-plus/)
7
-
8
- [![Docs](https://img.shields.io/badge/docs-online-blue)](https://pytest-html-plus.readthedocs.io/en/main/) [![PyPI Downloads](https://static.pepy.tech/badge/pytest-html-plus)](https://pepy.tech/projects/pytest-html-plus) ![PyPI](https://img.shields.io/pypi/v/pytest-html-plus) ![Python Versions](https://img.shields.io/pypi/pyversions/pytest-html-plus) ![License](https://img.shields.io/pypi/l/pytest-html-plus) [![Unit Tests](https://github.com/reporterplus/pytest-html-plus/actions/workflows/unit-test.yml/badge.svg)](https://github.com/reporterplus/pytest-html-plus/actions/workflows/unit-test.yml) [![codecov](https://codecov.io/gh/reporterplus/pytest-html-plus/branch/main/graph/badge.svg)](https://codecov.io/gh/reporterplus/pytest-html-plus)
9
-
10
- ---
11
-
12
- ## Already using pytest-html or Allure?
13
-
14
- No uninstall needed — `pytest-html-plus` works alongside `pytest-html`. Install it, run your suite, and see what you've been missing. Most teams uninstall `pytest-html` within the same day.
15
-
16
- ```bash
17
- pip install pytest-html-plus
18
- ```
19
-
20
- Your existing `pytest --html=report.html` commands keep working unchanged.
21
-
22
- | Feature | pytest-html | Allure | pytest-html-plus |
23
- |---|:---:|:---:|:---:|
24
- | Self-contained single HTML file | ✅ | ❌ | ✅ |
25
- | No server or CLI tool needed | ✅ | ❌ | ✅ |
26
- | Zero config — works out of the box | ✅ | ❌ | ✅ |
27
- | xdist parallel run support | ⚠️ extra plugin | ✅ | ✅ built-in |
28
- | Screenshots (no hooks or decorators) | ❌ | ❌ requires decorators | ✅ |
29
- | Automatic log & print() capture | ❌ | ✅ | ✅ |
30
- | Flaky test detection + retry history | ❌ | ✅ | ✅ |
31
- | Slow test highlighting | ❌ | ❌ | ✅ |
32
- | Traceability links (Jira, Testmo, etc.) | ❌ | ✅ | ✅ |
33
- | JUnit XML export (merged, one flag) | ❌ extra steps | ✅ | ✅ |
34
- | Run metadata (branch, commit, env) | ❌ | ✅ | ✅ |
35
- | Reusable config profiles | ❌ | ❌ | ✅ |
36
- | Unlinked test detection | ❌ | ❌ | ✅ |
37
- | Copy logs & traces to clipboard | ❌ | ❌ | ✅ |
38
- | Email reports | ❌ | ❌ | ✅ |
39
- | Mobile-friendly layout | ❌ | ✅ | ✅ |
40
- | Report size | 🟢 single file | 🔴 many files | 🟢 single file |
41
-
42
- ---
43
-
44
- ## 🚀 Installation
45
-
46
- ```bash
47
- pip install pytest-html-plus
48
- # or with Poetry
49
- poetry add pytest-html-plus
50
- ```
51
-
52
- ## Pytest HTML Plus Action
53
-
54
- If you don't want the burden of installing pytest-html-plus manually and your project already manages dependencies with `requirements.txt` or Poetry, use this GitHub Action to generate rich pytest reports automatically.
55
-
56
- [![🚀 Checkout on GitHub Marketplace](https://img.shields.io/badge/Marketplace-Pytest%20HTML%20Plus-blue?logo=github)](https://github.com/marketplace/actions/pytest-html-plus-action)
57
- [![Documentation](https://img.shields.io/badge/docs-readthedocs.io-brightgreen)](https://pytest-html-plus.readthedocs.io/en/main/marketplace/usage.html)
58
-
59
- ## Pytest HTML Plus VSCode
60
-
61
- [![VS Code Marketplace](https://img.shields.io/visual-studio-marketplace/v/reporterplus.pytest-html-plus-vscode?label=VS%20Code%20Marketplace&logo=visualstudiocode&logoColor=white&color=0078d7)](https://marketplace.visualstudio.com/items?itemName=reporterplus.pytest-html-plus-vscode)
62
- [![Installs](https://img.shields.io/visual-studio-marketplace/i/reporterplus.pytest-html-plus-vscode)]
63
- [![Docs](https://img.shields.io/badge/docs-online-blue)](https://pytest-html-plus.readthedocs.io/en/main/extensions/vscode/usage.html)
64
-
65
- ## ✨ Features
66
-
67
- #### 🧩 Seamless Combined XML Export to your favourite test management tools — No Plugins Needed
68
- Export a fully merged JUnit XML report effortlessly — no external tools or plugins required. (No More merge html additional plugins or steps in your YAML to feed xml reports)
69
-
70
- ✔ Links, logs, stdout/stderr, and even flaky history — all included
71
- ✔ Works out-of-the-box with your test management tools (like TestRail, XRay, Zephyr)
72
- ✔ Just one flag. No extra lines of code. Total traceability.
73
-
74
- ![ScreenRecording2025-07-06at11 38 21PM-ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/02da5cc9-7ef5-4a3a-a475-88907964a9c6)
75
-
76
- #### 🔄 Stop Guessing — See What's Breaking Your Flaky Tests
77
- Instantly see how your tests behave across retries — from failure to recovery. Spot patterns like cache issues, race conditions, and random crashes without the guesswork.
78
-
79
- ![ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/1f7e0cd8-d2f9-47fd-8909-6f12adf8a800)
80
-
81
- #### 🏷️ Tag your tests on the fly!
82
- With dynamic markers, you can assign tags like `api`, `critical`, or `slow` — or any custom label — at runtime using standard `pytest.mark.*`.
83
- No need for custom marker definitions. Perfect for smarter filtering, reporting, and analysis.
84
-
85
- ![ScreenRecording2025-07-12at10 15 33PM-ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/f000388f-cdbc-418d-829b-a54309b8ffc4)
86
-
87
- #### 📦 Ship reports with provenance 📜 — full run metadata included 📋 and copy-ready.
88
-
89
- ![ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/fa397d22-e40b-4e4a-9321-a2e88aea1c08)
90
-
91
- #### 📋⚡ Turn failure context into a single click — copy logs, traces, and errors instantly for your team.
92
-
93
- ![ezgif com-video-to-gif-converter (1)](https://github.com/user-attachments/assets/396e8cf6-862b-4619-82bf-81a8eae8e7b6)
94
-
95
- #### Easily track Untracked test scenarios
96
-
97
- ![ScreenRecording2025-06-29at1 06 02AM-ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/af40622f-f548-44a5-982b-344c74a65e13)
98
-
99
- #### 🔍 Universal Test Search + Smart Traceability
100
-
101
- Whether you're tracing coverage, investigating failures, or tracking unlinked test cases — this search has your back!
102
-
103
- Just start typing, and the dashboard will instantly filter tests by:
104
-
105
- ✅ Test names
106
-
107
- ✅ Linked issue or documentation IDs (JIRA, Testmo, Notion, etc.)
108
-
109
- ✅ Custom URLs or keywords present in linked references
110
-
111
- ✅ Error messages and trace snippets to quickly group related failures
112
-
113
- <img width="800" height="421" alt="new_search" src="https://github.com/user-attachments/assets/54858747-ab16-4d4f-baa9-0d651a1d8bac" />
114
-
115
-
116
- #### 📸 Screenshot Support: View screenshots directly in the report to understand failures faster.
117
-
118
- #### 📧 Email Test Reports: Send your reports via email effortlessly using SendGrid integration.
119
-
120
- ![Screenshot 2025-05-28 at 4 38 49 PM](https://github.com/user-attachments/assets/3f40e206-5dfd-45e9-a511-4dd206cf3318)
121
-
122
- #### 🐢 Spot Slow Tests: Highlights the slowest tests so you know where to optimize your suite.
123
-
124
- ![ScreenRecording2025-06-21at2 52 49PM-ezgif com-video-to-gif-converter](https://github.com/user-attachments/assets/b9760927-7c67-4bbf-b03d-e13964c727ee)
125
-
126
- #### 📝 Configurable output capture: Test logs, print() statements, stdout/stderr, and screenshots are automatically captured and embedded in the report. Use `--plus-output=failed-only` to omit captured stdout/stderr from passing tests and reduce report size; logger and screenshot behavior is unchanged.
127
-
128
- ![ezgif-744a5d34a4c46d](https://github.com/user-attachments/assets/209cd2c0-d33b-48ec-b58b-8c8991ce35be)
129
-
130
- ### Complete Feature List
131
-
132
- | Feature | Details |
133
- |---|---|
134
- | 📊 **Single-file HTML report** | Fully self-contained — no external CSS, JS, or image folders to archive |
135
- | 🔄 **Flaky test detection** | Detects tests that fail then pass on retry; shows full retry history |
136
- | 📸 **Automatic screenshots** | Selenium & Playwright screenshots captured and embedded with no conftest hooks |
137
- | 🧩 **JUnit XML export** | Merged XML output compatible with TestRail, Xray, and Zephyr (`--generate-xml`) |
138
- | 🔗 **Traceability links** | Attach Jira, Testmo, Notion, or any URL to a test; rendered and searchable in the report |
139
- | 🏷️ **Dynamic markers** | Tag tests at runtime with `pytest.mark.*` — no marker pre-registration needed |
140
- | 🔍 **Universal search** | Filter tests by name, issue ID, or any URL keyword in real time |
141
- | 🐢 **Slow test highlighting** | Slowest tests in the run automatically flagged |
142
- | 📋 **Copy-to-clipboard** | Copy test path, logs, trace, and errors in one click |
143
- | 📦 **Run metadata** | Branch, commit SHA, environment, and custom metadata embedded in the report header |
144
- | 📝 **Configurable stream capture** | Control captured stdout/stderr with `--plus-output`; logger and screenshot behavior remains unchanged |
145
- | ⚡ **xdist support** | Parallel runs with `pytest-xdist` produce a single merged report, no extra steps |
146
- | 🌐 **Auto-open report** | `--should-open-report` opens the report in your browser after a run (always / failed / never) |
147
- | 📄 **JSON report** | Raw JSON output (`--json-report`) for custom dashboards or post-processing |
148
- | 🔎 **Unlinked test detection** | Instantly filter tests that have no associated issue or documentation link |
149
- | ⚙️ **Reusable config profiles** | Define named profiles in `pyproject.toml` (`--profile=ci`) — no more repeated CLI flags |
150
- | 📱 **Mobile-friendly layout** | Report renders cleanly on any screen size |
151
- | 📧 **Email reports** | Send reports via SendGrid integration (`--send-email`) |
152
-
153
- ## Target Audience
154
-
155
- This plugin is aimed at those who are:
156
-
157
- - Tired of writing extra code just to generate reports or capture screenshots
158
-
159
- - Manually attaching logs or outputs to test results
160
-
161
- - Are frustrated with archiving folders full of assets, CSS, JS, and dashboards just to share test results.
162
-
163
- - Don't want to refactor existing test suites or tag everything with new decorators just to integrate with a reporting tool.
164
-
165
- - Prefer simplicity — a zero-config, zero code, lightweight report that still looks clean, useful, and polished.
166
-
167
- - Want "just enough" — not bare-bones plain text, not a full dashboard with database setup — just a portable HTML report that STILL supports features like links, screenshots, and markers.
168
-
169
- ## Project Status
170
-
171
- pytest-html-plus is stable and actively maintained, with its core reporting experience now well established. Future development will prioritize compatibility, reliability, bug fixes, and thoughtfully selected enhancements.
172
-
173
- We're also looking for co-maintainers to help review pull requests, triage issues, and keep the project healthy across future Python and pytest releases.
174
-
175
- If you're interested in becoming a long-term contributor, we'd love to hear from you. Please open an issue or start a discussion.
176
-
177
- ## Contributing
178
-
179
- We welcome pull requests, issues, and feature suggestions from the community.
180
-
181
- See the [contribution guide](CONTRIBUTING.md) for setup instructions.
182
-
183
- ## 📜 License
184
-
185
- MIT