"""Teste US-003 — pasul „Potriveste coloanele" arata antet + prima inregistrare. Acceptance criteria: - Deasupra/langa randurile de mapare, un mic tabel orizontal: cap de tabel = numele coloanelor din fisier, rand = valorile primei inregistrari (truncate; `title` pe valoarea integrala). - Foloseste .tablewrap pentru scroll orizontal pe mobil. - Fiecare coloana din cap ramane asociata vizual cu select-ul ei de mapare. - Fisier fara randuri de date -> doar capul de tabel + mesaj explicit „antet fara randuri de date" (D#11) + butonul „Continua" dezactivat. """ from __future__ import annotations import io import os import tempfile import pytest @pytest.fixture() def client(monkeypatch): tmp = tempfile.mkdtemp() monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t.db")) monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "false") from app.config import get_settings get_settings.cache_clear() from app.main import app from fastapi.testclient import TestClient with TestClient(app) as c: yield c get_settings.cache_clear() def _make_xlsx_bytes(rows: list[dict]) -> bytes: """Construieste un xlsx minimal cu openpyxl.""" openpyxl = pytest.importorskip("openpyxl") wb = openpyxl.Workbook() ws = wb.active if not rows: return b"" headers = list(rows[0].keys()) ws.append(headers) for row in rows: ws.append([row.get(h) for h in headers]) buf = io.BytesIO() wb.save(buf) return buf.getvalue() def _make_xlsx_only_header(headers: list[str]) -> bytes: """Construieste un xlsx cu doar antet (fara randuri de date).""" openpyxl = pytest.importorskip("openpyxl") wb = openpyxl.Workbook() ws = wb.active ws.append(headers) buf = io.BytesIO() wb.save(buf) return buf.getvalue() _COLOANE = ["VIN", "Nr inmatriculare", "Data prestatie", "Odometru final", "Operatie"] _SAMPLE_ROWS = [ { "VIN": "WVWZZZ1KZAW000123", "Nr inmatriculare": "B001TST", "Data prestatie": "15.06.2026", "Odometru final": "123456", "Operatie": "Revizie", }, { "VIN": "WVWZZZ1KZAW000456", "Nr inmatriculare": "B002TST", "Data prestatie": "16.06.2026", "Odometru final": "200000", "Operatie": "Revizie", }, ] def _upload_csv_and_get_mapare(client, rows=None, headers=None) -> tuple[int, str]: """Incarca un xlsx si intoarce (import_id, html_text) din pasul de mapare coloane.""" if headers is not None: # Fisier cu doar antet xlsx = _make_xlsx_only_header(headers) else: xlsx = _make_xlsx_bytes(rows or _SAMPLE_ROWS) r = client.post( "/_import/upload", files={"file": ("test.xlsx", xlsx, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")}, ) return r.status_code, r.text # --------------------------------------------------------------------------- # # test_mapcoloane_arata_cap_tabel_coloane # # --------------------------------------------------------------------------- # def test_mapcoloane_arata_cap_tabel_coloane(client): """Pasul de mapare coloane afiseaza un tabel orizontal cu antetul fisierului. Fiecare coloana din fisier trebuie sa apara ca in capul tabelului. Tabelul trebuie inconjurat de .tablewrap pentru scroll orizontal. """ status, html = _upload_csv_and_get_mapare(client) assert status == 200 # Tabelul de preview al antetului trebuie sa fie prezent assert "tablewrap" in html, "Trebuie .tablewrap pentru scroll orizontal" # Fiecare coloana din fisier trebuie sa apara ca in tabel for col in _COLOANE: assert f" in capul tabelului" assert col in html, f"Coloana '{col}' trebuie sa apara in antetul tabelului" # Tabelul de preview (cu class sau id distinct pentru antet preview) assert "preview-antet" in html, "Tabelul de preview trebuie sa aiba class/id 'preview-antet'" # --------------------------------------------------------------------------- # # test_mapcoloane_arata_valori_prima_inregistrare # # --------------------------------------------------------------------------- # def test_mapcoloane_arata_valori_prima_inregistrare(client): """Pasul de mapare coloane afiseaza valorile primei inregistrari din fisier. Valorile din primul rand de date trebuie sa apara in tabel. """ status, html = _upload_csv_and_get_mapare(client, rows=_SAMPLE_ROWS) assert status == 200 # Valorile primei inregistrari trebuie sa apara assert "WVWZZZ1KZAW000123" in html, "VIN-ul primei inregistrari trebuie sa apara" assert "B001TST" in html, "Nr inmatriculare al primei inregistrari trebuie sa apara" assert "15.06.2026" in html, "Data prestatiei primei inregistrari trebuie sa apara" assert "123456" in html, "Odometrul primei inregistrari trebuie sa apara" # Valorile celui de-al doilea rand NU trebuie sa apara ca rand de date (numai primul rand) # (Nota: pot aparea ca exemple in alt context, dar randul de date e primul) # --------------------------------------------------------------------------- # # test_mapcoloane_fara_randuri_degradeaza # # --------------------------------------------------------------------------- # def test_mapcoloane_fara_randuri_degradeaza(client): """Fisier xlsx cu antet dar fara randuri de date → degradare grijulie. Trebuie sa: - Nu crape (status 200) - Arate capul de tabel cu coloanele - Arate mesajul explicit 'antet fara randuri de date' - Dezactiveze butonul 'Salveaza si continua' (disabled) """ status, html = _upload_csv_and_get_mapare(client, headers=_COLOANE) assert status == 200, f"Status neasteptat: {status}" # Nu trebuie sa crape — formular de mapare afisat assert "Mapare coloane" in html, "Formularul de mapare trebuie afisat" # Capul de tabel cu coloanele trebuie afisat for col in _COLOANE: assert col in html, f"Coloana '{col}' trebuie sa apara in antet chiar si fara date" # Mesaj explicit despre lipsa datelor assert "antet fara randuri de date" in html.lower() or "fara randuri de date" in html.lower(), \ "Trebuie mesaj explicit despre lipsa randurilor de date" # Butonul Continua trebuie dezactivat assert "disabled" in html, "Butonul 'Salveaza si continua' trebuie dezactivat cand nu sunt randuri"