diff --git a/EssentialCSharp.Web.Tests/ReferralServiceTests.cs b/EssentialCSharp.Web.Tests/ReferralServiceTests.cs new file mode 100644 index 00000000..2f99f677 --- /dev/null +++ b/EssentialCSharp.Web.Tests/ReferralServiceTests.cs @@ -0,0 +1,119 @@ +using System.Security.Claims; +using EssentialCSharp.Web.Areas.Identity.Data; +using EssentialCSharp.Web.Data; +using EssentialCSharp.Web.Extensions; +using EssentialCSharp.Web.Services.Referrals; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace EssentialCSharp.Web.Tests; + +public class ReferralServiceTests : IntegrationTestBase +{ + [Test] + public async Task EnsureReferralIdAsync_NullUser_ReturnsNull() + { + string? referralId = await InServiceScopeAsync(async services => + await services.GetRequiredService().EnsureReferralIdAsync(null)); + + await Assert.That(referralId).IsNull(); + } + + [Test] + public async Task TrackReferralAsync_ExistingReferrer_IncrementsReferralCount() + { + string userId = CreateUserId(); + string referralId = await CreateUserWithReferralIdAsync(userId); + string unrelatedUserId = CreateUserId(); + await CreateUserAsync(unrelatedUserId); + + InServiceScope(services => + services.GetRequiredService().TrackReferralAsync(referralId, null)); + + int referralCount = await GetReferralCountAsync(userId); + await Assert.That(referralCount).IsEqualTo(1); + int unrelatedReferralCount = await GetReferralCountAsync(unrelatedUserId); + await Assert.That(unrelatedReferralCount).IsEqualTo(0); + } + + [Test] + public async Task TrackReferralAsync_UserHasSameReferralId_DoesNotIncrementReferralCount() + { + string userId = CreateUserId(); + string referralId = await CreateUserWithReferralIdAsync(userId); + ClaimsPrincipal user = new(new ClaimsIdentity( + [ + new Claim(ClaimsExtensions.ReferrerIdClaimType, referralId) + ])); + + InServiceScope(services => + services.GetRequiredService().TrackReferralAsync(referralId, user)); + + int referralCount = await GetReferralCountAsync(userId); + await Assert.That(referralCount).IsEqualTo(0); + } + + [Test] + public async Task TrackReferralAsync_UnknownReferralId_DoesNotThrowOrChangeUser() + { + string userId = CreateUserId(); + await CreateUserAsync(userId); + + InServiceScope(services => + services.GetRequiredService().TrackReferralAsync("unknown", null)); + + int referralCount = await GetReferralCountAsync(userId); + await Assert.That(referralCount).IsEqualTo(0); + } + + private async Task CreateUserWithReferralIdAsync(string userId) + { + await CreateUserAsync(userId); + + return await InServiceScopeAsync(async services => + { + UserManager userManager = + services.GetRequiredService>(); + EssentialCSharpWebUser user = await userManager.FindByIdAsync(userId) + ?? throw new InvalidOperationException($"Test user '{userId}' was not created."); + + string referralId = await services.GetRequiredService() + .EnsureReferralIdAsync(user) + ?? throw new InvalidOperationException("A referral ID was not generated."); + return referralId; + }); + } + + private async Task CreateUserAsync(string userId) + { + await InServiceScopeAsync(async services => + { + UserManager userManager = + services.GetRequiredService>(); + IdentityResult result = await userManager.CreateAsync( + new EssentialCSharpWebUser + { + Id = userId, + UserName = $"{userId}@example.test", + Email = $"{userId}@example.test" + }); + if (!result.Succeeded) + { + throw new InvalidOperationException( + $"Could not create test user: {string.Join(", ", result.Errors.Select(error => error.Description))}"); + } + }); + } + + private async Task GetReferralCountAsync(string userId) + { + return await InServiceScopeAsync(async services => + await services.GetRequiredService().Users + .Where(user => user.Id == userId) + .Select(user => user.ReferralCount) + .SingleAsync()); + } + + private static string CreateUserId() => $"user-{Guid.NewGuid():N}"; +}