porchlight/tests/e2e/setup_db.py
Johan Lundberg 2dfa3f3bff
test: add profile validation e2e tests and fix pre-existing failures
Add 7 new e2e tests verifying profile form validation in both manage
and admin UIs: invalid phone number, phone normalization, E.164 hint
attributes, and admin-side email/phone/picture URL validation errors.

Fix 3 pre-existing test failures:
- Replace invalid seeded phone number (+1234567890) with valid E.164
  (+12025551234) that was causing profile update tests to fail
- Update email validation error assertion to match actual pydantic
  message (value_error type uses raw message, not label-prefixed)
2026-03-16 10:00:46 +01:00

130 lines
4.8 KiB
Python

#!/usr/bin/env python3
"""Seed the e2e test database with test fixtures.
Outputs JSON with the created test data (magic link tokens, usernames, etc.)
so the JS tests can use them.
Requires OIDC_OP_SQLITE_PATH env var pointing to the app's SQLite DB.
"""
import asyncio
import json
import os
import sys
import aiosqlite
from porchlight.authn.password import PasswordService
from porchlight.invite.service import MagicLinkService
from porchlight.models import PasswordCredential, User
from porchlight.store.sqlite.repositories import (
SQLiteCredentialRepository,
SQLiteMagicLinkRepository,
SQLiteUserRepository,
)
async def seed() -> None:
db_path = os.environ.get("OIDC_OP_SQLITE_PATH")
if not db_path:
print("OIDC_OP_SQLITE_PATH not set", file=sys.stderr)
sys.exit(1)
db = await aiosqlite.connect(db_path)
db.row_factory = aiosqlite.Row
user_repo = SQLiteUserRepository(db)
cred_repo = SQLiteCredentialRepository(db)
magic_link_repo = SQLiteMagicLinkRepository(db)
password_service = PasswordService()
magic_link_service = MagicLinkService(repo=magic_link_repo)
result = {}
# 1. Create a magic link for registration test
link = await magic_link_service.create(username="newuser")
result["register_token"] = link.token
result["register_username"] = "newuser"
# 2. Create a user with a password for login test
user = User(userid="test-user-01", username="testuser", groups=["users"])
await user_repo.create(user)
password_hash = password_service.hash("testpassword123")
await cred_repo.create_password(PasswordCredential(user_id=user.userid, password_hash=password_hash))
result["login_username"] = "testuser"
result["login_password"] = "testpassword123"
# 3. Create a separate user for credentials management test
cred_user = User(userid="test-user-02", username="creduser", groups=["users"])
await user_repo.create(cred_user)
cred_password_hash = password_service.hash("credpassword123")
await cred_repo.create_password(PasswordCredential(user_id=cred_user.userid, password_hash=cred_password_hash))
result["cred_username"] = "creduser"
result["cred_password"] = "credpassword123"
# 5. Create a user with password for WebAuthn registration tests
# (login with password first, then register a passkey)
webauthn_user = User(userid="test-user-03", username="webauthnuser", groups=["users"])
await user_repo.create(webauthn_user)
webauthn_password_hash = password_service.hash("webauthnpass123")
await cred_repo.create_password(
PasswordCredential(user_id=webauthn_user.userid, password_hash=webauthn_password_hash)
)
result["webauthn_username"] = "webauthnuser"
result["webauthn_password"] = "webauthnpass123"
result["webauthn_userid"] = "test-user-03"
# 4. Create an expired/used magic link for negative test
expired_link = await magic_link_service.create(username="expired")
await magic_link_service.mark_used(expired_link.token)
result["used_token"] = expired_link.token
# 5. Create a user with profile data for profile management tests
profile_user = User(
userid="test-user-04",
username="profileuser",
given_name="Alice",
family_name="Smith",
preferred_username="asmith",
email="alice@example.com",
phone_number="+12025551234",
picture="https://example.com/alice.jpg",
locale="en",
groups=["users"],
)
await user_repo.create(profile_user)
profile_password_hash = password_service.hash("profilepass123")
await cred_repo.create_password(
PasswordCredential(user_id=profile_user.userid, password_hash=profile_password_hash)
)
result["profile_username"] = "profileuser"
result["profile_password"] = "profilepass123"
# 6. Admin user for admin page tests
admin_user = User(
userid="test-user-05",
username="adminuser",
given_name="Admin",
family_name="User",
email="admin@example.com",
groups=["admin", "users"],
)
await user_repo.create(admin_user)
admin_password_hash = password_service.hash("adminpass123")
await cred_repo.create_password(PasswordCredential(user_id=admin_user.userid, password_hash=admin_password_hash))
result["admin_username"] = "adminuser"
result["admin_password"] = "adminpass123"
result["admin_userid"] = "test-user-05"
# 7. Disposable user for admin delete test (not used by any other tests)
disposable_user = User(userid="test-user-06", username="disposableuser", groups=["users"])
await user_repo.create(disposable_user)
result["disposable_userid"] = "test-user-06"
result["disposable_username"] = "disposableuser"
await db.commit()
await db.close()
print(json.dumps(result))
asyncio.run(seed())