import hashlib import time from datetime import datetime, timedelta, timezone from tests.conftest import BASE_URL from devplacepy.database import get_table from devplacepy.utils import hash_password, generate_uid def test_forgot_password_page_loads(page, app_server): page.goto(f"{BASE_URL}/auth/forgot-password", wait_until="domcontentloaded") assert page.is_visible("input#email") assert page.is_visible("button:has-text('Send Reset Link')") def test_forgot_password_submit_shows_sent(page, app_server): page.goto(f"{BASE_URL}/auth/forgot-password", wait_until="domcontentloaded") page.fill("#email", "anybody@example.com") page.click("button:has-text('Send Reset Link')") page.locator(".auth-success").wait_for(state="visible") def test_reset_password_page_loads(page, app_server): page.goto(f"{BASE_URL}/auth/reset-password/sometoken", wait_until="domcontentloaded") assert page.is_visible("input#password") assert page.is_visible("input#confirm_password") def test_reset_password_mismatch_shows_error(page, app_server): page.goto(f"{BASE_URL}/auth/reset-password/sometoken", wait_until="domcontentloaded") page.fill("#password", "abcdef1") page.fill("#confirm_password", "different1") page.click("button:has-text('Reset Password')") page.locator(".auth-error").wait_for(state="visible") def test_reset_password_full_flow(page, app_server): uname = f"reset_{int(time.time() * 1000)}" email = f"{uname}@t.dev" uid = generate_uid() get_table("users").insert({ "uid": uid, "username": uname, "email": email, "password_hash": hash_password("oldpass123"), "bio": "", "location": "", "git_link": "", "website": "", "role": "Member", "is_active": True, "level": 1, "xp": 0, "stars": 0, "created_at": datetime.now(timezone.utc).isoformat(), }) token = f"tok{uid[:8]}" get_table("password_resets").insert({ "uid": generate_uid(), "user_uid": uid, "token": hashlib.sha256(token.encode()).hexdigest(), "expires_at": (datetime.now(timezone.utc) + timedelta(hours=1)).isoformat(), "used": False, "created_at": datetime.now(timezone.utc).isoformat(), }) page.goto(f"{BASE_URL}/auth/reset-password/{token}", wait_until="domcontentloaded") page.fill("#password", "newpass456") page.fill("#confirm_password", "newpass456") page.click("button:has-text('Reset Password')") page.wait_for_url("**/auth/login", wait_until="domcontentloaded") page.fill("#email", email) page.fill("#password", "newpass456") page.click("button:has-text('Sign in')") page.wait_for_url("**/feed", wait_until="domcontentloaded") assert "/feed" in page.url def test_signup_page_loads(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") assert page.is_visible("h2:has-text('Join the Community')") assert page.is_visible("#username") assert page.is_visible("#email") assert page.is_visible("#password") assert page.is_visible("#confirm_password") def test_signup_success(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "fresh_user") page.fill("#email", "fresh@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") assert page.is_visible("text=fresh_user") def test_signup_existing_username(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "dup_user") page.fill("#email", "dup1@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") page.context.clear_cookies() page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "dup_user") page.fill("#email", "dup2@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_timeout(300) assert page.is_visible("text=Username already taken") def test_signup_existing_email(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "email_dup1") page.fill("#email", "sameemail@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") page.context.clear_cookies() page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "email_dup2") page.fill("#email", "sameemail@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_timeout(300) assert page.is_visible("text=Email already registered") def test_signup_password_mismatch(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "mismatch_user") page.fill("#email", "mismatch@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "different456") page.click("button:has-text('Create account')") page.wait_for_timeout(300) assert page.is_visible("text=Passwords do not match") def test_signup_short_password(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "shortpw_user") page.fill("#email", "shortpw@test.devplace") page.fill("#password", "ab") page.fill("#confirm_password", "ab") page.click("button:has-text('Create account')") page.wait_for_timeout(300) assert page.is_visible("text=Password must be at least 6 characters") def test_signup_invalid_username(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "ab") page.fill("#email", "shortname@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_timeout(300) assert page.is_visible("text=Username must be between 3 and 32 characters") def test_login_page_loads(page, app_server): page.goto(f"{BASE_URL}/auth/login", wait_until="domcontentloaded") assert page.is_visible("h2:has-text('Welcome Back')") assert page.is_visible("#email") assert page.is_visible("#password") assert page.is_visible("button:has-text('Sign in')") def test_login_success(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "login_user") page.fill("#email", "login@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") page.goto(f"{BASE_URL}/auth/logout", wait_until="domcontentloaded") page.goto(f"{BASE_URL}/auth/login", wait_until="domcontentloaded") page.fill("#email", "login@test.devplace") page.fill("#password", "secret123") page.click("button:has-text('Sign in')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") assert page.is_visible("text=login_user") def test_login_wrong_password(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "wrongpw_user") page.fill("#email", "wrongpw@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") page.goto(f"{BASE_URL}/auth/logout", wait_until="domcontentloaded") page.goto(f"{BASE_URL}/auth/login", wait_until="domcontentloaded") page.fill("#email", "wrongpw@test.devplace") page.fill("#password", "badpassword") page.click("button:has-text('Sign in')") page.wait_for_timeout(300) assert page.is_visible("text=Invalid email or password") def test_login_nonexistent_email(page, app_server): page.goto(f"{BASE_URL}/auth/login", wait_until="domcontentloaded") page.fill("#email", "nobody@nowhere.devplace") page.fill("#password", "secret123") page.click("button:has-text('Sign in')") page.wait_for_timeout(300) assert page.is_visible("text=Invalid email or password") def test_login_remember_me(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "remember_user") page.fill("#email", "remember@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") page.goto(f"{BASE_URL}/auth/logout", wait_until="domcontentloaded") page.goto(f"{BASE_URL}/auth/login", wait_until="domcontentloaded") page.fill("#email", "remember@test.devplace") page.fill("#password", "secret123") page.check("input[name='remember_me']") page.click("button:has-text('Sign in')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") assert page.is_visible("text=remember_user") def test_logout(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.fill("#username", "logout_user") page.fill("#email", "logout@test.devplace") page.fill("#password", "secret123") page.fill("#confirm_password", "secret123") page.click("button:has-text('Create account')") page.wait_for_url("**/feed", timeout=10000, wait_until="domcontentloaded") page.goto(f"{BASE_URL}/auth/logout", wait_until="domcontentloaded") page.wait_for_url("**/", wait_until="domcontentloaded") assert page.is_visible("text=Join DevPlace Free") def test_signup_link_from_login(page, app_server): page.goto(f"{BASE_URL}/auth/login", wait_until="domcontentloaded") page.click("a:has-text('Create new account')") page.wait_for_url("**/auth/signup", wait_until="domcontentloaded") def test_login_link_from_signup(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") page.click("a:has-text('Sign in instead')") page.wait_for_url("**/auth/login", wait_until="domcontentloaded") def test_password_toggle(page, app_server): page.goto(f"{BASE_URL}/auth/signup", wait_until="domcontentloaded") pw_input = page.locator("#password") toggle = page.locator(".auth-toggle-pw").first assert pw_input.get_attribute("type") == "password" toggle.click() assert pw_input.get_attribute("type") == "text" toggle.click() assert pw_input.get_attribute("type") == "password"