"""Integration tests for Story 1.1: Initial Admin Setup.""" from src.app import bcrypt from src.models import Admin class TestInitialAdminSetup: """Test cases for initial admin setup flow (Story 1.1).""" def test_setup_screen_appears_on_first_access(self, client, db): # noqa: ARG002 """Test that setup screen appears when no admin exists. Acceptance Criteria: - Setup screen appears on first application access """ # Access root path - should redirect to setup response = client.get("/") assert response.status_code == 302 assert "/setup" in response.location # Accessing setup directly should show setup form response = client.get("/setup", follow_redirects=False) assert response.status_code == 200 assert b"Admin Setup" in response.data or b"Create Admin" in response.data assert b"email" in response.data.lower() assert b"password" in response.data.lower() def test_setup_requires_email_and_password(self, client, db): # noqa: ARG002 """Test that setup form requires email and password. Acceptance Criteria: - Requires email address and password """ response = client.get("/setup") assert response.status_code == 200 # Check form has email and password fields assert b'type="email"' in response.data or b'name="email"' in response.data assert ( b'type="password"' in response.data or b'name="password"' in response.data ) def test_setup_with_valid_data_creates_admin(self, client, db): """Test that valid setup data creates admin account. Acceptance Criteria: - After setup, admin account is created """ response = client.post( "/setup", data={ "email": "admin@example.com", "password": "validpassword123", "password_confirm": "validpassword123", }, follow_redirects=False, ) # Should redirect after successful setup assert response.status_code == 302 # Verify admin was created admin = db.session.query(Admin).filter_by(email="admin@example.com").first() assert admin is not None assert admin.email == "admin@example.com" # Verify password was hashed assert admin.password_hash is not None assert admin.password_hash != "validpassword123" assert bcrypt.check_password_hash(admin.password_hash, "validpassword123") def test_setup_validates_password_minimum_length(self, client, db): """Test that password must meet minimum length requirement. Acceptance Criteria: - Password must meet minimum security requirements (12 characters) """ # Try with password too short response = client.post( "/setup", data={ "email": "admin@example.com", "password": "short", # Less than 12 characters "password_confirm": "short", }, follow_redirects=True, ) # Should show error and not create admin assert ( b"at least 12 characters" in response.data.lower() or b"too short" in response.data.lower() ) # Verify no admin was created admin_count = db.session.query(Admin).count() assert admin_count == 0 def test_setup_validates_password_confirmation(self, client, db): """Test that password confirmation must match. Acceptance Criteria: - Password confirmation must match password """ response = client.post( "/setup", data={ "email": "admin@example.com", "password": "validpassword123", "password_confirm": "differentpassword123", }, follow_redirects=True, ) # Should show error about passwords not matching assert b"match" in response.data.lower() or b"same" in response.data.lower() # Verify no admin was created admin_count = db.session.query(Admin).count() assert admin_count == 0 def test_setup_validates_email_format(self, client, db): """Test that email must be valid format. Acceptance Criteria: - Email address must be valid format """ response = client.post( "/setup", data={ "email": "not-a-valid-email", "password": "validpassword123", "password_confirm": "validpassword123", }, follow_redirects=True, ) # Should show error about invalid email assert ( b"valid email" in response.data.lower() or b"invalid email" in response.data.lower() ) # Verify no admin was created admin_count = db.session.query(Admin).count() assert admin_count == 0 def test_setup_logs_in_admin_after_creation(self, client, db): # noqa: ARG002 """Test that user is logged in after successful setup. Acceptance Criteria: - After setup, user is logged in as admin """ response = client.post( "/setup", data={ "email": "admin@example.com", "password": "validpassword123", "password_confirm": "validpassword123", }, follow_redirects=True, ) # Should redirect to admin dashboard assert response.status_code == 200 assert ( b"dashboard" in response.data.lower() or b"admin" in response.data.lower() ) # Verify session is set (check that we can access admin routes) response = client.get("/admin/dashboard", follow_redirects=False) # 404 is OK if route not implemented yet assert response.status_code in (200, 404) def test_setup_not_accessible_after_admin_exists( self, client, db, admin, # noqa: ARG002 ): """Test that setup page returns 404 after admin exists. Acceptance Criteria: - Setup screen is not accessible after initial admin creation """ # Try to access setup when admin already exists response = client.get("/setup", follow_redirects=False) assert response.status_code == 404 # Try to POST to setup when admin already exists response = client.post( "/setup", data={ "email": "another@example.com", "password": "validpassword123", "password_confirm": "validpassword123", }, follow_redirects=False, ) assert response.status_code == 404 # Verify no second admin was created admin_count = db.session.query(Admin).count() assert admin_count == 1 def test_root_redirects_to_admin_dashboard_when_admin_exists( self, client, db, # noqa: ARG002 admin, # noqa: ARG002 ): """Test that root path redirects normally when admin exists. Once setup is complete, the root path should not redirect to setup. """ response = client.get("/", follow_redirects=False) # Should either render landing page or redirect to login (not to setup) assert "/setup" not in (response.location or "")