From e8bd795f8cdb7a1d40f843f5d78f3f7b551dd978 Mon Sep 17 00:00:00 2001 From: Memet Bilgin Date: Sat, 27 Jun 2020 20:44:20 +1000 Subject: [PATCH 1/6] enhance html output structure to allow for easier styling content will be created with the following document structure: body .content .content-header h1 .content-environment .content-summary .content-results #results-container Javascript for dealing with table interactivity has been updated to use container id instead of relying on appending as final element of body. --- pytest_html/plugin.py | 41 +++++++++++++++++++++-------------- pytest_html/resources/main.js | 2 +- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/pytest_html/plugin.py b/pytest_html/plugin.py index b92236a9..5133efa7 100644 --- a/pytest_html/plugin.py +++ b/pytest_html/plugin.py @@ -524,29 +524,38 @@ def generate_summary_item(self): session.config.hook.pytest_html_report_title(report=self) + summary_prefix, summary_postfix = [], [] + session.config.hook.pytest_html_results_summary( + prefix=summary_prefix, summary=summary, postfix=summary_postfix + ) + summary = [html.h2("Summary"), *summary_prefix, *summary, *summary_postfix] + body = html.body( html.script(raw(main_js)), - html.h1(self.title), - html.p( - "Report generated on {} at {} by ".format( - generated.strftime("%d-%b-%Y"), generated.strftime("%H:%M:%S") + html.div( + html.div( + html.h1(self.title), + html.p( + "Report generated on {} at {} by ".format( + generated.strftime("%d-%b-%Y"), + generated.strftime("%H:%M:%S"), + ), + html.a("pytest-html", href=__pypi_url__), + f" v{__version__}", + ), + html.div( + *self._generate_environment(session.config), + class_="content-environment", + ), + html.div(*summary, class_="content-summary"), + class_="content-header", ), - html.a("pytest-html", href=__pypi_url__), - f" v{__version__}", + html.div(*results, class_="content-results", id="results-container"), + class_="content", ), onLoad="init()", ) - body.extend(self._generate_environment(session.config)) - - summary_prefix, summary_postfix = [], [] - session.config.hook.pytest_html_results_summary( - prefix=summary_prefix, summary=summary, postfix=summary_postfix - ) - body.extend([html.h2("Summary")] + summary_prefix + summary + summary_postfix) - - body.extend(results) - doc = html.html(head, body) unicode_doc = "\n{}".format(doc.unicode(indent=2)) diff --git a/pytest_html/resources/main.js b/pytest_html/resources/main.js index d2be8b8a..e4c04793 100644 --- a/pytest_html/resources/main.js +++ b/pytest_html/resources/main.js @@ -139,7 +139,7 @@ function sort_table(clicked, key_func) { sorted_rows.forEach(function(elem) { parent.appendChild(elem); }); - document.getElementsByTagName("BODY")[0].appendChild(parent); + document.getElementById("results-container").appendChild(parent); } function sort(items, key_func, reversed) { From 8c9704508002af6b84e27497eb11ba680c446545 Mon Sep 17 00:00:00 2001 From: Memet Bilgin Date: Sat, 27 Jun 2020 23:36:22 +1000 Subject: [PATCH 2/6] hook point for inspecting/modifying dom output prior to finalization --- pytest_html/hooks.py | 6 ++++++ pytest_html/plugin.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/pytest_html/hooks.py b/pytest_html/hooks.py index 7b75120b..0483cd6f 100644 --- a/pytest_html/hooks.py +++ b/pytest_html/hooks.py @@ -2,6 +2,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +from py.xml import html + def pytest_html_report_title(report): """ Called before adding the title to the report """ @@ -21,3 +23,7 @@ def pytest_html_results_table_row(report, cells): def pytest_html_results_table_html(report, data): """ Called after building results table additional HTML. """ + + +def pytest_html_report_final_dom(document: html.html): + """ Called after the entire document has been created. """ diff --git a/pytest_html/plugin.py b/pytest_html/plugin.py index 5133efa7..74b57b42 100644 --- a/pytest_html/plugin.py +++ b/pytest_html/plugin.py @@ -558,6 +558,8 @@ def generate_summary_item(self): doc = html.html(head, body) + session.config.hook.pytest_html_report_final_dom(document=doc) + unicode_doc = "\n{}".format(doc.unicode(indent=2)) # Fix encoding issues, e.g. with surrogates From b062c66e8ff3381fa449d2e6228991ecbd2d115b Mon Sep 17 00:00:00 2001 From: Memet Bilgin Date: Sun, 28 Jun 2020 00:00:09 +1000 Subject: [PATCH 3/6] remove type hints for backward compatibility --- pytest_html/hooks.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pytest_html/hooks.py b/pytest_html/hooks.py index 0483cd6f..9e39d41a 100644 --- a/pytest_html/hooks.py +++ b/pytest_html/hooks.py @@ -2,8 +2,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from py.xml import html - def pytest_html_report_title(report): """ Called before adding the title to the report """ @@ -25,5 +23,5 @@ def pytest_html_results_table_html(report, data): """ Called after building results table additional HTML. """ -def pytest_html_report_final_dom(document: html.html): +def pytest_html_report_final_dom(document): """ Called after the entire document has been created. """ From 1473ea8ae04ab9a12a38cfcba5fc7578774a83e7 Mon Sep 17 00:00:00 2001 From: Memet Bilgin Date: Sun, 28 Jun 2020 15:48:17 +1000 Subject: [PATCH 4/6] update qunit test fixture to include results-container element --- testing/js_test_report.html | 94 +++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/testing/js_test_report.html b/testing/js_test_report.html index a4a9e309..6a0b72cb 100644 --- a/testing/js_test_report.html +++ b/testing/js_test_report.html @@ -14,51 +14,53 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ResultTestDurationLinks
Rerunrerun.py::test_rexample_11.00
-
@pytest.mark.flaky(reruns=5)
def test_example():
import random
> assert random.choice([True, False])
E assert False
E + where False = <bound method Random.choice of <random.Random object at 0x7fe80b85f420>>([True, False])
E + where <bound method Random.choice of <random.Random object at 0x7fe80b85f420>> = <module 'random' from '/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/random.pyc'>.choice

