Skip to content

Commit 1bee989

Browse files
committed
Feature: Update json-data-blob (#704)
1 parent af4c653 commit 1bee989

File tree

6 files changed

+171
-118
lines changed

6 files changed

+171
-118
lines changed

src/pytest_html/basereport.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,17 @@ def _generate_report(self, self_contained=False):
5555
version=__version__,
5656
styles=self.css,
5757
run_count=self._run_count(),
58+
running_state=self._report.running_state,
5859
self_contained=self_contained,
59-
outcomes=self._report.data["outcomes"],
60+
outcomes=self._report.outcomes,
6061
test_data=test_data,
61-
table_head=self._report.data["resultsTableHeader"],
62-
prefix=self._report.data["additionalSummary"]["prefix"],
63-
summary=self._report.data["additionalSummary"]["summary"],
64-
postfix=self._report.data["additionalSummary"]["postfix"],
62+
table_head=self._report.table_header,
63+
additional_summary=self._report.additional_summary,
6564
)
6665

6766
self._write_report(rendered_report)
6867

69-
def _generate_environment(self, metadata_key):
68+
def _generate_environment(self):
7069
metadata = self._config.stash[metadata_key]
7170
for key in metadata.keys():
7271
value = metadata[key]
@@ -126,45 +125,42 @@ def _write_report(self, rendered_report):
126125
f.write(rendered_report)
127126

128127
def _run_count(self):
129-
data = self._report.data
130128
relevant_outcomes = ["passed", "failed", "xpassed", "xfailed"]
131129
counts = 0
132-
for outcome in data["outcomes"].keys():
130+
for outcome in self._report.outcomes.keys():
133131
if outcome in relevant_outcomes:
134-
counts += data["outcomes"][outcome]["value"]
132+
counts += self._report.outcomes[outcome]["value"]
135133

136134
plural = counts > 1
137-
duration = _format_duration(data["totalDuration"])
135+
duration = _format_duration(self._report.total_duration)
138136

139-
if data["runningState"].lower() == "finished":
137+
if self._report.running_state == "finished":
140138
return f"{counts} {'tests' if plural else 'test'} took {duration}."
141139

142-
return (
143-
f"{counts}/{data['collectedItems']} {'tests' if plural else 'test'} done."
144-
)
140+
return f"{counts}/{self._report.collected_items} {'tests' if plural else 'test'} done."
145141

146142
@pytest.hookimpl(trylast=True)
147143
def pytest_sessionstart(self, session):
148-
self._report.set_data("environment", self._generate_environment(metadata_key))
144+
self._report.set_data("environment", self._generate_environment())
149145

150146
session.config.hook.pytest_html_report_title(report=self._report)
151147

152-
headers = self._report.data["resultsTableHeader"]
148+
headers = self._report.table_header
153149
session.config.hook.pytest_html_results_table_header(cells=headers)
154-
self._report.data["resultsTableHeader"] = _fix_py(headers)
150+
self._report.table_header = _fix_py(headers)
155151

156-
self._report.set_data("runningState", "Started")
152+
self._report.running_state = "started"
157153
self._generate_report()
158154

159155
@pytest.hookimpl(trylast=True)
160156
def pytest_sessionfinish(self, session):
161157
session.config.hook.pytest_html_results_summary(
162-
prefix=self._report.data["additionalSummary"]["prefix"],
163-
summary=self._report.data["additionalSummary"]["summary"],
164-
postfix=self._report.data["additionalSummary"]["postfix"],
158+
prefix=self._report.additional_summary["prefix"],
159+
summary=self._report.additional_summary["summary"],
160+
postfix=self._report.additional_summary["postfix"],
165161
session=session,
166162
)
167-
self._report.set_data("runningState", "Finished")
163+
self._report.running_state = "finished"
168164
self._generate_report()
169165

170166
@pytest.hookimpl(trylast=True)
@@ -176,7 +172,7 @@ def pytest_terminal_summary(self, terminalreporter):
176172

177173
@pytest.hookimpl(trylast=True)
178174
def pytest_collection_finish(self, session):
179-
self._report.set_data("collectedItems", len(session.items))
175+
self._report.collected_items = len(session.items)
180176

181177
@pytest.hookimpl(trylast=True)
182178
def pytest_runtest_logreport(self, report):
@@ -191,7 +187,7 @@ def pytest_runtest_logreport(self, report):
191187
"result": outcome,
192188
"duration": _format_duration(report.duration),
193189
}
194-
self._report.data["totalDuration"] += report.duration
190+
self._report.total_duration += report.duration
195191

196192
test_id = report.nodeid
197193
if report.when != "call":
@@ -220,7 +216,7 @@ def pytest_runtest_logreport(self, report):
220216

221217
# don't count passed setups and teardowns
222218
if not (report.when in ["setup", "teardown"] and report.outcome == "passed"):
223-
self._report.data["outcomes"][outcome.lower()]["value"] += 1
219+
self._report.outcomes = outcome
224220

