Skip to content

Commit bd929f9

Browse files
committed
fix(html): fix a few problems with the html report
- highlights weren't showing - anchored lines were not visible - some j/k motions were broken - clicking the big buttons at the top didn't work
1 parent c8ac448 commit bd929f9

File tree

7 files changed

+64
-43
lines changed

7 files changed

+64
-43
lines changed

coverage/htmlfiles/coverage_html.js

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ function debounce(callback, wait) {
1919
};
2020

2121
function checkVisible(element) {
22-
var rect = element.getBoundingClientRect();
23-
var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
24-
return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
22+
const rect = element.getBoundingClientRect();
23+
const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight);
24+
const viewTop = 30;
25+
return !(rect.bottom < viewTop || rect.top >= viewBottom);
2526
}
2627

2728
// Helpers for table sorting
@@ -204,7 +205,7 @@ coverage.pyfile_ready = function () {
204205
// If we're directed to a particular line number, highlight the line.
205206
var frag = location.hash;
206207
if (frag.length > 2 && frag[1] === 't') {
207-
document.getElementById(frag.substring(1)).classList.add("highlight");
208+
document.querySelector(frag).closest(".n").classList.add("highlight");
208209
coverage.set_sel(parseInt(frag.substr(2), 10));
209210
} else {
210211
coverage.set_sel(0);
@@ -245,7 +246,7 @@ coverage.pyfile_ready = function () {
245246
};
246247

247248
coverage.toggle_lines = function (event) {
248-
const btn = event.target;
249+
const btn = event.target.closest("button");
249250
const category = btn.value
250251
const show = !btn.classList.contains("show_" + category);
251252
coverage.set_line_visibilty(category, show);
@@ -271,7 +272,7 @@ coverage.set_line_visibilty = function (category, should_show) {
271272

272273
// Return the nth line div.
273274
coverage.line_elt = function (n) {
274-
return document.getElementById("t" + n);
275+
return document.getElementById("t" + n)?.closest("p");
275276
};
276277

277278
// Set the selection. b and e are line numbers.
@@ -295,7 +296,7 @@ coverage.to_first_chunk = function () {
295296
// Return a string indicating what kind of chunk this line belongs to,
296297
// or null if not a chunk.
297298
coverage.chunk_indicator = function (line_elt) {
298-
const classes = line_elt.className;
299+
const classes = line_elt?.className;
299300
if (!classes) {
300301
return null;
301302
}
@@ -344,11 +345,11 @@ coverage.to_prev_chunk = function () {
344345
// Find the end of the prev colored chunk.
345346
var probe = c.sel_begin-1;
346347
var probe_line = c.line_elt(probe);
347-
if (probe_line.length === 0) {
348+
if (!probe_line) {
348349
return;
349350
}
350351
var chunk_indicator = c.chunk_indicator(probe_line);
351-
while (probe > 0 && !chunk_indicator) {
352+
while (probe > 1 && !chunk_indicator) {
352353
probe--;
353354
probe_line = c.line_elt(probe);
354355
if (!probe_line) {
@@ -364,6 +365,9 @@ coverage.to_prev_chunk = function () {
364365
var prev_indicator = chunk_indicator;
365366
while (prev_indicator === chunk_indicator) {
366367
probe--;
368+
if (probe <= 0) {
369+
return;
370+
}
367371
probe_line = c.line_elt(probe);
368372
prev_indicator = c.chunk_indicator(probe_line);
369373
}
@@ -430,7 +434,7 @@ coverage.to_prev_chunk_nicely = function () {
430434
coverage.select_line_or_chunk = function (lineno) {
431435
var c = coverage;
432436
var probe_line = c.line_elt(lineno);
433-
if (probe_line.length === 0) {
437+
if (!probe_line) {
434438
return;
435439
}
436440
var the_indicator = c.chunk_indicator(probe_line);
@@ -442,7 +446,7 @@ coverage.select_line_or_chunk = function (lineno) {
442446
while (probe > 0 && indicator === the_indicator) {
443447
probe--;
444448
probe_line = c.line_elt(probe);
445-
if (probe_line.length === 0) {
449+
if (!probe_line) {
446450
break;
447451
}
448452
indicator = c.chunk_indicator(probe_line);
@@ -469,7 +473,7 @@ coverage.show_selection = function () {
469473
// Highlight the lines in the chunk
470474
document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight"));
471475
for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) {
472-
coverage.line_elt(probe).classList.add("highlight");
476+
coverage.line_elt(probe).querySelector(".n").classList.add("highlight");
473477
}
474478

475479
coverage.scroll_to_selection();
@@ -479,7 +483,7 @@ coverage.scroll_to_selection = function () {
479483
// Scroll the page if the chunk isn't fully visible.
480484
if (coverage.selection_ends_on_screen() < 2) {
481485
const element = coverage.line_elt(coverage.sel_begin);
482-
coverage.scroll_window(element.offsetTop - 30);
486+
coverage.scroll_window(element.offsetTop - 60);
483487
}
484488
};
485489

coverage/htmlfiles/pyfile.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ <h2>
7575
<main id="source">
7676
{% for line in lines -%}
7777
{% joined %}
78-
<p id="t{{line.number}}" class="{{line.css_class}}">
79-
<span class="n"><a href="#t{{line.number}}">{{line.number}}</a></span>
78+
<p class="{{line.css_class}}">
79+
<span class="n"><a id="t{{line.number}}" href="#t{{line.number}}">{{line.number}}</a></span>
8080
<span class="t">{{line.html}}&nbsp;</span>
8181
{% if line.context_list %}
8282
<input type="checkbox" id="ctxs{{line.number}}" />

coverage/htmlfiles/style.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,24 +140,24 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
140140

141141
#source { padding: 1em 0 1em 3.5rem; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
142142

143-
#source p { margin-top: -4em; padding-top: 4em; position: relative; white-space: pre; }
143+
#source p { position: relative; white-space: pre; }
144144

145145
#source p * { box-sizing: border-box; }
146146

147147
#source p .n { float: left; text-align: right; width: 3.5rem; box-sizing: border-box; margin-left: -3.5rem; padding-right: 1em; color: #999; }
148148

149149
@media (prefers-color-scheme: dark) { #source p .n { color: #777; } }
150150

151-
#source p .n a { text-decoration: none; color: #999; }
151+
#source p .n.highlight { background: #ffdd00; }
152+
153+
#source p .n a { margin-top: -4em; padding-top: 4em; text-decoration: none; color: #999; }
152154

153155
@media (prefers-color-scheme: dark) { #source p .n a { color: #777; } }
154156

155157
#source p .n a:hover { text-decoration: underline; color: #999; }
156158

157159
@media (prefers-color-scheme: dark) { #source p .n a:hover { color: #777; } }
158160

159-
#source p.highlight .n { background: #ffdd00; }
160-
161161
#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid #fff; }
162162

163163
@media (prefers-color-scheme: dark) { #source p .t { border-color: #1e1e1e; } }

coverage/htmlfiles/style.scss

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -395,11 +395,6 @@ $border-indicator-width: .2em;
395395
font-family: $font-code;
396396

397397
p {
398-
// These two lines make anchors to the line scroll the line to be
399-
// visible beneath the fixed-position header.
400-
margin-top: -4em;
401-
padding-top: 4em;
402-
403398
// position relative makes position:absolute pop-ups appear in the right place.
404399
position: relative;
405400
white-space: pre;
@@ -418,7 +413,16 @@ $border-indicator-width: .2em;
418413
color: $light-gray4;
419414
@include color-dark($dark-gray4);
420415

416+
&.highlight {
417+
background: #ffdd00;
418+
}
419+
421420
a {
421+
// These two lines make anchors to the line scroll the line to be
422+
// visible beneath the fixed-position header.
423+
margin-top: -4em;
424+
padding-top: 4em;
425+
422426
text-decoration: none;
423427
color: $light-gray4;
424428
@include color-dark($dark-gray4);
@@ -430,10 +434,6 @@ $border-indicator-width: .2em;
430434
}
431435
}
432436

433-
&.highlight .n {
434-
background: #ffdd00;
435-
}
436-
437437
.t {
438438
display: inline-block;
439439
width: 100%;

tests/gold/html/styled/style.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,24 +140,24 @@ kbd { border: 1px solid black; border-color: #888 #333 #333 #888; padding: .1em
140140

141141
#source { padding: 1em 0 1em 3.5rem; font-family: SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
142142

143-
#source p { margin-top: -4em; padding-top: 4em; position: relative; white-space: pre; }
143+
#source p { position: relative; white-space: pre; }
144144

145145
#source p * { box-sizing: border-box; }
146146

147147
#source p .n { float: left; text-align: right; width: 3.5rem; box-sizing: border-box; margin-left: -3.5rem; padding-right: 1em; color: #999; }
148148

149149
@media (prefers-color-scheme: dark) { #source p .n { color: #777; } }
150150

151-
#source p .n a { text-decoration: none; color: #999; }
151+
#source p .n.highlight { background: #ffdd00; }
152+
153+
#source p .n a { margin-top: -4em; padding-top: 4em; text-decoration: none; color: #999; }
152154

153155
@media (prefers-color-scheme: dark) { #source p .n a { color: #777; } }
154156

155157
#source p .n a:hover { text-decoration: underline; color: #999; }
156158

157159
@media (prefers-color-scheme: dark) { #source p .n a:hover { color: #777; } }
158160

159-
#source p.highlight .n { background: #ffdd00; }
160-
161161
#source p .t { display: inline-block; width: 100%; box-sizing: border-box; margin-left: -.5em; padding-left: 0.3em; border-left: 0.2em solid #fff; }
162162

163163
@media (prefers-color-scheme: dark) { #source p .t { border-color: #1e1e1e; } }

tests/goldtest.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,35 @@ def contains(filename, *strlist):
134134
missing in `filename`.
135135
136136
"""
137+
__tracebackhide__ = True # pytest, please don't show me this function.
137138
with open(filename) as fobj:
138139
text = fobj.read()
139140
for s in strlist:
140141
assert s in text, f"Missing content in {filename}: {s!r}"
141142

142143

144+
def contains_rx(filename, *rxlist):
145+
"""Check that the file has lines that re.search all of the regexes.
146+
147+
An assert will be raised if one of the regexes in `rxlist` doesn't match
148+
any lines in `filename`.
149+
150+
"""
151+
__tracebackhide__ = True # pytest, please don't show me this function.
152+
with open(filename) as fobj:
153+
lines = fobj.readlines()
154+
for rx in rxlist:
155+
assert any(re.search(rx, line) for line in lines), f"Missing rx in {filename}: {rx!r}"
156+
157+
143158
def contains_any(filename, *strlist):
144159
"""Check that the file contains at least one of a list of strings.
145160
146161
An assert will be raised if none of the arguments in `strlist` is in
147162
`filename`.
148163
149164
"""
165+
__tracebackhide__ = True # pytest, please don't show me this function.
150166
with open(filename) as fobj:
151167
text = fobj.read()
152168
for s in strlist:
@@ -165,6 +181,7 @@ def doesnt_contain(filename, *strlist):
165181
`filename`.
166182
167183
"""
184+
__tracebackhide__ = True # pytest, please don't show me this function.
168185
with open(filename) as fobj:
169186
text = fobj.read()
170187
for s in strlist:

tests/test_html.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
from tests.coveragetest import CoverageTest, TESTS_DIR
2525
from tests.goldtest import gold_path
26-
from tests.goldtest import compare, contains, doesnt_contain, contains_any
26+
from tests.goldtest import compare, contains, contains_rx, doesnt_contain, contains_any
2727
from tests.helpers import assert_coverage_warnings, change_dir
2828

2929

@@ -893,14 +893,14 @@ def test_partial(self):
893893
if env.PYBEHAVIOR.pep626:
894894
cov.html_report(partial, directory="out/partial_626")
895895
compare_html(gold_path("html/partial_626"), "out/partial_626")
896-
contains(
896+
contains_rx(
897897
"out/partial_626/partial_py.html",
898-
'<p id="t4" class="par run show_par">',
899-
'<p id="t7" class="run">',
898+
r'<p class="par run show_par">.* id="t4"',
899+
r'<p class="run">.* id="t7"',
900900
# The "if 0" and "if 1" statements are marked as run.
901-
'<p id="t10" class="run">',
901+
r'<p class="run">.* id="t10"',
902902
# The "raise ZeroDivisionError" is excluded by regex in the .ini.
903-
'<p id="t17" class="exc show_exc">',
903+
r'<p class="exc show_exc">.* id="t17"',
904904
)
905905
contains(
906906
"out/partial_626/index.html",
@@ -910,14 +910,14 @@ def test_partial(self):
910910
else:
911911
cov.html_report(partial, directory="out/partial")
912912
compare_html(gold_path("html/partial"), "out/partial")
913-
contains(
913+
contains_rx(
914914
"out/partial/partial_py.html",
915-
'<p id="t4" class="par run show_par">',
916-
'<p id="t7" class="run">',
915+
r'<p class="par run show_par">.* id="t4"',
916+
r'<p class="run">.* id="t7"',
917917
# The "if 0" and "if 1" statements are optimized away.
918-
'<p id="t10" class="pln">',
918+
r'<p class="pln">.* id="t10"',
919919
# The "raise ZeroDivisionError" is excluded by regex in the .ini.
920-
'<p id="t17" class="exc show_exc">',
920+
r'<p class="exc show_exc">.* id="t17"',
921921
)
922922
contains(
923923
"out/partial/index.html",

0 commit comments

Comments
 (0)