refactor: comentarii strict functionale, fara referinte PRD/stories

Curatare globala a comentariilor si docstring-urilor (app, tools, teste,
scripturi): eliminate referintele la PRD-uri, US-xxx, task-uri istorice si
review-uri; pastrata doar informatia functionala, formulata scurt. Regula
adaugata in CLAUDE.md (sectiunea Stil). Fara modificari de cod sau comportament.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-07-06 13:48:38 +00:00
parent 86408887e5
commit 44f261e269
226 changed files with 1313 additions and 1760 deletions

View File

@@ -22,9 +22,9 @@ os.environ.setdefault("AUTOPASS_WORKER_USE_TEST_CREDS", "false")
# lazy-load-eze modelul de ~230MB la fiecare test care atinge editorul de mapari
# (suita rapida, fara download in CI). Testele de embeddings il pornesc punctual.
os.environ.setdefault("AUTOPASS_EMBEDDINGS_ENABLED", "false")
# Seed-ul de operatii etichetate (SILVER, PRD 5.18) e ON in app, dar OFF in teste:
# multe teste presupun mapping_suggestions GOL la init_db. Testele US-004/005/006 il
# pornesc punctual (object.__setattr__ pe settings sau apel direct la seeder).
# Seed-ul de operatii etichetate e ON in app, dar OFF in teste: multe teste presupun
# mapping_suggestions GOL la init_db. Testele care au nevoie de el il pornesc punctual
# (object.__setattr__ pe settings sau apel direct la seeder).
os.environ.setdefault("AUTOPASS_SEED_OPERATII_ENABLED", "false")
@@ -35,15 +35,15 @@ _REAL_INIT_DB = None
@pytest.fixture(autouse=True)
def _auto_send_on_default_account(request, monkeypatch):
"""PRD 5.19 US-009: contul default id=1 (seed schema.sql, INSERT OR IGNORE) porneste pe
"""Contul default id=1 (seed schema.sql, INSERT OR IGNORE) porneste pe
`auto_send_enabled=0` (Auto OFF) — corect in productie (nimic nu pleaca fara confirmare).
Dar suita exercita lantul `POST -> claim_one -> sent` pe contul id=1
(test_import_e2e, test_creds_delivery, test_live_rar): cu Auto OFF, ingestia ar marca
`held=1` (US-002) si worker-ul (`claim_one ... AND held=0`, US-003) nu ar mai lua randul
`held=1` si worker-ul (`claim_one ... AND held=0`) nu ar mai lua randul
-> testele ar stagna tacit. E un fix de STARE DB, nu env var (coloana e per-rand in
`accounts`), deci il aplicam wraparind `init_db` (contul id=1 NU e creat de `create_account`
-> un patch pe factory NU l-ar acoperi — Eng HIGH).
-> un patch pe factory NU l-ar acoperi).
Wrapam `init_db` astfel incat orice DB de test creat sa aiba id=1 pe Auto ON (held=0 la
ingestie), pastrand suita verde ca inainte de 5.19. Conturile create explicit de teste
@@ -114,7 +114,7 @@ def _reset_embeddings_singleton():
def make_test_cui(seed: str = "") -> str:
"""Factory centralizat (D#14, PRD 5.12 US-001): genereaza un CUI de test unic din seed.
"""Factory centralizat: genereaza un CUI de test unic din seed.
Folosit de fixture-urile de test care creeaza conturi via /signup sau create_account
si au nevoie de un CUI unic per test (altfel unicitatea CUI-ului bloca al doilea signup

View File

@@ -1,8 +1,8 @@
"""Teste US-003 (PRD 3.6): Acasa unificata — Trimiteri ca sectiune permanenta.
"""Teste Acasa unificata — Trimiteri ca sectiune permanenta.
Tab-ul "Trimiteri" (coada) eliminat din tab-bar; Trimiterile devin o sectiune sub
upload pe Acasa, cu heading "Trimiterile tale". ?tab=coada si /_fragments/coada
servesc continutul Acasa (nu 404, nu fragment orfan). Poll aliniat la 15s (M5).
servesc continutul Acasa (nu 404, nu fragment orfan).
"""
from __future__ import annotations
@@ -50,14 +50,14 @@ def _seed_submission(status: str = "sent", n: int = 1) -> None:
def test_tab_bar_fara_trimiteri(client):
"""US-009: tab-bar eliminat; 'Coada' nu exista; Mapari/Cont/Nomenclator raman in meniu."""
"""Tab-bar eliminat; 'Coada' nu exista; Mapari/Cont/Nomenclator raman in meniu."""
r = client.get("/")
assert r.status_code == 200
html = r.text
# "Coada" nu trebuie sa existe nici ca tab, nici ca link in meniu
assert 'id="tab-coada"' not in html
assert 'href="/?tab=coada"' not in html
# US-009: tab-bar eliminat; Mapari/Cont/Nomenclator sunt in meniul hamburger
# Mapari/Cont/Nomenclator sunt in meniul hamburger
for label in ("Mapari", "Cont", "Nomenclator"):
assert f">{label}" in html or f"{label}<" in html, f"lipseste intrarea {label} in meniu"
@@ -70,8 +70,7 @@ def test_acasa_contine_sectiunea_trimiteri(client):
html = r.text
assert 'id="filtre-trimiteri"' in html
assert "/_fragments/submissions" in html
# PRD 5.9 US-003: detaliul s-a mutat in modalul global (#modal-detaliu); vechiul
# panou inert #trimitere-detaliu a fost eliminat.
# Detaliul e in modalul global (#modal-detaliu); panoul inert vechi eliminat.
assert 'id="modal-detaliu"' in html
assert 'id="trimitere-detaliu"' not in html
@@ -108,7 +107,7 @@ def test_acasa_fara_linkuri_ajutor(client):
def test_acasa_fara_wayfinding_ajutor(client):
"""US-001 (5.5): randul 'Ajutor' (wayfinding Mapari/Coduri RAR) eliminat din Acasa —
"""Randul 'Ajutor' (wayfinding Mapari/Coduri RAR) eliminat din Acasa —
navigarea traieste in tab-bar si in meniul de cont."""
r = client.get("/?tab=acasa")
html = r.text
@@ -132,7 +131,7 @@ def test_trimiteri_fara_poll_periodic_pe_tabel(client):
"""Tabelul de trimiteri NU se reimprospateaza periodic: #submissions-wrap se
incarca la load / actiunile utilizatorului (trimiteriChanged) / reincarcaTrimiteri.
Reimprospatarea automata la date noi externe se face prin pollerul de versiune
care cheama reincarcaTrimiteri() — fara nudge manual (US-008)."""
care cheama reincarcaTrimiteri()."""
_seed_submission("sent")
r = client.get("/?tab=acasa")
html = r.text
@@ -142,6 +141,6 @@ def test_trimiteri_fara_poll_periodic_pe_tabel(client):
assert "every" not in wrap, f"tabelul nu trebuie sa aiba poll periodic: {wrap}"
assert "reincarcaTrimiteri" in wrap
assert "trimiteriChanged" in wrap
# Pollerul de versiune exista (auto-refresh la date noi externe). Nudge eliminat (US-008).
# Pollerul de versiune exista (auto-refresh la date noi externe); fara nudge manual.
assert "/_fragments/trimiteri-versiune" in html
assert 'id="nudge-trimiteri"' not in html

View File

@@ -1,4 +1,4 @@
"""Teste US-004 (PRD 5.5): model de stare a contului `accounts.status` + helperi.
"""Teste model de stare a contului `accounts.status` + helperi.
Acopera: derivarea status din active la migrare, invariantul active=1 <=> status='active',
helperii set_status/delete_account, protectia contului de sistem id=1, excluderea 'deleted'
@@ -94,7 +94,7 @@ def test_delete_purjeaza_pii_si_elibereaza_cui(conn):
"""Stergerea soft purjeaza creds RAR + revoca cheile API + elibereaza CUI (re-inregistrabil)."""
from app.accounts import create_account, delete_account, list_accounts
acct_id = create_account(conn, "Service GDPR", cui="RO12345", active=True)
# US-013: creds in sloturi per-env (rar_creds_enc legacy dropata)
# creds in sloturi per-env
conn.execute(
"UPDATE accounts SET rar_creds_test_enc='secret_enc_test', rar_creds_prod_enc='secret_enc_prod' WHERE id=?",
(acct_id,),
@@ -138,7 +138,6 @@ def test_migrare_deriva_status_din_active(conn):
from app.db import _migrate
# Reconstruim accounts fara `status` (rebuild de tabela — singura cale in SQLite vechi).
# US-013: rar_creds_enc nu mai exista in accounts (dropata); nu e in legacy DDL.
conn.executescript(
"""
PRAGMA foreign_keys=OFF;

View File

@@ -1,4 +1,4 @@
"""Teste US-001 (PRD 3.1): coloana accounts.active + helper-e cont in app/accounts.py."""
"""Teste coloana accounts.active + helper-e cont in app/accounts.py."""
from __future__ import annotations
@@ -119,7 +119,7 @@ def test_list_accounts_ordonat_fara_creds(conn):
# ---------------------------------------------------------------------------
# US-001 (PRD 5.12): accounts.email + validari companie/email/CUI
# accounts.email + validari companie/email/CUI
# ---------------------------------------------------------------------------
def test_create_account_fara_email_ridica(conn):
@@ -176,7 +176,7 @@ def test_account_is_complete_false_pe_legacy_incomplet(conn):
# ---------------------------------------------------------------------------
# 5.17 US-001/US-008: schema tier + trial_until + set_tier + CLI set-tier
# schema tier + trial_until + set_tier + CLI set-tier
# ---------------------------------------------------------------------------
def test_migrare_tier_trial_defensiva(conn):

View File

@@ -1,4 +1,4 @@
"""Teste US-008 (PRD 5.5): rute admin pentru ciclul de viata al conturilor —
"""Rute admin pentru ciclul de viata al conturilor —
block/archive/delete + bulk pe lista account_id, require_admin + CSRF + PRG, dev id=1 protejat.
"""

View File

@@ -1,7 +1,4 @@
"""Teste US-011 (PRD 3.3b): panou admin web /admin — conturi in asteptare + activare.
TDD strict: testele se scriu INAINTE de implementare; la inceput pica (RED),
dupa implementare trec (GREEN).
"""Teste panou admin web /admin — conturi in asteptare + activare.
Fisiere testate: app/web/admin_routes.py, app/web/templates/admin.html.
"""
@@ -175,7 +172,7 @@ def test_non_admin_403(client):
Creeaza intai un cont admin (bootstrap: primul user devine admin),
apoi un al doilea cont (non-admin) si verifica ca al doilea primeste 403.
"""
# Primul signup devine automat admin (bootstrap US-010)
# Primul signup devine automat admin (bootstrap)
_signup(client, "Admin Bootstrap SA", "bootstrap@test.ro")
# Al doilea user NU e admin
@@ -286,7 +283,7 @@ def test_set_tier_din_admin_incheie_trial(client):
"""POST /admin/set-tier -> tier actualizat, trial_until=NULL (trial incheiat), 303.
Contul nou are trial Pro 30z; alocarea manuala trebuie sa-l incheie ca alegerea
sa aiba efect imediat (decizie user 2026-06-29)."""
sa aiba efect imediat."""
target_id = _signup(client, "Firma Upgrade SRL", "upgrade@test.ro")
tier0, trial0 = _get_tier_trial(target_id)
assert tier0 == "free", "cont nou trebuie sa porneasca pe free"

View File

@@ -1,4 +1,4 @@
"""Teste US-010 (PRD 3.3b): rol admin + bootstrap + guard require_admin.
"""Teste rol admin + bootstrap + guard require_admin.
Fisiere testate: app/users.py (helper-e admin), app/web/session.py (require_admin),
tools/account.py (subcomanda set-admin).

View File

@@ -1,4 +1,4 @@
"""Teste API /v1/prezentari — rutare validare (T3) + idempotenta."""
"""Teste API /v1/prezentari — rutare validare + idempotenta."""
from __future__ import annotations
@@ -63,7 +63,7 @@ def test_idempotenta_dedup(client):
# --------------------------------------------------------------------------- #
# PRD 5.7 — raspuns onest: erori/nemapate/motiv pe randuri blocate #
# Raspuns onest: erori/nemapate/motiv pe randuri blocate #
# --------------------------------------------------------------------------- #
def test_needs_data_intoarce_erori(client):

View File

@@ -1,4 +1,4 @@
"""Teste US-010 (PRD 5.6): API DELETE + re-pune in coada, scoped + oracol scope/stare."""
"""Teste API DELETE + re-pune in coada, scoped + oracol scope/stare."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""Teste US-005 — camp rar_env pe POST /v1/prezentari si /valideaza.
"""Teste camp rar_env pe POST /v1/prezentari si /valideaza.
Acopera: default din cont, tinta explicita, respingere tinta indisponibila,
echo GET, valoare invalida (422 Pydantic), echo dry-run valideaza.

View File

@@ -1,4 +1,4 @@
"""US-011 (PRD 5.15): account-scope pe GET-urile de listare API (securitate).
"""Teste account-scope pe GET-urile de listare API (securitate).
Verifica:
- GET /v1/prezentari: un cont nu vede submissions ale altui cont
@@ -6,9 +6,8 @@ Verifica:
- Unauthenticated access cu require_api_key=True -> 401
- Filtre si paginare nu sparg scope-ul
Legatura cu implementare: resolve_account_id + account_scope_clause (mecanisme
existente, reutilizate). Testele LOCK DOWN comportamentul deja implementat
si verifica alinierea cu AUTOPASS_REQUIRE_API_KEY (dev vs prod).
Foloseste resolve_account_id + account_scope_clause; verifica alinierea
cu AUTOPASS_REQUIRE_API_KEY (dev vs prod).
"""
from __future__ import annotations
@@ -227,7 +226,7 @@ def test_get_listare_filtru_status_nu_sparge_scope(client):
# ============================================================================
# PRD 5.17 — enforcement planuri: gate API (T4) + volum (T3) + kill-switch (T5)
# Enforcement planuri: gate API + volum + kill-switch
# ============================================================================
_PREZ_PLAN = {
@@ -279,7 +278,7 @@ def _insert_n_submissions(account_id: int, n: int) -> None:
def test_free_fara_api_403(client):
"""Cont free (non-default, cu cheie API) → 403 PLAN_FARA_API pe POST /v1/prezentari.
T4 PRD 5.17: gate API refuza conturi cu api_access=False in PLANS.
Gate-ul API refuza conturi cu api_access=False in PLANS.
"""
acct_id, key = _create_account_with_key("FreePlanGate")
_set_tier_acct(acct_id, "free", trial_until=None)
@@ -349,8 +348,8 @@ def test_trial_pro_api_ok(client):
def test_dry_run_valideaza_ramane_permis(client):
"""POST /v1/prezentari/valideaza (dry-run) e permis pe orice plan, inclusiv free.
Decizie design (PRD 5.17): valideaza nu face enqueue si nu consuma cota,
deci NU e protejat de gate-ul API — integratorii pot testa fara upgrade.
Valideaza nu face enqueue si nu consuma cota, deci NU e protejat de
gate-ul API — integratorii pot testa fara upgrade.
"""
acct_id, key = _create_account_with_key("FreeValideazaTest")
_set_tier_acct(acct_id, "free", trial_until=None)
@@ -374,8 +373,8 @@ def test_dry_run_valideaza_ramane_permis(client):
def test_free_peste_60_respins_api(client):
"""Dev account (id=1) la 60/60 pe free → a 61-a prezentare respinsa 422 PLAN_LIMITA_LUNARA.
Dev account (id=1) in dev mode (require_api_key=False) are bypass la gate-ul API (T4),
dar NU la verificarea de volum (T3). La 60/60, urmatoarea cerere trebuie respinsa 422.
Dev account (id=1) in dev mode (require_api_key=False) are bypass la gate-ul API,
dar NU la verificarea de volum. La 60/60, urmatoarea cerere trebuie respinsa 422.
"""
_set_tier_acct(1, "free", trial_until=None)
_insert_n_submissions(1, 60)
@@ -392,7 +391,7 @@ def test_free_peste_60_respins_api(client):
def test_eroare_3_niveluri_plan_limita(client):
"""Eroarea PLAN_LIMITA_LUNARA contine toate 3 nivelurile: cod, problema, cauza, fix.
Pattern standard (PRD 5.17): eroare structurata pe 3 niveluri — nu 500, nu catch-all.
Pattern standard de eroare structurata pe 3 niveluri — nu 500, nu catch-all.
"""
_set_tier_acct(1, "free", trial_until=None)
_insert_n_submissions(1, 60)
@@ -512,7 +511,7 @@ def test_dev_id1_neblocat(client):
def test_flag_enforce_plans_false_sare_enforcement(client, monkeypatch):
"""Kill-switch AUTOPASS_ENFORCE_PLANS=false sare toate gate-urile de plan.
T5 PRD 5.17: flag de operare pentru debugging sau rollback rapid fara revert de cod.
Flag de operare pentru debugging sau rollback rapid fara revert de cod.
Chiar si cu free la 60/60, nu trebuie 422 cand flag-ul e oprit.
"""
from app.config import get_settings

View File

@@ -1,4 +1,4 @@
"""Teste US-004 (PRD 5.6): audit cerere API per cont in jurnal."""
"""Teste audit cerere API per cont in jurnal."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""US-001 (PRD 5.19): schema comutator Auto per cont + flag `held` pe submission.
"""Schema comutator Auto per cont + flag `held` pe submission.
Acopera: migrarea aditiva idempotenta (coloane + index partial pe DB vechi), helperii
`get_auto_send`/`set_auto_send`/`held_for_account` din app/accounts.py si default-ul 0.

View File

@@ -1,6 +1,5 @@
"""Teste US-007 (PRD 3.6) actualizate dupa US-002 (PRD 5.11).
"""Teste comutator auto_send: macro autosend_toggle neutralizat (intoarce string gol).
US-002: macro autosend_toggle neutralizat (intoarce string gol).
Checkbox-ul name=auto_send a fost scos din UI. Coloanele DB raman.
Testele de UI verifica ABSENTA toggle-ului; testele de backend (stocare DB) raman.
"""
@@ -97,24 +96,24 @@ def _macro_html(checked: bool = True, form_id: str = "") -> str:
return str(mod.autosend_toggle(form_id=form_id, checked=checked))
# --- markup: macro neutralizat dupa US-002 ---
# --- markup: macro neutralizat ---
def test_comutator_coada_prezent():
"""US-002: macro autosend_toggle neutralizat -> output gol (fara checkbox)."""
"""macro autosend_toggle neutralizat -> output gol (fara checkbox)."""
html = _macro_html()
assert 'name="auto_send"' not in html, "US-002: checkbox auto_send scos din UI"
assert 'name="auto_send"' not in html, "checkbox auto_send scos din UI"
assert html.strip() == "", f"macro neutralizat trebuie sa intoarca string gol, got: {html!r}"
def test_eticheta_scoped_pe_operatie():
"""US-002: macro neutralizat -> nicio eticheta scoped."""
"""macro neutralizat -> nicio eticheta scoped."""
html = _macro_html()
assert "aceasta operatie" not in html
assert html.strip() == ""
def test_default_pune_automat():
"""US-002: macro neutralizat intoarce gol indiferent de parametrul checked."""
"""macro neutralizat intoarce gol indiferent de parametrul checked."""
html_default = _macro_html(checked=True)
assert html_default.strip() == ""
html_off = _macro_html(checked=False)
@@ -154,7 +153,7 @@ def test_tine_pentru_verificare_mapeaza_auto_send_false(client):
# --- prezent in AMBELE locuri (mapari tab + panou preview) ---
def test_comutator_in_tab_mapari(client):
"""US-002: tabul Mapari nu mai contine checkbox auto_send (macro neutralizat)."""
"""Tabul Mapari nu mai contine checkbox auto_send (macro neutralizat)."""
from app.db import get_connection
import json
acct = _create_account_user("tm@test.com")
@@ -172,12 +171,12 @@ def test_comutator_in_tab_mapari(client):
_login(client, "tm@test.com")
resp = client.get("/?tab=mapari")
assert resp.status_code == 200
assert 'name="auto_send"' not in resp.text, "US-002: checkbox auto_send scos din UI"
assert "In coada" not in resp.text, "US-002: coloana 'In coada' scoasa"
assert 'name="auto_send"' not in resp.text, "checkbox auto_send scos din UI"
assert "In coada" not in resp.text, "coloana 'In coada' scoasa"
def test_comutator_in_panou_preview(client):
"""US-002: panoul de mapare din preview nu mai contine checkbox auto_send."""
"""Panoul de mapare din preview nu mai contine checkbox auto_send."""
_create_account_user("pp@test.com")
_seed_nomenclator("R-FRANE")
_login(client, "pp@test.com")
@@ -203,5 +202,5 @@ def test_comutator_in_panou_preview(client):
})
assert r.status_code == 200
assert "OP-NEMAPAT" in r.text, "operatia nemapata trebuie sa apara in panoul de mapare"
assert 'name="auto_send"' not in r.text, "US-002: checkbox auto_send scos din preview"
assert "In coada automat" not in r.text, "US-002: eticheta 'In coada automat' scoasa"
assert 'name="auto_send"' not in r.text, "checkbox auto_send scos din preview"
assert "In coada automat" not in r.text, "eticheta 'In coada automat' scoasa"

