feat(5.15+5.14): CLOSE — fix-uri code-review + embeddings functional
5.15 (propagare design + dashboard editare) si 5.14 (mapare LLM distilata) inchise dupa /code-review high. 8 buguri reparate TDD: - HIGH modal nu se deschidea pe randul slim (base.html: trimitere-slim) - HIGH /repune trunchia prestatii (declaratie incompleta la RAR) -> iterare peste existing, codes pozitional - HIGH embeddings incarca model ~230MB degeaba pe corpus gol -> poarta has_corpus() - HIGH picker chips gol pe re-render eroare -> conn/account_id pe toate ramurile - MED obs re-derivat dupa stergere explicita -> _merge_override pastreaza obs='' - MED mapare salvata fara denumire poluă GOLD -> _record_gold_validation guard - MED typo nome_prestatie -> nume_prestatie in select /repune - MED bucketare timp +3h gresita iarna -> SQLite localtime + TZ=Europe/Bucharest Embeddings WIRE-uit functional (PRD #15, decizie user): ensure_embeddings_corpus construieste corpus din nomenclator, gated pe AUTOPASS_EMBEDDINGS_ENABLED (default off). Marime model corectata ~50MB->~230MB (estimare PRD gresita). Cleanup: hoist load_* din bucla bulk-fix; import re la top. Regresie: 1256 passed, 1 deselected (live), 0 failed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -500,3 +500,241 @@ def test_liste_actionabile_o_coloana_pana_1024(client):
|
||||
# Blocul tableta cardifica listele (thead ascuns = card per rand, o coloana).
|
||||
assert ".tabel-trimiteri thead, .tabel-card thead { display:none; }" in html, \
|
||||
"Blocul tableta nu ascunde thead-ul pentru cardificare (o coloana)"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PRD 5.15 US-002: componente de design slim (CSS, fara consumatori)
|
||||
# ============================================================
|
||||
|
||||
|
||||
def _bloc_componente_slim(html: str) -> str:
|
||||
"""Extrage blocul CSS dintre sentinelii SENTINEL-COMPONENTE-SLIM (inceput si sfarsit).
|
||||
Testeaza existenta ambilor sentineli si returneaza continutul dintre ei.
|
||||
"""
|
||||
sentinel = "SENTINEL-COMPONENTE-SLIM"
|
||||
i = html.find(sentinel)
|
||||
assert i != -1, "Lipseste SENTINEL-COMPONENTE-SLIM in base.html (US-002 PRD 5.15)"
|
||||
i2 = html.find(sentinel, i + len(sentinel))
|
||||
assert i2 != -1, "Lipseste al doilea SENTINEL-COMPONENTE-SLIM (sfarsit bloc US-002)"
|
||||
return html[i : i2 + len(sentinel)]
|
||||
|
||||
|
||||
def test_clasa_contor_card(client):
|
||||
""".contor-card: fundal --card2, bordura --line, radius 8px, padding.
|
||||
Sub-elemente: .contor-cifra (cifra mare bold), .contor-label (muted), .contor-sub (mono).
|
||||
"""
|
||||
_create_account_user("cc2@test.com")
|
||||
_login(client, "cc2@test.com")
|
||||
html = client.get("/?tab=acasa").text
|
||||
|
||||
assert ".contor-card" in html, ".contor-card lipseste din CSS (base.html)"
|
||||
|
||||
bloc = _bloc_componente_slim(html)
|
||||
assert "var(--card2)" in bloc, ".contor-card nu foloseste var(--card2) ca fundal"
|
||||
assert "var(--line)" in bloc, ".contor-card nu are bordura var(--line)"
|
||||
assert "border-radius:8px" in bloc, ".contor-card lipseste border-radius:8px"
|
||||
assert ".contor-cifra" in bloc, "sub-elementul .contor-cifra lipseste din bloc"
|
||||
assert ".contor-label" in bloc, "sub-elementul .contor-label lipseste din bloc"
|
||||
assert "var(--muted)" in bloc, ".contor-label nu foloseste var(--muted)"
|
||||
|
||||
|
||||
def test_clasa_lista_slim(client):
|
||||
""".lista-trimiteri-slim + .trimitere-slim: separator --line2, padding, tinta min-height:44px.
|
||||
Sub-elemente: .slim-vin (mono) si .slim-meta (muted 11px).
|
||||
"""
|
||||
_create_account_user("ls2@test.com")
|
||||
_login(client, "ls2@test.com")
|
||||
html = client.get("/?tab=acasa").text
|
||||
|
||||
assert ".lista-trimiteri-slim" in html, ".lista-trimiteri-slim lipseste din CSS (base.html)"
|
||||
assert ".trimitere-slim" in html, ".trimitere-slim lipseste din CSS (base.html)"
|
||||
|
||||
bloc = _bloc_componente_slim(html)
|
||||
assert "var(--line2)" in bloc, ".trimitere-slim nu foloseste var(--line2) ca separator"
|
||||
assert "min-height:44px" in bloc, ".trimitere-slim nu are tinta min-height:44px"
|
||||
assert ".slim-vin" in bloc, ".slim-vin lipseste din bloc"
|
||||
assert ".slim-meta" in bloc, ".slim-meta lipseste din bloc"
|
||||
assert "var(--muted)" in bloc, ".slim-meta nu foloseste var(--muted)"
|
||||
|
||||
|
||||
def test_clasa_camp_slim(client):
|
||||
""".camp-slim CSS exista cu fundal --card2.
|
||||
Macro-ul camp() din _macros.html suporta parametrul slim=False ca default.
|
||||
Default slim=False garanteaza ca randarea actuala ramane neschimbata.
|
||||
"""
|
||||
_create_account_user("cslim2@test.com")
|
||||
_login(client, "cslim2@test.com")
|
||||
html = client.get("/?tab=acasa").text
|
||||
|
||||
assert ".camp-slim" in html, ".camp-slim lipseste din CSS (base.html)"
|
||||
|
||||
bloc = _bloc_componente_slim(html)
|
||||
assert "var(--card2)" in bloc, ".camp-slim nu foloseste var(--card2) ca fundal"
|
||||
|
||||
# Macro-ul camp() din _macros.html trebuie sa aiba parametrul slim
|
||||
macros_path = os.path.join(
|
||||
os.path.dirname(__file__), "..", "app", "web", "templates", "_macros.html"
|
||||
)
|
||||
with open(macros_path, encoding="utf-8") as f:
|
||||
macros = f.read()
|
||||
assert "slim" in macros, "macro-ul camp() nu are parametrul slim in _macros.html"
|
||||
assert "slim=False" in macros, (
|
||||
"macro-ul camp() nu are slim=False ca default — randarea actuala poate fi rupta"
|
||||
)
|
||||
|
||||
|
||||
def test_clasa_chips(client):
|
||||
""".chips (container) + .chip (item): accent 18%, font 10-11px.
|
||||
.chip-del: buton de stergere accesibil (element separat in CSS).
|
||||
"""
|
||||
_create_account_user("chp2@test.com")
|
||||
_login(client, "chp2@test.com")
|
||||
html = client.get("/?tab=acasa").text
|
||||
|
||||
assert ".chips" in html, ".chips lipseste din CSS (base.html)"
|
||||
assert ".chip" in html, ".chip lipseste din CSS (base.html)"
|
||||
|
||||
bloc = _bloc_componente_slim(html)
|
||||
assert "var(--accent)" in bloc, ".chip nu foloseste var(--accent)"
|
||||
assert "18%" in bloc, ".chip nu are fundal accent 18% (color-mix accent 18%)"
|
||||
assert "11px" in bloc or "10px" in bloc, ".chip nu are font 10-11px"
|
||||
assert ".chip-del" in bloc, ".chip-del (buton de stergere) lipseste din bloc"
|
||||
|
||||
|
||||
def test_fara_hex_in_componente_noi(client):
|
||||
"""Zero hex literal in blocul CSS nou (SENTINEL-COMPONENTE-SLIM).
|
||||
Toate culorile folosesc EXCLUSIV var(--token), zero #rrggbb hardcodat.
|
||||
Ancorat pe SENTINEL ca sa nu scaneze blocul CSS vechi (unde exista #fff).
|
||||
"""
|
||||
_create_account_user("hexfree2@test.com")
|
||||
_login(client, "hexfree2@test.com")
|
||||
html = client.get("/?tab=acasa").text
|
||||
|
||||
bloc = _bloc_componente_slim(html)
|
||||
# Cauta hex literals in proprietati CSS de culoare
|
||||
hex_in_props = re.findall(
|
||||
r"(?:color|background|border(?:-color)?|fill|stroke)\s*:[^;{}]*?"
|
||||
r"(#[0-9a-fA-F]{3,8})",
|
||||
bloc,
|
||||
)
|
||||
assert not hex_in_props, (
|
||||
f"Hex literal gasit in componente noi US-002 — folositi var(--token): {hex_in_props}"
|
||||
)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PRD 5.15 US-004: lista slim trimiteri — layout consistent desktop + <=1024px
|
||||
# ============================================================
|
||||
|
||||
|
||||
def test_lista_slim_randeaza_si_are_tinta_touch(client):
|
||||
"""US-004: lista slim randeaza cu .trimitere-slim; tinta touch >=44px
|
||||
e garantata de CSS (min-height:44px din blocul SENTINEL-COMPONENTE-SLIM).
|
||||
Cardurile .tabel-trimiteri din 5.8 nu regreseaza: regula tabel-trimiteri
|
||||
thead display:none (card pe mobil) exista in continuare in base.html.
|
||||
"""
|
||||
acct = _create_account_user("slim_resp@test.com")
|
||||
_insert_submission(acct, status="sent")
|
||||
_login(client, "slim_resp@test.com")
|
||||
|
||||
html = client.get("/?tab=acasa").text
|
||||
|
||||
# Lista slim randeaza (elementele sunt injectate via hx-get="/_fragments/submissions"
|
||||
# -> testam ca clasele CSS sunt prezente in base.html, gata sa fie consumate)
|
||||
bloc = _bloc_componente_slim(html)
|
||||
assert "lista-trimiteri-slim" in bloc, \
|
||||
".lista-trimiteri-slim lipseste din blocul CSS slim (US-002 prerequisite)"
|
||||
assert "trimitere-slim" in bloc, \
|
||||
".trimitere-slim lipseste din blocul CSS slim"
|
||||
assert "min-height:44px" in bloc, \
|
||||
".trimitere-slim nu are min-height:44px — tinta touch mobil garantata"
|
||||
|
||||
# Regresie guard: regula card per rand 5.8 supravietuieste (o coloana pe mobil)
|
||||
mobil = _bloc_mobil_principal(html)
|
||||
assert ".tabel-trimiteri thead { display:none; }" in mobil, \
|
||||
"Regula card 5.8 (.tabel-trimiteri thead display:none) a disparut din CSS"
|
||||
|
||||
|
||||
def test_lista_slim_layout_tableta_1024(client):
|
||||
"""US-004: blocul tableta (768-1024px) nu rupe lista slim.
|
||||
.trimitere-slim e o lista stivuita (o coloana), fara grila 2/rand.
|
||||
Regula tableta cardifica listele existente (thead display:none) fara a elimina slim.
|
||||
"""
|
||||
_create_account_user("slim_tab@test.com")
|
||||
_login(client, "slim_tab@test.com")
|
||||
html = client.get("/?tab=acasa").text
|
||||
|
||||
# Blocul tableta exista (PRD 5.12/5.13 — pastrat)
|
||||
assert "@media (min-width:768px) and (max-width:1024px)" in html, \
|
||||
"Lipseste blocul @media tableta — regresia 5.12"
|
||||
|
||||
idx_t = html.find("@media (min-width:768px) and (max-width:1024px)")
|
||||
tableta = html[idx_t:idx_t + 800]
|
||||
|
||||
# Tableta ascunde thead (card per rand, o coloana) — lista slim e deja o coloana
|
||||
assert "thead" in tableta, \
|
||||
"Blocul tableta nu contine reguli pentru thead"
|
||||
|
||||
# Lista slim (ul.lista-trimiteri-slim) e o coloana prin constructie (flex-direction:column
|
||||
# implicit pe ul); nu trebuie repeat(2) in CSS.
|
||||
assert "repeat(2" not in html, \
|
||||
"CSS contine repeat(2 — listele NU trebuie sa fie 2/rand pana la 1024px"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# PRD 5.15 US-008: regresie componente slim + fara overflow orizontal
|
||||
# ============================================================
|
||||
|
||||
|
||||
def test_slim_list_fara_overflow_orizontal_css(client):
|
||||
"""US-008: lista slim (.trimitere-slim) nu forteaza overflow orizontal pe 390px / 1280px.
|
||||
|
||||
Verifica la nivel CSS / markup (nu browser): display:flex garanteaza adaptarea
|
||||
naturala la latimea containerului; niciun min-width fix mai mare de 390px pe elementele
|
||||
din blocul SENTINEL-COMPONENTE-SLIM (ar depasi viewport-ul mobil de 390px).
|
||||
Ancorare pe SENTINEL-COMPONENTE-SLIM — nu pe felii fixe din CSS global.
|
||||
"""
|
||||
_create_account_user("noovf_slim@test.com")
|
||||
_login(client, "noovf_slim@test.com")
|
||||
html = client.get("/?tab=acasa").text
|
||||
|
||||
bloc = _bloc_componente_slim(html)
|
||||
|
||||
# display:flex pe .trimitere-slim asigura adaptarea la latimea oricarui viewport
|
||||
assert "display:flex" in bloc, (
|
||||
".trimitere-slim nu are display:flex in SENTINEL-COMPONENTE-SLIM — "
|
||||
"layout nu se adapteaza la viewport; poate cauza overflow orizontal."
|
||||
)
|
||||
|
||||
# nicio valoare min-width > 390 in blocul slim (ar depasi viewport-ul mobil 390px)
|
||||
min_widths = re.findall(r'min-width:(\d+)px', bloc)
|
||||
for w in min_widths:
|
||||
assert int(w) <= 390, (
|
||||
f"min-width:{w}px in SENTINEL-COMPONENTE-SLIM poate cauza overflow orizontal "
|
||||
f"pe viewport de 390px (mobil). Verificati daca e pe .trimitere-slim."
|
||||
)
|
||||
|
||||
|
||||
def test_strip_sanatate_fara_hex_hardcodat():
|
||||
"""US-008: _status.html (strip sanatate D6 + contoare-contor) nu contine hex literal de culoare.
|
||||
|
||||
Garanteaza ca strip-ul adapteaza la temele luminoase (hartie/light) si intunecate (grafit/dark)
|
||||
exclusiv prin var(--token), NU prin valori hex hardcodate care ar ramane aceleasi
|
||||
indiferent de tema selectata.
|
||||
|
||||
Complement la test_fara_hex_in_componente_noi (care verifica SENTINEL din base.html).
|
||||
Strip sanatate traieste in _status.html, deci e verificat separat.
|
||||
"""
|
||||
from pathlib import Path
|
||||
templates_dir = Path(__file__).parent.parent / "app" / "web" / "templates"
|
||||
content = (templates_dir / "_status.html").read_text(encoding="utf-8")
|
||||
|
||||
# Hex literals in context de proprietate CSS de culoare (color/background/border + inline style)
|
||||
hex_in_culori = re.findall(
|
||||
r'(?:color|background|border)\s*[:=][^;{}\n"\']*?(#[0-9a-fA-F]{6,8})\b',
|
||||
content,
|
||||
)
|
||||
assert not hex_in_culori, (
|
||||
f"Hex literal de culoare in _status.html — strip sanatate va arata gresit pe "
|
||||
f"tema hartie (luminoasa) / light. Folositi var(--token). Gasite: {hex_in_culori}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user