Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Borken HTML in jinja template #712

Merged
merged 1 commit into from
Aug 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 41 additions & 34 deletions src/pytest_html/resources/index.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,27 @@
<td></td>
</tr>
</template>
<template id="template_results-table__head">
<thead id="results-table-head">
<tr>
{%- for th in table_head %}
{{ th|safe }}
{%- endfor %}
</tr>
</thead>
</template>
<template id="template_results-table__body--empty">
<tbody class="results-table-row">
<tr id="not-found-message">
<td colspan="{{ table_head|length }}">No results found. Check the filters.</th>
</tr>
</template>
<template id="template_results-table__tbody">
<tbody class="results-table-row">
<tr class="collapsible">
</tr>
<tr class="extras-row">
<td class="extra" colspan="4">
<td class="extra" colspan="{{ table_head|length }}">
<div class="extraHTML"></div>
<div class="media">
<div class="media-container">
Expand All @@ -52,27 +67,15 @@
</tr>
</tbody>
</template>
<template id="template_results-table__head">
<thead id="results-table-head">
<tr>
{%- for th in table_head %}
{{ th|safe }}
{%- endfor %}
</tr>
</thead>
</template>
<template id="template_results-table__head--empty">
<tr id="not-found-message">
<th colspan="4">No results found. Check the filters.</th>
</tr>
</template>
<!-- END TEMPLATES -->
<div class="summary">
<div class="summary__data">
<h2>Summary</h2>
{%- for p in additional_summary['prefix'] %}
{{ p|safe }}
{%- endfor %}
<div class="additional-summary prefix">
{%- for p in additional_summary['prefix'] %}
{{ p|safe }}
{%- endfor %}
</div>
<p class="run-count">{{ run_count }}</p>
<p class="filter">(Un)check the boxes to filter the results.</p>
<div class="summary__reload">
Expand All @@ -81,25 +84,29 @@
</div>
</div>
<div class="summary__spacer"></div>
<div class="controls">
<div class="filters">
{%- for result, values in outcomes.items() %}
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="{{ result }}" {{ "disabled" if values["value"] == 0 }}/>
<span class="{{ result }}">{{ values["value"] }} {{ values["label"] }}{{ "," if result != "rerun" }}</span>
{%- endfor %}
</div>
<div class="collapse">
<button id="show_all_details">Show all details</button>&nbsp;/&nbsp;<button id="hide_all_details">Hide all details</button>
<div>
<div class="controls">
<div class="filters">
{%- for result, values in outcomes.items() %}
<input checked="true" class="filter" name="filter_checkbox" type="checkbox" data-test-result="{{ result }}" {{ "disabled" if values["value"] == 0 }}/>
<span class="{{ result }}">{{ values["value"] }} {{ values["label"] }}{{ "," if result != "rerun" }}</span>
{%- endfor %}
</div>
<div class="collapse">
<button id="show_all_details">Show all details</button>&nbsp;/&nbsp;<button id="hide_all_details">Hide all details</button>
</div>
</div>
</div>
{%- for s in additional_summary['summary'] %}
{{ s|safe }}
{%- endfor %}
{%- for p in additional_summary['postfix'] %}
{{ p|safe }}
{%- endfor %}
<div class="additional-summary summary">
{%- for s in additional_summary['summary'] %}
{{ s|safe }}
{%- endfor %}
</div>
<div class="additional-summary postfix">
{%- for p in additional_summary['postfix'] %}
{{ p|safe }}
{%- endfor %}
</div>
</div>
<table id="results-table"></table>
</body>
<footer>
Expand Down
2 changes: 0 additions & 2 deletions src/pytest_html/scripts/dom.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const mediaViewer = require('./mediaviewer.js')
const templateEnvRow = document.getElementById('template_environment_row')
const templateResult = document.getElementById('template_results-table__tbody')
const listHeaderEmpty = document.getElementById('template_results-table__head--empty')

