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"