Skip to content
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## Unreleased

- Result tables: the limit source wraps instead of running into the tolerance
band, and the tolerance band scales to its column instead of touching the
status badge
- Tolerance bands are no longer black in PDFs made with WeasyPrint

## 0.1.1 — 2026-11-08

- Docker image `ghcr.io/steitec/test-protocol` with WeasyPrint and its system libraries,
Expand Down
14 changes: 9 additions & 5 deletions src/test_protocol/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def _limits(item: Item, lang: str) -> str:
text = f"≤ {fmt_number(item.high, lang)}"
else:
return "—"
text = f'<span class="num">{text}</span>'
if item.limit_source:
text += f' <span class="muted">({_e(item.limit_source)})</span>'
return text
Expand All @@ -93,10 +94,10 @@ def x(v: float) -> float:
return 4 + 112 * (min(max(v, lo), hi) - lo) / (hi - lo)

color = _STATUS_COLORS["PASS" if low <= value <= high else "FAIL"]
return (f'<svg width="120" height="14" role="img" aria-label="{_e(value)} in {low}..{high}">'
f'<rect x="4" y="5" width="112" height="4" rx="2" fill="var(--track)"/>'
return (f'<svg class="gauge" viewBox="0 0 120 14" role="img" aria-label="{_e(value)} in {low}..{high}">'
f'<rect x="4" y="5" width="112" height="4" rx="2" class="gauge-track" fill="#d0d7de"/>'
f'<rect x="{x(low):.1f}" y="3" width="{x(high) - x(low):.1f}" height="8" rx="2" '
f'fill="var(--band)"/>'
f'class="gauge-band" fill="#aceebb"/>'
f'<circle cx="{x(value):.1f}" cy="7" r="4.5" fill="{color}"/></svg>')


Expand Down Expand Up @@ -141,7 +142,7 @@ def _summary(p: Protocol, lang: str) -> str:
else:
rows.append(f"<tr><td>{_e(group.name)}</td><td>{_e(item.name)}</td>"
f'<td class="num">{_value(item, lang)}</td>'
f'<td class="num">{_limits(item, lang)}</td>'
f'<td class="limit">{_limits(item, lang)}</td>'
f"<td>{_e(item.message)}</td><td>{_badge(item.status or 'FAIL')}</td></tr>")
table = (f'<h3>{t(lang, "failures")}</h3><table class="grid"><thead><tr>'
f'<th>{t(lang, "group")}</th><th>{t(lang, "item")}</th>'
Expand All @@ -162,7 +163,7 @@ def _group(group: Group, lang: str) -> str:
status = _badge(item.status) if item.status in STATUSES else ""
rows.append(f"<tr><td>{_e(item.name)}{message}</td>"
f'<td class="num">{_value(item, lang)}</td>'
f'<td class="num">{_limits(item, lang)}</td>'
f'<td class="limit">{_limits(item, lang)}</td>'
f"<td>{_gauge(item)}</td><td>{status}</td></tr>")
table = ""
if rows:
Expand Down Expand Up @@ -242,6 +243,9 @@ def _signatures(p: Protocol, opts: RenderOptions) -> str:
.group .grid { table-layout:fixed; }
.group .grid th:nth-child(1) { width:32%; } .group .grid th:nth-child(2) { width:16%; } .group .grid th:nth-child(3) { width:24%; } .group .grid th:nth-child(4) { width:16%; }
.num { font-variant-numeric:tabular-nums; white-space:nowrap; }
.limit { overflow-wrap:anywhere; }
.gauge { display:block; width:100%; max-width:120px; height:auto; }
.gauge-track { fill:var(--track); } .gauge-band { fill:var(--band); }
.hash { font-family:ui-monospace, monospace; font-size:11px; word-break:break-all; }
.note { color:var(--muted); font-size:12px; }
.counts .badge { margin-left:10px; } .counts .badge:first-child { margin-left:0; }
Expand Down
26 changes: 26 additions & 0 deletions tests/test_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,29 @@ def test_print_css():
assert "size: A4" in out
assert "counter(pages)" in out
assert "@media screen and (prefers-color-scheme: dark)" in out


def _gauge_item() -> Item:
return Item("3V3", "PASS", value=3.3, low=3.234, high=3.366)


def test_limit_source_can_wrap_in_its_fixed_width_column():
item = _gauge_item()
item.limit_source = "limits.toml"
p = Protocol(header={"serial": "S"}, groups=[Group("g", [item])])
out = render(p)
assert '<td class="limit"><span class="num">3.234 … 3.366</span> ' in out
assert ".limit { overflow-wrap:anywhere; }" in out


def test_gauge_scales_to_its_column():
p = Protocol(header={"serial": "S"}, groups=[Group("g", [_gauge_item()])])
out = render(p)
assert 'viewBox="0 0 120 14"' in out
assert '<svg width="120"' not in out


def test_gauge_has_real_colors_for_svg_renderers_without_css_variables():
p = Protocol(header={"serial": "S"}, groups=[Group("g", [_gauge_item()])])
svg = render(p).split("<svg", 1)[1].split("</svg>", 1)[0]
assert 'fill="var(' not in svg
Loading