View File

@@ -1,4 +1,4 @@
"""Teste US-010 (PRD 5.20): badge mediu RAR in liste/detaliu/audit/ecou API.
"""Teste badge mediu RAR in liste/detaliu/audit/ecou API.
Teste:
test_badge_in_lista -- /_fragments/submissions afiseaza PRODUCȚIE / Testare per rand

View File

@@ -137,7 +137,7 @@ def test_legacy_dual_lookup_strategy():
assert found, "dual-lookup trebuie sa gaseasca randul vechi"
# --- Integrare: API route foloseste build_key (OV-2) ---
# --- Integrare: API route foloseste build_key ---
@pytest.fixture()
def client(monkeypatch):

View File

@@ -1,4 +1,4 @@
"""Teste PRD 5.19 R4 — tools/carantina_held.py (atenuare hazard de rollback).
"""Teste tools/carantina_held.py (atenuare hazard de rollback).
Carantineaza randurile `queued AND held=1` (-> `error`/`ROLLBACK_QUARANTINE`)
ca sa nu fie trimise de un worker fara filtrul `AND held=0` dupa un revert.
@@ -63,7 +63,7 @@ def test_carantineaza_rand_tinut(env, capsys):
r = _row(conn, sid)
assert r["status"] == "error"
assert r["rar_error"] == "ROLLBACK_QUARANTINE"
# /code-review #4: randul carantinat primeste purge_after (altfel PII ar sta la nesfarsit,
# randul carantinat primeste purge_after (altfel PII ar sta la nesfarsit,
# purge_expired sterge doar randuri cu purge_after setat).
assert r["purge_after"] is not None
assert conn.execute(

View File

@@ -1,4 +1,4 @@
"""Teste US-008 (PRD 5.20): configurare medii RAR per cont — Testare + Productie.
"""Teste configurare medii RAR per cont — Testare + Productie.
Ruta testata: POST /cont/rar-medii

View File

@@ -47,12 +47,12 @@ def _body(**over):
def test_dashboard_renders_with_rar_state(client):
r = client.get("/")
assert r.status_code == 200
# Dupa US-003 bara de status e incarcata via HTMX (hx-trigger=load, every 15s)
# Bara de status e incarcata via HTMX (hx-trigger=load, every 15s)
assert "/_fragments/status" in r.text, "Dashboard-ul trebuie sa referenceze fragmentul de status"
# Fragmentul de status contine starea de sanatate (text uman, nu brut tehnic)
rs = client.get("/_fragments/status")
assert rs.status_code == 200
# US-003 D6: strip sanatate unificat — "declaratiile" apare in orice stare (curg/blocat)
# strip sanatate unificat — "declaratiile" apare in orice stare (curg/blocat)
assert "declaratiile" in rs.text.lower(), (
f"Strip sanatate lipseste din fragment. HTML: {rs.text[:500]}"
)
@@ -73,7 +73,7 @@ def test_nomenclator_fragment_lists_seed(client):
def test_submissions_fragment_empty_state(client):
r = client.get("/_fragments/submissions")
assert r.status_code == 200
# US-005: empty state prietenos cu indemn la Import (nu mesajul tehnic vechi)
# empty state prietenos cu indemn la Import (nu mesajul tehnic vechi)
assert "Nicio trimitere" in r.text or "incepe cu Import" in r.text or "?tab=import" in r.text

View File

@@ -1,7 +1,6 @@
"""Test US-011 (discoverability): linkul 'Panou admin' apare pe dashboard doar pentru admini.
"""Linkul 'Panou admin' apare pe dashboard doar pentru admini.
Completeaza intentia US-011 — adminul trebuie sa poata descoperi /admin din UI, nu doar
prin URL direct.
Adminul trebuie sa poata descoperi /admin din UI, nu doar prin URL direct.
"""
from __future__ import annotations

View File

@@ -1,6 +1,6 @@
"""Teste US-005 (PRD 3.3): scoping dashboard pe sesiune (2 conturi, citiri).
"""Teste scoping dashboard pe sesiune (2 conturi, citiri).
Comportamental (C6): nu grep, ci verificare reala cu 2 conturi + date distincte.
Verificare comportamentala reala cu 2 conturi + date distincte, nu grep.
"""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""Teste US-012 (PRD 5.6): un rand `error` nu mai blocheaza retrimiterea (dedup).
"""Un rand `error` nu mai blocheaza retrimiterea (dedup).
La resubmit cu aceeasi cheie de continut peste un rand `error`: se RE-ACTIVEAZA
(reactivated:true + stare noua), creds-urile se actualizeaza. Peste sent/queued/
@@ -82,7 +82,7 @@ def test_resubmit_actualizeaza_creds_pe_reactivare(client):
enc_dupa = _creds_enc(sid)
assert enc_dupa is not None
assert enc_dupa != enc_initial, "creds-urile trebuie actualizate la reactivare"
# US-013: creds propagate in slotul per-env (rar_creds_test_enc, ancora globala=test)
# creds propagate in slotul per-env (rar_creds_test_enc, ancora globala=test)
from app.db import get_connection
from app.crypto import decrypt_creds
conn = get_connection()
@@ -118,7 +118,7 @@ def test_resubmit_peste_queued_ramane_deduped(client):
def test_reactivare_pe_needs_data_expune_erori(client):
"""PRD 5.7: reactivarea unui rand error care re-clasifica needs_data trebuie sa
"""Reactivarea unui rand error care re-clasifica needs_data trebuie sa
expuna erori/motiv (raspuns onest), nu doar status + reactivated."""
# rand initial valid -> queued; il fortam error
r1 = client.post("/v1/prezentari", json=_body())

View File

@@ -1,6 +1,4 @@
"""Teste US-012 (PRD 5.15): Analytics device-mix — validare premisa mobil, fara PII.
TDD: RED inainte de implementare.
"""Teste analytics device-mix — validare premisa mobil, fara PII.
Semnal: la acces dashboard -> eveniment 'device_mix' in app_events cu cod 'desktop'/'mobil'.
Zero PII: nu se stocheaza UA brut, IP sau VIN.

View File

@@ -1,6 +1,4 @@
"""Teste US-012 (PRD 5.20): audit evenimente medii RAR + e2e lant submission.
Fisier nou; nu modifica teste existente.
"""Teste audit evenimente medii RAR + e2e lant submission.
Teste:
test_lant_import_pana_la_queued -- submission ajunge la status=queued cu rar_env corect

View File

@@ -1,7 +1,7 @@
"""US-005 (PRD 5.18) — embeddings indexeaza corpusul etichetat (NU nomenclatorul).
"""Embeddings indexeaza corpusul etichetat (NU nomenclatorul).
k-NN peste exemple reale etichetate (denumire_normalizata -> cod, is_nul) e net mai
precis decat peste cele 18 categorii generice. Acopera si simetria corpus/query (F1):
precis decat peste cele 18 categorii generice. Acopera si simetria corpus/query:
corpusul e text NORMALIZAT, deci query-ul trebuie normalizat la fel inainte de embedding.
"""
@@ -34,7 +34,7 @@ def env(monkeypatch):
tmp = tempfile.mkdtemp()
monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "us005.db"))
monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "false")
monkeypatch.setenv("AUTOPASS_EMBEDDINGS_ENABLED", "true") # US-005 are nevoie de embeddings ON
monkeypatch.setenv("AUTOPASS_EMBEDDINGS_ENABLED", "true") # necesar pentru testele de embeddings
from app.config import get_settings
get_settings.cache_clear()
from app.db import init_db
@@ -115,7 +115,7 @@ def test_semnatura_corpus_pe_seed(conn):
def test_query_normalizat_ca_si_corpusul(conn, monkeypatch):
"""F1 (HIGH): enrich_suggestions interogheaza suggest_nearest cu textul NORMALIZAT."""
"""enrich_suggestions interogheaza suggest_nearest cu textul NORMALIZAT."""
import app.embeddings as emb
captura = {}
monkeypatch.setattr(emb, "has_corpus", lambda: True)

View File

@@ -1,8 +1,8 @@
"""US-006 (PRD 5.18) — enrich_suggestions = pre-filtru NUL + k-NN pe corpus etichetat.
"""enrich_suggestions = pre-filtru NUL + k-NN pe corpus etichetat.
Ordinea de precedenta: pre-filtru NUL -> (daca NUL: fara cod) altfel GOLD partajat >
exact (SILVER) > k-NN embeddings. k-NN sub prag -> abtinere. Vecin k-NN NUL -> supresie.
Invariant #13: nimic din asta nu intra in resolve_prestatii/load_mapping.
Nimic din enrich_suggestions nu intra in resolve_prestatii/load_mapping.
"""
from __future__ import annotations
@@ -123,7 +123,7 @@ def test_vecin_knn_nul_supreseaza(conn, monkeypatch):
def test_invariant_13_resolve_neatins(conn):
"""Regresie #13: SILVER populat NU produce auto-rezolvare in resolve_prestatii."""
"""SILVER populat NU produce auto-rezolvare in resolve_prestatii."""
from app.mapping import resolve_prestatii, normalize_for_match
_silver(conn, normalize_for_match("OPERATIE X"), "OE-1")
resolved, unmapped = resolve_prestatii(

View File

@@ -1,4 +1,4 @@
"""Teste US-001 (PRD 5.6): handler global de excepții -> 500 structurat (3 niveluri) + log."""
"""Teste handler global de exceptii -> 500 structurat (3 niveluri) + log."""
from __future__ import annotations
@@ -39,7 +39,7 @@ def test_exceptie_neasteptata_da_500_structurat(client, monkeypatch):
assert r.status_code == 500
body = r.json()
assert body["cod"] == "EROARE_INTERNA"
# 3 niveluri (PRD 5.4): problema + fix
# 3 niveluri: cod + problema + fix
assert body["problema"]
assert body["fix"]
assert "request_id" in body

View File

@@ -1,7 +1,4 @@
"""Teste pentru app/errors.py — catalog central de erori (US-001 / PRD 5.4).
Urmeaza TDD: testele sunt scrise INAINTE de implementare.
"""
"""Teste pentru app/errors.py — catalog central de erori."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""US-002 (PRD 5.18) — etichetator offline multi-backend cu prompt procedural.
"""Etichetator offline multi-backend cu prompt procedural.
Toate testele ruleaza FARA retea reala (transport injectabil / inspectie body).
Acopera: prompt 3 pasi, envelope json_schema strict + enum, backend selectabil
@@ -70,7 +70,7 @@ def test_parseaza_raspuns_si_garda_truncare():
def test_backend_selectabil_env(monkeypatch):
# Default = lmstudio (backend aprobat v1, D4).
# Default = lmstudio.
monkeypatch.delenv("ETICHETARE_BACKEND", raising=False)
assert eticheteaza.get_backend().name == "lmstudio"
# Selectie prin env.

View File

@@ -1,4 +1,4 @@
"""Teste US-006 (PRD 3.6): "Formate de coloane salvate" randate ca TABEL.
"""Teste "Formate de coloane salvate" randate ca TABEL.
Doar marcaj de template — POST-urile /formate-coloane/editeaza si /formate-coloane/sterge
raman identice. .tablewrap pentru consistenta cu celelalte tabele.

View File

@@ -1,4 +1,4 @@
"""Teste FOUNDATION (Task #1): schema + migrari idempotente + openpyxl disponibil."""
"""Teste schema + migrari idempotente + openpyxl disponibil."""
from __future__ import annotations
@@ -35,11 +35,11 @@ def _tables(conn) -> set[str]:
# --- Coloane noi ---
def test_accounts_rar_creds_enc_dropata(db_conn):
"""US-013: accounts.rar_creds_enc a fost dropata; submissions.rar_creds_enc ramane."""
"""accounts.rar_creds_enc a fost dropata; submissions.rar_creds_enc ramane."""
acc_cols = _table_cols(db_conn, "accounts")
sub_cols = _table_cols(db_conn, "submissions")
assert "rar_creds_enc" not in acc_cols, \
"accounts.rar_creds_enc trebuie sa fie ABSENTA dupa US-013 DROP"
"accounts.rar_creds_enc trebuie sa fie ABSENTA"
assert "rar_creds_enc" in sub_cols, \
"submissions.rar_creds_enc trebuie sa RAMANA (creds efemere per-cerere)"
@@ -158,7 +158,7 @@ def test_migrate_on_existing_db(monkeypatch):
assert "batch_id" in sub_cols
assert "row_index" in sub_cols
assert "purge_after" in sub_cols
# US-013: accounts.rar_creds_enc a fost dropata.
# accounts.rar_creds_enc a fost dropata.
assert "rar_creds_enc" not in acc_cols
conn.close()
get_settings.cache_clear()

View File

@@ -1,10 +1,10 @@
"""US-003 (PRD 5.18) — generare seed etichetat in faze pe frecventa.
"""Generare seed etichetat in faze pe frecventa.
Pipeline dedup OBLIGATORIU inainte de orice apel LLM (D5):
Pipeline dedup OBLIGATORIU inainte de orice apel LLM:
brut -> normalize_for_match -> arunca chei vide -> dedup pe cheie (freq=suma NR)
-> reuse etichete existente (labels-groq + seed comis, conflict freq-max) -> de_etichetat.
Idempotenta cross-run (F2/F7): a doua rulare consuma seedul comis ca cache -> 0 apeluri LLM.
Idempotenta cross-run: a doua rulare consuma seedul comis ca cache -> 0 apeluri LLM.
Toate testele FARA retea: `clasifica` e injectat (mock care inregistreaza ce primeste).
"""
@@ -134,7 +134,7 @@ def test_zero_duplicate_trimis_la_llm(tmp_path):
def test_rerun_zero_apeluri_llm(tmp_path):
"""Criteriul real de idempotenta (F2/F7): a doua rulare = 0 apeluri LLM, seed identic."""
"""Criteriul real de idempotenta: a doua rulare = 0 apeluri LLM, seed identic."""
f = tmp_path / "a.csv"
_scrie_csv(f, [("OP UNU", 10), ("OP DOI", 5)])
seed = tmp_path / "seed.json"

View File

@@ -1,4 +1,4 @@
"""Teste scope cont pe GET /v1/audit/export (US-003, PRD 3.2)."""
"""Teste scope cont pe GET /v1/audit/export."""
from __future__ import annotations
@@ -51,7 +51,7 @@ def test_export_doar_contul_cheii(env):
from app.db import get_connection
conn = get_connection()
try:
# tier='pro' ca sa treaca gate-ul API (T4 PRD 5.17); testul masoara scoping, nu planuri.
# tier='pro' ca sa treaca gate-ul API; testul masoara scoping, nu planuri.
conn.execute("INSERT INTO accounts (id, name, tier) VALUES (2, 'al-doilea', 'pro')")
k1 = create_api_key(conn, 1)
k2 = create_api_key(conn, 2)

View File

@@ -1,6 +1,6 @@
"""Teste scope cont pe GET /v1/mapari + /pending (US-002, PRD 3.2).
"""Teste scope cont pe GET /v1/mapari + /pending.
TD-3.2 (decis la poarta): parametrul ?account_id= din query se pastreaza DAR:
Parametrul ?account_id= din query se pastreaza DAR:
- daca e prezent SI difera de contul cheii -> 400 explicit
- daca e prezent si egal -> ok
- daca lipseste -> contul cheii
@@ -69,7 +69,7 @@ def test_mapari_doar_contul_cheii(env):
def test_mapari_query_account_id_diferit_400(env):
"""Daca ?account_id difera de contul cheii -> 400 explicit (TD-3.2)."""
"""Daca ?account_id difera de contul cheii -> 400 explicit."""
with _client() as c:
from app.auth import create_api_key
from app.db import get_connection
@@ -85,7 +85,7 @@ def test_mapari_query_account_id_diferit_400(env):
def test_mapari_query_account_id_egal_ok(env):
"""Daca ?account_id egal cu contul cheii -> 200 (TD-3.2)."""
"""Daca ?account_id egal cu contul cheii -> 200."""
with _client() as c:
from app.auth import create_api_key
from app.db import get_connection
@@ -161,7 +161,7 @@ def test_pending_web_global_neschimbat(env):
def test_pending_filtreaza_in_sql_cu_regula_null(env):
"""B1: pending_unmapped(conn, account_id=1) include si randuri cu account_id=NULL (legacy).
"""pending_unmapped(conn, account_id=1) include si randuri cu account_id=NULL (legacy).
Filtrarea trebuie sa se faca IN SQL cu:
WHERE status='needs_mapping' AND (account_id=? OR (account_id IS NULL AND ?=1))

View File

@@ -1,8 +1,4 @@
"""Teste scope cont pe GET /v1/prezentari + /{id} (US-001, PRD 3.2).
Metoda TDD: testele se scriu inainte de implementare (RED) si trebuie sa ramana
verzi dupa implementare (GREEN).
"""
"""Teste scope cont pe GET /v1/prezentari + /{id}."""
from __future__ import annotations
@@ -47,7 +43,7 @@ def test_lista_doar_contul_cheii(env):
from app.db import get_connection
conn = get_connection()
try:
# tier='pro' pe ambele conturi — testul verifica scoping GET, nu planuri (T4 PRD 5.17).
# tier='pro' pe ambele conturi — testul verifica scoping GET, nu planuri.
conn.execute("UPDATE accounts SET tier='pro' WHERE id=1")
conn.execute("INSERT INTO accounts (id, name, tier) VALUES (2, 'al-doilea', 'pro')")
k1 = create_api_key(conn, 1)
@@ -77,7 +73,7 @@ def test_lista_doar_contul_cheii(env):
def test_detaliu_cross_account_404(env):
"""GET /{id} cu cheia contului B pentru submission-ul contului A -> 404.
B3: detail-ul 404 cross-account trebuie byte-identic cu cel al unui id inexistent
Raspunsul 404 cross-account trebuie byte-identic cu cel al unui id inexistent
(acelasi status + acelasi mesaj) — nu dam indicii ca randul exista.
"""
with _client() as c:
@@ -103,7 +99,7 @@ def test_detaliu_cross_account_404(env):
def test_legacy_null_vizibil_pentru_cont_1(env):
"""Randuri cu account_id=NULL apartin contului 1 (legacy OV-2); contul 2 nu le vede."""
"""Randuri cu account_id=NULL apartin contului 1 (legacy); contul 2 nu le vede."""
with _client() as c:
from app.auth import create_api_key
from app.db import get_connection
@@ -149,11 +145,11 @@ def test_fara_cheie_flag_off_vede_contul_1(env):
def test_detaliu_nu_expune_creds(env):
"""B4: GET /v1/prezentari/{id} nu expune campuri sensibile (rar_creds_enc, payload_json,
"""GET /v1/prezentari/{id} nu expune campuri sensibile (rar_creds_enc, payload_json,
idempotency_key).
NOTA T9 (PRD 5.6): `rar_error` e ACUM expus intentionat (recovery API observabil) —
contine doar coduri/mesaje de validare RAR, niciodata creds.
`rar_error` e expus intentionat (recovery API observabil) — contine doar
coduri/mesaje de validare RAR, niciodata creds.
"""
with _client() as c:
from app.auth import create_api_key

View File

@@ -1,4 +1,4 @@
"""Teste PRD 5.19 US-010 — onestitate + observabilitate `held` pe canalul API.
"""Onestitate + observabilitate `held` pe canalul API.
- `held` in raspunsul enqueue (SubmissionResult) + motiv non-null.
- `held` in proiectiile GET /v1/prezentari si /v1/prezentari/{id}.

View File

@@ -1,6 +1,6 @@
"""Teste PRD 5.19 US-002 — snapshot `held` la ingestie din comutatorul de cont.
"""Teste snapshot `held` la ingestie din comutatorul de cont.
Acopera TOATE situ-rile care scriu `status='queued'` prin ingestie (chokepoint
Acopera TOATE situatiile care scriu `status='queued'` prin ingestie (chokepoint
`held_for_account`): enqueue API, reactivare error->queued, dedup echo, commit import,
reresolve `needs_mapping`. `held` NU intra in idempotency_key.
@@ -107,7 +107,7 @@ def test_auto_on_ingestie_not_held(client):
# --------------------------------------------------------------------------- #
# Reactivare error->queued (bug de bypass Eng Finding A) #
# Reactivare error->queued #
# --------------------------------------------------------------------------- #
def test_reactivare_respecta_auto_off(client):

View File

@@ -1,9 +1,9 @@
"""Regresie PRD 5.19 US-002 — re-snapshot `held` pe caile de re-punere in coada.
"""Regresie — re-snapshot `held` pe caile de re-punere in coada.
Bug (gasit la /code-review high): create_prezentari (reactivare) si reresolve_account
re-calculau `held` din comutatorul contului la tranzitia -> queued, dar caile de
re-punere din dashboard/admin (requeue_submission, corectie, repune-cu-cod, bulk-fix)
lasau `held` pe valoarea VECHE. Consecinta: un rand ingerat pe Auto ON (held=0) care a
Bug: create_prezentari (reactivare) si reresolve_account re-calculau `held` din
comutatorul contului la tranzitia -> queued, dar caile de re-punere din
dashboard/admin (requeue_submission, corectie, repune-cu-cod, bulk-fix) lasau
`held` pe valoarea VECHE. Consecinta: un rand ingerat pe Auto ON (held=0) care a
esuat, apoi contul trecut pe Auto OFF, la re-punere pastra held=0 -> worker-ul il
auto-trimitea la RAR (FINALIZATA ireversibil) desi contul e Auto OFF.

View File

@@ -1,4 +1,4 @@
"""Teste TDD pentru tools/mapare-llm/heldout_eval.py (L14-S5).
"""Teste pentru tools/mapare-llm/heldout_eval.py.
Fixture sintetic cu predictii+ground_truth cunoscute. Verifica:
- precizie globala
@@ -398,8 +398,7 @@ class TestExportForLabeling:
for row in reader:
# Coloana cod_gold trebuie sa fie vida (nu etichetata de cod!)
assert row["cod_gold"] == "", (
"cod_gold nu trebuie pre-completat: ar fi 'antrenare pe test' "
"(Decision #19 PRD 5.14)"
"cod_gold nu trebuie pre-completat: ar fi 'antrenare pe test'"
)
def test_n_randuri_egal_cu_sample(self, tmp_path):
@@ -413,7 +412,7 @@ class TestExportForLabeling:
# ---------------------------------------------------------------------------
# Sectiunea 8: kill_criterion — pragul de acceptanta (F-E, PRD 5.14)
# Sectiunea 8: kill_criterion — pragul de acceptanta
# ---------------------------------------------------------------------------
class TestKillCriterion:
@@ -424,8 +423,8 @@ class TestKillCriterion:
Justificare threshold 0.5% (0.005):
Un service cu 200 operatii/zi auto-rezolvate = 1 FINALIZATA gresita/zi.
FINALIZATA e ireversibila (cf. PRD 5.14 Premisa 3 / invariant CLAUDE.md).
Pragul poate fi RELAXAT empiric; nu INASPRIT post-hoc (sesizare-in-timp).
FINALIZATA e ireversibila.
Pragul poate fi RELAXAT empiric; nu INASPRIT post-hoc.
"""
def test_trece_cand_sub_prag(self):

View File

@@ -1,4 +1,4 @@
"""US-003 (PRD 5.20): build_key incorporeaza rar_env."""
"""build_key incorporeaza rar_env."""
from __future__ import annotations

View File

@@ -1,10 +1,10 @@
"""Teste API import Treapta 2 — POST /v1/import, preview, commit, export-failed.
"""Teste API import — POST /v1/import, preview, commit, export-failed.
Acopera:
- #11 U1+T4: upload + staging + mapare coloane semnatura/drift/fuzzy
- #12 T2+T11: preview 6 stari + already_sent batch lookup + intra-batch collision
- #13 T5+T12: gate HARD confirmare + atestare valori + commit ON CONFLICT (TOCTOU)
- #14 T8: export randuri esuate CSV
- upload + staging + mapare coloane semnatura/drift/fuzzy
- preview 6 stari + already_sent batch lookup + intra-batch collision
- gate HARD confirmare + atestare valori + commit ON CONFLICT (TOCTOU)
- export randuri esuate CSV
"""
from __future__ import annotations
@@ -91,15 +91,11 @@ def _default_column_mapping() -> dict:
def _setup_nomenclator(client: TestClient) -> None:
"""Seed nomenclator cu un cod de prestatie pentru teste."""
# Folosim POST /v1/prezentari pentru a forta seed-ul nomenclatorului
# care are loc in init_db -> seed_nomenclator_if_empty
pass # seed-ul se face automat in init_db
def _seed_operation_mapping(client: TestClient, cod_op: str = "Revizie", cod_prest: str = "OE-1") -> None:
"""Salveaza o mapare de operatii pentru teste."""
# Adauga mai intai in nomenclator daca nu exista (prin POST prezentare care creeaza cod)
# De fapt, cod OE-1 e in nomenclatorul seed
client.post("/v1/mapari", json={
"cod_op_service": cod_op,
"cod_prestatie": cod_prest,
@@ -108,7 +104,7 @@ def _seed_operation_mapping(client: TestClient, cod_op: str = "Revizie", cod_pre
# =========================================================================== #
# #11 — Upload + staging (U1+T4) #
# Upload + staging #
# =========================================================================== #
class TestUploadStaging:
@@ -144,7 +140,7 @@ class TestUploadStaging:
assert r.status_code == 422
def test_issue5a_raw_json_criptat(self, client):
"""Issue 5a: raw_json din import_rows trebuie sa fie criptat (ciphertext la rest)."""
"""raw_json din import_rows trebuie sa fie criptat (ciphertext la rest)."""
data = _make_xlsx([_HEADER, _ROW_OK])
r = _upload_file(client, data, "test.xlsx")
assert r.status_code == 200
@@ -173,7 +169,7 @@ class TestUploadStaging:
conn.close()
def test_issue5b_fuzzy_coloane_refoloseste_normalize_for_match(self, client):
"""Issue 5b: fuzzy_suggestions din raspuns foloseste normalize_for_match (fara duplicat)."""
"""fuzzy_suggestions din raspuns foloseste normalize_for_match (fara duplicat)."""
data = _make_xlsx([_HEADER, _ROW_OK])
r = _upload_file(client, data, "test.xlsx")
assert r.status_code == 200
@@ -190,7 +186,7 @@ class TestUploadStaging:
assert "odometru_final" in camps, f"'odometru_final' trebuie in sugestii"
def test_drift_semnatura_coloane(self, client):
"""T4/D3: upload 2 cu coloane mutate -> mapping_status='new' (nu aplica orb)."""
"""Upload 2 cu coloane mutate -> mapping_status='new' (nu aplica orb)."""
# Upload 1 cu header standard
data1 = _make_xlsx([_HEADER, _ROW_OK])
r1 = _upload_file(client, data1, "test.xlsx")
@@ -275,7 +271,7 @@ class TestUploadStaging:
assert body["sample_rows"][0]["VIN"] == _ROW_OK2[0]
def test_purge_after_setat_la_insert(self, client):
"""T16: purge_after trebuie setat la insert import_batches."""
"""purge_after trebuie setat la insert import_batches."""
data = _make_xlsx([_HEADER, _ROW_OK])
r = _upload_file(client, data, "test.xlsx")
import_id = r.json()["import_id"]
@@ -294,7 +290,7 @@ class TestUploadStaging:
# =========================================================================== #
# #11 — Mapare coloane (T4) #
# Mapare coloane #
# =========================================================================== #
class TestColumnMapping:
@@ -349,7 +345,7 @@ class TestColumnMapping:
# =========================================================================== #
# #12 — Preview 6 stari (T2 + T11) #
# Preview 6 stari #
# =========================================================================== #
class TestPreview:
@@ -405,7 +401,7 @@ class TestPreview:
assert any(r["resolved_status"] in ("needs_data",) for r in body["rows"])
def test_preview_already_sent_dupa_submit(self, client):
"""Rand deja trimis prin API -> stare already_sent la preview (T2/D5)."""
"""Rand deja trimis prin API -> stare already_sent la preview."""
# Trimite prin API canalul standard
client.post("/v1/prezentari", json={
"rar_credentials": {"email": "x@y.ro", "password": "s"},
@@ -430,7 +426,7 @@ class TestPreview:
assert "already_sent" in statuses, f"Asteptat 'already_sent', primit: {statuses}"
def test_preview_duplicate_in_file(self, client):
"""T11/OV-3: 2 randuri identice in ACELASI fisier -> duplicate_in_file."""
"""2 randuri identice in ACELASI fisier -> duplicate_in_file."""
# Acelasi rand de doua ori
rows = [_HEADER, _ROW_OK, _ROW_OK] # duplicat exact
import_id = self._upload_and_map(client, rows=rows)
@@ -444,7 +440,7 @@ class TestPreview:
f"Asteptat 'duplicate_in_file', primit: {statuses}"
def test_preview_already_sent_batch_lookup_nu_n_plus_1(self, client):
"""Eng#5: already_sent lookup BATCH (nu N+1) — ≤7 interogari pentru 5 randuri."""
"""already_sent lookup BATCH (nu N+1) — ≤7 interogari pentru 5 randuri."""
# Cream 5 randuri distincte
rows_data = [_HEADER]
for i in range(5):
@@ -492,7 +488,7 @@ class TestPreview:
# =========================================================================== #
# #13 — Commit gate HARD + atestare + TOCTOU (T5 + T12) #
# Commit gate HARD + atestare + TOCTOU #
# =========================================================================== #
class TestCommit:
@@ -528,7 +524,7 @@ class TestCommit:
assert body["enqueued"] == n_ok
def test_commit_cu_n_gresit_reject(self, client):
"""T5/D3: commit cu N gresit -> 422, nu enqueue."""
"""Commit cu N gresit -> 422, nu enqueue."""
import_id, preview = self._upload_preview_ok(client)
n_ok = preview["summary"].get("ok", 0)
@@ -543,7 +539,7 @@ class TestCommit:
f"Eroare neasteptata: {detail}"
def test_commit_log_atestare(self, client):
"""T12/Voce#9: commit scrie import_attestations cu rows_hash + n_confirmed."""
"""Commit scrie import_attestations cu rows_hash + n_confirmed."""
import_id, preview = self._upload_preview_ok(client)
n_ok = preview["summary"].get("ok", 0)
@@ -574,7 +570,7 @@ class TestCommit:
conn.close()
def test_commit_batch_id_setat_pe_submission(self, client):
"""T7: submission creata la commit trebuie sa aiba batch_id + row_index setate."""
"""Submission creata la commit trebuie sa aiba batch_id + row_index setate."""
import_id, preview = self._upload_preview_ok(client)
n_ok = preview["summary"].get("ok", 0)
@@ -602,7 +598,7 @@ class TestCommit:
conn.close()
def test_commit_toctou_cheie_inserata_concurent(self, client):
"""Issue 1 (TOCTOU): cheie inserata de canal concurent -> reclasificata already_sent.
"""Cheie inserata de canal concurent (TOCTOU) -> reclasificata already_sent.
Simulam TOCTOU inserand cheia direct in submissions inainte de commit.
"""
@@ -635,7 +631,6 @@ class TestCommit:
"reviewed_rows": [],
})
# Poate fi 200 cu toctou_collisions sau 422 cu informatii clare
# Conform planului Issue 1: reclasificat already_sent, nu rollback
# Dar n_enqueued va fi 0 daca toate colideaza
if rc.status_code == 200:
body = rc.json()
@@ -644,7 +639,7 @@ class TestCommit:
# (dupa reclasificare, n_total_ok scade)
def test_commit_needs_review_nebifat_exclus_din_n(self, client):
"""Voce#1: rand needs_review nebifat explicit -> NU intra in N, NU se enqueued."""
"""Rand needs_review nebifat explicit -> NU intra in N, NU se enqueued."""
# Rand cu VIN numeric (coercion -> needs_review)
import datetime as dt
wb = openpyxl.Workbook()
@@ -704,7 +699,7 @@ class TestCommit:
assert r2.status_code == 409
def test_atestare_purge_after_setat_pe_submission(self, client):
"""T16: submissions create la commit trebuie sa aiba purge_after setat."""
"""Submissions create la commit trebuie sa aiba purge_after setat."""
import_id, preview = self._upload_preview_ok(client)
n_ok = preview["summary"].get("ok", 0)
@@ -732,7 +727,7 @@ class TestCommit:
# =========================================================================== #
# #14 — Export randuri esuate CSV (T8) #
# Export randuri esuate CSV #
# =========================================================================== #
class TestExportFailed:
@@ -806,12 +801,12 @@ class TestExportFailed:
# =========================================================================== #
# Regresie: reconcile.py ramane op-blind (OV-3) #
# Regresie: reconcile.py ramane op-blind #
# =========================================================================== #
class TestReconcileRegresie:
def test_match_finalizata_ramane_op_blind(self):
"""OV-3: reconcile.py trebuie sa ramana op-blind (nu editat de import).
"""reconcile.py trebuie sa ramana op-blind (nu editat de import).
Importam reconcile si verificam ca nu s-au adaugat parametri de operatie.
"""

View File

@@ -1,6 +1,5 @@
"""Teste US-007 (PRD 5.11) — Post-commit: lista Trimiteri apare + refresh auto.
"""Teste post-commit: lista Trimiteri apare + refresh auto.
TDD RED: testele sunt scrise inainte de implementare.
Verifica:
1. Raspunsul confirma emite header HX-Trigger: trimiteriChanged.
2. Raspunsul confirma include OOB swap al #trimiteri-section cu submissions-wrap.
@@ -130,7 +129,7 @@ _ROWS_OK = [
# --------------------------------------------------------------------------- #
# Teste RED → GREEN #
# Teste #
# --------------------------------------------------------------------------- #
def test_confirma_emite_hx_trigger(client):

View File

@@ -1,16 +1,16 @@
"""Teste E2E T15 — integrare import->commit->worker (RAR mock) + masina de stari + failure registry.
"""Teste E2E: integrare import->commit->worker (RAR mock) + masina de stari + failure registry.
Acopera (plan T15, sect.12):
Acopera:
- Scenariul 1: upload xlsx/csv -> column-mapping -> preview -> commit N
-> worker process_one (MockRar) -> submission FINALIZATA cu id_prezentare.
- Scenariul 2: re-upload acelasi continut -> preview marcheaza already_sent
(NU al doilea FINALIZATA dupa commit).
- Scenariul 3: coada MIXTA API(creds efemere)+web(creds durabile per-env, US-013):
- Scenariul 3: coada mixta API(creds efemere)+web(creds durabile per-env):
dupa login + purjare creds efemere, submission-urile web tot se trimit
prin fallback accounts.rar_creds_{env}_enc (T1/Voce#5).
- Masina de stari (sect. 6): tranzitii queued->sending->sent/requeued/error.
- Failure registry (sect. 8): 400/403/503+reconciliere.
- T16: purge_expired + purge_after setat la commit.
prin fallback accounts.rar_creds_{env}_enc.
- Masina de stari: tranzitii queued->sending->sent/requeued/error.
- Failure registry: 400/403/503+reconciliere.
- Purjare: purge_expired + purge_after setat la commit.
"""
from __future__ import annotations
@@ -451,10 +451,10 @@ class TestE2EAlreadySent:
class TestE2EMixedQueue:
def test_coada_mixta_ambele_trimise(self, env, monkeypatch):
"""Scenariul 3 (T1/Voce#5): API (creds efemere) + web (canal import, fara creds pe submission).
"""Scenariul 3: API (creds efemere) + web (canal import, fara creds pe submission).
Dupa purjarea creds efemere ale canalului API (la primul login), submission-urile
import (web) tot se trimit prin fallback accounts.rar_creds_{env}_enc (US-013, per-env).
import (web) tot se trimit prin fallback accounts.rar_creds_{env}_enc, per-env.
Verificam ca ambele submission-uri ajung la status='sent'.
"""
import app.worker.__main__ as w
@@ -486,11 +486,11 @@ class TestE2EMixedQueue:
assert r_api.status_code == 200, r_api.text
sub_api_id = r_api.json()["results"][0]["submission_id"]
# 3. Seteaza creds durabile in accounts per-env (US-013, canal web fallback)
# 3. Seteaza creds durabile in accounts per-env (canal web fallback)
conn = get_connection()
try:
web_creds_enc = encrypt_creds({"email": "web@test.ro", "password": "pass_web"})
# US-013: scrie in slotul per-env test (rar_env default = 'test')
# scrie in slotul per-env test (rar_env default = 'test')
conn.execute(
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1",
(web_creds_enc,),
@@ -522,7 +522,7 @@ class TestE2EMixedQueue:
try:
processed = 0
# Drena coada simuland bucla worker completa (T1/D4: creds efemere + fallback per-env)
# Drena coada simuland bucla worker completa: creds efemere + fallback per-env
for _ in range(10): # limita de siguranta
claimed = w.claim_one(conn)
if claimed is None:
@@ -532,7 +532,7 @@ class TestE2EMixedQueue:
account_id = claimed["account_id"]
rar_env = claimed.get("rar_env", "test")
# T1/D4: creds din submission (API efemer) OR fallback per-env (US-013)
# creds din submission (API efemer) OR fallback per-env
creds = w._creds_for(claimed, settings) or w._creds_from_account(conn, account_id, rar_env=rar_env)
assert creds is not None, \
f"Creds None pentru submission {sid} — fallback durabil trebuie sa existe"
@@ -566,9 +566,9 @@ class TestE2EMixedQueue:
assert mock_rar.post_calls == 2
def test_purjare_creds_efemere_nu_sterge_durabile(self, env, monkeypatch):
"""T1/Gate purjare (OV-5): dupa login, submissions.rar_creds_enc sterse DAR per-env INTACT.
"""Dupa login, submissions.rar_creds_enc sterse DAR per-env INTACT.
Worker sterge DOAR submissions.rar_creds_enc (efemere), NU accounts.rar_creds_{env}_enc (durabile, US-013).
Worker sterge DOAR submissions.rar_creds_enc (efemere), NU accounts.rar_creds_{env}_enc (durabile).
"""
import app.worker.__main__ as w
from app.crypto import encrypt_creds
@@ -590,7 +590,7 @@ class TestE2EMixedQueue:
assert r_api.status_code == 200
sub_id = r_api.json()["results"][0]["submission_id"]
# Seteaza creds durabile pe cont (slotul per-env, US-013)
# Seteaza creds durabile pe cont (slotul per-env)
conn = get_connection()
try:
web_creds_enc = encrypt_creds({"email": "web@test.ro", "password": "pass_web"})
@@ -634,7 +634,7 @@ class TestE2EMixedQueue:
# =========================================================================== #
# Masina de stari (sect. 6 din plan): tranzitii explicite per submission #
# Masina de stari: tranzitii explicite per submission #
# =========================================================================== #
class TestStateMachine:
@@ -797,7 +797,7 @@ class TestStateMachine:
# =========================================================================== #
# Registrul de esecuri (sect. 8): tipuri de eroare RAR si recuperare #
# Registrul de esecuri: tipuri de eroare RAR si recuperare #
# =========================================================================== #
class TestFailureRegistry:
@@ -929,12 +929,12 @@ class TestFailureRegistry:
# =========================================================================== #
# T16 — Purjare (purge_expired + purge_after setat la commit) #
# Purjare (purge_expired + purge_after setat la commit) #
# =========================================================================== #
class TestPurjare:
def test_purge_expired_sterge_sent_expirate(self, env):
"""T16: purge_expired sterge submissions cu status='sent' si purge_after in trecut."""
"""purge_expired sterge submissions cu status='sent' si purge_after in trecut."""
from app.worker.__main__ import purge_expired
client, get_connection, get_settings = env
@@ -958,7 +958,7 @@ class TestPurjare:
conn.close()
def test_purge_expired_nu_sterge_queued(self, env):
"""T16: purge_expired NU sterge non-sent (queued/error) chiar daca purge_after < now."""
"""purge_expired NU sterge non-sent (queued/error) chiar daca purge_after < now."""
from app.worker.__main__ import purge_expired
client, get_connection, get_settings = env
@@ -981,7 +981,7 @@ class TestPurjare:
conn.close()
def test_purge_after_setat_la_commit_import(self, env):
"""T16: submissions create la commit import au purge_after setat (!=NULL)."""
"""submissions create la commit import au purge_after setat (!=NULL)."""
client, get_connection, get_settings = env
import_id = _upload_and_map(client, rows=[_HEADER, _ROW_1])
@@ -1005,7 +1005,7 @@ class TestPurjare:
conn.close()
def test_purge_after_setat_la_trimitere_worker(self, env):
"""T16: dupa trimitere (status='sent'), purge_after se (re)seteaza la now+90 zile."""
"""dupa trimitere (status='sent'), purge_after se (re)seteaza la now+90 zile."""
import app.worker.__main__ as w
client, get_connection, get_settings = env

View File

@@ -1,10 +1,8 @@
"""Teste US-001 (PRD 3.6): backend — persista editarea unui rand de preview.
"""Teste backend — persista editarea unui rand de preview.
Approach B: editarea scrie un patch CANONIC in import_rows.override_json (criptat
Editarea scrie un patch CANONIC in import_rows.override_json (criptat
Fernet), aplicat ULTIMUL in _resolve_row_for_preview + commit. raw_json/idempotency
raman neatinse. Ruta editare = mutatie PURA (nu re-deriva status, nu atinge submissions).
TDD: testele se scriu inainte de implementare (RED -> GREEN).
"""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""Teste US-005 (PRD 5.4): erori de import imbracate pe 3 niveluri.
"""Teste erori de import imbracate pe 3 niveluri.
Verifica ca fiecare HTTPException de import in scop are `detail` superset:
- cheile vechi: `error`, `message`, context specific (sheets/found/n_ok)
@@ -327,7 +327,6 @@ class TestOverrideIlizibil3Niveluri:
assert r.status_code == 422, f"Asteptat 422, primit {r.status_code}: {r.text}"
detail = r.json()["detail"]
# Dupa US-005: detail trebuie sa fie dict, nu string
assert isinstance(detail, dict), f"detail trebuie sa fie dict, primit: {type(detail)}"
assert detail.get("error") == "override_ilizibil"
assert detail.get("cod") == "IMPORT_OVERRIDE_ILIZIBIL"

View File

@@ -143,7 +143,7 @@ def test_preview_arata_panoul_de_mapare(client):
assert r.status_code == 200
assert "Operatii de mapat la cod RAR" in r.text
assert "OP-REV" in r.text
# US-004: panoul foloseste ruta plurala (un singur form pentru toate operatiile)
# Panoul foloseste ruta plurala (un singur form pentru toate operatiile)
assert "/_import/%d/mapare-operatii" % import_id in r.text

View File

@@ -1,7 +1,7 @@
"""Teste pentru app/import_parse.py (T14 + T3 + T10 + T13).
"""Teste pentru app/import_parse.py.
Fixture-urile xlsx sunt generate in-memory cu openpyxl (nu fisiere binare commituite).
Fiecare sectiune acopera un task distinct.
Fiecare sectiune acopera un scenariu distinct.
"""
from __future__ import annotations
@@ -77,7 +77,7 @@ _ROW2 = ["WVWZZZ1KZAW000124", "CJ001AB", "2026-05-10", "98765", "Reparatie"]
# =========================================================================== #
# T14 — CSV delimiter sniff + encoding + cap #
# CSV delimiter sniff + encoding + cap #
# =========================================================================== #
class TestCsvDelimiter:
@@ -134,7 +134,7 @@ class TestCsvDelimiter:
# =========================================================================== #
# T14 — XLSX read_only dim-check + cap #
# XLSX read_only dim-check + cap #
# =========================================================================== #
class TestXlsxDimcheck:
@@ -176,7 +176,7 @@ class TestXlsxDimcheck:
# =========================================================================== #
# T3 — coercion guard + needs_review + mesaj formule-None #
# Coercion guard + needs_review + mesaj formule-None #
# =========================================================================== #
class TestCoercionNeedsReview:
@@ -278,7 +278,7 @@ class TestCoercionNeedsReview:
# =========================================================================== #
# T10 — dezambiguizare data la nivel de COLOANA (OV-8) #
# Dezambiguizare data la nivel de coloana #
# =========================================================================== #
class TestDateColumnDisambiguation:
@@ -344,7 +344,7 @@ class TestDateColumnDisambiguation:
# =========================================================================== #
# T13 — robustete export RO (multi-sheet + merged header + footer trim) #
# Robustete export RO (multi-sheet + merged header + footer trim) #
# =========================================================================== #
class TestRobustetExportRO:

View File

@@ -1,4 +1,4 @@
"""Teste US-009 (PRD 5.20) — Import web: selector mediu RAR conditionat de disponibilitate.
"""Teste import web: selector mediu RAR conditionat de disponibilitate.
Verifica:
- La 0 medii: banner avertisment non-blocant (upload functioneaza, commit foloseste ancora globala).
@@ -326,7 +326,7 @@ def test_commit_cu_doua_medii_respecta_alegerea(client):
def test_badge_mediu_in_preview(client):
"""Preview-ul afiseaza badge-ul cu mediul tinta (US-009, F9/F10)."""
"""Preview-ul afiseaza badge-ul cu mediul tinta."""
_seed_nomenclator_si_mapare(client)
_configureaza_un_mediu(client, env="test")

View File

@@ -1,13 +1,11 @@
"""Teste US-007 (PRD 5.12): gate review in modal — import_rows.reviewed + confirmare.
TDD RED: testele sunt scrise inainte de implementare.
"""Gate review in modal — import_rows.reviewed + confirmare.
Scenarii:
1. Migrare: import_rows.reviewed INTEGER DEFAULT 0, idempotent.
2. Rand needs_review exclus din "gata de trimis" pana la confirmare explicita.
3. POST confirma-review seteaza reviewed=1 → randul devine ok la recalcul.
4. `reviewed` NU intra in payload/idempotency (marcaj separat).
5. Editarea unei valori pe un rand confirmat reseteaza reviewed=0 (D#9).
5. Editarea unei valori pe un rand confirmat reseteaza reviewed=0.
"""
from __future__ import annotations
@@ -268,8 +266,8 @@ def test_migrare_adauga_coloana_reviewed_idempotent():
def test_needs_review_exclus_din_gata_pana_la_confirmare(client):
"""Un rand needs_review nu intra in 'gata de trimis' (n_confirmat = 0) pana la confirmare.
US-007 Q1: randul cu data ambigua apare cu pill 'Verifica valori' si este
EXCLUS din n_confirmat. Bannerul de discoverability (T1) trebuie sa fie prezent.
Randul cu data ambigua apare cu pill 'Verifica valori' si este
EXCLUS din n_confirmat. Bannerul de discoverability trebuie sa fie prezent.
"""
_seed_op1()
iid = _upload_and_preview_needs_review(client)
@@ -295,7 +293,7 @@ def test_needs_review_exclus_din_gata_pana_la_confirmare(client):
assert n_val == 0, \
f"n_confirmat trebuie sa fie 0 cand randul e needs_review (negasit), got {n_val}"
# Bannerul de discoverability (T1) — prezent cand summary.needs_review > 0
# Bannerul de discoverability — prezent cand summary.needs_review > 0
# Trebuie sa contina un mesaj despre faptul ca randurile nu pleaca pana la confirmare
# (ex. 'nu pleaca la RAR' sau 'confirmi in modal' sau 'Verifica valori')
banner_present = (
@@ -304,13 +302,13 @@ def test_needs_review_exclus_din_gata_pana_la_confirmare(client):
"preview-needs-review-banner" in html
)
assert banner_present, \
"Bannerul de discoverability (T1) trebuie sa fie prezent cand exista randuri needs_review"
"Bannerul de discoverability trebuie sa fie prezent cand exista randuri needs_review"
def test_confirmare_in_modal_seteaza_reviewed_si_devine_ok(client):
"""POST /_import/{id}/rand/0/confirma-review seteaza reviewed=1.
US-007 T2: operatorul apasa 'Confirma valorile' in modal →
Operatorul apasa 'Confirma valorile' in modal →
reviewed=1 in DB → randul devine ok la recalcul preview.
Verifica:
@@ -350,9 +348,8 @@ def test_confirmare_in_modal_seteaza_reviewed_si_devine_ok(client):
def test_reviewed_nu_intra_in_payload_sau_idempotency(client):
"""reviewed NU intra in payload, override_json sau cheia de idempotenta.
US-007 marcaj separat (D#8): reviewed e DOAR un flag de confirmare umana,
nu un camp de continut. Cheia de idempotenta trebuie sa fie identica inainte
si dupa confirmare.
reviewed e DOAR un flag de confirmare umana, nu un camp de continut.
Cheia de idempotenta trebuie sa fie identica inainte si dupa confirmare.
"""
_seed_op1()
iid = _upload_and_preview_needs_review(client)
@@ -393,7 +390,7 @@ def test_reviewed_nu_intra_in_payload_sau_idempotency(client):
def test_editare_valoare_pe_needs_review_reseteaza_reviewed(client):
"""Editarea unei valori pe un rand confirmat reseteaza reviewed=0 (D#9).
"""Editarea unei valori pe un rand confirmat reseteaza reviewed=0.
Cand operatorul SCHIMBA o valoare (via POST editeaza) pe un rand deja confirmat
(reviewed=1), apply_row_override trebuie sa reseteze reviewed=0.
@@ -418,7 +415,7 @@ def test_editare_valoare_pe_needs_review_reseteaza_reviewed(client):
# reviewed trebuie sa fie 0 (resetat de apply_row_override)
assert _get_reviewed(iid, 0) == 0, \
"reviewed trebuie sa fie resetat la 0 dupa editarea unei valori (D#9 — re-cere confirmare)"
"reviewed trebuie sa fie resetat la 0 dupa editarea unei valori (re-cere confirmare)"
def test_confirma_review_guard_committed_409(client):
@@ -544,11 +541,11 @@ def test_confirma_review_scoped_404_alt_cont():
# --------------------------------------------------------------------------- #
# Teste markup Bug 1: confirma-review form swap (B1) #
# Teste markup: confirma-review form swap #
# --------------------------------------------------------------------------- #
def test_confirma_review_form_nu_foloseste_hx_swap_none():
"""Bug B1 (markup): formularul confirma-review NU trebuie sa foloseasca
"""Formularul confirma-review NU trebuie sa foloseasca
hx-swap='none' — cu none, htmx aplica doar OOB-urile dar NU executa scriptul
din continutul principal → updateN() nu ruleaza → n_confirmat stale → 422.
@@ -561,7 +558,7 @@ def test_confirma_review_form_nu_foloseste_hx_swap_none():
)
html = template.read_text(encoding="utf-8")
# Gasim sectiunea formularului confirma-review (dupa marcajul T2)
# Gasim sectiunea formularului confirma-review
idx = html.find("confirma-review")
assert idx >= 0, "Formularul confirma-review nu a fost gasit in template"
form_section = html[idx:]
@@ -622,7 +619,7 @@ _ROWS_MULTI_NEEDS_REVIEW = [
def test_confirma_toate_review_marcheaza_toate(client):
"""B1 bulk: POST /_import/{id}/confirma-toate-review seteaza reviewed=1 pe TOATE
"""POST /_import/{id}/confirma-toate-review seteaza reviewed=1 pe TOATE
randurile needs_review din batch cu un singur click.
Verifica:
@@ -776,7 +773,7 @@ def test_confirma_toate_review_scoped_404_alt_cont():
def test_confirm_rapid_buton_prezent_in_tabel(client):
"""B1 quick: randul needs_review are butonul de confirm rapid direct in tabel,
"""Randul needs_review are butonul de confirm rapid direct in tabel,
care POST-eaza pe ruta /confirma-review (fara a deschide modalul)."""
_seed_op1()
iid = _upload_and_preview_needs_review(client)
@@ -791,7 +788,7 @@ def test_confirm_rapid_buton_prezent_in_tabel(client):
def test_confirm_rapid_per_rand_seteaza_reviewed(client):
"""B1 quick: POST /confirma-review din tabel (fara modal) seteaza reviewed=1 pe un
"""POST /confirma-review din tabel (fara modal) seteaza reviewed=1 pe un
singur rand si NU atinge celelalte randuri needs_review din batch."""
_seed_op1()
iid = _upload_and_preview_rows(client, _ROWS_MULTI_NEEDS_REVIEW)
@@ -806,7 +803,7 @@ def test_confirm_rapid_per_rand_seteaza_reviewed(client):
def test_confirma_review_cere_reincarcarea_preview(client):
"""Contractul nou (dogfood 5.13): confirma-review NU mai depinde de scriptul updateN
"""Confirma-review NU mai depinde de scriptul updateN
din payload (care, cu OOB pe <tr> rupt, lasa randul stale). Acum cere reincarcaPreview,
iar preview-ul reincarcat re-randeaza contorul si butonul de confirmare cu n_confirmat
corect server-side — deci problema B1 (n_confirmat stale -> 422) dispare structural.

View File

@@ -1,4 +1,4 @@
"""Teste UI web import (U5) — upload → mapare coloane → preview → confirmare.
"""Teste UI web import — upload → mapare coloane → preview → confirmare.
Verifica:
- Dashboard randeaza sectiunea de upload
@@ -104,7 +104,7 @@ def _seed_op_mapping(client, cod_op: str = "Revizie", cod_prest: str = "OE-1") -
def test_dashboard_contine_drop_zone(client):
"""Tab-ul Import randeaza sectiunea de upload cu drop zone si mesaj warmth.
Dupa US-003 sectiunea de import e in tab-ul Import (?tab=import), nu pe pagina principala.
Sectiunea de import e in tab-ul Import (?tab=import), nu pe pagina principala.
"""
r = client.get("/?tab=import")
assert r.status_code == 200
@@ -389,11 +389,11 @@ def test_upload_multi_sheet_arata_selector(client):
# --------------------------------------------------------------------------- #
# Elemente a11y (D10/D11/D12) #
# Elemente a11y #
# --------------------------------------------------------------------------- #
def test_preview_contine_banner_declarant(client):
"""Preview contine bannerul declarant (D12) cu text despre ireversibil."""
"""Preview contine bannerul declarant cu text despre ireversibil."""
import_id = _setup_preview(client)
r = client.get(f"/_import/{import_id}/preview")
assert r.status_code == 200
@@ -403,7 +403,7 @@ def test_preview_contine_banner_declarant(client):
def test_preview_contine_checkboxuri_needs_review(client):
"""Randurile needs_review au checkbox 'verificat' (D11)."""
"""Randurile needs_review au checkbox 'verificat'."""
# Cream un rand cu VIN numeric → needs_review
rows_with_review = [
{
@@ -431,7 +431,7 @@ def test_preview_contine_checkboxuri_needs_review(client):
def test_preview_duplicate_in_file_are_text(client):
"""Randurile duplicate_in_file arata text 'dubla cu randul N' (D10 — nu doar culoare)."""
"""Randurile duplicate_in_file arata text 'dubla cu randul N' (nu doar culoare)."""
_seed_op_mapping(client, "Revizie", "OE-1")
# Doua randuri identice → duplicate_in_file
dup_rows = [
@@ -451,6 +451,6 @@ def test_preview_duplicate_in_file_are_text(client):
)
r = client.get(f"/_import/{import_id}/preview")
assert r.status_code == 200
# Text explicit pentru duplicate_in_file (nu doar culoare — cerinta daltonism D10)
# Text explicit pentru duplicate_in_file (nu doar culoare — cerinta daltonism)
assert "dubla cu randul" in r.text
assert "duplicate_in_file" in r.text

View File

@@ -1,8 +1,8 @@
"""Teste US-006a/b (PRD 3.3): scoping import web pe sesiune.
"""Scoping import web pe sesiune.
US-006a: citiri (upload, preview, mapare-coloane) pe contul sesiunii.
US-006b: scrieri (confirma) pe contul sesiunii; alt cont -> inaccesibil.
C8/OV-2: aceeasi cheie idempotenta prin API si web pe acelasi cont.
Citiri (upload, preview, mapare-coloane) pe contul sesiunii.
Scrieri (confirma) pe contul sesiunii; alt cont -> inaccesibil.
Aceeasi cheie idempotenta prin API si web pe acelasi cont.
"""
from __future__ import annotations
@@ -144,7 +144,7 @@ def test_commit_creeaza_submissions_pe_cont(env, monkeypatch):
def test_cheie_identica_api_vs_web_acelasi_cont(env, monkeypatch):
"""C8/OV-2: import web si API pe acelasi cont produc aceeasi cheie idempotenta."""
"""Import web si API pe acelasi cont produc aceeasi cheie idempotenta."""
from app.idempotency import build_key, canonicalize_row
client, conn, acct_a, acct_b = env
_setup_op_mapping(conn, acct_a)

View File

@@ -1,7 +1,4 @@
"""Teste US-001: endpoint-uri de integrare (GET /v1/ping + export Postman).
TDD — toate testele RED inainte de implementare.
"""
"""Teste endpoint-uri de integrare (GET /v1/ping + export Postman)."""
from __future__ import annotations
@@ -64,13 +61,13 @@ def _creeaza_cheie(monkeypatch) -> str:
def _seteaza_rar_creds(monkeypatch=None) -> None:
"""Seteaza creds RAR pe contul id=1 (slotul per-env, US-013)."""
"""Seteaza creds RAR pe contul id=1 (slotul per-env)."""
from app.db import get_connection
from app.crypto import encrypt_creds
conn = get_connection()
try:
enc = encrypt_creds({"email": "test@rar.ro", "password": "secret"})
# US-013: scrie in slotul per-env (test = ancora globala in teste)
# Scrie in slotul per-env (test = ancora globala in teste)
conn.execute(
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc,)
)

View File

@@ -1,11 +1,4 @@
"""Teste US-004: POST /integrare/test-cheie — verifica cheia API lipita de utilizator.
TDD: testele se scriu INAINTE de implementare; la inceput pica (RED),
dupa implementare trec (GREEN).
Ruta testata:
- POST /integrare/test-cheie -> fragment HTML cu rezultat validare
"""
"""Teste POST /integrare/test-cheie — verifica cheia API lipita de utilizator."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""Teste US-007 (PRD 5.6): gard de redactare PII/parole in jurnal (L.142/GDPR)."""
"""Gard de redactare PII/parole in jurnal (L.142/GDPR)."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""Teste US-008 (PRD 5.6): retentie / purjare jurnal + RotatingFileHandler."""
"""Teste retentie / purjare jurnal + RotatingFileHandler."""
from __future__ import annotations

View File

@@ -1,19 +1,10 @@
"""
Teste pentru eticheta_scurta (US-006, PRD 5.8).
RED intai: scrise inainte de implementarea functiei.
Fisiere atinse: app/web/labels.py, tests/test_labels.py.
"""
"""Teste pentru eticheta_scurta."""
import pytest
from app.web.labels import eticheta_scurta, eticheta_stare
# ---------------------------------------------------------------------------
# test_eticheta_scurta_pentru_fiecare_stare
# ---------------------------------------------------------------------------
def test_eticheta_scurta_pentru_fiecare_stare():
"""Fiecare stare cunoscuta intoarce eticheta scurta corecta (pill)."""
cazuri = {
@@ -37,13 +28,8 @@ def test_eticheta_scurta_stare_necunoscuta_ridica_keyerror():
eticheta_scurta("stare_inexistenta")
# ---------------------------------------------------------------------------
# test_eticheta_lunga_ramane_pentru_subtext
# ---------------------------------------------------------------------------
def test_eticheta_lunga_ramane_pentru_subtext():
"""eticheta_stare inca intoarce textele lungi neschimbate (compat cu template-uri)."""
# Verificam fragmentele de text lung care existau inainte de US-006
cazuri_lungi = {
"queued": "In asteptare",
"sending": "Se trimite acum",
@@ -57,7 +43,6 @@ def test_eticheta_lunga_ramane_pentru_subtext():
assert fragment.lower() in text.lower(), (
f"eticheta_stare({status!r}) text lung modificat — asteptam {fragment!r} in {text!r}"
)
# Verifica ca tuple-ul are exact 3 elemente (invariant arhitectura C1)
assert isinstance(css_class, str) and css_class, (
f"eticheta_stare({status!r}) trebuie sa aiba css_class non-vida la pozitia 3"
)

View File

@@ -1,15 +1,11 @@
"""
Teste pentru eticheta randurilor tinute manual (held) — US-006, PRD 5.19.
Teste pentru eticheta randurilor tinute manual (held).
RED intai: scrise inainte de a extinde labels.py cu parametrul `held`.
Regula de afisaj (D5, PRD 5.19):
Regula de afisaj:
- `status='queued' AND held=1` -> "In asteptare (manual)" + clasa CSS de
AVERTIZARE (amber, `--warn`) — asteptare benigna, NU eroare (rosu).
- `held=0` (sau lipsa) -> comportament neschimbat pentru TOATE starile.
- `held` NU e stare noua in masina de stari: CHECK-ul din schema ramane neatins.
Fisiere atinse: app/web/labels.py, tests/test_labels_held.py.
"""
import pytest
@@ -44,7 +40,7 @@ def test_queued_held_are_eticheta_manuala_si_clasa_warn():
def test_queued_held_false_ramane_neschimbat():
"""queued fara held == comportamentul dinainte de US-006 (PRD 5.19)."""
"""queued fara held == comportamentul dinainte de introducerea held."""
fara_held = eticheta_stare("queued")
held_false = eticheta_stare("queued", held=False)
assert fara_held == held_false, "held=False trebuie identic cu apelul fara held"
@@ -67,14 +63,14 @@ def test_apel_pozitional_compat():
# ---------------------------------------------------------------------------
# eticheta_scurta (pill) — pill-ul trebuie sa distinga held de queued normal (D5)
# eticheta_scurta (pill) — pill-ul trebuie sa distinga held de queued normal
# ---------------------------------------------------------------------------
def test_pill_queued_held_diferit_de_queued_normal():
pill_held = eticheta_scurta("queued", held=True)
pill_normal = eticheta_scurta("queued", held=False)
assert pill_held != pill_normal, (
"pill-ul trebuie sa distinga randul tinut (D5: altfel randa 'In coada' identic)"
"pill-ul trebuie sa distinga randul tinut (altfel randa 'In coada' identic)"
)
assert pill_normal == "In coada"

View File

@@ -1,11 +1,11 @@
"""TDD L14-S6 — Integrare Layer 2/3 in editor (suggestion-only, DUPA 5.15).
"""Integrare sugestii de mapare in editor (suggestion-only).
Scenarii acoperite:
- F1-regression CRITIC: SILVER/shared GOLD NU auto-trimit (resolve_prestatii neschimbat)
- pending_unmapped include sugestie GOLD partajat > SILVER > embeddings (precedenta Eng-F2)
- SILVER/shared GOLD NU auto-trimit (resolve_prestatii neschimbat)
- pending_unmapped include sugestie GOLD partajat > SILVER > embeddings
- record_human_validation apelat la confirmare umana (POST /mapari -> shared_mappings)
- Degradare gratioasa cand embeddings indisponibil (mock is_available=False)
- Separare structurala #13: resolve_prestatii/load_mapping NU citesc tabelele de sugestii
- Separare structurala: resolve_prestatii/load_mapping NU citesc tabelele de sugestii
"""
from __future__ import annotations
@@ -62,11 +62,11 @@ def client(env):
# --------------------------------------------------------------------------- #
# F1-regression CRITIC: SILVER/shared GOLD NU auto-trimit #
# Regresie critica: SILVER/shared GOLD NU auto-trimit #
# --------------------------------------------------------------------------- #
def test_f1_silver_nu_auto_trimite(conn):
"""CRITICAL F1: un cod in SILVER (mapping_suggestions) NU produce auto-trimitere.
"""Un cod in SILVER (mapping_suggestions) NU produce auto-trimitere.
resolve_prestatii cu mapping gol + SILVER existent -> operatie ramane nemapata.
Submissionul ar ramane needs_mapping, NU queued.
@@ -84,13 +84,13 @@ def test_f1_silver_nu_auto_trimite(conn):
[{"cod_op_service": "OP-REV", "denumire": "Revizie periodica"}],
{}, # operations_mapping gol
)
# Operatia ramane nemapata (SILVER nu e in resolve, #13)
# Operatia ramane nemapata (SILVER nu e in resolve)
assert resolved[0]["cod_prestatie"] is None
assert len(unmapped) == 1
def test_f1_shared_gold_nu_auto_trimite(conn):
"""CRITICAL F1: un cod in shared_mappings (GOLD partajat) NU produce auto-trimitere.
"""Un cod in shared_mappings (GOLD partajat) NU produce auto-trimitere.
resolve_prestatii cu mapping gol + shared GOLD existent -> operatie ramane nemapata.
"""
@@ -105,13 +105,13 @@ def test_f1_shared_gold_nu_auto_trimite(conn):
[{"cod_op_service": "OP-ULEI", "denumire": "Schimb ulei motor"}],
{}, # operations_mapping gol
)
# Operatia ramane nemapata (GOLD partajat nu e in resolve, #13)
# Operatia ramane nemapata (GOLD partajat nu e in resolve)
assert resolved[0]["cod_prestatie"] is None
assert len(unmapped) == 1
def test_f1_load_mapping_nu_citeste_shared_gold(conn):
"""Separare #13: load_mapping NU returneaza coduri din shared_mappings."""
"""load_mapping NU returneaza coduri din shared_mappings."""
from app.shared_store import record_human_validation
from app.mapping import load_mapping
@@ -175,7 +175,7 @@ def test_enrich_include_silver(conn):
def test_enrich_precedenta_gold_peste_silver(conn):
"""Precedenta Eng-F2: GOLD partajat castiga fata de SILVER cand ambele exista."""
"""GOLD partajat castiga fata de SILVER cand ambele exista."""
from app.shared_store import seed_suggestions, record_human_validation
from app.mapping import enrich_suggestions
@@ -197,7 +197,7 @@ def test_enrich_precedenta_gold_peste_silver(conn):
def test_enrich_degradare_embeddings_indisponibil(conn, monkeypatch):
"""Degradare gratioasa (#16b): cand embeddings nu e disponibil, nu eroare."""
"""Degradare gratioasa: cand embeddings nu e disponibil, nu eroare."""
import app.embeddings as emb_mod
monkeypatch.setattr(emb_mod, "is_available", lambda: False)
@@ -210,7 +210,7 @@ def test_enrich_degradare_embeddings_indisponibil(conn, monkeypatch):
def test_enrich_corpus_gol_nu_incarca_modelul(conn, monkeypatch):
"""Bug fix (code-review): enrich_suggestions NU lazy-load-eaza modelul de 220MB
"""enrich_suggestions NU lazy-load-eaza modelul de 220MB
cand corpus-ul embeddings e gol.
Implementarea veche apela `is_available()` neconditionat -> `_get_engine()` ->
@@ -258,7 +258,7 @@ class _FakeEmbedBackend:
def test_embeddings_functional_cand_flag_activ(conn, monkeypatch):
"""PRD #15: cu AUTOPASS_EMBEDDINGS_ENABLED=true, embeddings produce efectiv o sugestie.
"""Cu AUTOPASS_EMBEDDINGS_ENABLED=true, embeddings produce efectiv o sugestie.
Wire-uieste ensure_embeddings_corpus (corpus din nomenclator) + enrich_suggestions.
Backend injectat (determinist) -> nu incarca modelul real de 230MB.
@@ -272,7 +272,7 @@ def test_embeddings_functional_cand_flag_activ(conn, monkeypatch):
get_settings.cache_clear()
monkeypatch.setattr(emb_mod, "_engine", EmbeddingEngine(backend=_FakeEmbedBackend()))
# Corpusul sursa = mapping_suggestions (SILVER) -- PRD 5.18 US-005.
# Corpusul sursa = mapping_suggestions (SILVER).
# (Inainte era nomenclator_rar; migrat la mapping_suggestions ca k-NN sa
# opereze pe exemple reale etichetate, nu pe categorii generice RAR.)
conn.execute(
@@ -362,7 +362,7 @@ def test_pending_unmapped_include_sugestie_principala(conn):
assert len(pending) == 1
entry = pending[0]
# sugestie_principala adaugat de enrich_suggestions (L14-S6)
# sugestie_principala adaugat de enrich_suggestions
assert "sugestie_principala" in entry
sp = entry["sugestie_principala"]
assert sp is not None
@@ -434,7 +434,7 @@ def test_record_human_validation_la_post_mapari(env, client):
finally:
conn_setup.close()
# POST /mapari cu denumire (L14-S6: form include denumire hidden)
# POST /mapari cu denumire (form include denumire hidden)
resp = client.post(
"/mapari",
data={
@@ -511,7 +511,7 @@ def test_record_human_validation_la_mapeaza_inline(env, client):
def test_mapare_salvata_fara_denumire_nu_polueaza_gold(env, client):
"""Bug fix (code-review 5.15): editarea unei mapari salvate FARA denumire NU scrie
"""Editarea unei mapari salvate FARA denumire NU scrie
o intrare bogus in GOLD partajat (cheiata pe cod_op_service in loc de denumire umana).
Formularul din _mapari.html nu trimite denumire; vechiul fallback `denumire or
@@ -554,11 +554,11 @@ def test_mapare_salvata_fara_denumire_nu_polueaza_gold(env, client):
# --------------------------------------------------------------------------- #
# Separare structurala #13 (redundant cu test_shared_store dar explicit L14) #
# Separare structurala (redundant cu test_shared_store dar explicit) #
# --------------------------------------------------------------------------- #
def test_separare_silver_din_resolve_prestatii():
"""#13: resolve_prestatii nu citeste mapping_suggestions (SILVER)."""
"""resolve_prestatii nu citeste mapping_suggestions (SILVER)."""
from app.mapping import resolve_prestatii
# Apelam fara conn (pur) — SILVER nu e parametru si nu e accesat
@@ -571,7 +571,7 @@ def test_separare_silver_din_resolve_prestatii():
def test_separare_shared_gold_din_resolve_prestatii():
"""#13: resolve_prestatii nu citeste shared_mappings (GOLD partajat)."""
"""resolve_prestatii nu citeste shared_mappings (GOLD partajat)."""
from app.mapping import resolve_prestatii
resolved, unmapped = resolve_prestatii(

View File

@@ -1,7 +1,7 @@
"""Teste US-005 (PRD 3.6): "De rezolvat" si "Operatii salvate" randate ca TABELE.
"""Teste: "De rezolvat" si "Operatii salvate" randate ca TABELE.
Doar marcaj de template — POST-urile /mapari, /mapari/salvate, /mapari/salvate/sterge
raman identice. H4: comutatorul auto-send din tabelul salvate reflecta valoarea STOCATA
raman identice. Comutatorul auto-send din tabelul salvate reflecta valoarea STOCATA
per mapare (din _load_saved_op_mappings), nu un default hard.
"""
@@ -150,7 +150,7 @@ def test_mapari_de_rezolvat_in_tabel(client):
def test_mapari_salvate_in_tabel(client):
"""Sectiunea "Operatii salvate" randata ca tabel. US-002: fara coloana auto_send."""
"""Sectiunea "Operatii salvate" randata ca tabel, fara coloana auto_send."""
acct = _create_account_user("salv@test.com")
_seed_nomenclator("R-FRANE", "Reparatie frane")
_seed_nomenclator("R-MOTOR", "Reparatie motor")
@@ -165,9 +165,9 @@ def test_mapari_salvate_in_tabel(client):
assert "tablewrap" in sec, "tabelul Operatii salvate trebuie sa foloseasca .tablewrap"
assert "<table" in sec and "<th" in sec, "Operatii salvate trebuie randat ca tabel cu antet"
assert "OP-AUTO" in sec and "OP-MANUAL" in sec
# US-002: checkbox auto_send si coloana In coada scoase din UI
assert 'name="auto_send"' not in sec, "US-002: checkbox auto_send scos din tabelul salvate"
assert "In coada" not in sec, "US-002: coloana In coada scoasa din tabelul salvate"
# checkbox auto_send si coloana In coada scoase din UI
assert 'name="auto_send"' not in sec, "checkbox auto_send scos din tabelul salvate"
assert "In coada" not in sec, "coloana In coada scoasa din tabelul salvate"
# POST-urile neschimbate
assert 'hx-post="/mapari/salvate"' in sec
assert 'hx-post="/mapari/salvate/sterge"' in sec

View File

@@ -1,7 +1,7 @@
"""Teste mapare op ROAAUTO -> cod RAR: fuzzy, rezolvare pura, flux on-demand.
Contract hibrid (decis 2026-06-15): item de prestatie cu cod_prestatie (RAR direct)
SAU cod_op_service+denumire (mapat de gateway). Op nemapata -> needs_mapping, apare
Contract hibrid: item de prestatie cu cod_prestatie (RAR direct) SAU
cod_op_service+denumire (mapat de gateway). Op nemapata -> needs_mapping, apare
in editor; la salvarea maparii submission-ul se re-rezolva automat.
"""
@@ -109,7 +109,7 @@ def test_resolve_fara_valid_codes_e_backcompat():
# --------------------------------------------------------------------------- #
# US-002: reguli text (substring) dupa maparea exacta #
# reguli text (substring) dupa maparea exacta #
# --------------------------------------------------------------------------- #
def test_regula_text_contains_rezolva():
@@ -313,7 +313,7 @@ def test_on_unmapped_error_respinge_fara_enqueue(client):
assert res["status"] == "error"
assert res["submission_id"] is None
assert res["erori"] and res["erori"][0]["cod"] == "COD_NEMAPAT"
# PRD 5.7: raspuns onest si pe ramura respinsa — nemapate + motiv populate (aditiv).
# raspuns onest si pe ramura respinsa — nemapate + motiv populate (aditiv).
assert res["nemapate"] and res["nemapate"][0]["cod_op_service"] == _COD_INTERN
assert res["motiv"]
# Nu s-a creat nimic in coada.
@@ -348,7 +348,7 @@ def test_valideaza_error_mode(client):
# --------------------------------------------------------------------------- #
# US-003: 3 niveluri in classify_prezentare (needs_mapping) #
# 3 niveluri in classify_prezentare (needs_mapping) #
# --------------------------------------------------------------------------- #
def test_unmapped_are_3niveluri(client):
@@ -381,9 +381,9 @@ def test_unmapped_are_3niveluri(client):
def test_auto_send_oprit_3niveluri_noul_comportament(client):
"""Mapare cu auto_send=0 -> queued (auto_send ignorat dupa US-001).
"""Mapare cu auto_send=0 -> queued (auto_send ignorat).
Dupa US-001: classify_prezentare nu mai produce ramura AUTO_SEND_OPRIT.
classify_prezentare nu mai produce ramura AUTO_SEND_OPRIT.
O operatie cu cod rezolvat (indiferent de auto_send) -> queued direct.
"""
import json
@@ -400,12 +400,12 @@ def test_auto_send_oprit_3niveluri_noul_comportament(client):
mapping_meta = {"OP_REVIEW": {"cod_prestatie": "OE-1", "auto_send": False}}
res = classify_prezentare(content, mapping, mapping_meta)
assert res["status"] == "queued", (
f"dupa US-001 auto_send=0 -> queued (nu needs_mapping), got {res['status']}"
f"auto_send=0 -> queued (nu needs_mapping), got {res['status']}"
)
def test_needs_data_pass_through(client):
"""VIN invalid -> needs_data; rar_error = array cu erori care au cod/problema/fix (US-002)."""
"""VIN invalid -> needs_data; rar_error = array cu erori care au cod/problema/fix."""
import json
from app.mapping import classify_prezentare
@@ -423,7 +423,7 @@ def test_needs_data_pass_through(client):
erori = json.loads(res["rar_error"])
assert isinstance(erori, list)
assert len(erori) >= 1
# Fiecare eroare are cele 3 niveluri (pass-through US-002)
# Fiecare eroare are cele 3 niveluri (pass-through)
for e in erori:
assert "cod" in e, f"lipseste 'cod' in {e}"
assert "problema" in e, f"lipseste 'problema' in {e}"
@@ -431,7 +431,7 @@ def test_needs_data_pass_through(client):
# =========================================================================== #
# US-001: Scoate hold auto_send din mapare — teste RED (inainte de implementare)
# Scoate hold auto_send din mapare #
# =========================================================================== #
@pytest.fixture()
@@ -453,7 +453,7 @@ def db_conn(monkeypatch, tmp_path):
def test_operatie_mapata_intra_in_queued_indiferent_de_autosend():
"""classify_prezentare cu mapare auto_send=0 -> queued (nu needs_mapping).
Dupa US-001: has_no_auto_send nu mai blocheaza; un cod rezolvat e direct queued.
has_no_auto_send nu mai blocheaza; un cod rezolvat e direct queued.
"""
from app.mapping import classify_prezentare
content = {
@@ -475,7 +475,7 @@ def test_operatie_mapata_intra_in_queued_indiferent_de_autosend():
def test_regula_text_rezolvata_nu_mai_tine_randul():
"""Regula text cu auto_send=0 rezolva codul -> queued (nu needs_mapping held).
Dupa US-001: regula_fara_autosend nu se mai seteaza; codul rezolvat = queued direct.
regula_fara_autosend nu se mai seteaza; codul rezolvat = queued direct.
"""
from app.mapping import classify_prezentare
content = {
@@ -494,16 +494,16 @@ def test_regula_text_rezolvata_nu_mai_tine_randul():
def test_fara_stare_needs_mapping_pe_auto_send_oprit():
"""has_no_auto_send intotdeauna False dupa US-001; nu mai produce AUTO_SEND_OPRIT."""
"""has_no_auto_send intotdeauna False; nu mai produce AUTO_SEND_OPRIT."""
from app.mapping import has_no_auto_send
mapping_meta_false = {"OP_REVIEW": {"cod_prestatie": "OE-1", "auto_send": False}}
resolved = [{"cod_op_service": "OP_REVIEW", "cod_prestatie": "OE-1"}]
assert has_no_auto_send(resolved, mapping_meta_false) is False, (
"has_no_auto_send trebuie sa intoarca mereu False dupa US-001"
"has_no_auto_send trebuie sa intoarca mereu False"
)
resolved_cu_flag = [{"cod_op_service": "X", "cod_prestatie": "OE-1", "regula_fara_autosend": True}]
assert has_no_auto_send(resolved_cu_flag, {}) is False, (
"has_no_auto_send ignora regula_fara_autosend dupa US-001"
"has_no_auto_send ignora regula_fara_autosend"
)

View File

@@ -1,4 +1,4 @@
"""Teste US-011 (PRD 5.8) — helper pur `text_rules_overlap`.
"""Helper pur `text_rules_overlap`.
Avertisment neblocant cand o regula text noua se suprapune (substring, oricare
directie) cu una existenta. Helper determinist, fara DB.

View File

@@ -1,6 +1,6 @@
"""US-001: Schema + persistenta reguli text de mapare (operation_text_rules).
"""Schema + persistenta reguli text de mapare (operation_text_rules).
Teste RED-first: verifica tabela, functiile de persistenta si unicitatea per cont.
Verifica tabela, functiile de persistenta si unicitatea per cont.
"""
from __future__ import annotations

View File

@@ -1,11 +1,11 @@
"""Teste PRD 5.19 US-007 — gauge-uri /metrics pentru coada tinuta.
"""Teste gauge-uri /metrics pentru coada tinuta.
/metrics expune, pe langa `autopass_submissions{status=...}`, doua gauge-uri
DERIVATE (zero stare noua), scoped global:
- autopass_held_submissions = COUNT(queued AND held=1)
- autopass_held_oldest_age_seconds = varsta (s) a celui mai vechi rand tinut
TDD: fixtura izoleaza DB per test (pattern din test_worker_held.py).
Fixtura izoleaza DB per test (pattern din test_worker_held.py).
"""
from __future__ import annotations

View File

@@ -1,6 +1,6 @@
"""Teste US-003 (PRD 5.6): logger structurat central observ.log_event.
"""Logger structurat central observ.log_event.
TDD: scrie in app_events SI in log text, redacteaza creds/PII, filtreaza pe nivel.
Scrie in app_events SI in log text, redacteaza creds/PII, filtreaza pe nivel.
"""
from __future__ import annotations
@@ -97,9 +97,9 @@ def test_nivel_filtrat_din_env(env, monkeypatch):
def test_log_event_best_effort_nu_propaga(env, monkeypatch):
"""O eroare interna de scriere nu propaga (jurnal best-effort)."""
from app import observ
# Forteaza o eroare in insert pasand o conexiune invalida
class Boom:
def execute(self, *a, **k):
raise RuntimeError("boom")
# nu trebuie sa ridice
observ.log_event("nepasator", conn=Boom())

View File

@@ -1,8 +1,8 @@
"""US-004 (PRD 5.18) — seeder corpus etichetat in mapping_suggestions (SILVER).
"""Seeder corpus etichetat in mapping_suggestions (SILVER).
INSERT OR IGNORE din artefactul comis -> SILVER nu mai e gol in productie.
NB (F10): confirmarile UMANE stau in shared_mappings, NU aici; deci INSERT OR IGNORE
pastreaza codul LLM existent la re-seed (v1 = ignore, nu upsert).
Confirmarile UMANE stau in shared_mappings, NU aici; deci INSERT OR IGNORE
pastreaza codul LLM existent la re-seed (ignore, nu upsert).
"""
from __future__ import annotations

View File

@@ -1,6 +1,6 @@
"""Teste US-003 (PRD 3.5): helper pur payload -> campuri afisabile.
"""Teste helper pur payload -> campuri afisabile.
Helper partajat web + API (DRY, eng review). Defensiv: nu arunca pe payload
Helper partajat web + API (DRY). Defensiv: nu arunca pe payload
malformat; tolerant la diferentele de chei intre canale (numar vs
numarInmatriculare) si la coercion Excel (odometru "123.0", VIN non-string).
"""
@@ -82,7 +82,7 @@ def test_operatie_fallback_la_cod():
assert d["operatie"] == "OP-77"
# --- US-005: cod_rar distinct ---
# --- cod_rar distinct ---
def test_cod_rar_prezent_cand_mapat():
"""cod_prestatie prezent -> cod_rar e uppercase + strip '.0'."""
@@ -148,7 +148,7 @@ def test_operatie_ramane_denumire_sau_op():
assert d3["cod"] == "oe-2" # cod ramas neschimbat (nu uppercase)
# --- US-002: op_service_cod + op_service_denumire distincte ---
# --- op_service_cod + op_service_denumire distincte ---
def test_operatie_service_din_cod_op_service():
"""cod_op_service prezent -> op_service_cod contine valoarea; string gol cand lipseste."""

View File

@@ -1,4 +1,4 @@
"""Teste US-001/US-002 (PRD 5.17): app/plans.py — definitia planurilor + helperi tier/consum."""
"""app/plans.py — definitia planurilor + helperi tier/consum."""
from __future__ import annotations
@@ -307,7 +307,7 @@ def test_consum_lunar_nu_numara_cross_account(conn):
# ---------------------------------------------------------------------------
# PRD 5.17 enforcement — logica de limita + kill-switch config
# Enforcement — logica de limita + kill-switch config
# ---------------------------------------------------------------------------
def test_volume_la_limita_exacta(conn):
@@ -339,8 +339,8 @@ def test_volume_la_limita_exacta(conn):
def test_enforce_plans_config_default_true(monkeypatch):
"""AUTOPASS_ENFORCE_PLANS implicit True — enforcement activ de la deploy.
Decizie user (autoplan 2026-06-28): nu exista conturi legacy, produs in TESTE,
enforcement DUR activ implicit. Kill-switch oprit explicit cand e necesar.
Nu exista conturi legacy; enforcement DUR activ implicit.
Kill-switch oprit explicit cand e necesar.
"""
from app.config import Settings
# Creem Settings fresh (fara env var setata) -> default True

View File

@@ -1,13 +1,13 @@
"""US-001 (PRD 5.18) — pre-filtru determinist non-operatii (NUL).
"""Pre-filtru determinist non-operatii (NUL).
Masuratoarea k-NN (memorie test-precizie-knn-embeddings) arata recall NUL doar 64%:
gunoiul evident (ITP, plata, discount, nr. inmatriculare, tractare) scapa ca OE-1.
Un pre-filtru determinist il marcheaza NUL INAINTE de k-NN.
Recall NUL doar 64% cu k-NN: gunoiul evident (ITP, plata, discount,
nr. inmatriculare, tractare) scapa ca OE-1. Un pre-filtru determinist il
marcheaza NUL INAINTE de k-NN.
Garantie non-negociabila (AC): ZERO fals-pozitiv pe operatii reale. Regulile
text/regex au fost calibrate pe `docs/operatii-service/*.csv` (vezi sesiunea de
implementare): triggerele ambigue (TRACTARE, NR INMATRICULARE/placuta) sunt
ECRANATE de un context de piesa/operatie (D/R, CARLIG, CAPAC, INLOCUIT...).
Garantie non-negociabila: ZERO fals-pozitiv pe operatii reale. Regulile
text/regex au fost calibrate pe `docs/operatii-service/*.csv`: triggerele
ambigue (TRACTARE, NR INMATRICULARE/placuta) sunt ECRANATE de un context de
piesa/operatie (D/R, CARLIG, CAPAC, INLOCUIT...).
"""
from __future__ import annotations
@@ -53,7 +53,7 @@ def test_operatie_reala_nu_e_nul():
def test_zero_fals_pozitiv_pe_set_operatii_reale():
"""AC: zero fals-pozitiv pe un set de 20 operatii reale (din docs/operatii-service)."""
"""Zero fals-pozitiv pe un set de 20 operatii reale (din docs/operatii-service)."""
reale = [
"REVIZIE", "SCHIMB ULEI MOTOR", "INLOCUIT PLACUTE FRANA FATA",
"D/R BARA FATA", "VOPSIT USA DR FATA", "INLOCUIT FILTRU AER",

View File

@@ -1,8 +1,8 @@
"""Teste US-002 (PRD 3.6): buton "Editeaza" pe rand in tabelul de preview.
"""Buton "Editeaza" pe rand in tabelul de preview.
Mod editare pe rand (form propriu, NU #confirm-form). Swap pe rand + OOB contoare,
NU pe #import-section (D-3.1). La eroare de validare randul ramane in editare cu
valorile pastrate (D-2.1/D-2.2). Enter intr-un camp salveaza randul, nu confirma (D-3.3).
NU pe #import-section. La eroare de validare randul ramane in editare cu
valorile pastrate. Enter intr-un camp salveaza randul, nu confirma.
"""
from __future__ import annotations
@@ -98,9 +98,9 @@ def test_editeaza_intra_in_mod_editare_form_propriu(client):
def test_salveaza_cere_reincarcare_si_toast(client):
"""POST editeaza: raspuns minimal + HX-Trigger(reincarcaPreview + randSalvat).
Contractul nou (dogfood 5.13): nu mai facem OOB swap pe <tr> (fragil in htmx 1.9 ->
randul ramanea cu starea veche). Raspunsul cere reincarcarea preview-ului si emite
detaliile randului salvat pentru toast/evidentiere."""
Nu se face OOB swap pe <tr> (fragil in htmx 1.9 -> randul ramanea cu starea veche).
Raspunsul cere reincarcarea preview-ului si emite detaliile randului salvat pentru
toast/evidentiere."""
import json as _json
_seed_op1()
iid = _upload_and_preview(client)

View File

@@ -1,6 +1,6 @@
"""Teste US-003 (PRD 5.11) — Preview pas 3 in format identic cu tabelul Trimiteri.
"""Teste preview pas 3 in format identic cu tabelul Trimiteri.
Proces TDD: aceste teste sunt scrise INAINTE de implementare (RED) si verifica:
Verifica:
1. Coloana Note nu afiseaza repr Python brut (lista/dict Python) pentru needs_mapping.
2. Starea afisata in pill-ul randului este eticheta umana (nu codul brut).
3. Tabelul de preview foloseste clasa CSS .tabel-trimiteri.
@@ -161,7 +161,7 @@ _ROWS_DUPLICATE = [
# --------------------------------------------------------------------------- #
# Teste RED → GREEN #
# Teste #
# --------------------------------------------------------------------------- #
def test_preview_nu_contine_repr_python(client):
@@ -245,11 +245,10 @@ def test_preview_stare_eticheta_umana_duplicate(client):
def test_nota_umana_preview_needs_mapping_cu_flag_prioritizeaza_unmapped():
"""needs_mapping + flag -> Note afiseaza 'Cod RAR lipsa', nu textul flag-ului.
BUG 3: nota_umana_preview verifica `if flags:` inaintea ramurei unmapped.
Un rand needs_mapping care are si un flag (ex. VIN numeric) afisa textul
flag-ului in loc de 'Cod RAR lipsa pentru: COD' — exact confuzia US-003
voia s-o evite (userul corecteaza data si ramane blocat pe cod).
Fix: cand status == 'needs_mapping', prioritizeaza ramura unmapped.
Un rand needs_mapping care are si un flag (ex. VIN numeric) nu trebuie sa
afiseze textul flag-ului in loc de 'Cod RAR lipsa pentru: COD' (userul ar
corecta data si ar ramane blocat pe cod). Cand status == 'needs_mapping',
nota_umana_preview prioritizeaza ramura unmapped.
"""
from app.web.labels import nota_umana_preview

View File

@@ -1,4 +1,4 @@
"""Teste US-013 (PRD 5.6): retentie / purjare randuri ne-sent blocate."""
"""Teste retentie / purjare randuri ne-sent blocate."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""US-002 (PRD 5.20): medii_disponibile + rar_env_efectiv (REQ-DISP / REQ-DEFAULT)."""
"""medii_disponibile + rar_env_efectiv (REQ-DISP / REQ-DEFAULT)."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""Teste US-004 (PRD 5.20): rezolvare mediu tinta la ingestie + respingere tinte indisponibile.
"""Rezolvare mediu tinta la ingestie + respingere tinte indisponibile.
Fixtura `conn` urmareste acelasi pattern ca tests/test_accounts.py:
monkeypatch AUTOPASS_DB_PATH pe tempdir, cache_clear, init_db, get_connection.

View File

@@ -1,4 +1,4 @@
"""Teste US-002 (PRD 5.6): request_id per cerere + header X-Request-ID."""
"""Teste request_id per cerere + header X-Request-ID."""
from __future__ import annotations

View File

@@ -1,11 +1,11 @@
"""US-003: Reguli text active la ingestie (API + import + corectie web) si la
"""Reguli text active la ingestie (API + import + corectie web) si la
re-rezolvarea blocajelor (`reresolve_account`).
Verifica ca o regula text salvata in prealabil rezolva o operatie fara mapare
exacta pe TOATE caile de ingestie, in loc sa o lase `needs_mapping`, si ca la
re-rezolvare un rand `needs_mapping` care acum da match pe o regula se deblocheaza.
Codul rezolvat din regula respecta validarea fata de nomenclator (US-002): folosim
Codul rezolvat din regula respecta validarea fata de nomenclator: folosim
`OE-2`, cod valid din seed-ul nomenclatorului.
"""

View File

@@ -1,4 +1,4 @@
"""Teste US-013 (PRD 5.20): retragere coloana legacy accounts.rar_creds_enc.
"""Retragere coloana legacy accounts.rar_creds_enc.
Teste:
test_niciun_read_pe_coloana_veche -- DB fresh: accounts N-are rar_creds_enc, submissions ARE
@@ -236,7 +236,7 @@ def test_are_creds_pe_per_env(client):
def test_drop_cu_garda_blocat_daca_lipsa_copiere(conn_izolat):
"""Garda refuza DROP cand exista cont cu rar_creds_enc dar ambele sloturi per-env goale.
Apelam _garda_si_drop direct (fara re-backfill 6c) pe o stare adversariala:
Apelam _garda_si_drop direct (fara re-backfill) pe o stare adversariala:
cont cu valoare in coloana legacy, rar_creds_test_enc=NULL, rar_creds_prod_enc=NULL.
Rezultat asteptat: DROP refuzat (coloana inca prezenta pe accounts).
"""
@@ -263,7 +263,7 @@ def test_drop_cu_garda_blocat_daca_lipsa_copiere(conn_izolat):
assert row_before["rar_creds_test_enc"] is None
assert row_before["rar_creds_prod_enc"] is None
# Apelam _garda_si_drop direct (fara re-backfill 6c)
# Apelam _garda_si_drop direct (fara re-backfill)
from app.db import _garda_si_drop
_garda_si_drop(conn)

View File

@@ -1,4 +1,4 @@
"""US-001 (PRD 5.20): schema medii per cont + env pe submission + migrare/backfill."""
"""Schema medii per cont + env pe submission + migrare/backfill."""
from __future__ import annotations
@@ -26,7 +26,7 @@ def fresh_conn(monkeypatch):
def _old_db(path: str) -> sqlite3.Connection:
"""Construieste un DB in forma PRE-5.20 (fara coloanele de mediu)."""
"""Construieste un DB in forma veche (fara coloanele de mediu)."""
conn = sqlite3.connect(path, isolation_level=None)
conn.row_factory = sqlite3.Row
conn.execute(
@@ -109,7 +109,7 @@ def test_migrare_cont_fara_creds_ramane_pe_default(tmp_path, monkeypatch):
def test_submissions_rar_env(tmp_path, monkeypatch):
"""Un rand PRE-migrare ajunge cu env-ul global (NU 'test') + cheie recalculata env-aware."""
"""Un rand pre-migrare ajunge cu env-ul global (NU 'test') + cheie recalculata env-aware."""
path = str(tmp_path / "old.db")
old = _old_db(path)
payload = {

View File

@@ -148,7 +148,7 @@ def test_prod_requires_key(env):
conn = get_connection()
try:
key = create_api_key(conn, 1)
# Testul verifica autentificarea, nu planul — tier='pro' ca sa treaca gate-ul API (T4).
# Testul verifica autentificarea, nu planul — tier='pro' ca sa treaca gate-ul API.
conn.execute("UPDATE accounts SET tier='pro' WHERE id=1")
finally:
conn.close()
@@ -186,7 +186,7 @@ def test_key_account_routes_idempotency(env):
conn = get_connection()
try:
# tier='pro' pe ambele conturi — testul verifica idempotenta, nu planuri (T4 PRD 5.17).
# tier='pro' pe ambele conturi — testul verifica idempotenta, nu planuri.
conn.execute("UPDATE accounts SET tier='pro' WHERE id=1")
conn.execute("INSERT INTO accounts (id, name, tier) VALUES (2, 'al-doilea', 'pro')")
k1 = create_api_key(conn, 1)

View File

@@ -1,7 +1,4 @@
"""Teste US-001 (PRD 5.12): companie/email/CUI obligatorii la signup.
TDD strict: testele se scriu INAINTE de implementare (RED), dupa implementare trec (GREEN).
"""
"""Companie/email/CUI obligatorii la signup."""
from __future__ import annotations
@@ -37,7 +34,7 @@ def _csrf(html: str) -> str:
def test_signup_html_cui_obligatoriu_ui(client):
"""GET /signup: campul CUI NU contine '(optional)' si are atribut required (US-001 UI)."""
"""GET /signup: campul CUI NU contine '(optional)' si are atribut required."""
resp = client.get("/signup")
assert resp.status_code == 200
# (a) NU trebuie sa apara textul "(optional)" langa CUI

View File

@@ -1,8 +1,4 @@
"""Teste US-012 (PRD 3.3b): notificare email admin la signup (degradat) + bootstrap admin.
TDD: testele se scriu INAINTE de implementare; la inceput pica (RED),
dupa implementare trec (GREEN).
"""
"""Notificare email admin la signup (degradat) + bootstrap admin."""
from __future__ import annotations
@@ -152,13 +148,13 @@ def test_primul_signup_devine_admin(client):
# ---------------------------------------------------------------------------
# Teste C16 (log SIGNUP pastrat) si best-effort E2E
# Teste log SIGNUP pastrat si best-effort E2E
# ---------------------------------------------------------------------------
def test_signup_logheaza_fara_pii_in_stdout(client, capsys):
"""Signup reusit -> NU se mai printeaza email-ul in clar in stdout (P2-7).
"""Signup reusit -> NU se mai printeaza email-ul in clar in stdout.
C16 (jurnalizarea signup-ului) e pastrata, dar prin `log_event` (app_events +
Jurnalizarea signup-ului e pastrata, dar prin `log_event` (app_events +
log text redactat), nu prin print() cu PII."""
resp = _do_signup(client, "Service Log Test", "log@test.com")
assert resp.status_code == 200

View File

@@ -1,4 +1,4 @@
"""Teste US-011 (PRD 5.20): indicator mediu RAR in statusbar + toggle conditionat.
"""Indicator mediu RAR in statusbar + toggle conditionat.
Rute testate:
GET /_fragments/status -- indicator mediu (eticheta statica sau toggle)
@@ -135,7 +135,7 @@ def _get_csrf_din_status(client) -> str:
def test_afiseaza_env_default(client):
"""Cont cu UN singur mediu disponibil (prod) -> statusbar contine eticheta pentru Productie,
fara niciun control de toggle/comutare.
US-010 (PRD 5.20): eticheta foloseste acum 'PRODUCȚIE' (diacritice + majuscule).
Eticheta foloseste 'PRODUCȚIE' (diacritice + majuscule).
"""
acct_id, _ = _create_account_user("Firma Env1", "env1@test.com")
_seteaza_mediu_disponibil(acct_id, "prod")
@@ -145,7 +145,7 @@ def test_afiseaza_env_default(client):
assert resp.status_code == 200, f"Status HTTP neasteptat: {resp.status_code}"
html = resp.text
# Eticheta mediului trebuie prezenta — "PRODUC" acopera atat 'PRODUCȚIE' (US-010) cat si
# Eticheta mediului trebuie prezenta — "PRODUC" acopera atat 'PRODUCȚIE' cat si
# formele anterioare 'Productie'/'PRODUCTIE' (anti-regresie).
assert "PRODUC" in html.upper(), f"Eticheta Productie absenta in statusbar: {html[:800]}"

View File

@@ -1,4 +1,4 @@
"""Teste US-009 (PRD 5.6): helper sterge / re-pune in coada randuri blocate."""
"""Helper sterge / re-pune in coada randuri blocate."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""Teste T16: job purjare + purge_after SET la insert (OV-5).
"""Job purjare + purge_after SET la insert.
Verify:
(a) insert/sent -> purge_after populat (sent+90z).
@@ -68,7 +68,7 @@ def test_mark_sent_seteaza_purge_after(conn):
def test_mark_queued_nu_seteaza_purge_after(conn):
"""Starile active (queued) nu primesc purge_after.
NOTA US-013: error/needs_data/needs_mapping primesc ACUM purge_after (retentie
NOTA: error/needs_data/needs_mapping primesc ACUM purge_after (retentie
blocate, 30z) — vezi tests/test_purge_blocate.py. Doar queued/sending raman fara.
"""
import app.worker.__main__ as w

View File

@@ -1,11 +1,11 @@
"""Teste T1: creds durabile per-cont (per-env, US-013) + worker re-login fallback + gate purjare.
"""Creds durabile per-cont (per-env) + worker re-login fallback + gate purjare.
Verify:
(a) Serie web, worker restart (sesiune goala), token expirat -> re-login din accounts -> trimite.
(b) Coada MIXTA API(efemer)+web(durabil): dupa login web, submission-urile API tot se trimit
(purjarea nu le-a rupt prematur).
US-013: accounts.rar_creds_enc (legacy) a fost dropata; sloturile per-env sunt singura sursa.
accounts.rar_creds_enc (legacy) a fost dropata; sloturile per-env sunt singura sursa.
"""
from __future__ import annotations
@@ -83,7 +83,7 @@ def test_creds_from_account_fallback(env, monkeypatch):
conn = get_connection()
try:
enc = encrypt_creds({"email": "web@test.ro", "password": "webpass"})
# US-013: scrie in slotul per-env test (slotul legacy rar_creds_enc dropat)
# scrie in slotul per-env test (slotul legacy rar_creds_enc dropat)
conn.execute(
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc,)
)
@@ -122,7 +122,7 @@ def test_worker_relogin_dupa_restart(env, monkeypatch):
conn = get_connection()
try:
enc = encrypt_creds({"email": "web@test.ro", "password": "webpass"})
# US-013: scrie in slotul per-env test
# scrie in slotul per-env test
conn.execute(
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc,)
)
@@ -152,7 +152,7 @@ def test_coada_mixta_api_web(env, monkeypatch):
1. S1 = submission API cu creds efemere in submissions.rar_creds_enc
2. S2 = submission WEB fara creds (foloseste accounts.rar_creds_test_enc per-env)
3. Login cu creds S1 -> purjare S1.rar_creds_enc (pe submissions) -> OK (worker are token)
4. S2 tot se poate procesa (creds din accounts per-env, US-013)
4. S2 tot se poate procesa (creds din accounts per-env)
"""
import app.worker.__main__ as w
from app.crypto import encrypt_creds
@@ -162,7 +162,7 @@ def test_coada_mixta_api_web(env, monkeypatch):
conn = get_connection()
try:
# Creds durabile pentru contul web (slotul per-env, US-013)
# Creds durabile pentru contul web (slotul per-env)
enc_web = encrypt_creds({"email": "web@test.ro", "password": "webpass"})
conn.execute(
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc_web,)
@@ -209,7 +209,7 @@ def client(env):
def test_endpoint_set_rar_creds(client, env):
"""POST /v1/conturi/rar-creds seteaza creds criptate in slotul per-env (US-013)."""
"""POST /v1/conturi/rar-creds seteaza creds criptate in slotul per-env."""
from app.crypto import decrypt_creds
from app.db import get_connection
@@ -235,7 +235,7 @@ def test_endpoint_set_rar_creds(client, env):
def test_endpoint_delete_rar_creds(client, env):
"""DELETE /v1/conturi/rar-creds sterge creds durabile (ambele sloturi per-env, US-013)."""
"""DELETE /v1/conturi/rar-creds sterge creds durabile (ambele sloturi per-env)."""
# Mai intai seteaza pe test si prod
client.post("/v1/conturi/rar-creds", json={"email": "u@test.ro", "password": "pass123", "rar_target": "test"})
client.post("/v1/conturi/rar-creds", json={"email": "u@prod.ro", "password": "pass456", "rar_target": "prod"})
@@ -257,7 +257,7 @@ def test_endpoint_delete_rar_creds(client, env):
def test_gate_purjare_nu_sterge_accounts(env, monkeypatch):
"""Gate purjare T1: stergerea submissions.rar_creds_enc NU atinge accounts per-env (US-013)."""
"""Gate purjare: stergerea submissions.rar_creds_enc NU atinge accounts per-env."""
import app.worker.__main__ as w
from app.crypto import encrypt_creds
from app.db import get_connection
@@ -267,7 +267,7 @@ def test_gate_purjare_nu_sterge_accounts(env, monkeypatch):
conn = get_connection()
try:
enc = encrypt_creds({"email": "u@test.ro", "password": "p"})
# US-013: scrie in slotul per-env test
# scrie in slotul per-env test
conn.execute(
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc,)
)

View File

@@ -1,18 +1,15 @@
"""Teste T6: comportament dupa US-001 (PRD 5.11) — auto_send nu mai tine randuri.
"""auto_send nu mai tine randuri.
US-001: has_no_auto_send neutralizat (return False); un cod rezolvat (mapare exacta
has_no_auto_send neutralizat (return False); un cod rezolvat (mapare exacta
sau regula text) -> queued direct, indiferent de auto_send=0/1 in mapping_meta.
Coloanele DB operations_mapping.auto_send si operation_text_rules.auto_send RAMAN
(default 1, ne-citite pentru hold). Functia has_no_auto_send RAMANE DEFINITA (importata
in routes.py + import_router.py) dar intoarce mereu False.
Inainte de US-001:
(a) cod nou-mapat cu auto_send=0 -> nu auto-send, review manual (needs_mapping).
Comportament:
(a) cod nou-mapat cu auto_send=0 -> queued.
(b) mapare existenta cu auto_send=1 -> queued.
Dupa US-001:
(a) cod nou-mapat cu auto_send=0 -> queued (ca si (b)).
(b) mapare existenta cu auto_send=1 -> queued (neschimbat).
"""
from __future__ import annotations
@@ -93,7 +90,7 @@ def test_load_mapping_meta_returns_auto_send(conn):
# --- has_no_auto_send (neutralizat, mereu False) ---
def test_has_no_auto_send_mereu_false_cu_auto_send_fals(conn):
"""has_no_auto_send intoarce False chiar si cand auto_send=False in mapping_meta (US-001)."""
"""has_no_auto_send intoarce False chiar si cand auto_send=False in mapping_meta."""
from app.mapping import has_no_auto_send
mapping_meta = {
"ITP-1": {"cod_prestatie": "OE-1", "auto_send": False},
@@ -120,10 +117,10 @@ def test_has_no_auto_send_direct_cod_prestatie(conn):
assert has_no_auto_send(resolved, mapping_meta) is False
# --- reresolve_account cu auto_send=0 (US-001: acum requeue) ---
# --- reresolve_account cu auto_send=0 (acum requeue) ---
def test_reresolve_auto_send_zero_acum_requeue(conn):
"""(US-001) cod nou-mapat cu auto_send=0 -> queued (nu mai review_manual)."""
"""cod nou-mapat cu auto_send=0 -> queued (nu mai review_manual)."""
from app.mapping import reresolve_account
sid = _insert_needs_mapping(conn, cod_op="ITP-CHECK")
_add_mapping(conn, cod_op="ITP-CHECK", cod_prestatie="OE-1", auto_send=False)
@@ -150,7 +147,7 @@ def test_reresolve_auto_send_unu_requeue(conn):
assert row["status"] == "queued"
# --- POST /v1/prezentari cu auto_send=0 (US-001: acum queued) ---
# --- POST /v1/prezentari cu auto_send=0 (acum queued) ---
def _body_with_op(cod_op="ITP-CHECK"):
return {
@@ -166,7 +163,7 @@ def _body_with_op(cod_op="ITP-CHECK"):
def test_post_auto_send_zero_acum_queued(client, env):
"""(US-001) Via API: cod nou-mapat cu auto_send=0 -> queued (nu mai needs_mapping)."""
"""Via API: cod nou-mapat cu auto_send=0 -> queued (nu mai needs_mapping)."""
from app.db import get_connection
conn2 = get_connection()
try:
@@ -177,7 +174,7 @@ def test_post_auto_send_zero_acum_queued(client, env):
r = client.post("/v1/prezentari", json=_body_with_op("ITP-X"))
assert r.status_code == 200
status = r.json()["results"][0]["status"]
assert status == "queued", f"auto_send=0 dupa US-001 -> queued, e: {status}"
assert status == "queued", f"auto_send=0 -> queued, e: {status}"
def test_post_auto_send_unu_queued(client, env):

View File

@@ -1,7 +1,4 @@
"""Teste US-001 + US-002 (PRD 5.3): Light/Dark mode comutator tema.
TDD: testele se scriu INAINTE de implementare (RED), dupa implementare trec (GREEN).
"""
"""Light/Dark mode comutator tema."""
from __future__ import annotations
@@ -52,7 +49,7 @@ def _login(client, email: str, password: str = "parolasecreta") -> None:
assert resp.status_code == 303, f"Login esuat: {resp.status_code}"
# ── US-001: Tema light ─────────────────────────────────────────────────────────
# ── Tema light ─────────────────────────────────────────────────────────────────
def test_paleta_light_definita(client):
"""HTML de la GET /login contine un selector [data-theme="light"] care redefineste
@@ -72,7 +69,7 @@ def test_paleta_light_definita(client):
def test_dark_ramane_default(client):
""":root contine paleta dark exacta: --bg:#0f1218, --card:#181c24, --ink:#e6e9ef.
Valorile actualizate la US-013 (PRD 5.10) conform DESIGN.md (accent azur ROMFAST).
Conform DESIGN.md (accent azur ROMFAST).
"""
resp = client.get("/login")
assert resp.status_code == 200
@@ -98,7 +95,7 @@ def test_suprafete_fara_fundal_hardcodat(client):
assert "#16241c" not in style, "Fundalul hardcodat #16241c (flash) inca in <style>"
# ── US-002: Comutator tema + anti-FOUC ────────────────────────────────────────
# ── Comutator tema + anti-FOUC ─────────────────────────────────────────────────
def test_script_antifouc_in_head_inainte_de_style(client):
"""<head> contine un <script> care citeste localStorage (cheia 'theme') si seteaza
@@ -166,7 +163,7 @@ def test_toggle_pe_login_si_dashboard(client):
), "Butonul toggle lipseste pe dashboard"
# ── US-003: Fragmente HTMX fara fundal hardcodat ──────────────────────────────
# ── Fragmente HTMX fara fundal hardcodat ───────────────────────────────────────
def test_fragmente_fara_fundal_hardcodat():
"""Niciun fisier _*.html din app/web/templates/ nu contine literalii hex dark-fix
@@ -188,7 +185,7 @@ def test_fragmente_fara_fundal_hardcodat():
)
# ── US-001 (PRD 5.15): Teme aditive + tokeni --card2/--line2 ──────────────────
# ── Teme aditive + tokeni --card2/--line2 ──────────────────────────────────────
def test_cele_4_teme_definite(client):
"""Cele 4 teme noi (grafit/cobalt/cupru/hartie) au blocuri CSS [data-theme="..."]
@@ -326,12 +323,12 @@ def test_themes_dry_single_source(client):
)
# ── US-008: Test parametrizat robust — token critic in fiecare tema ─────────────
# ── Test parametrizat robust — token critic in fiecare tema ────────────────────
@pytest.mark.parametrize("token", ["--card2", "--line2", "--accent", "--ok", "--err"])
@pytest.mark.parametrize("tema", ["light", "dark", "petrol", "grafit", "cobalt", "cupru", "hartie"])
def test_token_critic_in_tema_parametrizat(client, tema, token):
"""US-008: test parametrizat robust — fiecare token critic e definit in fiecare tema.
"""Test parametrizat robust — fiecare token critic e definit in fiecare tema.
Ancorare pe selectorul CSS [data-theme="X"] {...} (sau :root pentru dark),
NU pe felii fixe [idx:idx+N]. Evita false-green-ul din regresia 5.13:
@@ -372,24 +369,24 @@ def test_token_critic_in_tema_parametrizat(client, tema, token):
)
# ── US-001 PRD 5.16: Stiva font sistem standard web ───────────────────────────
# ── Stiva font sistem standard web ─────────────────────────────────────────────
def test_font_stack_system_in_base(client):
"""T-E2 (PRD 5.16): base.html DEFINESTE --font-ui si --font-mono in :root
"""base.html DEFINESTE --font-ui si --font-mono in :root
si body foloseste var(--font-ui). Niciun @font-face IBM Plex nu mai exista."""
resp = client.get("/login")
assert resp.status_code == 200
html = resp.text
assert "--font-ui" in html, "Token --font-ui lipseste din :root (US-001 PRD 5.16)"
assert "--font-mono" in html, "Token --font-mono lipseste din :root (US-001 PRD 5.16)"
assert "var(--font-ui)" in html, "body nu foloseste var(--font-ui) (US-001 PRD 5.16)"
assert "--font-ui" in html, "Token --font-ui lipseste din :root"
assert "--font-mono" in html, "Token --font-mono lipseste din :root"
assert "var(--font-ui)" in html, "body nu foloseste var(--font-ui)"
assert "@font-face" not in html, \
"@font-face inca prezent in base.html — sterge toate regulile IBM Plex (US-001 PRD 5.16)"
"@font-face inca prezent in base.html — sterge toate regulile IBM Plex"
def test_zero_referinte_static_fonts(client):
"""T-E1 (PRD 5.16): nicio referinta /static/fonts/ in template-urile randate de app.
"""Nicio referinta /static/fonts/ in template-urile randate de app.
Toate literalele 'IBM Plex Sans' si 'IBM Plex Mono' sunt eliminate."""
resp = client.get("/login")
assert resp.status_code == 200
@@ -404,24 +401,24 @@ def test_zero_referinte_static_fonts(client):
def test_landing_fara_font_face_ibm_plex():
"""T-E1 (PRD 5.16): landing.html nu contine @font-face IBM Plex si niciun
"""landing.html nu contine @font-face IBM Plex si niciun
literal 'IBM Plex Sans' sau 'IBM Plex Mono' ca font primary."""
landing = Path(__file__).parent.parent / "app" / "web" / "templates" / "landing.html"
assert landing.exists(), f"landing.html negasit la {landing}"
content = landing.read_text(encoding="utf-8")
assert "@font-face" not in content, \
"@font-face inca in landing.html — sterge toate regulile IBM Plex (US-008 PRD 5.16)"
"@font-face inca in landing.html — sterge toate regulile IBM Plex"
assert "IBM Plex Sans" not in content, \
"Literal 'IBM Plex Sans' inca in landing.html — inlocuieste cu var(--font-ui)"
assert "IBM Plex Mono" not in content, \
"Literal 'IBM Plex Mono' inca in landing.html — inlocuieste cu var(--font-mono)"
# ── US-002 PRD 5.16: Scala tipografica ────────────────────────────────────────
# ── Scala tipografica ───────────────────────────────────────────────────────────
def test_tokeni_scala_fs_definiti(client):
"""US-002 (PRD 5.16): tokenurile de scala tipografica --fs-xs..--fs-3xl si
"""Tokenurile de scala tipografica --fs-xs..--fs-3xl si
--lh-tight/--lh-body sunt definiti in :root."""
resp = client.get("/login")
assert resp.status_code == 200
@@ -433,21 +430,21 @@ def test_tokeni_scala_fs_definiti(client):
"--lh-tight", "--lh-body",
]
for tok in tokeni:
assert tok in html, f"Token {tok} lipseste din :root (US-002 PRD 5.16)"
assert tok in html, f"Token {tok} lipseste din :root"
# ── US-011 PRD 5.16: Selector tema pill cu eticheta ───────────────────────────
# ── Selector tema pill cu eticheta ─────────────────────────────────────────────
def test_selector_tema_are_eticheta(client):
"""US-011 (PRD 5.16): butonul de tema este un pill cu clasa .tema-btn,
"""Butonul de tema este un pill cu clasa .tema-btn,
contine .tema-icon si #tema-label (eticheta vizibila a temei curente)."""
resp = client.get("/login")
assert resp.status_code == 200
html = resp.text
assert "tema-btn" in html, \
"Clasa .tema-btn lipseste din HTML — butonul de tema nu e pill (US-011 PRD 5.16)"
"Clasa .tema-btn lipseste din HTML — butonul de tema nu e pill"
assert "tema-icon" in html, \
".tema-icon lipseste — iconita temei nu e separat de eticheta (US-011 PRD 5.16)"
".tema-icon lipseste — iconita temei nu e separat de eticheta"
assert 'id="tema-label"' in html, \
'#tema-label lipseste — eticheta temei nu e prezenta in pill (US-011 PRD 5.16)'
'#tema-label lipseste — eticheta temei nu e prezenta in pill'

View File

@@ -1,9 +1,6 @@
"""Teste reguli text + auto_send dupa US-001 (PRD 5.11).
"""Teste reguli text + auto_send.
Inainte de US-001: o regula text cu auto_send=0 tinea randul in needs_mapping
(regula_fara_autosend=True + has_no_auto_send -> True).
Dupa US-001: has_no_auto_send mereu False; o regula text cu auto_send=0 rezolva
has_no_auto_send e mereu False; o regula text cu auto_send=0 rezolva
codul RAR si randul intra in queued direct. regula_fara_autosend nu se mai seteaza.
Functii pure -> teste fara DB.
@@ -28,7 +25,7 @@ def _content_cu(op_denumire="Verificare faruri"):
def test_regula_auto_send_0_acum_queued():
"""Regula text auto_send=0 + continut valid -> queued (nu mai needs_mapping) dupa US-001."""
"""Regula text auto_send=0 + continut valid -> queued (nu needs_mapping)."""
tr = [{"pattern": "verificare", "cod_prestatie": "OE-2", "auto_send": 0, "priority": 0}]
cl = classify_prezentare(_content_cu(), {}, {}, VALID, tr)
assert cl["status"] == "queued", f"asteptat queued (auto_send ignorat), got {cl['status']}"
@@ -42,16 +39,16 @@ def test_regula_auto_send_1_trece_in_coada():
def test_has_no_auto_send_mereu_false_cu_flag_regula():
"""has_no_auto_send=False chiar daca regula_fara_autosend e prezent (US-001)."""
"""has_no_auto_send=False chiar daca regula_fara_autosend e prezent."""
tr = [{"pattern": "verificare", "cod_prestatie": "OE-2", "auto_send": 0, "priority": 0}]
resolved, unmapped = resolve_prestatii(
[{"cod_op_service": "X99", "denumire": "Verificare faruri"}], {}, VALID, tr
)
assert unmapped == []
assert resolved[0]["cod_prestatie"] == "OE-2"
# Flagul regula_fara_autosend nu se mai seteaza (US-001)
# Flagul regula_fara_autosend nu se mai seteaza
assert resolved[0].get("regula_fara_autosend") is None, (
"regula_fara_autosend nu trebuie sa mai fie setat dupa US-001"
"regula_fara_autosend nu trebuie sa mai fie setat"
)
assert has_no_auto_send(resolved, {}) is False

View File

@@ -1,4 +1,4 @@
"""US-010: Telemetrie hit regula text in `app_events`.
"""Telemetrie hit regula text in `app_events`.
Cand o operatie nemapata primeste cod RAR dintr-o regula text (substring), apelantii
cu `conn` (ingestie API, import, re-rezolvare) emit un eveniment `text_rule_hit` in

View File

@@ -1,4 +1,4 @@
"""Teste US-002 (PRD 3.1): CLI tools/account.py (create/list/activate/deactivate)."""
"""CLI tools/account.py (create/list/activate/deactivate)."""
from __future__ import annotations

View File

@@ -1,4 +1,4 @@
"""Teste US-004 (PRD 3.6): zona de upload comprimata la o bara slim.
"""Zona de upload comprimata la o bara slim.
Cand contul are deja trimiteri, upload-ul devine o bara pe un rand (eticheta + buton
+ zona de trage). First-run pastreaza hero-ul "Primul fisier?". Drag-drop + input file

View File

@@ -1,4 +1,4 @@
"""Teste US-001 (PRD 3.3): tabela users + helper-e parole scrypt in app/users.py."""
"""Tabela users + helper-e parole scrypt in app/users.py."""
from __future__ import annotations
@@ -83,7 +83,7 @@ def test_get_user_by_email(conn, account_id):
def test_parola_scurta_si_lunga_eroare(conn, account_id):
"""Parola < 10 caractere sau > 128 ridica ValueError (C9 anti-DoS)."""
"""Parola < 10 caractere sau > 128 ridica ValueError (anti-DoS)."""
from app.users import create_user
with pytest.raises(ValueError):
create_user(conn, account_id, "scurta@ex.ro", "scurt")

View File

@@ -1,4 +1,4 @@
"""Teste TDD pentru POST /v1/prezentari/valideaza (dry-run, PRD 5.2 US-001)."""
"""Teste pentru POST /v1/prezentari/valideaza (dry-run)."""
from __future__ import annotations
@@ -160,11 +160,11 @@ def test_shape_invalid_422(client):
# --------------------------------------------------------------------------- #
# US-003: 3 niveluri in raspunsul /valideaza #
# 3 niveluri in raspunsul /valideaza #
# --------------------------------------------------------------------------- #
def test_erori_au_3niveluri(client):
"""/valideaza cu VIN invalid -> erori[i] au cod/problema/cauza/fix (pass-through US-002)."""
"""/valideaza cu VIN invalid -> erori[i] au cod/problema/cauza/fix (pass-through)."""
r = client.post("/v1/prezentari/valideaza", json=_body_v(vin="WVWZZZ1OZIQ45678"))
assert r.status_code == 200
res = r.json()["results"][0]

View File

@@ -1,6 +1,6 @@
"""Teste US-007 (PRD 5.20): validare credentiale RAR pe env-ul setului de creds.
"""Validare credentiale RAR pe env-ul setului de creds.
Premisa confirmata live (2026-06-29): creds prod NU se valideaza pe RAR test si
Premisa confirmata live: creds prod NU se valideaza pe RAR test si
invers (401 incrucisat). Deci login-ul de proba TREBUIE sa loveasca endpoint-ul
mediului caruia ii apartin credentialele, nu URL-ul global AUTOPASS_RAR_ENV.
@@ -97,7 +97,7 @@ class _RarClientFail:
def test_valideaza_pe_env_creds(env_db, monkeypatch):
"""Cand validezi creds pentru env='prod', clientul de login e creat cu base_url-ul prod.
US-007 AC: 'validarea foloseste env-ul setului de creds verificat'.
Validarea foloseste env-ul setului de creds verificat.
Premisa: creds prod nu se valideaza pe RAR test (401 incrucisat), deci
clientul TREBUIE sa foloseasca base_url-ul prod, nu cel de test.
"""
@@ -146,8 +146,8 @@ def test_valideaza_pe_env_creds_test(env_db, monkeypatch):
def test_mesaj_distinge_env(env_db, monkeypatch):
"""La esec de login pe test vs prod, mesajul difera ('TESTARE' vs 'PRODUCTIE').
US-007 AC: 'mesaj distinct creds invalide pe TESTARE vs pe PRODUCTIE'.
Design F6/F7: banner-ul de eroare indica pe ce mediu a esuat login-ul.
Mesaj distinct creds invalide pe TESTARE vs pe PRODUCTIE.
Banner-ul de eroare indica pe ce mediu a esuat login-ul.
"""
import app.web.routes as routes_mod
from app.config import get_settings

View File

@@ -1,4 +1,4 @@
"""Teste T3 — validare de domeniu prezentari (app.validation).
"""Validare de domeniu prezentari (app.validation).
Un test per regula din plan.md sect. 2 / contract. Validarea normalizeaza
(strip/upper) si intoarce erori structurate {field, message}; nu ridica exceptii.
@@ -140,7 +140,7 @@ def test_erori_multiple_cumulate():
# ---------------------------------------------------------------------------
# US-002: 3 niveluri — coduri stabile, forma aditiva, back-compat
# 3 niveluri — coduri stabile, forma aditiva, back-compat
# ---------------------------------------------------------------------------
from app import errors as err_mod # noqa: E402

View File

@@ -1,6 +1,4 @@
"""Teste US-006 (PRD 5.11): Import = container compact colapsabil.
TDD — testele sunt scrise INAINTE de implementare (RED), apoi devin GREEN.
"""Import: container compact colapsabil.
Verifica:
- Containerul de import e colapsat implicit cand exista trimiteri (are_trimiteri=True)

View File

@@ -1,4 +1,4 @@
"""Teste US-009 (PRD 5.5): panou admin UI — selectie cu bife + master, bara de actiuni bulk
"""Teste panou admin UI — selectie cu bife + master, bara de actiuni bulk
(Activeaza/Blocheaza/Arhiveaza/Sterge), actiuni per-rand, fara nota 'cont dev implicit',
grila standard.
"""

View File

@@ -1,6 +1,5 @@
"""Teste PRD 5.19 strat WEB: toggle "Trimite automat la RAR" (US-004), trimitere
manuala per rand + bulk (US-005), afisaj held (US-006 UI), banner coada tinuta
imbatranita + contor manual (US-007), audit app_events (US-009).
"""Strat web: toggle "Trimite automat la RAR", trimitere manuala per rand + bulk,
afisaj held, banner coada tinuta imbatranita + contor manual, audit app_events.
Model: TestClient + login web (ca tests/test_web_lifecycle.py). NU atinge conftest.
"""
@@ -107,7 +106,7 @@ def _held(sid):
# --------------------------------------------------------------------------- #
# US-004 — toggle Auto: persistenta + CSRF + scope #
# Toggle Auto: persistenta + CSRF + scope #
# --------------------------------------------------------------------------- #
def test_auto_send_persista(client):
@@ -154,7 +153,7 @@ def test_auto_send_scoped_ignora_account_id_din_formular(client):
# --------------------------------------------------------------------------- #
# US-004 — auto-release OFF->ON cu garda de confirmare #
# Auto-release OFF->ON cu garda de confirmare #
# --------------------------------------------------------------------------- #
def test_off_to_on_fara_confirmare_nu_elibereaza(client):
@@ -196,7 +195,7 @@ def test_off_to_on_fara_randuri_tinute_comite_direct(client):
# --------------------------------------------------------------------------- #
# US-005 — trimitere manuala per rand + bulk #
# Trimitere manuala per rand + bulk #
# --------------------------------------------------------------------------- #
def test_trimite_acum_rand_tinut(client):
@@ -256,7 +255,7 @@ def test_trimite_toate_scoped(client):
# --------------------------------------------------------------------------- #
# US-006 (UI) — eticheta held + buton Trimite in lista #
# Eticheta held + buton Trimite in lista #
# --------------------------------------------------------------------------- #
def test_rand_tinut_eticheta_si_buton(client):
@@ -277,7 +276,7 @@ def test_rand_ne_tinut_fara_buton(client):
# --------------------------------------------------------------------------- #
# US-007 — banner coada tinuta imbatranita + contor manual #
# Banner coada tinuta imbatranita + contor manual #
# --------------------------------------------------------------------------- #
def test_banner_aged_apare_pt_rand_vechi(client):
@@ -307,7 +306,7 @@ def test_contor_manual_apare(client):
# --------------------------------------------------------------------------- #
# US-009 — audit app_events #
# Audit app_events #
# --------------------------------------------------------------------------- #
def _events(account_id, tip):
@@ -348,8 +347,8 @@ def test_audit_held_eliberat_bulk(client):
# --------------------------------------------------------------------------- #
# /code-review (fix findings #2/#3/#5): stickiness filtru held, banner OOB, #
# afordanta de eliberare in panoul de detaliu. #
# Stickiness filtru held, banner OOB, afordanta de eliberare in panoul de #
# detaliu. #
# --------------------------------------------------------------------------- #
def test_fragment_held_gol_nu_da_422(client):
@@ -392,7 +391,7 @@ def test_fragment_lista_curata_reseteaza_f_held(client):
def test_banner_bulk_dispare_dupa_eliberare(client):
"""Banner 'Trimite toate (N)' e OOB (#bulk-held-banner-wrap): dupa eliberarea tuturor
randurilor tinute, wrapper-ul revine gol (fara buton) — nu mai ramane stale (#3)."""
randurilor tinute, wrapper-ul revine gol (fara buton) — nu mai ramane stale."""
aid = _account_user("k4@test.com")
csrf = _login(client, "k4@test.com")
_ins(aid, "queued", held=1)
@@ -410,7 +409,7 @@ def test_banner_bulk_dispare_dupa_eliberare(client):
def test_detaliu_rand_tinut_are_buton_trimite_acum(client):
"""Panoul de detaliu al unui rand tinut (queued AND held=1) arata eticheta manuala +
buton 'Trimite acum la RAR' (#5)."""
buton 'Trimite acum la RAR'."""
aid = _account_user("k5@test.com")
_login(client, "k5@test.com")
sid = _ins(aid, "queued", held=1)

View File

@@ -1,4 +1,4 @@
"""Teste US-011 (PRD 3.5): badge cu contoare pe tab-uri (atentionari).
"""Badge cu contoare pe tab-uri (atentionari).
Badge doar cand contorul > 0; numar corect scoped pe cont; aria-label cu sens.
"""
@@ -74,7 +74,7 @@ def client(monkeypatch):
def test_badge_mapari(client):
"""US-009: cu operatii needs_mapping, intrarea Mapari din meniu poarta un badge cu numar."""
"""Cu operatii needs_mapping, intrarea Mapari din meniu poarta un badge cu numar."""
acct = _create_account_user("bm@test.com")
_ins(acct, "needs_mapping")
_ins(acct, "needs_mapping")
@@ -83,7 +83,7 @@ def test_badge_mapari(client):
resp = client.get("/")
assert resp.status_code == 200
html = resp.text
# US-009: Mapari e acum in meniu (nu tab); badgeul apare in intrarea meniului
# Mapari e in meniu (nu tab); badgeul apare in intrarea meniului
idx = html.find('href="/?tab=mapari"')
assert idx != -1, "Intrarea Mapari lipseste din meniu"
# Cauta badgeul in contextul link-ului Mapari
@@ -93,7 +93,7 @@ def test_badge_mapari(client):
def test_badge_trimiteri_blocate(client):
"""US-003 (3.6): cu randuri blocate, marcajul de atentie apare in heading-ul
"""Cu randuri blocate, marcajul de atentie apare in heading-ul
sectiunii 'Trimiterile tale' de pe Acasa (tab-ul Trimiteri a disparut)."""
acct = _create_account_user("bt@test.com")
_ins(acct, "needs_data")

View File

@@ -1,11 +1,11 @@
"""TDD 5.18 US-007 — Badge sursa sugestie in editorul de mapare (_mapari.html).
"""Badge sursa sugestie in editorul de mapare (_mapari.html).
Chip mic langa sugestia sistemului care arata DE UNDE vine codul propus:
- "confirmat" -> GOLD partajat (validat de om, shared_mappings)
- "similar" -> SILVER exact-match / k-NN embeddings (exemplu deja vazut)
- "non-operatie" -> pre-filtru NUL determinist (ITP/plata/discount...)
Toate suggestion-only (#13): badge-ul e doar indiciu vizual, nu schimba enqueue.
Suggestion-only: badge-ul e doar indiciu vizual, nu schimba enqueue.
Render real prin GET /_fragments/mapari (fragmentul HTMX scoped pe cont).
"""

View File

@@ -1,6 +1,6 @@
"""Teste US-010 (PRD 5.15): Bulk-fix din lista selectie multipla -> actiune unica.
"""Bulk-fix din lista: selectie multipla -> actiune unica.
Acceptance criteria:
Cazuri:
- test_bulk_remapeaza_selectie: N randuri needs_mapping + aplica cod -> toate -> queued
- test_bulk_doar_blocate: randuri sent/sending nu sunt eligibile (sarite silentios)
- test_bulk_scoped_cont: 404-before-409 — un cont nu atinge randurile altui cont
@@ -120,11 +120,11 @@ def client(monkeypatch):
# ---------------------------------------------------------------------------
# Teste US-010
# Teste
# ---------------------------------------------------------------------------
def test_bulk_remapeaza_selectie(client):
"""US-010 AC principal: N randuri needs_mapping + aplica cod valid -> toate -> queued.
"""N randuri needs_mapping + aplica cod valid -> toate -> queued.
OE-1 face parte din nomenclatorul seed (nomenclator_seed.FALLBACK_NOMENCLATOR),
incarcat de init_db la startup; nu e nevoie de insert separat.
@@ -172,7 +172,7 @@ def test_bulk_remapeaza_selectie(client):
def test_bulk_doar_blocate(client):
"""US-010 AC eligibilitate: randuri sent/sending sarite silentios; doar blocate procesate."""
"""Randuri sent/sending sarite silentios; doar blocate procesate."""
acct = _create_account_user("bulk_fix2@test.com")
# Rand sent (read-only, nu trebuie atins)
@@ -211,7 +211,7 @@ def test_bulk_doar_blocate(client):
def test_bulk_scoped_cont(client):
"""US-010 AC scope: contul A nu poate modifica randurile contului B.
"""Contul A nu poate modifica randurile contului B.
Pattern 404-before-409: randurile cross-account sunt sarite silentios
(nu confirmam existenta), raspuns HTTP 200 cu sumar care reflecta 0 reusite.

Some files were not shown because too many files have changed in this diff Show More