feat(5.16+5.17): tipografie/antet branded + tipuri cont, planuri si enforcement
PRD 5.16 — propagare design finalizata (system font stack, fara IBM Plex self-hostat): - US-001/002/008: tokeni --font-ui/--font-mono (system stack) + scala --fs-*; zero @font-face si zero /static/fonts/; landing aliniat la acelasi stack - US-003: RAR online = dot compact in antet + meniu burger; banda rosie DOAR pe blocat (invariant zero-silent-failures pastrat) - US-010: antet "ROMFAST AUTOPASS" + nume service + /login brandeit 2 coloane + badge plan; meniu burger cu separatoare; gate strict pe is_authenticated - US-011: selector tema pill icon+eticheta (reuse THEMES) - US-004/005/006/007: bug-fix editor prestatii (picker cod+denumire, add_extra in mod operatii, cod ales se salveaza fara "+", Renunta inchide via closest) - US-012/013: landing Autentificare->/login; wizard import colapsat + 4 pasi pe tokeni - fix VERIFY E2E: contoare duplicate pe 390px (inline display:flex batea @media) -> CSS + test-lock PRD 5.17 — tipuri de cont + trial Pro 30z + enforcement DUR: - US-001/002/008: accounts.tier + trial_until (migrare aditiva defensiva); app/plans.py sursa unica (PLANS, FREE_MONTHLY_LIMIT=60, effective_tier(now injectabil), monthly_usage, CONSUMED_STATUSES); create_account trial Pro 30z; CLI set-tier (protejat id=1, audit) - US-003/004/005: enforce volum 60/luna INAINTE de build_key pe ambele canale (PLAN_LIMITA_LUNARA, 3 niveluri + log_event); gate API Pro+ (PLAN_FARA_API 403 actionabil); valideaza/nomenclator raman permise; downgrade lazy; flag AUTOPASS_ENFORCE_PLANS (kill-switch) - US-006: badge plan antet + linie burger + consum N/60 + warn>=80% + 6 stari + copy RO pluralizat + banner one-time trial->Gratuit + pagina Cont Regresie: 1380 passed, 0 failed, 1 deselected (live). E2E browser pe 390/1280 confirmat. Backend trimitere (worker/masina stari/idempotenta/contract RAR) NEATINS. Lucrul 5.18 (corpus kNN) ramane separat, necomis. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -81,7 +81,10 @@ def client(monkeypatch):
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_status_are_bife_verzi_cand_totul_ok(client):
|
||||
"""Worker viu + RAR login recent -> glifa verde ✓ + text 'declaratiile curg normal'."""
|
||||
"""US-003 PRD 5.16: worker viu + RAR login recent -> strip-sanatate in DOM dar ASCUNS (hidden).
|
||||
Banda rosie apare DOAR cand BLOCAT. Starea OK e indicata de dot-ul verde din antet (base.html).
|
||||
Elementul id=strip-sanatate ramane in DOM pentru compatibilitate (nu dispare complet).
|
||||
"""
|
||||
_create_account_user("bifeok@test.com")
|
||||
_login(client, "bifeok@test.com", "parolasecreta10")
|
||||
|
||||
@@ -91,12 +94,11 @@ def test_status_are_bife_verzi_cand_totul_ok(client):
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
# Glifa accesibila ✓ (nu doar culoare)
|
||||
assert "✓" in html, f"Lipseste glifa ✓ cand totul e ok. HTML: {html[:600]}"
|
||||
# US-003 D6: strip unificat (nu bife individuale worker/RAR)
|
||||
assert "curg normal" in html.lower(), (
|
||||
f"Textul 'curg normal' din strip sanatate lipseste. HTML: {html[:600]}"
|
||||
)
|
||||
# US-003: elementul strip-sanatate e prezent in DOM dar ascuns cand totul e ok
|
||||
assert 'id="strip-sanatate"' in html, f"id=strip-sanatate lipseste complet din fragment. HTML: {html[:600]}"
|
||||
# Cand OK, banda nu trebuie sa afiseze ✗ (eroare) — ✓ nu mai apare (banda e ascunsa)
|
||||
assert "✗" not in html, \
|
||||
f"Glifa ✗ (eroare) apare cand starea e ok — banda e gresit afisata. HTML: {html[:600]}"
|
||||
|
||||
|
||||
def test_status_are_bife_rosii_cand_worker_oprit(client):
|
||||
@@ -183,7 +185,8 @@ def test_strip_rosu_worker_oprit(client):
|
||||
|
||||
|
||||
def test_trei_contoare_card(client):
|
||||
"""US-003: fragment status contine exact 3 carduri .contor-card (In coada / Trimise / De corectat)."""
|
||||
"""US-002 PRD 5.16: fragment status contine 5 carduri .contor-card separate:
|
||||
Total / Luna asta / Azi / In coada / De corectat."""
|
||||
_create_account_user("treicont@test.com")
|
||||
_login(client, "treicont@test.com", "parolasecreta10")
|
||||
|
||||
@@ -192,12 +195,15 @@ def test_trei_contoare_card(client):
|
||||
html = resp.text
|
||||
|
||||
count = html.count("contor-card")
|
||||
assert count >= 3, (
|
||||
f"Trebuie minim 3 elemente contor-card in fragment, gasit: {count}. HTML: {html[:800]}"
|
||||
assert count >= 5, (
|
||||
f"Trebuie minim 5 elemente contor-card (US-002 PRD 5.16: Total/Luna/Azi/Coada/Corectat), "
|
||||
f"gasit: {count}. HTML: {html[:800]}"
|
||||
)
|
||||
# Etichete asteptate
|
||||
# Etichete asteptate (US-002 PRD 5.16: 5 carduri separate)
|
||||
assert "Total" in html, "Eticheta 'Total' lipseste din contoare (US-002 PRD 5.16)."
|
||||
assert "Luna asta" in html, "Eticheta 'Luna asta' lipseste din contoare (US-002 PRD 5.16)."
|
||||
assert "Azi" in html, "Eticheta 'Azi' lipseste din contoare (US-002 PRD 5.16)."
|
||||
assert "In coada" in html, "Eticheta 'In coada' lipseste din contoare."
|
||||
assert "Trimise" in html, "Eticheta 'Trimise' lipseste din contoare."
|
||||
assert "De corectat" in html, "Eticheta 'De corectat' lipseste din contoare."
|
||||
|
||||
|
||||
@@ -250,6 +256,98 @@ def test_fara_bara_veche(client):
|
||||
)
|
||||
|
||||
|
||||
def test_banda_apare_doar_cand_blocat(client):
|
||||
"""US-003 (PRD 5.16): banda rosie completa apare NUMAI cand BLOCAT.
|
||||
Cand totul e ok, strip-sanatate are atributul 'hidden' (ascuns, nu disparut).
|
||||
Cand worker e oprit, strip-sanatate NU are 'hidden' (e vizibil, rosu).
|
||||
"""
|
||||
_create_account_user("bandablocat@test.com")
|
||||
_login(client, "bandablocat@test.com", "parolasecreta10")
|
||||
|
||||
# Stare OK: strip ascuns
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
_set_heartbeat(last_beat=now, last_rar_login_ok=now)
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html_ok = resp.text
|
||||
# Cand OK, elementul e ascuns
|
||||
assert 'id="strip-sanatate"' in html_ok, "strip-sanatate lipseste din DOM cand totul e ok"
|
||||
assert "✗" not in html_ok, "Glifa eroare apare cand sanatate=ok (banda nu trebuie sa fie rosie)"
|
||||
|
||||
# Stare BLOCAT: strip vizibil cu glifa ✗
|
||||
_set_heartbeat(last_beat=None, last_rar_login_ok=None)
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html_err = resp.text
|
||||
assert 'id="strip-sanatate"' in html_err, "strip-sanatate lipseste din DOM cand blocat"
|
||||
assert "✗" in html_err, "Glifa ✗ lipseste cand BLOCAT (banda trebuie sa fie rosie)"
|
||||
|
||||
|
||||
def test_rar_dot_in_antet_ok(client):
|
||||
"""US-003 (PRD 5.16): cand logat si sanatate_ok, antetul contine chip-ul RAR cu clasa rar-ok.
|
||||
Starea ok se vede din header (dot verde pulsant), nu din banda de stare (care e ascunsa).
|
||||
"""
|
||||
_create_account_user("rardot@test.com")
|
||||
_login(client, "rardot@test.com", "parolasecreta10")
|
||||
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
_set_heartbeat(last_beat=now, last_rar_login_ok=now)
|
||||
|
||||
resp = client.get("/", follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
# Chip RAR in antet (nu in banda de stare)
|
||||
assert "rar-chip" in html, "Clasa rar-chip lipseste din HTML (dot RAR in antet, US-003)"
|
||||
assert "rar-ok" in html, "Clasa rar-ok lipseste — dot verde cand sanatate ok (US-003)"
|
||||
assert "rar-dot" in html, "Clasa rar-dot lipseste din chip (US-003)"
|
||||
|
||||
|
||||
def test_rar_in_meniu_burger(client):
|
||||
"""US-003/010 (PRD 5.16): meniul burger contine starea RAR ca prima intrare (RAR online / RAR indisponibil)."""
|
||||
_create_account_user("rarmeniu@test.com")
|
||||
_login(client, "rarmeniu@test.com", "parolasecreta10")
|
||||
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
_set_heartbeat(last_beat=now, last_rar_login_ok=now)
|
||||
|
||||
resp = client.get("/", follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
# Meniul burger (cont-menu) contine indicatorul RAR
|
||||
assert "cont-menu" in html, "Meniu burger (cont-menu) lipseste din HTML"
|
||||
assert "RAR online" in html or "RAR indisponibil" in html, \
|
||||
"Starea RAR nu apare in meniu burger (US-003/010)"
|
||||
# Prima intrare e starea RAR — prezenta class menu-rar-line
|
||||
assert "menu-rar-line" in html, "Clasa menu-rar-line lipseste din burger (US-003)"
|
||||
|
||||
|
||||
def test_anuleaza_are_data_modal_close(client):
|
||||
"""US-007 (PRD 5.16): overlay-ul modal si butonul de inchidere au atributul data-modal-close."""
|
||||
# Butonul si overlay-ul trebuie sa aiba data-modal-close pentru ca handler-ul cu .closest() sa functioneze
|
||||
# Verificam in baza template-ului base.html (modal e definit acolo, randat pe toate paginile)
|
||||
# Testam pe dashboard dupa login (unde baza e incarcata)
|
||||
_create_account_user("modalclose@test.com")
|
||||
_login(client, "modalclose@test.com", "parolasecreta10")
|
||||
resp = client.get("/", follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
assert "data-modal-close" in html, \
|
||||
"data-modal-close lipseste din template — modalul nu se poate inchide (US-007)"
|
||||
|
||||
|
||||
def test_modal_close_pe_element_interior(client):
|
||||
"""US-007 (PRD 5.16): handler-ul modal foloseste .closest('[data-modal-close]') nu
|
||||
.hasAttribute directe — astfel click pe un element interior al backdrop-ului functioneaza."""
|
||||
_create_account_user("modalclosest@test.com")
|
||||
_login(client, "modalclosest@test.com", "parolasecreta10")
|
||||
resp = client.get("/", follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
# Verificam ca JS-ul foloseste closest, nu hasAttribute
|
||||
assert "closest('[data-modal-close]')" in html, \
|
||||
"Handler-ul modal foloseste hasAttribute in loc de closest (US-007) — click pe copil nu va inchide modalul"
|
||||
|
||||
|
||||
def _set_tz_bucuresti(monkeypatch, request):
|
||||
"""Forteaza TZ=Europe/Bucharest pentru ca modificatorul SQLite 'localtime' sa
|
||||
rezolve la fusul RO indiferent de TZ-ul runner-ului (CI ruleaza de regula in UTC).
|
||||
@@ -359,3 +457,227 @@ def test_iarna_nu_bleed_in_ziua_urmatoare(monkeypatch, request):
|
||||
finally:
|
||||
conn.close()
|
||||
get_settings.cache_clear()
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# US-006 (PRD 5.17) — Afisaj plan curent: trial / consum / warn / banner
|
||||
# ===========================================================================
|
||||
|
||||
def _set_trial_until(account_id: int, trial_until_str: str | None) -> None:
|
||||
"""Seteaza direct trial_until pentru un cont (helper de test)."""
|
||||
from app.db import get_connection
|
||||
conn = get_connection()
|
||||
try:
|
||||
conn.execute(
|
||||
"UPDATE accounts SET trial_until=? WHERE id=?",
|
||||
(trial_until_str, account_id),
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def _insert_submissions_sent(account_id: int, n: int) -> None:
|
||||
"""Insereaza N submissions sent in luna curenta (helper de test)."""
|
||||
from app.db import get_connection
|
||||
import json as _json
|
||||
conn = get_connection()
|
||||
try:
|
||||
for i in range(n):
|
||||
conn.execute(
|
||||
"INSERT INTO submissions (account_id, status, payload_json, idempotency_key, created_at) "
|
||||
"VALUES (?, 'sent', ?, ?, datetime('now'))",
|
||||
(account_id, _json.dumps({"vin": f"VIN{i:013d}"}), f"key-plan-{account_id}-{i}"),
|
||||
)
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_afisaj_plan_si_zile_trial(client):
|
||||
"""US-006: cont in trial Pro -> fragment status arata 'trial N zile ramase'.
|
||||
Contul nou primeste trial_until=now+30z automat la creare.
|
||||
"""
|
||||
acct_id, _ = _create_account_user("trialzile@test.com")
|
||||
_login(client, "trialzile@test.com", "parolasecreta10")
|
||||
|
||||
# trial_until = now + 18 zile + 12h (buffer pt a evita delta.days=17 din timing test)
|
||||
future = (datetime.now(timezone.utc) + timedelta(days=18, hours=12)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
_set_trial_until(acct_id, future)
|
||||
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "Plan: Pro" in html, f"Textul 'Plan: Pro' lipseste in trial. HTML: {html[:800]}"
|
||||
assert "trial" in html.lower(), f"Cuvantul 'trial' lipseste in starea de trial. HTML: {html[:800]}"
|
||||
assert "18" in html, f"Numarul de zile (18) nu apare in afisaj. HTML: {html[:800]}"
|
||||
assert "zile" in html, f"Cuvantul 'zile' lipseste (pluralizare). HTML: {html[:800]}"
|
||||
|
||||
|
||||
def test_afisaj_consum_lunar(client):
|
||||
"""US-006: cont free (fara trial) -> fragment status arata 'Gratuit · N/60 luna asta'."""
|
||||
acct_id, _ = _create_account_user("consumlun@test.com")
|
||||
_login(client, "consumlun@test.com", "parolasecreta10")
|
||||
|
||||
# Dezactiveaza trial-ul (cont free pur)
|
||||
_set_trial_until(acct_id, None)
|
||||
# Insereaza 5 submissions sent luna asta
|
||||
_insert_submissions_sent(acct_id, 5)
|
||||
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "Gratuit" in html, f"'Gratuit' lipseste din afisajul de consum. HTML: {html[:800]}"
|
||||
assert "5" in html, f"Contorul de consum (5) nu apare. HTML: {html[:800]}"
|
||||
assert "60" in html, f"Limita (60) nu apare in afisajul de consum. HTML: {html[:800]}"
|
||||
assert "luna asta" in html, f"'luna asta' lipseste din afisajul de consum. HTML: {html[:800]}"
|
||||
|
||||
|
||||
def test_avertizare_aproape_de_limita(client):
|
||||
"""US-006: >=80% din 60 -> avertizare cu text 'aproape de limita' + culoare warn."""
|
||||
acct_id, _ = _create_account_user("aproapelim@test.com")
|
||||
_login(client, "aproapelim@test.com", "parolasecreta10")
|
||||
|
||||
_set_trial_until(acct_id, None)
|
||||
# 50/60 = 83% -> warn
|
||||
_insert_submissions_sent(acct_id, 50)
|
||||
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "aproape de limita" in html, (
|
||||
f"Textul 'aproape de limita' lipseste la 50/60. HTML: {html[:800]}"
|
||||
)
|
||||
assert "50" in html, f"Contorul 50 nu apare. HTML: {html[:800]}"
|
||||
# Warn = culoare (var(--warn) in inline style)
|
||||
assert "var(--warn)" in html or "plan-warn" in html, (
|
||||
f"Stilul de warn (var(--warn) sau clasa plan-warn) lipseste la aproape-de-limita. HTML: {html[:800]}"
|
||||
)
|
||||
|
||||
|
||||
def test_limita_atinsa(client):
|
||||
"""US-006: 60/60 -> text 'limita atinsa'."""
|
||||
acct_id, _ = _create_account_user("limitaatinsa@test.com")
|
||||
_login(client, "limitaatinsa@test.com", "parolasecreta10")
|
||||
|
||||
_set_trial_until(acct_id, None)
|
||||
_insert_submissions_sent(acct_id, 60)
|
||||
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "limita atinsa" in html, (
|
||||
f"Textul 'limita atinsa' lipseste la 60/60. HTML: {html[:800]}"
|
||||
)
|
||||
|
||||
|
||||
def test_copy_pluralizare_zi_zile(client):
|
||||
"""US-006: pluralizare RO corecta — 1 zi (nu '1 zile'), 18 zile (nu '18 zi')."""
|
||||
acct_id, _ = _create_account_user("pluralzile@test.com")
|
||||
_login(client, "pluralzile@test.com", "parolasecreta10")
|
||||
|
||||
# 18 zile: trebuie "18 zile ramase" (buffer 12h pt delta.days determinist)
|
||||
future_18 = (datetime.now(timezone.utc) + timedelta(days=18, hours=12)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
_set_trial_until(acct_id, future_18)
|
||||
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
assert "18 zile" in html, f"'18 zile' lipseste. HTML: {html[:800]}"
|
||||
assert "18 zi " not in html and "18 zi<" not in html, (
|
||||
f"'18 zi' (plural gresit) apare in loc de '18 zile'. HTML: {html[:800]}"
|
||||
)
|
||||
|
||||
# 1 zi: trebuie "1 zi ramasa" (singular); buffer 12h
|
||||
future_1 = (datetime.now(timezone.utc) + timedelta(days=1, hours=12)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
_set_trial_until(acct_id, future_1)
|
||||
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
assert "1 zi" in html, f"'1 zi' (singular) lipseste la o zi ramasa. HTML: {html[:800]}"
|
||||
assert "1 zile" not in html, (
|
||||
f"'1 zile' (plural gresit) apare in loc de '1 zi'. HTML: {html[:800]}"
|
||||
)
|
||||
|
||||
|
||||
def test_banner_one_time_trial_expirat(client):
|
||||
"""US-006 T-DES-1: dupa expirarea trial-ului, banner 'Trial Pro expirat' apare in _status.html."""
|
||||
acct_id, _ = _create_account_user("trialexp@test.com")
|
||||
_login(client, "trialexp@test.com", "parolasecreta10")
|
||||
|
||||
# trial_until in trecut -> trial expirat -> banner one-time
|
||||
past = (datetime.now(timezone.utc) - timedelta(days=2)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
_set_trial_until(acct_id, past)
|
||||
|
||||
resp = client.get("/_fragments/status")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "Trial Pro expirat" in html, (
|
||||
f"Banner 'Trial Pro expirat' lipseste dupa expirarea trial-ului. HTML: {html[:800]}"
|
||||
)
|
||||
assert "Gratuit" in html, (
|
||||
f"Dupa expirarea trial-ului, planul trebuie sa afiseze 'Gratuit'. HTML: {html[:800]}"
|
||||
)
|
||||
# Bannerul are buton de dismiss
|
||||
assert "banner-trial-expirat" in html, (
|
||||
f"Elementul id=banner-trial-expirat lipseste. HTML: {html[:800]}"
|
||||
)
|
||||
|
||||
|
||||
def test_cont_arata_plan(client):
|
||||
"""US-006: tab-ul Cont (/tab=cont) afiseaza planul curent si explicatia de upgrade."""
|
||||
acct_id, _ = _create_account_user("contplan@test.com")
|
||||
_login(client, "contplan@test.com", "parolasecreta10")
|
||||
|
||||
_set_trial_until(acct_id, None) # free fara trial
|
||||
|
||||
resp = client.get("/?tab=cont", follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "Plan curent" in html or "sectiune-plan" in html, (
|
||||
f"Sectiunea 'Plan curent' lipseste din tab-ul Cont. HTML: {html[:1000]}"
|
||||
)
|
||||
assert "Gratuit" in html, f"'Gratuit' lipseste din planul afisat in Cont. HTML: {html[:1000]}"
|
||||
assert "Standard" in html or "Pro" in html, (
|
||||
f"Optiunile de upgrade (Standard/Pro) lipsesc din sectiunea Plan. HTML: {html[:1000]}"
|
||||
)
|
||||
|
||||
|
||||
def test_plan_linie_in_burger(client):
|
||||
"""US-006: meniul burger contine linia de plan (Plan: Gratuit / Pro · trial N zile)."""
|
||||
acct_id, _ = _create_account_user("burgerplan@test.com")
|
||||
_login(client, "burgerplan@test.com", "parolasecreta10")
|
||||
|
||||
_set_trial_until(acct_id, None) # free fara trial
|
||||
|
||||
resp = client.get("/", follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
# Meniul burger trebuie sa contina linia de plan
|
||||
assert "Plan: Gratuit" in html, (
|
||||
f"'Plan: Gratuit' lipseste din meniu burger. HTML (fragment): {html[html.find('cont-menu'):html.find('cont-menu')+500] if 'cont-menu' in html else html[:500]}"
|
||||
)
|
||||
|
||||
|
||||
def test_trial_pro_arata_zile_in_burger(client):
|
||||
"""US-006: cont in trial -> burger arata 'Plan: Pro · trial N zile ramase'."""
|
||||
acct_id, _ = _create_account_user("burgertrial@test.com")
|
||||
_login(client, "burgertrial@test.com", "parolasecreta10")
|
||||
|
||||
future = (datetime.now(timezone.utc) + timedelta(days=10)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
_set_trial_until(acct_id, future)
|
||||
|
||||
resp = client.get("/", follow_redirects=True)
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "Plan: Pro" in html, f"'Plan: Pro' lipseste din burger in trial. HTML: {html[:800]}"
|
||||
assert "trial" in html.lower(), f"'trial' lipseste din linia de plan din burger. HTML: {html[:800]}"
|
||||
|
||||
Reference in New Issue
Block a user