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

220 lines
6.6 KiB
C#

namespace Application.Tests.Auth;
using Application.Auth;
using Application.Auth.Commands;
using Domain.Entities;
using Domain.Ports.Repositories;
using FluentAssertions;
using NSubstitute;
using Xunit;
public class RegisterCommandTests
{
private readonly IUserRepository _userRepository;
private readonly IStudentRepository _studentRepository;
private readonly IPasswordService _passwordService;
private readonly IJwtService _jwtService;
private readonly IUnitOfWork _unitOfWork;
private readonly RegisterCommandHandler _handler;
public RegisterCommandTests()
{
_userRepository = Substitute.For<IUserRepository>();
_studentRepository = Substitute.For<IStudentRepository>();
_passwordService = Substitute.For<IPasswordService>();
_jwtService = Substitute.For<IJwtService>();
_unitOfWork = Substitute.For<IUnitOfWork>();
_passwordService.HashPassword(Arg.Any<string>()).Returns("hashed_value");
_handler = new RegisterCommandHandler(
_userRepository,
_studentRepository,
_passwordService,
_jwtService,
_unitOfWork
);
}
[Fact]
public async Task Handle_WithValidData_ShouldCreateUser()
{
// Arrange
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new RegisterCommand("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_WithExistingUsername_ShouldReturnError()
{
// Arrange
_userRepository.ExistsAsync("existinguser", Arg.Any<CancellationToken>())
.Returns(true);
var command = new RegisterCommand("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
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
var command = new RegisterCommand("newuser", "12345"); // 5 chars, less than 6
// 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_WithNameAndEmail_ShouldCreateStudent()
{
// Arrange
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new RegisterCommand(
"newuser",
"password123",
Name: "John Doe",
Email: "john@example.com"
);
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeTrue();
_studentRepository.Received(1).Add(Arg.Is<Student>(s => s.Name == "John Doe"));
await _unitOfWork.Received().SaveChangesAsync(Arg.Any<CancellationToken>());
}
[Fact]
public async Task Handle_WithInvalidEmail_ShouldReturnError()
{
// Arrange
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
var command = new RegisterCommand(
"newuser",
"password123",
Name: "John Doe",
Email: "invalid-email"
);
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeFalse();
result.Error.Should().NotBeNullOrEmpty();
}
[Fact]
public async Task Handle_ShouldGenerateRecoveryCode()
{
// Arrange
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new RegisterCommand("newuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.RecoveryCode.Should().NotBeNullOrEmpty();
result.RecoveryCode!.Length.Should().Be(12);
result.RecoveryCode.Should().MatchRegex("^[A-Z0-9]+$");
}
[Fact]
public async Task Handle_ShouldHashPasswordBeforeSaving()
{
// Arrange
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new RegisterCommand("newuser", "password123");
// Act
await _handler.Handle(command, CancellationToken.None);
// Assert
_passwordService.Received(1).HashPassword("password123");
await _userRepository.Received(1).AddAsync(
Arg.Is<User>(u => u.PasswordHash == "hashed_value"),
Arg.Any<CancellationToken>()
);
}
[Fact]
public async Task Handle_ShouldNormalizeUsernameToLowercase()
{
// Arrange
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new RegisterCommand("NEWUSER", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.Success.Should().BeTrue();
result.User!.Username.Should().Be("newuser");
}
[Fact]
public async Task Handle_NewUserShouldHaveStudentRole()
{
// Arrange
_userRepository.ExistsAsync("newuser", Arg.Any<CancellationToken>())
.Returns(false);
_jwtService.GenerateToken(Arg.Any<User>())
.Returns("new.jwt.token");
var command = new RegisterCommand("newuser", "password123");
// Act
var result = await _handler.Handle(command, CancellationToken.None);
// Assert
result.User!.Role.Should().Be(UserRoles.Student);
}
}