Skip to content

Commit ed86ca0

Browse files
committed
Fix: Handle appends on table hooks
1 parent e4ad806 commit ed86ca0

File tree

5 files changed

+104
-13
lines changed

5 files changed

+104
-13
lines changed

src/pytest_html/scripts/dom.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const storageModule = require('./storage.js')
2-
const { formatDuration } = require('./utils.js')
2+
const { formatDuration, transformTableObj } = require('./utils.js')
33
const mediaViewer = require('./mediaviewer.js')
44
const templateEnvRow = document.querySelector('#template_environment_row')
55
const templateCollGroup = document.querySelector('#template_table-colgroup')
@@ -28,9 +28,9 @@ const findAll = (selector, elem) => {
2828
return [...elem.querySelectorAll(selector)]
2929
}
3030

31-
const insertAdditionalHTML = (html, element, selector) => {
31+
const insertAdditionalHTML = (html, element, selector, position = 'beforebegin') => {
3232
Object.keys(html).map((key) => {
33-
element.querySelectorAll(selector).item(key).insertAdjacentHTML('beforebegin', html[key])
33+
element.querySelectorAll(selector).item(key).insertAdjacentHTML(position, html[key])
3434
})
3535
}
3636

@@ -66,7 +66,9 @@ const dom = {
6666
const sortables = ['result', 'testId', 'duration', ...cols]
6767

6868
// Add custom html from the pytest_html_results_table_header hook
69-
insertAdditionalHTML(resultsTableHeader, header, 'th')
69+
const headers = transformTableObj(resultsTableHeader)
70+
insertAdditionalHTML(headers.inserts, header, 'th')
71+
insertAdditionalHTML(headers.appends, header, 'tr', 'beforeend')
7072

7173
sortables.forEach((sortCol) => {
7274
if (sortCol === sortAttr) {
@@ -92,7 +94,6 @@ const dom = {
9294

9395
resultBody.querySelector('.col-duration').innerText = duration < 1 ? formatDuration(duration).ms : formatDuration(duration).formatted
9496

95-
9697
if (log) {
9798
resultBody.querySelector('.log').innerHTML = log
9899
} else {
@@ -126,7 +127,9 @@ const dom = {
126127
mediaViewer.setUp(resultBody, media)
127128

128129
// Add custom html from the pytest_html_results_table_row hook
129-
resultsTableRow && insertAdditionalHTML(resultsTableRow, resultBody, 'td')
130+
const rows = transformTableObj(resultsTableRow)
131+
resultsTableRow && insertAdditionalHTML(rows.inserts, resultBody, 'td')
132+
resultsTableRow && insertAdditionalHTML(rows.appends, resultBody, 'tr', 'beforeend')
130133

131134
// Add custom html from the pytest_html_results_table_html hook
132135
tableHtml?.forEach((item) => {

src/pytest_html/scripts/utils.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,19 @@ const formatDuration = ( totalSeconds ) => {
2121
}
2222
}
2323

24-
module.exports = { formatDuration }
24+
const transformTableObj = (obj) => {
25+
const appends = {}
26+
const inserts = {}
27+
for (const key in obj) {
28+
key.startsWith("Z") ? appends[key] = obj[key] : inserts[key] = obj[key]
29+
}
30+
return {
31+
appends,
32+
inserts,
33+
}
34+
}
35+
36+
module.exports = {
37+
formatDuration,
38+
transformTableObj,
39+
}

src/pytest_html/table.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ def append(self, html):
2929

3030

3131
class Cell(Table):
32+
def __init__(self):
33+
super().__init__()
34+
self._append_counter = 0
35+
3236
def __setitem__(self, key, value):
3337
warnings.warn(
3438
"list-type assignment is deprecated and support "
@@ -38,6 +42,12 @@ def __setitem__(self, key, value):
3842
)
3943
self.insert(key, value)
4044

45+
def append(self, item):
46+
# We need a way of separating inserts from appends in JS,
47+
# hence the "Z" prefix
48+
self.insert(f"Z{self._append_counter}", item)
49+
self._append_counter += 1
50+
4151
def insert(self, index, html):
4252
# backwards-compat
4353
if not isinstance(html, str):

testing/test_integration.py

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,44 @@ def test_xdist(self, pytester):
516516
page = run(pytester, cmd_flags=["-n1"])
517517
assert_results(page, passed=1)
518518

519+
def test_results_table_hook_append(self, pytester):
520+
header_selector = (
521+
".summary #results-table-head tr:nth-child(1) th:nth-child({})"
522+
)
523+
row_selector = ".summary #results-table tr:nth-child(1) td:nth-child({})"
524+
525+
pytester.makeconftest(
526+
"""
527+
def pytest_html_results_table_header(cells):
528+
cells.append("<th>Description</th>")
529+
cells.append(
530+
'<th class="sortable time" data-column-type="time">Time</th>'
531+
)
532+
533+
def pytest_html_results_table_row(report, cells):
534+
cells.append("<td>A description</td>")
535+
cells.append('<td class="col-time">A time</td>')
536+
"""
537+
)
538+
pytester.makepyfile("def test_pass(): pass")
539+
page = run(pytester)
540+
541+
description_index = 5
542+
time_index = 6
543+
assert_that(get_text(page, header_selector.format(time_index))).is_equal_to(
544+
"Time"
545+
)
546+
assert_that(
547+
get_text(page, header_selector.format(description_index))
548+
).is_equal_to("Description")
549+
550+
assert_that(get_text(page, row_selector.format(time_index))).is_equal_to(
551+
"A time"
552+
)
553+
assert_that(get_text(page, row_selector.format(description_index))).is_equal_to(
554+
"A description"
555+
)
556+
519557
def test_results_table_hook_insert(self, pytester):
520558
header_selector = (
521559
".summary #results-table-head tr:nth-child(1) th:nth-child({})"
@@ -539,13 +577,21 @@ def pytest_html_results_table_row(report, cells):
539577
pytester.makepyfile("def test_pass(): pass")
540578
page = run(pytester)
541579

542-
assert_that(get_text(page, header_selector.format(2))).is_equal_to("Time")
543-
assert_that(get_text(page, header_selector.format(3))).is_equal_to(
544-
"Description"
580+
description_index = 3
581+
time_index = 2
582+
assert_that(get_text(page, header_selector.format(time_index))).is_equal_to(
583+
"Time"
545584
)
585+
assert_that(
586+
get_text(page, header_selector.format(description_index))
587+
).is_equal_to("Description")
546588

547-
assert_that(get_text(page, row_selector.format(2))).is_equal_to("A time")
548-
assert_that(get_text(page, row_selector.format(3))).is_equal_to("A description")
589+
assert_that(get_text(page, row_selector.format(time_index))).is_equal_to(
590+
"A time"
591+
)
592+
assert_that(get_text(page, row_selector.format(description_index))).is_equal_to(
593+
"A description"
594+
)
549595

550596
def test_results_table_hook_delete(self, pytester):
551597
pytester.makeconftest(

testing/unittest.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const { expect } = require('chai')
22
const sinon = require('sinon')
33
const { doInitFilter, doFilter } = require('../src/pytest_html/scripts/filter.js')
44
const { doInitSort, doSort } = require('../src/pytest_html/scripts/sort.js')
5-
const { formatDuration } = require('../src/pytest_html/scripts/utils.js')
5+
const { formatDuration, transformTableObj } = require('../src/pytest_html/scripts/utils.js')
66
const dataModule = require('../src/pytest_html/scripts/datamanager.js')
77
const storageModule = require('../src/pytest_html/scripts/storage.js')
88

@@ -155,6 +155,23 @@ describe('utils tests', () => {
155155
expect(formatDuration(12345.678).formatted).to.eql('03:25:46')
156156
})
157157
})
158+
describe('transformTableObj', () => {
159+
it('handles empty object', () => {
160+
expect(transformTableObj({})).to.eql({appends: {}, inserts: {}})
161+
})
162+
it('handles no appends', () => {
163+
const expected = {1: "hello", 2: "goodbye"}
164+
expect(transformTableObj(expected)).to.eql({appends: {}, inserts: expected})
165+
})
166+
it('handles no inserts', () => {
167+
const expected = {"Z1": "hello", "Z2": "goodbye"}
168+
expect(transformTableObj(expected)).to.eql({appends: expected, inserts: {}})
169+
})
170+
it('handles both', () => {
171+
const expected = {appends: {"Z1": "hello", "Z2": "goodbye"}, inserts: {1: "mee", 2: "moo"}}
172+
expect(transformTableObj({...expected.appends, ...expected.inserts})).to.eql(expected)
173+
})
174+
})
158175
})
159176

160177
describe('Storage tests', () => {

0 commit comments

Comments
 (0)