Skip to content

Commit 55948d4

Browse files
committed
fix: Broken duration
1 parent 8523105 commit 55948d4

File tree

2 files changed

+45
-15
lines changed

2 files changed

+45
-15
lines changed

src/pytest_html/basereport.py

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import os
88
import re
99
import warnings
10+
from collections import defaultdict
1011
from pathlib import Path
1112

1213
import pytest
@@ -29,6 +30,7 @@ def __init__(self, report_path, config, report_data, template, css):
2930
config.getini("max_asset_filename_length")
3031
)
3132

33+
self._reports = defaultdict(dict)
3234
self._report = report_data
3335
self._report.title = self._report_path.name
3436

@@ -204,15 +206,50 @@ def pytest_runtest_logreport(self, report):
204206
DeprecationWarning,
205207
)
206208

209+
# "reruns" makes this code a mess.
210+
# We store each combination of when and outcome
211+
# exactly once, unless that outcome is a "rerun"
212+
# then we store all of them.
213+
key = (report.when, report.outcome)
214+
if report.outcome == "rerun":
215+
if key not in self._reports[report.nodeid]:
216+
self._reports[report.nodeid][key] = list()
217+
self._reports[report.nodeid][key].append(report)
218+
else:
219+
self._reports[report.nodeid][key] = [report]
220+
221+
self._report.total_duration += report.duration
222+
223+
finished = report.when == "teardown" and report.outcome != "rerun"
224+
if not finished:
225+
return
226+
227+
# Calculate total duration for a single test.
228+
# This is needed to add the "teardown" duration
229+
# to tests total duration.
230+
test_duration = 0
231+
for key, reports in self._reports[report.nodeid].items():
232+
_, outcome = key
233+
if outcome != "rerun":
234+
test_duration += reports[0].duration
235+
236+
for key, reports in self._reports[report.nodeid].items():
237+
when, _ = key
238+
for each in reports:
239+
dur = test_duration if when == "call" else each.duration
240+
self._process_report(each, dur)
241+
242+
self._generate_report()
243+
244+
def _process_report(self, report, duration):
207245
outcome = _process_outcome(report)
208246
try:
209247
# hook returns as list for some reason
210-
duration = self._config.hook.pytest_html_duration_format(
211-
duration=report.duration
248+
formatted_duration = self._config.hook.pytest_html_duration_format(
249+
duration=duration
212250
)[0]
213251
except IndexError:
214-
duration = _format_duration(report.duration)
215-
self._report.total_duration += report.duration
252+
formatted_duration = _format_duration(duration)
216253

217254
test_id = report.nodeid
218255
if report.when != "call":
@@ -229,7 +266,7 @@ def pytest_runtest_logreport(self, report):
229266
cells = [
230267
f'<td class="col-result">{outcome}</td>',
231268
f'<td class="col-testId">{test_id}</td>',
232-
f'<td class="col-duration">{duration}</td>',
269+
f'<td class="col-duration">{formatted_duration}</td>',
233270
f'<td class="col-links">{_process_links(links)}</td>',
234271
]
235272
self._config.hook.pytest_html_results_table_row(report=report, cells=cells)
@@ -240,17 +277,12 @@ def pytest_runtest_logreport(self, report):
240277
self._hydrate_data(data, cells)
241278
data["resultsTableRow"] = cells
242279

243-
# don't count passed setups and teardowns
244-
if not (report.when in ["setup", "teardown"] and report.outcome == "passed"):
245-
self._report.outcomes = outcome
246-
247280
processed_logs = _process_logs(report)
248281
self._config.hook.pytest_html_results_table_html(
249282
report=report, data=processed_logs
250283
)
251284

252-
if self._report.add_test(data, report, processed_logs):
253-
self._generate_report()
285+
self._report.add_test(data, report, outcome, processed_logs)
254286

255287

256288
def _format_duration(duration):

src/pytest_html/report_data.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def total_duration(self, duration):
127127
def set_data(self, key, value):
128128
self._data[key] = value
129129

130-
def add_test(self, test_data, report, logs):
130+
def add_test(self, test_data, report, outcome, logs):
131131
# regardless of pass or fail we must add teardown logging to "call"
132132
if report.when == "teardown":
133133
self.append_teardown_log(report)
@@ -137,10 +137,8 @@ def add_test(self, test_data, report, logs):
137137
report.when in ["setup", "teardown"] and report.outcome != "passed"
138138
):
139139
test_data["log"] = _handle_ansi("\n".join(logs))
140+
self.outcomes = outcome
140141
self._data["tests"][report.nodeid].append(test_data)
141-
return True
142-
143-
return False
144142

145143
def append_teardown_log(self, report):
146144
log = []

0 commit comments

Comments
 (0)