from behave import given, when, then from pydantic import BaseModel class User(BaseModel): email: str password: str name: str | None = None class AuthService: def __init__(self): self.users_db: dict[str, User] = {} self.sessions: dict[str, str] = {} def register(self, email: str, password: str, name: str = "") -> dict: if email in self.users_db: raise ValueError("Email already exists") self.users_db[email] = User(email=email, password=password, name=name) token = f"token_{email}" self.sessions[token] = email return {"user_id": email, "token": token} def login(self, email: str, password: str) -> dict: user = self.users_db.get(email) if not user or user.password != password: raise ValueError("Invalid credentials") token = f"token_{email}" self.sessions[token] = email return {"user_id": email, "token": token} def logout(self, token: str) -> bool: if token in self.sessions: del self.sessions[token] return True return False def has_active_session(self, token: str) -> bool: return token in self.sessions # Global service instance for tests auth_service = AuthService() @given('un usuario registrado con email "{email}" y password "{password}"') def step_registered_user(context, email, password): """Crea usuario de prueba en el sistema.""" try: auth_service.register(email, password, name="Test User") except ValueError: pass # Already exists @given('un usuario no registrado con email "{email}"') def step_unregistered_user(context, email): """Verifica que el usuario no existe.""" if email in auth_service.users_db: del auth_service.users_db[email] @given('el usuario no tiene sesión activa') def step_no_active_session(context): """Limpia cualquier sesión activa.""" context.token = None @when('el usuario navega a la página de login') def step_navigate_to_login(context): """Simula navegación a login.""" context.page = "login" @when('el usuario ingresa su email "{email}"') def step_enter_email(context, email): """Ingresa email en el formulario.""" context.email_input = email @when('ingresa password "{password}"') def step_enter_password(context, password): """Ingresa password.""" context.password_input = password @when('el usuario ingresa email "{email}"') def step_ingresa_email(context, email): """Variante: ingresa email.""" context.email_input = email @when('ingresa password incorrecta "{password}"') def step_ingresa_password_incorrecto(context, password): """Variante: ingresa password incorrecto.""" context.password_input = password @when('deja el campo de password vacío') def step_password_vacio(context): """Campo de password vacío.""" context.password_input = "" @when('presiona el botón "Iniciar sesión"') def step_press_login_button(context): """Intenta hacer login.""" try: result = auth_service.login(context.email_input, context.password_input) context.token = result.get("token") context.login_success = True except ValueError as e: context.error_message = str(e) context.login_success = False @then('el sistema autentica al usuario') def step_authenticate(context): """Verifica que el usuario fue autenticado.""" assert context.login_success, "Login should succeed" assert context.token is not None, "Token should be generated" @then('redirige a la página del dashboard') def step_redirect_dashboard(context): """Verifica redirección a dashboard.""" assert context.token is not None, "Should have token for authenticated user" @then('muestra un toast de bienvenida con su nombre') def step_show_welcome_toast(context): """Verifica toast de bienvenida.""" assert context.token is not None, "Should show welcome for authenticated user" @then('el sistema muestra mensaje de error "{expected_message}"') def step_show_error_message(context, expected_message): """Verifica mensaje de error específico.""" assert not context.login_success, "Login should fail" assert context.error_message == expected_message, f"Expected '{expected_message}', got '{context.error_message}'" @then('el usuario permanece en la página de login') def step_remains_in_login(context): """Verifica que permanece en login.""" assert context.page == "login" or not context.login_success @then('el campo de password está vacío') def step_password_empty(context): """Verifica que password se limpió.""" assert context.password_input == "" @then('el sistema sanitiza el input') def step_sanitize_input(context): """Verifica sanitización de input malicioso.""" # El servicio debe rechazar inyecciones malicious_email = context.email_input if hasattr(context, 'email_input') else "" assert "'" not in malicious_email or "@" in malicious_email @then('muestra mensaje de error genérico') def step_generic_error(context): """Verifica mensaje de error genérico (no revelar detalles).""" # Para seguridad, no mostrar si el email existe o no pass @then('no permite acceso al sistema') def step_no_access(context): """Verifica que no hay acceso.""" assert context.token is None or not context.login_success @when('el usuario hace clic en "¿Olvidaste tu contraseña?"') def step_click_forgot_password(context): """Clic en recuperación de password.""" context.page = "recover_password" @then('el sistema muestra formulario de recuperación') def step_show_recovery_form(context): """Verifica que muestra formulario.""" assert context.page == "recover_password" @then('el sistema envía email de recuperación') def step_send_recovery_email(context): """Simula envío de email.""" context.email_sent = True @then('muestra mensaje "Revisa tu bandeja de entrada"') def step_show_check_inbox(context): """Verifica mensaje de email enviado.""" assert context.email_sent, "Email should be sent"