225221
processed_logs = _process_logs(report)
226222
self._config.hook.pytest_html_results_table_html(

src/pytest_html/report_data.py

Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ class ReportData:
1111
def __init__(self, config):
1212
self._config = config
1313

14-
default_headers = [
15-
'<th class="sortable" data-column-type="result">Result</th>',
16-
'<th class="sortable" data-column-type="testId">Test</th>',
17-
'<th class="sortable" data-column-type="duration">Duration</th>',
18-
"<th>Links</th>",
19-
]
14+
self._additional_summary = {
15+
"prefix": [],
16+
"summary": [],
17+
"postfix": [],
18+
}
2019

21-
outcomes = {
20+
self._collected_items = 0
21+
self._total_duration = 0
22+
self._running_state = "not_started"
23+
24+
self._outcomes = {
2225
"failed": {"label": "Failed", "value": 0},
2326
"passed": {"label": "Passed", "value": 0},
2427
"skipped": {"label": "Skipped", "value": 0},
@@ -28,15 +31,17 @@ def __init__(self, config):
2831
"rerun": {"label": "Reruns", "value": 0},
2932
}
3033

34+
self._results_table_header = [
35+
'<th class="sortable" data-column-type="result">Result</th>',
36+
'<th class="sortable" data-column-type="testId">Test</th>',
37+
'<th class="sortable" data-column-type="duration">Duration</th>',
38+
"<th>Links</th>",
39+
]
40+
3141
self._data = {
32-
"collectedItems": 0,
33-
"totalDuration": 0,
34-
"runningState": "not_started",
3542
"environment": {},
36-
"outcomes": outcomes,
3743
"tests": defaultdict(list),
38-
"additionalSummary": defaultdict(list),
39-
"resultsTableHeader": default_headers,
44+
"resultsTableRow": None,
4045
}
4146

4247
collapsed = config.getini("render_collapsed")
@@ -49,20 +54,28 @@ def __init__(self, config):
4954
)
5055
collapsed = "all"
5156

52-
self.set_data(
53-
"renderCollapsed", [outcome.lower() for outcome in collapsed.split(",")]
54-
)
57+
self._data["renderCollapsed"] = [
58+
outcome.lower() for outcome in collapsed.split(",")
59+
]
5560

5661
initial_sort = config.getini("initial_sort")
57-
self.set_data("initialSort", initial_sort)
62+
self._data["initialSort"] = initial_sort
5863

5964
@property
60-
def title(self):
61-
return self._data["title"]
65+
def additional_summary(self):
66+
return self._additional_summary
6267

63-
@title.setter
64-
def title(self, title):
65-
self._data["title"] = title
68+
@additional_summary.setter
69+
def additional_summary(self, value):
70+
self._additional_summary = value
71+
72+
@property
73+
def collected_items(self):
74+
return self._collected_items
75+
76+
@collected_items.setter
77+
def collected_items(self, count):
78+
self._collected_items = count
6679

6780
@property
6881
def config(self):
@@ -72,6 +85,46 @@ def config(self):
7285
def data(self):
7386
return self._data
7487

88+
@property
89+
def outcomes(self):
90+
return self._outcomes
91+
92+
@outcomes.setter
93+
def outcomes(self, outcome):
94+
self._outcomes[outcome.lower()]["value"] += 1
95+
96+
@property
97+
def running_state(self):
98+
return self._running_state
99+
100+
@running_state.setter
101+
def running_state(self, state):
102+
self._running_state = state
103+
104+
@property
105+
def table_header(self):
106+
return self._results_table_header
107+
108+
@table_header.setter
109+
def table_header(self, header):
110+
self._results_table_header = header
111+
112+
@property
113+
def title(self):
114+
return self._data["title"]
115+
116+
@title.setter
117+
def title(self, title):
118+
self._data["title"] = title
119+
120+
@property
121+
def total_duration(self):
122+
return self._total_duration
123+
124+
@total_duration.setter
125+
def total_duration(self, duration):
126+
self._total_duration = duration
127+
75128
def set_data(self, key, value):
76129
self._data[key] = value
77130

src/pytest_html/resources/index.jinja2

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,27 @@
2626
<td></td>
2727
</tr>
2828
</template>
29+
<template id="template_results-table__head">
30+
<thead id="results-table-head">
31+
<tr>
32+
{%- for th in table_head %}
33+
{{ th|safe }}
34+
{%- endfor %}
35+
</tr>
36+
</thead>
37+
</template>
38+
<template id="template_results-table__body--empty">
39+
<tbody class="results-table-row">
40+
<tr id="not-found-message">
41+
<td colspan="{{ table_head|length }}">No results found. Check the filters.</th>
42+
</tr>
43+
</template>
2944
<template id="template_results-table__tbody">
3045
<tbody class="results-table-row">
3146
<tr class="collapsible">
3247
</tr>
3348
<tr class="extras-row">
34-
<td class="extra" colspan="4">
49+
<td class="extra" colspan="{{ table_head|length }}">
3550
<div class="extraHTML"></div>
3651
<div class="media">
3752
<div class="media-container">
@@ -52,54 +67,46 @@
5267
</tr>
5368
</tbody>
5469
</template>
55-
<template id="template_results-table__head">
56-
<thead id="results-table-head">
57-
<tr>
58-
{%- for th in table_head %}
59-
{{ th|safe }}
60-
{%- endfor %}
61-
</tr>
62-
</thead>
63-
</template>
64-
<template id="template_results-table__head--empty">
65-
<tr id="not-found-message">
66-
<th colspan="4">No results found. Check the filters.</th>
67-
</tr>
68-
</template>
6970
<!-- END TEMPLATES -->
7071
<div class="summary">
7172
<div class="summary__data">
7273
<h2>Summary</h2>
73-
{%- for p in prefix %}
74-
{{ p|safe }}
75-
{%- endfor %}
74+
<div class="additional-summary prefix">
75+
{%- for p in additional_summary['prefix'] %}
76+
{{ p|safe }}
77+
{%- endfor %}
78+
</div>
7679
<p class="run-count">{{ run_count }}</p>
7780
<p class="filter">(Un)check the boxes to filter the results.</p>
7881
<div class="summary__reload">
79-
<div class="summary__reload__button {{'hidden' if 'took' in run_count}}" onclick="location.reload()">
82+
<div class="summary__reload__button {{ 'hidden' if running_state == 'finished' }}" onclick="location.reload()">
8083
<div>There are still tests running. <br />Reload this page to ge the latest results!</div>
8184
</div>
8285
</div>
8386
<div class="summary__spacer"></div>
84-
<div class="controls">
85-
<div class="filters">
86-
{%- for result, values in outcomes.items() %}
87-
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="{{ result }}" {{ "disabled" if values["value"] == 0 }}/>
88-
<span class="{{ result }}">{{ values["value"] }} {{ values["label"] }}{{ "," if result != "rerun" }}</span>
89-
{%- endfor %}
90-
</div>
91-
<div class="collapse">
92-
<button id="show_all_details">Show all details</button>&nbsp;/&nbsp;<button id="hide_all_details">Hide all details</button>
93-
<div>
87+
<div class="controls">
88+
<div class="filters">
89+
{%- for result, values in outcomes.items() %}
90+
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="{{ result }}" {{ "disabled" if values["value"] == 0 }}/>
91+
<span class="{{ result }}">{{ values["value"] }} {{ values["label"] }}{{ "," if result != "rerun" }}</span>
92+
{%- endfor %}
93+
</div>
94+
<div class="collapse">
95+
<button id="show_all_details">Show all details</button>&nbsp;/&nbsp;<button id="hide_all_details">Hide all details</button>
9496
</div>
9597
</div>
9698
</div>
97-
{%- for s in summary %}
98-
{{ s|safe }}
99-
{%- endfor %}
100-
{%- for p in postfix %}
101-
{{ p|safe }}
102-
{%- endfor %}
99+
<div class="additional-summary summary">
100+
{%- for s in additional_summary['summary'] %}
101+
{{ s|safe }}
102+
{%- endfor %}
103+
</div>
104+
<div class="additional-summary postfix">
105+
{%- for p in additional_summary['postfix'] %}
106+
{{ p|safe }}
107+
{%- endfor %}
108+
</div>
109+
</div>
103110
<table id="results-table"></table>
104111
</body>
105112
<footer>

src/pytest_html/scripts/dom.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const mediaViewer = require('./mediaviewer.js')
22
const templateEnvRow = document.getElementById('template_environment_row')
33
const templateResult = document.getElementById('template_results-table__tbody')
4-
const listHeaderEmpty = document.getElementById('template_results-table__head--empty')
54

65
function htmlToElements(html) {
76
const temp = document.createElement('template')
@@ -37,7 +36,6 @@ const dom = {
3736

3837
return envRow
3938
},
40-
getListHeaderEmpty: () => listHeaderEmpty.content.cloneNode(true),
4139
getResultTBody: ({ testId, id, log, duration, extras, resultsTableRow, tableHtml, result, collapsed }) => {
4240
const resultLower = result.toLowerCase()
4341
const resultBody = templateResult.content.cloneNode(true)

src/pytest_html/scripts/main.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,14 @@ const renderContent = (tests) => {
3838
removeChildren(table)
3939

4040
tableHeader.querySelector(`.sortable[data-column-type="${sortAttr}"]`)?.classList.add(sortAsc ? 'desc' : 'asc')
41+
table.appendChild(tableHeader)
4142
if (!rows.length) {
42-
tableHeader.appendChild(dom.getListHeaderEmpty())
43+
const emptyTable = document.getElementById('template_results-table__body--empty').content.cloneNode(true)
44+
table.appendChild(emptyTable)
4345
}
44-
table.appendChild(tableHeader)
4546

4647
rows.forEach((row) => !!row && table.appendChild(row))
4748

48-
table.querySelectorAll('.extra').forEach((item) => {
49-
item.colSpan = document.querySelectorAll('th').length
50-
})
51-
5249
findAll('.sortable').forEach((elem) => {
5350
elem.addEventListener('click', (evt) => {
5451
const { target: element } = evt

0 commit comments

Comments
 (0)