fix: Table hooks (#599)
This commit is contained in:
parent
079681decc
commit
40a80d535d
|
@ -197,20 +197,17 @@ adds a sortable time column, and removes the links column:
|
|||
.. code-block:: python
|
||||
|
||||
from datetime import datetime
|
||||
from py.xml import html
|
||||
import pytest
|
||||
|
||||
|
||||
def pytest_html_results_table_header(cells):
|
||||
cells.insert(2, html.th("Description"))
|
||||
cells.insert(1, html.th("Time", class_="sortable time", col="time"))
|
||||
cells.pop()
|
||||
cells.insert(2, "<th>Description</th>")
|
||||
cells.insert(1, '<th class="sortable time" data-column-type="time">Time</th>')
|
||||
|
||||
|
||||
def pytest_html_results_table_row(report, cells):
|
||||
cells.insert(2, html.td(report.description))
|
||||
cells.insert(1, html.td(datetime.utcnow(), class_="col-time"))
|
||||
cells.pop()
|
||||
cells.insert(2, "<td>A description</td>")
|
||||
cells.insert(1, '<td class="col-time">A time</td>')
|
||||
|
||||
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
|
|
|
@ -37,11 +37,25 @@ class BaseReport:
|
|||
def __init__(self):
|
||||
self._html = {}
|
||||
|
||||
def __delitem__(self, key):
|
||||
# This means the item should be removed
|
||||
self._html = None
|
||||
|
||||
@property
|
||||
def html(self):
|
||||
return self._html
|
||||
|
||||
def insert(self, index, html):
|
||||
# backwards-compat
|
||||
if not isinstance(html, str):
|
||||
if html.__module__.startswith("py."):
|
||||
warnings.warn(
|
||||
"The 'py' module is deprecated and support "
|
||||
"will be removed in a future release.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
html = str(html)
|
||||
html = html.replace("col", "data-column-type")
|
||||
self._html[index] = html
|
||||
|
||||
class Report:
|
||||
|
@ -219,6 +233,7 @@ class BaseReport:
|
|||
|
||||
header_cells = self.Cells()
|
||||
session.config.hook.pytest_html_results_table_header(cells=header_cells)
|
||||
|
||||
self._report.set_data("resultsTableHeader", header_cells.html)
|
||||
|
||||
self._report.set_data("runningState", "Started")
|
||||
|
@ -258,25 +273,30 @@ class BaseReport:
|
|||
}
|
||||
|
||||
test_id = report.nodeid
|
||||
if report.when != "call":
|
||||
if report.when == "call":
|
||||
row_cells = self.Cells()
|
||||
self._config.hook.pytest_html_results_table_row(
|
||||
report=report, cells=row_cells
|
||||
)
|
||||
if row_cells.html is None:
|
||||
return
|
||||
data["resultsTableRow"] = row_cells.html
|
||||
|
||||
table_html = []
|
||||
self._config.hook.pytest_html_results_table_html(
|
||||
report=report, data=table_html
|
||||
)
|
||||
data["tableHtml"] = table_html
|
||||
else:
|
||||
test_id += f"::{report.when}"
|
||||
data["testId"] = test_id
|
||||
|
||||
# Order here matters!
|
||||
log = report.longreprtext or report.capstdout or "No log output captured."
|
||||
data["log"] = _handle_ansi(log)
|
||||
|
||||
data["result"] = _process_outcome(report)
|
||||
|
||||
row_cells = self.Cells()
|
||||
self._config.hook.pytest_html_results_table_row(report=report, cells=row_cells)
|
||||
data["resultsTableRow"] = row_cells.html
|
||||
|
||||
table_html = []
|
||||
self._config.hook.pytest_html_results_table_html(report=report, data=table_html)
|
||||
data["tableHtml"] = table_html
|
||||
|
||||
data["extras"] = self._process_extras(report, test_id)
|
||||
|
||||
self._report.add_test(data)
|
||||
self._generate_report()
|
||||
|
||||
|
|
|
@ -52,7 +52,21 @@ const dom = {
|
|||
const header = listHeader.content.cloneNode(true)
|
||||
const sortAttr = storageModule.getSort()
|
||||
const sortAsc = JSON.parse(storageModule.getSortDirection())
|
||||
const sortables = ['result', 'testId', 'duration']
|
||||
|
||||
const regex = /data-column-type="(\w+)/
|
||||
const cols = Object.values(resultsTableHeader).reduce((result, value) => {
|
||||
if (value.includes("sortable")) {
|
||||
const matches = regex.exec(value)
|
||||
if (matches) {
|
||||
result.push(matches[1])
|
||||
}
|
||||
}
|
||||
return result
|
||||
}, [])
|
||||
const sortables = ['result', 'testId', 'duration', ...cols]
|
||||
|
||||
// Add custom html from the pytest_html_results_table_header hook
|
||||
insertAdditionalHTML(resultsTableHeader, header, 'th')
|
||||
|
||||
sortables.forEach((sortCol) => {
|
||||
if (sortCol === sortAttr) {
|
||||
|
@ -60,9 +74,6 @@ const dom = {
|
|||
}
|
||||
})
|
||||
|
||||
// Add custom html from the pytest_html_results_table_header hook
|
||||
insertAdditionalHTML(resultsTableHeader, header, 'th')
|
||||
|
||||
return header
|
||||
},
|
||||
getListHeaderEmpty: () => listHeaderEmpty.content.cloneNode(true),
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
const possibleFiltes = ['passed', 'skipped', 'failed', 'error', 'xfailed', 'xpassed', 'rerun']
|
||||
const possibleFilters = ['passed', 'skipped', 'failed', 'error', 'xfailed', 'xpassed', 'rerun']
|
||||
|
||||
const getVisible = () => {
|
||||
const url = new URL(window.location.href)
|
||||
const settings = new URLSearchParams(url.search).get('visible') || ''
|
||||
return settings ?
|
||||
[...new Set(settings.split(',').filter((filter) => possibleFiltes.includes(filter)))] : possibleFiltes
|
||||
[...new Set(settings.split(',').filter((filter) => possibleFilters.includes(filter)))] : possibleFilters
|
||||
}
|
||||
const hideCategory = (categoryToHide) => {
|
||||
const url = new URL(window.location.href)
|
||||
const visibleParams = new URLSearchParams(url.search).get('visible')
|
||||
const currentVisible = visibleParams ? visibleParams.split(',') : [...possibleFiltes]
|
||||
const currentVisible = visibleParams ? visibleParams.split(',') : [...possibleFilters]
|
||||
const settings = [...new Set(currentVisible)].filter((f) => f !== categoryToHide).join(',')
|
||||
|
||||
url.searchParams.set('visible', settings)
|
||||
|
@ -21,15 +21,15 @@ const showCategory = (categoryToShow) => {
|
|||
return
|
||||
}
|
||||
const url = new URL(window.location.href)
|
||||
const currentVisible = new URLSearchParams(url.search).get('visible')?.split(',') || [...possibleFiltes]
|
||||
const currentVisible = new URLSearchParams(url.search).get('visible')?.split(',') || [...possibleFilters]
|
||||
const settings = [...new Set([categoryToShow, ...currentVisible])]
|
||||
const noFilter = possibleFiltes.length === settings.length || !settings.length
|
||||
const noFilter = possibleFilters.length === settings.length || !settings.length
|
||||
|
||||
noFilter ? url.searchParams.delete('visible') : url.searchParams.set('visible', settings.join(','))
|
||||
history.pushState({}, null, unescape(url.href))
|
||||
}
|
||||
const setFilter = (currentFilter) => {
|
||||
if (!possibleFiltes.includes(currentFilter)) {
|
||||
if (!possibleFilters.includes(currentFilter)) {
|
||||
return
|
||||
}
|
||||
const url = new URL(window.location.href)
|
||||
|
|
|
@ -33,7 +33,6 @@ def run(pytester, path="report.html", *args):
|
|||
chrome_options = webdriver.ChromeOptions()
|
||||
chrome_options.add_argument("--headless")
|
||||
chrome_options.add_argument("--window-size=1920x1080")
|
||||
# chrome_options.add_argument("--allow-file-access-from-files")
|
||||
driver = webdriver.Remote(
|
||||
command_executor="http://127.0.0.1:4444", options=chrome_options
|
||||
)
|
||||
|
@ -476,3 +475,55 @@ class TestHTML:
|
|||
pytester.makepyfile("def test_xdist(): pass")
|
||||
page = run(pytester, "report.html", "-n1")
|
||||
assert_results(page, passed=1)
|
||||
|
||||
def test_results_table_hook_insert(self, pytester):
|
||||
header_selector = (
|
||||
".summary #results-table-head tr:nth-child(1) th:nth-child({})"
|
||||
)
|
||||
row_selector = ".summary #results-table tr:nth-child(1) td:nth-child({})"
|
||||
|
||||
pytester.makeconftest(
|
||||
"""
|
||||
def pytest_html_results_table_header(cells):
|
||||
cells.insert(2, "<th>Description</th>")
|
||||
cells.insert(
|
||||
1,
|
||||
'<th class="sortable time" data-column-type="time">Time</th>'
|
||||
)
|
||||
|
||||
def pytest_html_results_table_row(report, cells):
|
||||
cells.insert(2, "<td>A description</td>")
|
||||
cells.insert(1, '<td class="col-time">A time</td>')
|
||||
"""
|
||||
)
|
||||
pytester.makepyfile("def test_pass(): pass")
|
||||
page = run(pytester)
|
||||
|
||||
assert_that(get_text(page, header_selector.format(2))).is_equal_to("Time")
|
||||
assert_that(get_text(page, header_selector.format(3))).is_equal_to(
|
||||
"Description"
|
||||
)
|
||||
|
||||
assert_that(get_text(page, row_selector.format(2))).is_equal_to("A time")
|
||||
assert_that(get_text(page, row_selector.format(3))).is_equal_to("A description")
|
||||
|
||||
def test_results_table_hook_delete(self, pytester):
|
||||
pytester.makeconftest(
|
||||
"""
|
||||
def pytest_html_results_table_row(report, cells):
|
||||
if report.skipped:
|
||||
del cells[:]
|
||||
"""
|
||||
)
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
def test_skip():
|
||||
pytest.skip('reason')
|
||||
|
||||
def test_pass(): pass
|
||||
|
||||
"""
|
||||
)
|
||||
page = run(pytester)
|
||||
assert_results(page, passed=1)
|
||||
|
|
Loading…
Reference in New Issue