academia/tests/Application.Tests/Auth/ActivateAccountCommandTests.cs

279 lines
11 KiB
C#
Raw Normal View History

namespace Application.Tests.Auth;
using Application.Auth;
using Application.Auth.Commands;
using Domain.Entities;
using Domain.Ports.Repositories;
using Domain.ValueObjects;
using FluentAssertions;
using NSubstitute;
using Xunit;
public class ActivateAccountCommandTests
{
private readonly IStudentRepository _studentRepository;
private readonly IUserRepository _userRepository;
private readonly IPasswordService _passwordService;
private readonly IJwtService _jwtService;
private readonly IUnitOfWork _unitOfWork;
private readonly ActivateAccountHandler _handler;
public ActivateAccountCommandTests()
{
_studentRepository = Substitute.For<IStudentRepository>();
_userRepository = Substitute.For<IUserRepository>();
_passwordService = Substitute.For<IPasswordService>();
_jwtService = Substitute.For<IJwtService>();
_unitOfWork = Substitute.For<IUnitOfWork>();
_passwordService.HashPassword(Arg.Any<string>()).Returns("hashed_value");
_handler = new ActivateAccountHandler(
_studentRepository,
_userRepository,
_passwordService,
_jwtService,
_unitOfWork
);
}
[Fact]
public async Task Handle_WithValidActivationCode_ShouldActivateAccount()
{
// Arrange
var student = CreateStudentWithActivationCode("John Doe", "john@test.com", "activation_hash");
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("VALIDCODE123", "activation_hash")
.Returns(true);
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_studentRepository.GetByIdAsync(student.Id, Arg.Any<CancellationToken>())
.Returns(student);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new ActivateAccountCommand("VALIDCODE123", "newuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeTrue();
result.Token.Should().Be("new.jwt.token");
result.RecoveryCode.Should().NotBeNullOrEmpty();
result.Error.Should().BeNull();
}
[Fact]
public async Task Handle_WithInvalidActivationCode_ShouldReturnError()
{
// Arrange
var student = CreateStudentWithActivationCode("John Doe", "john@test.com", "activation_hash");
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("INVALIDCODE", Arg.Any<string>())
.Returns(false);
var command = new ActivateAccountCommand("INVALIDCODE", "newuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Error.Should().Contain("invalido");
}
[Fact]
public async Task Handle_WithExpiredActivationCode_ShouldReturnError()
{
// Arrange
var student = CreateStudentWithExpiredActivationCode("John Doe", "john@test.com", "activation_hash");
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("VALIDCODE123", "activation_hash")
.Returns(true);
var command = new ActivateAccountCommand("VALIDCODE123", "newuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Error.Should().Contain("expirado");
}
[Fact]
public async Task Handle_WithExistingUsername_ShouldReturnError()
{
// Arrange
var student = CreateStudentWithActivationCode("John Doe", "john@test.com", "activation_hash");
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("VALIDCODE123", "activation_hash")
.Returns(true);
_userRepository.ExistsAsync("existinguser", Arg.Any<CancellationToken>())
.Returns(true);
var command = new ActivateAccountCommand("VALIDCODE123", "existinguser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Error.Should().Contain("ya existe");
}
[Fact]
public async Task Handle_WithShortPassword_ShouldReturnError()
{
// Arrange
var student = CreateStudentWithActivationCode("John Doe", "john@test.com", "activation_hash");
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("VALIDCODE123", "activation_hash")
.Returns(true);
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
var command = new ActivateAccountCommand("VALIDCODE123", "newuser", "12345"); // 5 chars
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Error.Should().Contain("al menos 6 caracteres");
}
[Fact]
public async Task Handle_ShouldCreateUserWithStudentRole()
{
// Arrange
var student = CreateStudentWithActivationCode("John Doe", "john@test.com", "activation_hash");
SetEntityId(student, 5);
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("VALIDCODE123", "activation_hash")
.Returns(true);
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_studentRepository.GetByIdAsync(5, Arg.Any<CancellationToken>())
.Returns(student);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new ActivateAccountCommand("VALIDCODE123", "newuser", "password123");
// Act
await _handler.Handle(command, CancellationToken.None);
// Assert
await _userRepository.Received(1).AddAsync(
Arg.Is<User>(u => u.Role == UserRoles.Student && u.StudentId == 5),
Arg.Any<CancellationToken>()
);
}
[Fact]
public async Task Handle_ShouldGenerateRecoveryCode()
{
// Arrange
var student = CreateStudentWithActivationCode("John Doe", "john@test.com", "activation_hash");
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("VALIDCODE123", "activation_hash")
.Returns(true);
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_studentRepository.GetByIdAsync(student.Id, Arg.Any<CancellationToken>())
.Returns(student);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new ActivateAccountCommand("VALIDCODE123", "newuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.RecoveryCode.Should().NotBeNullOrEmpty();
result.RecoveryCode!.Length.Should().Be(12);
}
[Fact]
public async Task Handle_ShouldClearActivationCodeAfterSuccess()
{
// Arrange
var student = CreateStudentWithActivationCode("John Doe", "john@test.com", "activation_hash");
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("VALIDCODE123", "activation_hash")
.Returns(true);
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_studentRepository.GetByIdAsync(student.Id, Arg.Any<CancellationToken>())
.Returns(student);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new ActivateAccountCommand("VALIDCODE123", "newuser", "password123");
// Act
await _handler.Handle(command, CancellationToken.None);
// Assert
await _unitOfWork.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_ShouldReturnJwtTokenForAutoLogin()
{
// Arrange
var student = CreateStudentWithActivationCode("John Doe", "john@test.com", "activation_hash");
_studentRepository.GetPendingActivationAsync(Arg.Any<CancellationToken>())
.Returns(new List<Student> { student });
_passwordService.VerifyPassword("VALIDCODE123", "activation_hash")
.Returns(true);
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_studentRepository.GetByIdAsync(student.Id, Arg.Any<CancellationToken>())
.Returns(student);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("auto.login.token");
var command = new ActivateAccountCommand("VALIDCODE123", "newuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Token.Should().Be("auto.login.token");
_jwtService.Received(1).GenerateToken(Arg.Any<User>());
}
private static Student CreateStudentWithActivationCode(string name, string email, string activationHash)
{
var student = new Student(name, Email.Create(email));
typeof(Student).GetProperty("ActivationCodeHash")?.SetValue(student, activationHash);
typeof(Student).GetProperty("ActivationExpiresAt")?.SetValue(student, DateTime.UtcNow.AddDays(2));
return student;
}
private static Student CreateStudentWithExpiredActivationCode(string name, string email, string activationHash)
{
var student = new Student(name, Email.Create(email));
typeof(Student).GetProperty("ActivationCodeHash")?.SetValue(student, activationHash);
typeof(Student).GetProperty("ActivationExpiresAt")?.SetValue(student, DateTime.UtcNow.AddDays(-1));
return student;
}
private static void SetEntityId<T>(T entity, int id) where T : class
{
typeof(T).GetProperty("Id")?.SetValue(entity, id);
}
}