fix: icon()-Macro mit ignore-missing + Coverage-Test
Folge zum scales.svg-Vorfall (commit 01ea766):
1. icon.html: `{% include … ignore missing %}` — fehlende SVG-Files
rendern jetzt leeren Span statt einen 500 auszuloesen. data-icon-
Attribut zeigt den angefragten Namen, hilft im DevTools-Inspector.
2. tests/test_icons.py: scannt alle templates/-Files nach
icon("name")-Aufrufen und prueft, dass jedes referenzierte Icon
als SVG-File existiert. 4 Tests, alle gruen — verhindert dass
solche Aufrufe in Zukunft unentdeckt durchrutschen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
01ea7665cc
commit
c3d4ab186f
@ -1 +1,2 @@
|
|||||||
{% macro icon(name, size=16, cls="") %}<span class="v2-icon {{ cls }}" style="display:inline-flex;width:{{ size }}px;height:{{ size }}px;flex-shrink:0;vertical-align:middle;" aria-hidden="true">{% include "v2/icons/phosphor/" ~ name ~ ".svg" %}</span>{% endmacro %}
|
{# `ignore missing`: fehlendes Icon-File rendert leeren Span statt 500. #}
|
||||||
|
{% macro icon(name, size=16, cls="") %}<span class="v2-icon {{ cls }}" style="display:inline-flex;width:{{ size }}px;height:{{ size }}px;flex-shrink:0;vertical-align:middle;" aria-hidden="true" data-icon="{{ name }}">{% include "v2/icons/phosphor/" ~ name ~ ".svg" ignore missing %}</span>{% endmacro %}
|
||||||
|
|||||||
63
tests/test_icons.py
Normal file
63
tests/test_icons.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
"""Verify dass jeder im Template-Code referenzierte Icon-Name als
|
||||||
|
phosphor/<name>.svg-File existiert.
|
||||||
|
|
||||||
|
Hintergrund: Vor diesem Test gab es einen 500 nach Login, weil
|
||||||
|
`base.html` `icon("scales")` aufrief, das SVG aber nicht im Repo lag
|
||||||
|
(commit 741faae). Mit `ignore missing` rendert das Macro jetzt leer
|
||||||
|
statt zu crashen — aber wir wollen trotzdem in CI sehen, dass kein
|
||||||
|
Aufruf ins Leere läuft.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
TEMPLATES_DIR = REPO_ROOT / "app" / "templates"
|
||||||
|
ICONS_DIR = TEMPLATES_DIR / "v2" / "icons" / "phosphor"
|
||||||
|
|
||||||
|
# Matcht: icon("name", …) oder icon('name', …) — Default-Quote +/-.
|
||||||
|
ICON_CALL_PATTERN = re.compile(r"""\bicon\(\s*['"]([a-z0-9-]+)['"]""")
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_referenced_icons() -> set[str]:
|
||||||
|
"""Sammle alle Icon-Namen, die irgendwo in templates/ aufgerufen werden."""
|
||||||
|
referenced: set[str] = set()
|
||||||
|
for path in TEMPLATES_DIR.rglob("*.html"):
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
for m in ICON_CALL_PATTERN.finditer(text):
|
||||||
|
referenced.add(m.group(1))
|
||||||
|
return referenced
|
||||||
|
|
||||||
|
|
||||||
|
def _existing_icons() -> set[str]:
|
||||||
|
"""Set der existierenden phosphor-Icon-Namen (ohne .svg)."""
|
||||||
|
if not ICONS_DIR.exists():
|
||||||
|
return set()
|
||||||
|
return {p.stem for p in ICONS_DIR.glob("*.svg")}
|
||||||
|
|
||||||
|
|
||||||
|
class TestIconCoverage:
|
||||||
|
def test_phosphor_dir_exists(self):
|
||||||
|
assert ICONS_DIR.is_dir(), f"erwartetes Verzeichnis fehlt: {ICONS_DIR}"
|
||||||
|
|
||||||
|
def test_at_least_one_icon_present(self):
|
||||||
|
icons = _existing_icons()
|
||||||
|
assert icons, "keine Icon-Files im phosphor/-Verzeichnis"
|
||||||
|
|
||||||
|
def test_at_least_one_call_referenced(self):
|
||||||
|
refs = _collect_referenced_icons()
|
||||||
|
assert refs, "keine icon('name')-Aufrufe in Templates gefunden"
|
||||||
|
|
||||||
|
def test_every_referenced_icon_has_file(self):
|
||||||
|
"""Jeder im Template referenzierte Icon-Name muss als SVG-File existieren."""
|
||||||
|
referenced = _collect_referenced_icons()
|
||||||
|
existing = _existing_icons()
|
||||||
|
missing = referenced - existing
|
||||||
|
assert not missing, (
|
||||||
|
f"{len(missing)} referenzierte Icons fehlen in "
|
||||||
|
f"{ICONS_DIR.relative_to(REPO_ROOT)}: {sorted(missing)}"
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue
Block a user