rerun.py:6: AssertionError
Passedrerun.py::test_example_20.00
-
No log output captured.
-
Passedrerun.py::test_example_30.00
-
No log output captured.
-
-
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ResultTestDurationLinks
Rerunrerun.py::test_rexample_11.00
+
@pytest.mark.flaky(reruns=5)
def test_example():
import random
> assert random.choice([True, False])
E assert False
E + where False = <bound method Random.choice of <random.Random object at 0x7fe80b85f420>>([True, False])
E + where <bound method Random.choice of <random.Random object at 0x7fe80b85f420>> = <module 'random' from '/usr/local/Cellar/python/2.7.12/Frameworks/Python.framework/Versions/2.7/lib/python2.7/random.pyc'>.choice

rerun.py:6: AssertionError
Passedrerun.py::test_example_20.00
+
No log output captured.
+
Passedrerun.py::test_example_30.00
+
No log output captured.
+
+
+ From efa8c40664642dcd3e0cac0533cc9844979cf48f Mon Sep 17 00:00:00 2001 From: Memet Bilgin Date: Sun, 28 Jun 2020 19:25:12 +1000 Subject: [PATCH 5/6] add documentation and sample for dom finalization hook --- README.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.rst b/README.rst index 449cd815..49b6bc12 100644 --- a/README.rst +++ b/README.rst @@ -259,6 +259,27 @@ additional HTML and log output with a notice that the log is empty: del data[:] data.append(html.div('No log output captured.', class_='empty log')) +Modifying the whole test document +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Finally, for major customizations, you may manipulate and update the resulting +html document prior to finalization by hooking :code:`pytest_html_report_final_dom`. + +.. code-block:: python + + import pytest + + def pytest_html_report_final_dom(document): + from importlib.resources import read_text + js = read_text(".", "fancy.js") + for node in list(iter(document)): + if isinstance(node, html.head): + node.extend([html.script(raw(js), type="text/javascript")]) + + + + + Display options --------------- From 249b0d845f1f0088b3c2f5bbcd2b836e936fe92f Mon Sep 17 00:00:00 2001 From: Memet Bilgin Date: Mon, 29 Jun 2020 14:30:50 +1000 Subject: [PATCH 6/6] add session to dom finalization hook to give proper global state --- README.rst | 3 ++- pytest_html/hooks.py | 2 +- pytest_html/plugin.py | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 49b6bc12..12b94c16 100644 --- a/README.rst +++ b/README.rst @@ -269,7 +269,8 @@ html document prior to finalization by hooking :code:`pytest_html_report_final_d import pytest - def pytest_html_report_final_dom(document): + def pytest_html_report_final_dom(session, document): + # session is a `_pytest.main.Session` object from importlib.resources import read_text js = read_text(".", "fancy.js") for node in list(iter(document)): diff --git a/pytest_html/hooks.py b/pytest_html/hooks.py index 9e39d41a..7fe435e9 100644 --- a/pytest_html/hooks.py +++ b/pytest_html/hooks.py @@ -23,5 +23,5 @@ def pytest_html_results_table_html(report, data): """ Called after building results table additional HTML. """ -def pytest_html_report_final_dom(document): +def pytest_html_report_final_dom(session, document): """ Called after the entire document has been created. """ diff --git a/pytest_html/plugin.py b/pytest_html/plugin.py index 74b57b42..48186127 100644 --- a/pytest_html/plugin.py +++ b/pytest_html/plugin.py @@ -558,7 +558,7 @@ def generate_summary_item(self): doc = html.html(head, body) - session.config.hook.pytest_html_report_final_dom(document=doc) + session.config.hook.pytest_html_report_final_dom(session=session, document=doc) unicode_doc = "\n{}".format(doc.unicode(indent=2))