Fix: Broken sorting for custom columns (#715)

This commit is contained in:
Jim Brännlund 2023-08-24 22:08:21 +02:00 committed by GitHub
parent 5e3cca16ee
commit abde929fc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 78 additions and 13 deletions

View File

@ -149,6 +149,15 @@ class BaseReport:
return f"{counts}/{self._report.collected_items} {'tests' if plural else 'test'} done." return f"{counts}/{self._report.collected_items} {'tests' if plural else 'test'} done."
def _hydrate_data(self, data, cells):
for index, cell in enumerate(cells):
# extract column name and data if column is sortable
if "sortable" in self._report.table_header[index]:
name_match = re.search(r"col-(\w+)", cell)
data_match = re.search(r"<td.*?>(.*?)</td>", cell)
if name_match and data_match:
data[name_match.group(1)] = data_match.group(1)
@pytest.hookimpl(trylast=True) @pytest.hookimpl(trylast=True)
def pytest_sessionstart(self, session): def pytest_sessionstart(self, session):
self._report.set_data("environment", self._generate_environment()) self._report.set_data("environment", self._generate_environment())
@ -193,35 +202,33 @@ class BaseReport:
) )
outcome = _process_outcome(report) outcome = _process_outcome(report)
data = { duration = _format_duration(report.duration)
"result": outcome,
"duration": _format_duration(report.duration),
}
self._report.total_duration += report.duration self._report.total_duration += report.duration
test_id = report.nodeid test_id = report.nodeid
if report.when != "call": if report.when != "call":
test_id += f"::{report.when}" test_id += f"::{report.when}"
data["testId"] = test_id
data["extras"] = self._process_extras(report, test_id) data = {
"extras": self._process_extras(report, test_id),
}
links = [ links = [
extra extra
for extra in data["extras"] for extra in data["extras"]
if extra["format_type"] in ["json", "text", "url"] if extra["format_type"] in ["json", "text", "url"]
] ]
cells = [ cells = [
f'<td class="col-result">{data["result"]}</td>', f'<td class="col-result">{outcome}</td>',
f'<td class="col-name">{data["testId"]}</td>', f'<td class="col-testId">{test_id}</td>',
f'<td class="col-duration">{data["duration"]}</td>', f'<td class="col-duration">{duration}</td>',
f'<td class="col-links">{_process_links(links)}</td>', f'<td class="col-links">{_process_links(links)}</td>',
] ]
self._config.hook.pytest_html_results_table_row(report=report, cells=cells) self._config.hook.pytest_html_results_table_row(report=report, cells=cells)
if not cells: if not cells:
return return
cells = _fix_py(cells) cells = _fix_py(cells)
self._hydrate_data(data, cells)
data["resultsTableRow"] = cells data["resultsTableRow"] = cells
# don't count passed setups and teardowns # don't count passed setups and teardowns

View File

@ -41,7 +41,6 @@ class ReportData:
self._data = { self._data = {
"environment": {}, "environment": {},
"tests": defaultdict(list), "tests": defaultdict(list),
"resultsTableRow": None,
} }
collapsed = config.getini("render_collapsed") collapsed = config.getini("render_collapsed")

View File

@ -36,7 +36,7 @@ const dom = {
return envRow return envRow
}, },
getResultTBody: ({ testId, id, log, duration, extras, resultsTableRow, tableHtml, result, collapsed }) => { getResultTBody: ({ testId, id, log, extras, resultsTableRow, tableHtml, result, collapsed }) => {
const resultBody = templateResult.content.cloneNode(true) const resultBody = templateResult.content.cloneNode(true)
resultBody.querySelector('tbody').classList.add(result.toLowerCase()) resultBody.querySelector('tbody').classList.add(result.toLowerCase())
resultBody.querySelector('tbody').id = testId resultBody.querySelector('tbody').id = testId

View File

@ -54,6 +54,23 @@ def _encode_query_params(params):
return urllib.parse.urlencode(params) return urllib.parse.urlencode(params)
def _parse_result_table(driver):
table = driver.find_element(By.ID, "results-table")
headers = table.find_elements(By.CSS_SELECTOR, "thead th")
rows = table.find_elements(By.CSS_SELECTOR, "tbody tr.collapsible")
table_data = []
for row in rows:
data_dict = {}
cells = row.find_elements(By.TAG_NAME, "td")
for header, cell in zip(headers, cells):
data_dict[header.text.lower()] = cell.text
table_data.append(data_dict)
return table_data
def test_visible(pytester, path, driver): def test_visible(pytester, path, driver):
pytester.makepyfile( pytester.makepyfile(
""" """
@ -76,3 +93,45 @@ def test_visible(pytester, path, driver):
) )
result = driver.find_elements(By.CSS_SELECTOR, "tr.collapsible") result = driver.find_elements(By.CSS_SELECTOR, "tr.collapsible")
assert_that(result).is_length(0) assert_that(result).is_length(0)
def test_custom_sorting(pytester, path, driver):
pytester.makeconftest(
"""
def pytest_html_results_table_header(cells):
cells.append(
'<th class="sortable alpha" data-column-type="alpha">Alpha</th>'
)
def pytest_html_results_table_row(report, cells):
data = report.nodeid.split("_")[-1]
cells.append(f'<td class="col-alpha">{data}</td>')
"""
)
pytester.makepyfile(
"""
def test_AAA(): pass
def test_BBB(): pass
"""
)
query_params = _encode_query_params({"sort": "alpha"})
driver.get(f"file:///reports{path()}?{query_params}")
WebDriverWait(driver, 5).until(
ec.visibility_of_all_elements_located((By.CSS_SELECTOR, "#results-table"))
)
rows = _parse_result_table(driver)
assert_that(rows).is_length(2)
assert_that(rows[0]["test"]).contains("AAA")
assert_that(rows[0]["alpha"]).is_equal_to("AAA")
assert_that(rows[1]["test"]).contains("BBB")
assert_that(rows[1]["alpha"]).is_equal_to("BBB")
driver.find_element(By.CSS_SELECTOR, "th[data-column-type='alpha']").click()
# we might need some wait here to ensure sorting happened
rows = _parse_result_table(driver)
assert_that(rows).is_length(2)
assert_that(rows[0]["test"]).contains("BBB")
assert_that(rows[0]["alpha"]).is_equal_to("BBB")
assert_that(rows[1]["test"]).contains("AAA")
assert_that(rows[1]["alpha"]).is_equal_to("AAA")

View File

@ -358,7 +358,7 @@ class TestHTML:
page = run(pytester) page = run(pytester)
assert_results(page, error=1, total_tests=0) assert_results(page, error=1, total_tests=0)
col_name = get_text(page, "td[class='col-name']") col_name = get_text(page, "td[class='col-testId']")
assert_that(col_name).contains("::setup") assert_that(col_name).contains("::setup")
assert_that(get_log(page)).contains("ValueError") assert_that(get_log(page)).contains("ValueError")