function htmlToElements(html) {
const temp = document.createElement('template')
Expand Down Expand Up @@ -37,7 +36,6 @@ const dom = {

return envRow
},
getListHeaderEmpty: () => listHeaderEmpty.content.cloneNode(true),
getResultTBody: ({ testId, id, log, duration, extras, resultsTableRow, tableHtml, result, collapsed }) => {
const resultLower = result.toLowerCase()
const resultBody = templateResult.content.cloneNode(true)
Expand Down
9 changes: 3 additions & 6 deletions src/pytest_html/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,14 @@ const renderContent = (tests) => {
removeChildren(table)

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

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

table.querySelectorAll('.extra').forEach((item) => {
item.colSpan = document.querySelectorAll('th').length
})

findAll('.sortable').forEach((elem) => {
elem.addEventListener('click', (evt) => {
const { target: element } = evt
Expand Down
58 changes: 30 additions & 28 deletions testing/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,13 @@ def run(pytester, path="report.html", cmd_flags=None, query_params=None):
# End workaround

driver.get(f"file:///reports{path}?{query_params}")
return BeautifulSoup(driver.page_source, "html.parser")
soup = BeautifulSoup(driver.page_source, "html.parser")

# remove all templates as they bork the BS parsing
for template in soup("template"):
template.decompose()

return soup
finally:
driver.quit()

Expand Down Expand Up @@ -88,15 +94,15 @@ def get_text(page, selector):


def is_collapsed(page, test_name):
return get_element(page, f".summary tbody[id$='{test_name}'] .collapsed")
return get_element(page, f"tbody[id$='{test_name}'] .collapsed")


def get_log(page, test_id=None):
# TODO(jim) move to get_text (use .contents)
if test_id:
log = get_element(page, f".summary tbody[id$='{test_id}'] div[class='log']")
log = get_element(page, f"tbody[id$='{test_id}'] div[class='log']")
else:
log = get_element(page, ".summary div[class='log']")
log = get_element(page, "div[class='log']")
all_text = ""
for text in log.strings:
all_text += text
Expand Down Expand Up @@ -195,7 +201,7 @@ def test_skip():
page = run(pytester)
assert_results(page, skipped=1, total_tests=0)

log = get_text(page, ".summary div[class='log']")
log = get_text(page, "div[class='log']")
assert_that(log).contains(reason)

def test_skip_function_marker(self, pytester):
Expand All @@ -211,7 +217,7 @@ def test_skip():
page = run(pytester)
assert_results(page, skipped=1, total_tests=0)

log = get_text(page, ".summary div[class='log']")
log = get_text(page, "div[class='log']")
assert_that(log).contains(reason)

def test_skip_class_marker(self, pytester):
Expand All @@ -228,15 +234,15 @@ def test_skip():
page = run(pytester)
assert_results(page, skipped=1, total_tests=0)

log = get_text(page, ".summary div[class='log']")
log = get_text(page, "div[class='log']")
assert_that(log).contains(reason)

def test_fail(self, pytester):
pytester.makepyfile("def test_fail(): assert False")
page = run(pytester)
assert_results(page, failed=1)
assert_that(get_log(page)).contains("AssertionError")
assert_that(get_text(page, ".summary div[class='log'] span.error")).matches(
assert_that(get_text(page, "div[class='log'] span.error")).matches(
r"^E\s+assert False$"
)

Expand Down Expand Up @@ -352,7 +358,7 @@ def test_function(arg):
page = run(pytester)
assert_results(page, error=1, total_tests=0)

col_name = get_text(page, ".summary td[class='col-name']")
col_name = get_text(page, "td[class='col-name']")
assert_that(col_name).contains("::setup")
assert_that(get_log(page)).contains("ValueError")

Expand Down Expand Up @@ -411,7 +417,9 @@ def pytest_html_results_summary(prefix, summary, postfix):
pytester.makepyfile("def test_pass(): pass")
page = run(pytester)

elements = page.select(".summary__data p:not(.run-count):not(.filter)")
elements = page.select(
".additional-summary p"
) # ".summary__data p:not(.run-count):not(.filter)")
assert_that(elements).is_length(3)
for element in elements:
key = re.search(r"(\w+).*", element.string).group(1)
Expand All @@ -437,7 +445,7 @@ def pytest_runtest_makereport(item, call):
pytester.makepyfile("def test_pass(): pass")
page = run(pytester)

assert_that(page.select_one(".summary .extraHTML").string).is_equal_to(content)
assert_that(page.select_one(".extraHTML").string).is_equal_to(content)

@pytest.mark.parametrize(
"content, encoded",
Expand All @@ -460,7 +468,7 @@ def pytest_runtest_makereport(item, call):
pytester.makepyfile("def test_pass(): pass")
page = run(pytester, cmd_flags=["--self-contained-html"])

element = page.select_one(".summary a[class='col-links__extra text']")
element = page.select_one("a[class='col-links__extra text']")
assert_that(element.string).is_equal_to("Text")
assert_that(element["href"]).is_equal_to(
f"data:text/plain;charset=utf-8;base64,{encoded}"
Expand Down Expand Up @@ -488,7 +496,7 @@ def pytest_runtest_makereport(item, call):
content_str = json.dumps(content)
data = b64encode(content_str.encode("utf-8")).decode("ascii")

element = page.select_one(".summary a[class='col-links__extra json']")
element = page.select_one("a[class='col-links__extra json']")
assert_that(element.string).is_equal_to("JSON")
assert_that(element["href"]).is_equal_to(
f"data:application/json;charset=utf-8;base64,{data}"
Expand All @@ -512,7 +520,7 @@ def pytest_runtest_makereport(item, call):
pytester.makepyfile("def test_pass(): pass")
page = run(pytester)

element = page.select_one(".summary a[class='col-links__extra url']")
element = page.select_one("a[class='col-links__extra url']")
assert_that(element.string).is_equal_to("URL")
assert_that(element["href"]).is_equal_to(content)

Expand Down Expand Up @@ -551,7 +559,7 @@ def pytest_runtest_makereport(item, call):
# assert_that(element.string).is_equal_to("Image")
# assert_that(element["href"]).is_equal_to(src)

element = page.select_one(".summary .media img")
element = page.select_one(".media img")
assert_that(str(element)).is_equal_to(f'<img src="{src}"/>')

@pytest.mark.parametrize("mime_type, extension", [("video/mp4", "mp4")])
Expand Down Expand Up @@ -579,7 +587,7 @@ def pytest_runtest_makereport(item, call):
# assert_that(element.string).is_equal_to("Video")
# assert_that(element["href"]).is_equal_to(src)

element = page.select_one(".summary .media video")
element = page.select_one(".media video")
assert_that(str(element)).is_equal_to(
f'<video controls="">\n<source src="{src}" type="{mime_type}"/>\n</video>'
)
Expand All @@ -590,10 +598,8 @@ def test_xdist(self, pytester):
assert_results(page, passed=1)

def test_results_table_hook_append(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({})"
header_selector = "#results-table-head tr:nth-child(1) th:nth-child({})"
row_selector = "#results-table tr:nth-child(1) td:nth-child({})"

pytester.makeconftest(
"""
Expand Down Expand Up @@ -628,10 +634,8 @@ def pytest_html_results_table_row(report, cells):
)

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({})"
header_selector = "#results-table-head tr:nth-child(1) th:nth-child({})"
row_selector = "#results-table tr:nth-child(1) td:nth-child({})"

pytester.makeconftest(
"""
Expand Down Expand Up @@ -700,12 +704,10 @@ def pytest_html_results_table_row(report, cells):
pytester.makepyfile("def test_pass(): pass")
page = run(pytester)

header_columns = page.select(".summary #results-table-head th")
header_columns = page.select("#results-table-head th")
assert_that(header_columns).is_length(3)

row_columns = page.select_one(".summary .results-table-row").select(
"td:not(.extra)"
)
row_columns = page.select_one(".results-table-row").select("td:not(.extra)")
assert_that(row_columns).is_length(3)

@pytest.mark.parametrize("no_capture", ["", "-s"])
Expand Down