mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 06:03:12 +00:00
153 lines
6.2 KiB
C#
153 lines
6.2 KiB
C#
using System.Security.Claims;
|
|
using Data.SeaHavenIndustries;
|
|
using Data.SeaHavenIndustries.Enums;
|
|
using FluentAssertions;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using Moq;
|
|
using SeaHaven.DataServices.Interfaces;
|
|
using SeaHaven.Services.DTOs;
|
|
using SeaHaven.Services.Implementation;
|
|
using Xunit;
|
|
|
|
namespace Api.SeaHavenIndustries.Tests;
|
|
|
|
public sealed class TeamMemberServiceTests
|
|
{
|
|
[Fact]
|
|
public async Task Create_DispatcherRequiresAtLeastOneServiceArea()
|
|
{
|
|
var userManager = UserManager();
|
|
var roleManager = RoleManager();
|
|
var service = new TeamMemberService(
|
|
userManager.Object,
|
|
roleManager.Object,
|
|
Mock.Of<IUserServiceAreaDataService>(),
|
|
Mock.Of<ITeamPermissionOverrideDataService>());
|
|
|
|
var result = await service.CreateAsync(
|
|
ValidRequest() with { ServiceAreas = Array.Empty<string>() },
|
|
Admin(),
|
|
CancellationToken.None);
|
|
|
|
result.Success.Should().BeFalse();
|
|
result.Error.Should().Be("At least one service area is required for a Dispatcher.");
|
|
userManager.Verify(manager => manager.CreateAsync(It.IsAny<ApplicationUser>()), Times.Never);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Create_RejectsUnknownColorAndPermission()
|
|
{
|
|
var service = NewService(out var userManager, out _, out _, out _);
|
|
|
|
var badColor = await service.CreateAsync(
|
|
ValidRequest() with { Color = "#000000" },
|
|
Admin(),
|
|
CancellationToken.None);
|
|
var badPermission = await service.CreateAsync(
|
|
ValidRequest() with
|
|
{
|
|
PermissionOverrides = new Dictionary<string, UserPermissionState>
|
|
{
|
|
["not-a-permission"] = UserPermissionState.Allow
|
|
}
|
|
},
|
|
Admin(),
|
|
CancellationToken.None);
|
|
|
|
badColor.Error.Should().Be("Color must be selected from the accessible palette.");
|
|
badPermission.Error.Should().Be("Unknown permission key: not-a-permission.");
|
|
userManager.Verify(manager => manager.CreateAsync(It.IsAny<ApplicationUser>()), Times.Never);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Create_PersistsPendingUserWithoutPasswordAndStoresAreasAndOverrides()
|
|
{
|
|
var service = NewService(out var userManager, out var roleManager, out var areas, out var overrides);
|
|
ApplicationUser? created = null;
|
|
userManager
|
|
.Setup(manager => manager.CreateAsync(It.IsAny<ApplicationUser>()))
|
|
.Callback<ApplicationUser>(user =>
|
|
{
|
|
user.Id = "new-user";
|
|
created = user;
|
|
})
|
|
.ReturnsAsync(IdentityResult.Success);
|
|
userManager
|
|
.Setup(manager => manager.FindByEmailAsync(It.IsAny<string>()))
|
|
.ReturnsAsync((ApplicationUser?)null);
|
|
userManager
|
|
.Setup(manager => manager.AddToRoleAsync(It.IsAny<ApplicationUser>(), "Dispatcher"))
|
|
.ReturnsAsync(IdentityResult.Success);
|
|
roleManager.Setup(manager => manager.RoleExistsAsync("Dispatcher")).ReturnsAsync(true);
|
|
|
|
var result = await service.CreateAsync(ValidRequest(), Admin(), CancellationToken.None);
|
|
|
|
result.Success.Should().BeTrue();
|
|
created.Should().NotBeNull();
|
|
created!.PasswordHash.Should().BeNull();
|
|
created.EmailConfirmed.Should().BeFalse();
|
|
created.PendingRegistration.Should().BeTrue();
|
|
created.PhoneNumber.Should().Be("555-0100");
|
|
result.Member!.ServiceAreas.Should().Equal("East", "West");
|
|
areas.Verify(data => data.ReplaceAsync("new-user", It.Is<IReadOnlyCollection<string>>(value => value.SequenceEqual(new[] { "East", "West" })), It.IsAny<CancellationToken>()), Times.Once);
|
|
overrides.Verify(data => data.SetOverridesAsync("new-user", It.Is<IReadOnlyDictionary<string, UserPermissionState>>(value => value["deleteSites"] == UserPermissionState.Allow), It.IsAny<CancellationToken>()), Times.Once);
|
|
}
|
|
|
|
private static TeamMemberService NewService(
|
|
out Mock<UserManager<ApplicationUser>> userManager,
|
|
out Mock<RoleManager<IdentityRole>> roleManager,
|
|
out Mock<IUserServiceAreaDataService> areas,
|
|
out Mock<ITeamPermissionOverrideDataService> overrides)
|
|
{
|
|
userManager = UserManager();
|
|
roleManager = RoleManager();
|
|
areas = new Mock<IUserServiceAreaDataService>();
|
|
overrides = new Mock<ITeamPermissionOverrideDataService>();
|
|
return new TeamMemberService(userManager.Object, roleManager.Object, areas.Object, overrides.Object);
|
|
}
|
|
|
|
private static Mock<UserManager<ApplicationUser>> UserManager()
|
|
{
|
|
var store = new Mock<IUserStore<ApplicationUser>>();
|
|
return new Mock<UserManager<ApplicationUser>>(
|
|
store.Object,
|
|
Microsoft.Extensions.Options.Options.Create(new IdentityOptions()),
|
|
Mock.Of<IPasswordHasher<ApplicationUser>>(),
|
|
Array.Empty<IUserValidator<ApplicationUser>>(),
|
|
Array.Empty<IPasswordValidator<ApplicationUser>>(),
|
|
Mock.Of<ILookupNormalizer>(),
|
|
new IdentityErrorDescriber(),
|
|
Mock.Of<IServiceProvider>(),
|
|
Mock.Of<ILogger<UserManager<ApplicationUser>>>());
|
|
}
|
|
|
|
private static Mock<RoleManager<IdentityRole>> RoleManager()
|
|
{
|
|
var store = new Mock<IRoleStore<IdentityRole>>();
|
|
return new Mock<RoleManager<IdentityRole>>(
|
|
store.Object,
|
|
Array.Empty<IRoleValidator<IdentityRole>>(),
|
|
Mock.Of<ILookupNormalizer>(),
|
|
new IdentityErrorDescriber(),
|
|
Mock.Of<ILogger<RoleManager<IdentityRole>>>());
|
|
}
|
|
|
|
private static CreateTeamMemberRequestDTO ValidRequest() => new()
|
|
{
|
|
Name = "Taylor Dispatcher",
|
|
Role = "dispatcher",
|
|
Color = "#F59E0B",
|
|
Email = "taylor@example.com",
|
|
Phone = "555-0100",
|
|
ServiceAreas = new[] { "east", "West" },
|
|
PermissionOverrides = new Dictionary<string, UserPermissionState>
|
|
{
|
|
["deleteSites"] = UserPermissionState.Allow
|
|
}
|
|
};
|
|
|
|
private static ClaimsPrincipal Admin() =>
|
|
new(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Role, "Admin") }, "test"));
|
|
}
|