mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-14 17:54:42 +00:00
Show a user's avatar on the public profile (#333)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using Domain.Entities;
|
||||
using Domain.Exceptions;
|
||||
using Features.ImageUploads.Services;
|
||||
using Features.Users.Dtos;
|
||||
using Features.Users.Queries.GetPublicUserProfileById;
|
||||
using Features.Users.Repository;
|
||||
@@ -12,15 +13,21 @@ public class GetPublicUserProfileByIdHandlerTests
|
||||
{
|
||||
private readonly GetPublicUserProfileByIdHandler _handler;
|
||||
private readonly Mock<IUserListRepository> _repoMock = new();
|
||||
private readonly Mock<IFileStorageProvider> _storageMock = new();
|
||||
|
||||
public GetPublicUserProfileByIdHandlerTests()
|
||||
{
|
||||
_handler = new GetPublicUserProfileByIdHandler(_repoMock.Object);
|
||||
_storageMock
|
||||
.Setup(s => s.GetPresignedUrl(It.IsAny<string>(), It.IsAny<TimeSpan>()))
|
||||
.Returns((string key, TimeSpan _) => $"https://storage.test/{key}?signed");
|
||||
|
||||
_handler = new GetPublicUserProfileByIdHandler(_repoMock.Object, _storageMock.Object);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ReturnsPublicProfile_WhenFound()
|
||||
{
|
||||
string avatarKey = $"avatars/{Guid.NewGuid()}/{Guid.NewGuid()}";
|
||||
UserAccount user = new()
|
||||
{
|
||||
UserAccountId = Guid.NewGuid(),
|
||||
@@ -31,6 +38,7 @@ public class GetPublicUserProfileByIdHandlerTests
|
||||
DateOfBirth = new DateTime(1990, 1, 1),
|
||||
CreatedAt = new DateTime(2024, 1, 1),
|
||||
UserProfile = new UserProfile { Biography = "Drinks lagers." },
|
||||
UserAvatar = new UserAvatar { Photo = new Photo { Hyperlink = avatarKey } },
|
||||
};
|
||||
_repoMock.Setup(r => r.GetByIdAsync(user.UserAccountId)).ReturnsAsync(user);
|
||||
|
||||
@@ -48,13 +56,48 @@ public class GetPublicUserProfileByIdHandlerTests
|
||||
user.FirstName,
|
||||
user.LastName,
|
||||
"Drinks lagers.",
|
||||
$"https://storage.test/{avatarKey}?signed",
|
||||
user.CreatedAt
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <c>Photo.Hyperlink</c> holds an object key, so the DTO has to carry a signed URL rather than
|
||||
/// the stored value: a bare key resolves against the calling page's own origin.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Handle_ReturnsEmptyBiography_WhenProfileMissing()
|
||||
public async Task Handle_SignsTheAvatarKey_RatherThanReturningIt()
|
||||
{
|
||||
string avatarKey = $"avatars/{Guid.NewGuid()}/{Guid.NewGuid()}";
|
||||
UserAccount user = new()
|
||||
{
|
||||
UserAccountId = Guid.NewGuid(),
|
||||
Username = "test",
|
||||
FirstName = "Jane",
|
||||
LastName = "Doe",
|
||||
CreatedAt = new DateTime(2024, 1, 1),
|
||||
UserAvatar = new UserAvatar { Photo = new Photo { Hyperlink = avatarKey } },
|
||||
};
|
||||
_repoMock.Setup(r => r.GetByIdAsync(user.UserAccountId)).ReturnsAsync(user);
|
||||
|
||||
PublicUserProfileDto result = await _handler.Handle(
|
||||
new GetPublicUserProfileByIdQuery(user.UserAccountId),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
result.AvatarUrl.Should().NotBe(avatarKey);
|
||||
Uri.TryCreate(result.AvatarUrl, UriKind.Absolute, out Uri? uri).Should().BeTrue();
|
||||
uri!.Scheme.Should().BeOneOf("http", "https");
|
||||
uri.AbsolutePath.Should().EndWith(avatarKey);
|
||||
_storageMock.Verify(
|
||||
s => s.GetPresignedUrl(avatarKey, UserDtoMapper.AvatarUrlLifetime),
|
||||
Times.Once
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ReturnsEmptyBiographyAndAvatarUrl_WhenProfileMissing()
|
||||
{
|
||||
UserAccount user = new()
|
||||
{
|
||||
@@ -72,6 +115,57 @@ public class GetPublicUserProfileByIdHandlerTests
|
||||
);
|
||||
|
||||
result.Biography.Should().BeEmpty();
|
||||
result.AvatarUrl.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ReturnsEmptyAvatarUrl_WhenProfileHasNoAvatar()
|
||||
{
|
||||
UserAccount user = new()
|
||||
{
|
||||
UserAccountId = Guid.NewGuid(),
|
||||
Username = "test",
|
||||
FirstName = "Jane",
|
||||
LastName = "Doe",
|
||||
CreatedAt = new DateTime(2024, 1, 1),
|
||||
UserProfile = new UserProfile { Biography = "Drinks lagers." },
|
||||
};
|
||||
_repoMock.Setup(r => r.GetByIdAsync(user.UserAccountId)).ReturnsAsync(user);
|
||||
|
||||
PublicUserProfileDto result = await _handler.Handle(
|
||||
new GetPublicUserProfileByIdQuery(user.UserAccountId),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
result.Biography.Should().Be("Drinks lagers.");
|
||||
result.AvatarUrl.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Handle_ReturnsEmptyAvatarUrl_WhenAvatarHasNoPhoto()
|
||||
{
|
||||
UserAccount user = new()
|
||||
{
|
||||
UserAccountId = Guid.NewGuid(),
|
||||
Username = "test",
|
||||
FirstName = "Jane",
|
||||
LastName = "Doe",
|
||||
CreatedAt = new DateTime(2024, 1, 1),
|
||||
UserProfile = new UserProfile { Biography = "Drinks lagers." },
|
||||
UserAvatar = new UserAvatar(),
|
||||
};
|
||||
_repoMock.Setup(r => r.GetByIdAsync(user.UserAccountId)).ReturnsAsync(user);
|
||||
|
||||
PublicUserProfileDto result = await _handler.Handle(
|
||||
new GetPublicUserProfileByIdQuery(user.UserAccountId),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
result.AvatarUrl.Should().BeEmpty();
|
||||
_storageMock.Verify(
|
||||
s => s.GetPresignedUrl(It.IsAny<string>(), It.IsAny<TimeSpan>()),
|
||||
Times.Never
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user