Add test
This commit is contained in:
@@ -302,4 +302,225 @@ public sealed class UserTests
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("Cannot update SSO profile for local users");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VerifyEmail_WhenUnverified_ShouldSetVerifiedAt()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
user.ClearDomainEvents();
|
||||
|
||||
// Act
|
||||
user.VerifyEmail();
|
||||
|
||||
// Assert
|
||||
user.IsEmailVerified.Should().BeTrue();
|
||||
user.EmailVerifiedAt.Should().NotBeNull();
|
||||
user.EmailVerificationToken.Should().BeNull();
|
||||
user.DomainEvents.Should().ContainSingle();
|
||||
user.DomainEvents.Should().ContainItemsAssignableTo<EmailVerifiedEvent>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void VerifyEmail_WhenAlreadyVerified_ShouldBeIdempotent()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
user.VerifyEmail();
|
||||
var firstVerifiedAt = user.EmailVerifiedAt;
|
||||
user.ClearDomainEvents();
|
||||
|
||||
// Act
|
||||
user.VerifyEmail();
|
||||
|
||||
// Assert
|
||||
user.EmailVerifiedAt.Should().Be(firstVerifiedAt);
|
||||
user.DomainEvents.Should().BeEmpty(); // No new event for idempotent operation
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetEmailVerificationToken_ShouldHashToken()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
const string token = "verification_token";
|
||||
|
||||
// Act
|
||||
user.SetEmailVerificationToken(token);
|
||||
|
||||
// Assert
|
||||
user.EmailVerificationToken.Should().Be(token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetPasswordResetToken_ShouldSetTokenAndExpiration()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
const string token = "reset_token";
|
||||
var expiresAt = DateTime.UtcNow.AddHours(1);
|
||||
|
||||
// Act
|
||||
user.SetPasswordResetToken(token, expiresAt);
|
||||
|
||||
// Assert
|
||||
user.PasswordResetToken.Should().Be(token);
|
||||
user.PasswordResetTokenExpiresAt.Should().Be(expiresAt);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetPasswordResetToken_ForSsoUser_ShouldThrowException()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateFromSso(
|
||||
_tenantId,
|
||||
AuthenticationProvider.Google,
|
||||
"google-123",
|
||||
Email.Create("test@example.com"),
|
||||
FullName.Create("John Doe"));
|
||||
|
||||
// Act
|
||||
var act = () => user.SetPasswordResetToken("token", DateTime.UtcNow.AddHours(1));
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*Cannot set password reset token for SSO users*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClearPasswordResetToken_ShouldClearTokenAndExpiration()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
user.SetPasswordResetToken("token", DateTime.UtcNow.AddHours(1));
|
||||
|
||||
// Act
|
||||
user.ClearPasswordResetToken();
|
||||
|
||||
// Assert
|
||||
user.PasswordResetToken.Should().BeNull();
|
||||
user.PasswordResetTokenExpiresAt.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordLoginWithEvent_ShouldUpdateLastLogin()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
user.ClearDomainEvents();
|
||||
|
||||
// Act
|
||||
user.RecordLoginWithEvent(_tenantId, "192.168.1.1", "Mozilla/5.0");
|
||||
|
||||
// Assert
|
||||
user.LastLoginAt.Should().NotBeNull();
|
||||
user.LastLoginAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RecordLoginWithEvent_ShouldRaiseDomainEvent()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
user.ClearDomainEvents();
|
||||
const string ipAddress = "192.168.1.1";
|
||||
const string userAgent = "Mozilla/5.0";
|
||||
|
||||
// Act
|
||||
user.RecordLoginWithEvent(_tenantId, ipAddress, userAgent);
|
||||
|
||||
// Assert
|
||||
user.DomainEvents.Should().ContainSingle();
|
||||
user.DomainEvents.Should().ContainItemsAssignableTo<UserLoggedInEvent>();
|
||||
var domainEvent = user.DomainEvents.First() as UserLoggedInEvent;
|
||||
domainEvent.Should().NotBeNull();
|
||||
domainEvent!.UserId.Should().Be(user.Id);
|
||||
domainEvent.TenantId.Should().Be(_tenantId);
|
||||
domainEvent.IpAddress.Should().Be(ipAddress);
|
||||
domainEvent.UserAgent.Should().Be(userAgent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Delete_ShouldChangeStatusToDeleted()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
|
||||
// Act
|
||||
user.Delete();
|
||||
|
||||
// Assert
|
||||
user.Status.Should().Be(UserStatus.Deleted);
|
||||
user.UpdatedAt.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Suspend_WithDeletedUser_ShouldThrowException()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
user.Delete();
|
||||
|
||||
// Act
|
||||
var act = () => user.Suspend("Test reason");
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*Cannot suspend deleted user*");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Reactivate_WithDeletedUser_ShouldThrowException()
|
||||
{
|
||||
// Arrange
|
||||
var user = User.CreateLocal(
|
||||
_tenantId,
|
||||
Email.Create("test@example.com"),
|
||||
"hash",
|
||||
FullName.Create("John Doe"));
|
||||
user.Delete();
|
||||
|
||||
// Act
|
||||
var act = () => user.Reactivate();
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<InvalidOperationException>()
|
||||
.WithMessage("*Cannot reactivate deleted user*");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user