Skip to content

Commit

Permalink
Feature: Update json-data-blob (#704)
Browse files Browse the repository at this point in the history
  • Loading branch information
BeyondEvil committed Aug 13, 2023
1 parent af4c653 commit 1bee989
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 118 deletions.
46 changes: 21 additions & 25 deletions src/pytest_html/basereport.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,17 @@ def _generate_report(self, self_contained=False):
version=__version__,
styles=self.css,
run_count=self._run_count(),
running_state=self._report.running_state,
self_contained=self_contained,
outcomes=self._report.data["outcomes"],
outcomes=self._report.outcomes,
test_data=test_data,
table_head=self._report.data["resultsTableHeader"],
prefix=self._report.data["additionalSummary"]["prefix"],
summary=self._report.data["additionalSummary"]["summary"],
postfix=self._report.data["additionalSummary"]["postfix"],
table_head=self._report.table_header,
additional_summary=self._report.additional_summary,
)

self._write_report(rendered_report)

def _generate_environment(self, metadata_key):
def _generate_environment(self):
metadata = self._config.stash[metadata_key]
for key in metadata.keys():
value = metadata[key]
Expand Down Expand Up @@ -126,45 +125,42 @@ def _write_report(self, rendered_report):
f.write(rendered_report)

def _run_count(self):
data = self._report.data
relevant_outcomes = ["passed", "failed", "xpassed", "xfailed"]
counts = 0
for outcome in data["outcomes"].keys():
for outcome in self._report.outcomes.keys():
if outcome in relevant_outcomes:
counts += data["outcomes"][outcome]["value"]
counts += self._report.outcomes[outcome]["value"]

plural = counts > 1
duration = _format_duration(data["totalDuration"])
duration = _format_duration(self._report.total_duration)

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

return (
f"{counts}/{data['collectedItems']} {'tests' if plural else 'test'} done."
)
return f"{counts}/{self._report.collected_items} {'tests' if plural else 'test'} done."

@pytest.hookimpl(trylast=True)
def pytest_sessionstart(self, session):
self._report.set_data("environment", self._generate_environment(metadata_key))
self._report.set_data("environment", self._generate_environment())

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

headers = self._report.data["resultsTableHeader"]
headers = self._report.table_header
session.config.hook.pytest_html_results_table_header(cells=headers)
self._report.data["resultsTableHeader"] = _fix_py(headers)
self._report.table_header = _fix_py(headers)

self._report.set_data("runningState", "Started")
self._report.running_state = "started"
self._generate_report()

@pytest.hookimpl(trylast=True)
def pytest_sessionfinish(self, session):
session.config.hook.pytest_html_results_summary(
prefix=self._report.data["additionalSummary"]["prefix"],
summary=self._report.data["additionalSummary"]["summary"],
postfix=self._report.data["additionalSummary"]["postfix"],
prefix=self._report.additional_summary["prefix"],
summary=self._report.additional_summary["summary"],
postfix=self._report.additional_summary["postfix"],
session=session,
)
self._report.set_data("runningState", "Finished")
self._report.running_state = "finished"
self._generate_report()

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

@pytest.hookimpl(trylast=True)
def pytest_collection_finish(self, session):
self._report.set_data("collectedItems", len(session.items))
self._report.collected_items = len(session.items)

@pytest.hookimpl(trylast=True)
def pytest_runtest_logreport(self, report):
Expand All @@ -191,7 +187,7 @@ def pytest_runtest_logreport(self, report):
"result": outcome,
"duration": _format_duration(report.duration),
}
self._report.data["totalDuration"] += report.duration
self._report.total_duration += report.duration

test_id = report.nodeid
if report.when != "call":
Expand Down Expand Up @@ -220,7 +216,7 @@ def pytest_runtest_logreport(self, report):

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

processed_logs = _process_logs(report)
self._config.hook.pytest_html_results_table_html(
Expand Down
97 changes: 75 additions & 22 deletions src/pytest_html/report_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ class ReportData:
def __init__(self, config):
self._config = config

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

outcomes = {
self._collected_items = 0
self._total_duration = 0
self._running_state = "not_started"

self._outcomes = {
"failed": {"label": "Failed", "value": 0},
"passed": {"label": "Passed", "value": 0},
"skipped": {"label": "Skipped", "value": 0},
Expand All @@ -28,15 +31,17 @@ def __init__(self, config):
"rerun": {"label": "Reruns", "value": 0},
}

self._results_table_header = [
'<th class="sortable" data-column-type="result">Result</th>',
'<th class="sortable" data-column-type="testId">Test</th>',
'<th class="sortable" data-column-type="duration">Duration</th>',
"<th>Links</th>",
]

self._data = {
"collectedItems": 0,
"totalDuration": 0,
"runningState": "not_started",
"environment": {},
"outcomes": outcomes,
"tests": defaultdict(list),
"additionalSummary": defaultdict(list),
"resultsTableHeader": default_headers,
"resultsTableRow": None,
}

collapsed = config.getini("render_collapsed")
Expand All @@ -49,20 +54,28 @@ def __init__(self, config):
)
collapsed = "all"

self.set_data(
"renderCollapsed", [outcome.lower() for outcome in collapsed.split(",")]
)
self._data["renderCollapsed"] = [
outcome.lower() for outcome in collapsed.split(",")
]

initial_sort = config.getini("initial_sort")
self.set_data("initialSort", initial_sort)
self._data["initialSort"] = initial_sort

@property
def title(self):
return self._data["title"]
def additional_summary(self):
return self._additional_summary

@title.setter
def title(self, title):
self._data["title"] = title
@additional_summary.setter
def additional_summary(self, value):
self._additional_summary = value

@property
def collected_items(self):
return self._collected_items

@collected_items.setter
def collected_items(self, count):
self._collected_items = count

@property
def config(self):
Expand All @@ -72,6 +85,46 @@ def config(self):
def data(self):
return self._data

@property
def outcomes(self):
return self._outcomes

@outcomes.setter
def outcomes(self, outcome):
self._outcomes[outcome.lower()]["value"] += 1

@property
def running_state(self):
return self._running_state

@running_state.setter
def running_state(self, state):
self._running_state = state

@property
def table_header(self):
return self._results_table_header

@table_header.setter
def table_header(self, header):
self._results_table_header = header

@property
def title(self):
return self._data["title"]

@title.setter
def title(self, title):
self._data["title"] = title

@property
def total_duration(self):
return self._total_duration

@total_duration.setter
def total_duration(self, duration):
self._total_duration = duration

def set_data(self, key, value):
self._data[key] = value

Expand Down
77 changes: 42 additions & 35 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,54 +67,46 @@
</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 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">
<div class="summary__reload__button {{'hidden' if 'took' in run_count}}" onclick="location.reload()">
<div class="summary__reload__button {{ 'hidden' if running_state == 'finished' }}" onclick="location.reload()">
<div>There are still tests running. <br />Reload this page to ge the latest results!</div>
</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 summary %}
{{ s|safe }}
{%- endfor %}
{%- for p in 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
Loading

0 comments on commit 1bee989

Please sign in to comment.