belépés jó, rgisztráción kicsit faragni kell még

This commit is contained in:
Roo
2026-06-05 14:45:02 +00:00
parent f03b5f3916
commit b84b1bab41
7 changed files with 570 additions and 42 deletions

View File

@@ -0,0 +1,253 @@
#!/usr/bin/env python3
"""
Playwright E2E Test: Profile Address Persistence (Stairwell / Floor / Door)
This test:
1. Logs in as the configured test user (via LoginModal on the landing page).
2. Navigates to the Profile page (/profile).
3. Enters edit mode, fills every address field (city, zip, street, house number,
stairwell, floor, door), and saves.
4. Reloads the page and verifies that the stairwell, floor, and door values
persisted after the page refresh.
Requirements:
- playwright (Python) + dotenv
- .env.test file at the project root with TEST_USER_EMAIL and TEST_USER_PASS
Usage:
python tests/active/e2e_profile_address.py
To see the browser visually, change HEADLESS=False below.
"""
import os
import sys
import re
from pathlib import Path
from dotenv import load_dotenv
from playwright.sync_api import sync_playwright, TimeoutError as PwTimeout
# ── Configuration ──────────────────────────────────────────────────────────
BASE_URL = "https://app.servicefinder.hu"
HEADLESS = True # Set to False for visual debugging
SLOW_MO = 0 # ms delay between actions (useful for debugging)
ACTION_TIMEOUT = 15_000 # ms default timeout for element lookups
# ── Load .env.test from project root ──────────────────────────────────────
ENV_PATH = Path(__file__).resolve().parents[1] / ".env.test"
if not ENV_PATH.exists():
raise FileNotFoundError(
f".env.test not found at {ENV_PATH}. "
"Create it with TEST_USER_EMAIL and TEST_USER_PASS."
)
load_dotenv(dotenv_path=ENV_PATH, override=True)
TEST_EMAIL = os.getenv("TEST_USER_EMAIL")
TEST_PASS = os.getenv("TEST_USER_PASS")
if not TEST_EMAIL or not TEST_PASS:
raise ValueError(
"TEST_USER_EMAIL and/or TEST_USER_PASS are missing from .env.test. "
f"Loaded from: {ENV_PATH}"
)
# ── Test data ──────────────────────────────────────────────────────────────
ADDRESS_DATA = {
"address_city": "Dunakeszi",
"address_zip": "2120",
"address_street_name": "Határ",
"address_street_type": "utca",
"address_house_number": "8",
"address_stairwell": "A",
"address_floor": "3",
"address_door": "5",
}
# ═══════════════════════════════════════════════════════════════════════════
# Helper functions
# ═══════════════════════════════════════════════════════════════════════════
def log(msg: str) -> None:
"""Simple stdout logger."""
print(f"[E2E] {msg}")
def fill_input(page, placeholder: str, value: str) -> None:
"""Locate an <input> by its placeholder and fill it."""
locator = page.locator(f'input[placeholder="{placeholder}"]')
locator.wait_for(state="visible", timeout=ACTION_TIMEOUT)
locator.fill(value)
log(f" Filled '{placeholder}' → '{value}'")
# ═══════════════════════════════════════════════════════════════════════════
# Main test flow
# ═══════════════════════════════════════════════════════════════════════════
def main() -> None:
with sync_playwright() as pw:
# ── 1. Launch browser (local or remote via BROWSERLESS_URL) ──
browserless_url = os.getenv("BROWSERLESS_URL")
if browserless_url:
# Connect to a remote Browserless / Chrome container
browser = pw.chromium.connect_over_cdp(browserless_url)
log(f"Connected to remote browser at {browserless_url}")
else:
# Local fallback
browser = pw.chromium.launch(
headless=os.getenv("HEADLESS", "True").lower() == "true",
slow_mo=SLOW_MO,
)
log(f"Browser launched locally (headless={os.getenv('HEADLESS', 'True')})")
context = browser.new_context(
viewport={"width": 1280, "height": 800},
locale="hu-HU",
)
page = context.new_page()
log(f"Browser launched (headless={HEADLESS})")
# ── 2. Open landing page & login ─────────────────────────────
log("Navigating to landing page …")
page.goto(BASE_URL, wait_until="networkidle", timeout=30_000)
# Click the "Garázs Nyitása" button to open the LoginModal
login_trigger = page.locator("button:has-text('Garázs Nyitása')")
login_trigger.wait_for(state="visible", timeout=ACTION_TIMEOUT)
login_trigger.click()
log("Login modal opened")
# Fill email & password
page.fill("#login-email", TEST_EMAIL)
page.fill("#login-password", TEST_PASS)
log("Login credentials entered")
# Click the submit button (the first .btn-premium inside the visible form)
submit_btn = page.locator("form button[type='submit']").first
submit_btn.wait_for(state="visible", timeout=ACTION_TIMEOUT)
submit_btn.click()
log("Login submitted waiting for navigation …")
# Wait for redirect away from landing page (to /dashboard or /complete-kyc)
try:
page.wait_for_url(
lambda url: "/dashboard" in url or "/complete-kyc" in url,
timeout=15_000,
)
except PwTimeout:
# If still on landing, maybe login failed dump state
log(f"URL after login attempt: {page.url}")
page.screenshot(path="/tmp/e2e_login_fail.png")
raise AssertionError(
"Login failed did not redirect to dashboard. "
"Check credentials or UI state."
)
log(f"Login successful current URL: {page.url}")
# ── 3. Navigate to Profile page ──────────────────────────────
log("Navigating to /profile …")
page.goto(f"{BASE_URL}/profile", wait_until="networkidle", timeout=20_000)
# Wait for the profile page to finish loading (spinner disappears)
page.wait_for_selector("text=Profil beállítások", timeout=ACTION_TIMEOUT)
# Also wait until the loading spinner is gone
page.wait_for_function(
"() => !document.querySelector('.animate-spin')",
timeout=15_000,
)
log("Profile page loaded")
# ── 4. Enter edit mode ───────────────────────────────────────
edit_btn = page.locator("button:has-text('Szerkesztés')")
edit_btn.wait_for(state="visible", timeout=ACTION_TIMEOUT)
edit_btn.click()
log("Edit mode activated")
# ── 5. Fill in all address fields ────────────────────────────
log("Filling address form …")
fill_input(page, "Irányítószám", ADDRESS_DATA["address_zip"])
fill_input(page, "Város", ADDRESS_DATA["address_city"])
fill_input(page, "Utca", ADDRESS_DATA["address_street_name"])
fill_input(page, "Közterület jellege", ADDRESS_DATA["address_street_type"])
fill_input(page, "Házszám", ADDRESS_DATA["address_house_number"])
fill_input(page, "Lépcsőház", ADDRESS_DATA["address_stairwell"])
fill_input(page, "Emelet", ADDRESS_DATA["address_floor"])
fill_input(page, "Ajtó", ADDRESS_DATA["address_door"])
# ── 6. Save ──────────────────────────────────────────────────
save_btn = page.locator("button:has-text('Mentés')")
save_btn.wait_for(state="visible", timeout=ACTION_TIMEOUT)
save_btn.click()
log("Save clicked waiting for confirmation …")
# Wait for the success message to appear
success_locator = page.locator("text=A profil adatok és okmányok sikeresen frissítve!")
try:
success_locator.wait_for(state="visible", timeout=10_000)
log("Save succeeded success message visible")
except PwTimeout:
# Check for error message
error_locator = page.locator(".text-red-400")
if error_locator.is_visible():
error_text = error_locator.text_content()
log(f"Save FAILED with error: {error_text}")
page.screenshot(path="/tmp/e2e_save_fail.png")
raise AssertionError(f"Save failed: {error_text}")
page.screenshot(path="/tmp/e2e_save_timeout.png")
raise AssertionError(
"Save timeout neither success nor error message appeared."
)
# ── 7. Reload and verify persistence ─────────────────────────
log("Reloading page to verify persistence …")
page.reload(wait_until="networkidle")
page.wait_for_selector("text=Profil beállítások", timeout=ACTION_TIMEOUT)
page.wait_for_function(
"() => !document.querySelector('.animate-spin')",
timeout=15_000,
)
log("Page reloaded")
# Read the display text in the read-only address section
# The read-only view shows: Lépcsőház: …, Emelet: …, Ajtó: …
page_body = page.locator("body").inner_text()
log("── Read-only address block ──")
# Use a regex to extract values
stairwell_match = re.search(r"Lépcsőház:\s*(\S+)", page_body)
floor_match = re.search(r"Emelet:\s*(\S+)", page_body)
door_match = re.search(r"Ajtó:\s*(\S+)", page_body)
stairwell_val = stairwell_match.group(1) if stairwell_match else ""
floor_val = floor_match.group(1) if floor_match else ""
door_val = door_match.group(1) if door_match else ""
log(f" Stairwell (Lépcsőház): '{stairwell_val}'")
log(f" Floor (Emelet): '{floor_val}'")
log(f" Door (Ajtó): '{door_val}'")
# ── 8. Assertion: all three values must be present ───────────
errors = []
if not stairwell_val or stairwell_val in ("—", "null", "None"):
errors.append(f"stairwell (expected '{ADDRESS_DATA['address_stairwell']}', got '{stairwell_val}')")
if not floor_val or floor_val in ("—", "null", "None"):
errors.append(f"floor (expected '{ADDRESS_DATA['address_floor']}', got '{floor_val}')")
if not door_val or door_val in ("—", "null", "None"):
errors.append(f"door (expected '{ADDRESS_DATA['address_door']}', got '{door_val}')")
if errors:
page.screenshot(path="/tmp/e2e_persistence_fail.png")
raise AssertionError(
"Hibás backend mentés! Az emelet/ajtó adatok elvesztek az oldal "
f"frissítése után.\n Missing/empty fields: {', '.join(errors)}"
)
log("Sikeres E2E teszt: Az adatok megmaradtak a backend frissítés után is!")
log("ALL CHECKS PASSED.\n")