Files
PowderCoatingLogix/tests/PowderCoating.UnitTests/EmailBroadcastControllerTests.cs
T

204 lines
7.4 KiB
C#

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using PowderCoating.Application.Interfaces;
using PowderCoating.Core.Entities;
using PowderCoating.Core.Enums;
using PowderCoating.Infrastructure.Data;
using PowderCoating.Shared.Constants;
using PowderCoating.Web.Controllers;
namespace PowderCoating.UnitTests;
public class EmailBroadcastControllerTests
{
[Fact]
public async Task Preview_RendersMergedSampleAndSanitizesHtml()
{
await using var context = CreateContext();
context.Companies.Add(new Company
{
Id = 7,
CompanyId = 7,
CompanyName = "River City Powder",
PrimaryContactName = "Jamie Rivera",
PrimaryContactEmail = "jamie@example.com",
IsActive = true
});
context.Users.Add(new ApplicationUser
{
Id = "admin-7",
CompanyId = 7,
CompanyRole = AppConstants.CompanyRoles.CompanyAdmin,
FirstName = "Alex",
LastName = "Admin",
Email = "alex@example.com",
UserName = "alex@example.com",
IsActive = true
});
await context.SaveChangesAsync();
var controller = CreateController(context);
var result = await controller.Preview(new AdminEmailSelectionModel
{
Subject = "Update for {{CompanyName}}",
BodyHtml = "<p>Hi {{FirstName}}, contact {{CompanyAdminName}} at {{CompanyAdminEmail}}.</p><script>alert('x')</script>",
CompanyIds = [7]
});
var view = Assert.IsType<ViewResult>(result);
var model = Assert.IsType<AdminEmailPreviewModel>(view.Model);
Assert.Equal("Update for River City Powder", model.SamplePreview.RenderedSubject);
Assert.Contains("Hi Jamie", model.SamplePreview.RenderedHtmlBody);
Assert.Contains("Alex Admin", model.SamplePreview.RenderedHtmlBody);
Assert.Contains("alex@example.com", model.SamplePreview.RenderedHtmlBody);
Assert.DoesNotContain("<script", model.SamplePreview.RenderedHtmlBody, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public async Task Send_WhenEmailSucceeds_WritesAdminEmailLogAndUsesPlatformReplyTo()
{
await using var context = CreateContext();
context.Companies.Add(new Company
{
Id = 11,
CompanyId = 11,
CompanyName = "Summit Coatings",
PrimaryContactName = "Morgan Lee",
PrimaryContactEmail = "morgan@example.com",
IsActive = true
});
await context.SaveChangesAsync();
var emailService = new Mock<IEmailService>();
emailService
.Setup(x => x.SendEmailAsync(
"morgan@example.com",
"Morgan Lee",
"Notice for Summit Coatings",
It.IsAny<string>(),
It.IsAny<string>(),
null,
null,
null,
"admin-notify@example.com",
"Powder Coating Logix Admin"))
.ReturnsAsync((true, (string?)null));
var platformSettings = new Mock<IPlatformSettingsService>();
platformSettings
.Setup(x => x.GetAsync(PlatformSettingKeys.AdminNotificationEmail))
.ReturnsAsync("admin-notify@example.com,backup@example.com");
var controller = CreateController(context, emailService, platformSettings);
var result = await controller.Send(new AdminEmailSendRequest
{
Subject = "Notice for {{CompanyName}}",
BodyHtml = "<p>Hello {{FirstName}},</p><p>Thanks for using {{CompanyName}}.</p>",
CompanyIds = [11]
});
var redirect = Assert.IsType<RedirectToActionResult>(result);
Assert.Equal("Index", redirect.ActionName);
var log = await context.NotificationLogs.IgnoreQueryFilters().SingleAsync();
Assert.Equal(NotificationType.AdminEmail, log.NotificationType);
Assert.Equal(NotificationStatus.Sent, log.Status);
Assert.Equal("morgan@example.com", log.Recipient);
Assert.Equal("Notice for Summit Coatings", log.Subject);
Assert.Contains("Hello Morgan", log.Message);
emailService.VerifyAll();
}
[Fact]
public async Task Send_WhenPrimaryContactEmailMissing_WritesSkippedLogWithoutSending()
{
await using var context = CreateContext();
context.Companies.Add(new Company
{
Id = 13,
CompanyId = 13,
CompanyName = "No Inbox Inc",
PrimaryContactName = "Taylor Noemail",
PrimaryContactEmail = string.Empty,
IsActive = true
});
await context.SaveChangesAsync();
var emailService = new Mock<IEmailService>();
var controller = CreateController(context, emailService);
var result = await controller.Send(new AdminEmailSendRequest
{
Subject = "Heads up for {{CompanyName}}",
BodyHtml = "<p>Hello {{FirstName}}</p>",
CompanyIds = [13]
});
var redirect = Assert.IsType<RedirectToActionResult>(result);
Assert.Equal("Index", redirect.ActionName);
var log = await context.NotificationLogs.IgnoreQueryFilters().SingleAsync();
Assert.Equal(NotificationType.AdminEmail, log.NotificationType);
Assert.Equal(NotificationStatus.Skipped, log.Status);
Assert.Equal(string.Empty, log.Recipient);
Assert.Equal("Company primary contact email is not configured.", log.ErrorMessage);
emailService.Verify(
x => x.SendEmailAsync(
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string>(),
It.IsAny<string?>(),
It.IsAny<byte[]?>(),
It.IsAny<string?>(),
It.IsAny<string?>(),
It.IsAny<string?>(),
It.IsAny<string?>()),
Times.Never);
}
private static EmailBroadcastController CreateController(
ApplicationDbContext context,
Mock<IEmailService>? emailService = null,
Mock<IPlatformSettingsService>? platformSettings = null)
{
var controller = new EmailBroadcastController(
context,
(emailService ?? new Mock<IEmailService>()).Object,
(platformSettings ?? CreatePlatformSettings()).Object,
Mock.Of<ILogger<EmailBroadcastController>>());
var httpContext = new DefaultHttpContext();
controller.ControllerContext = new ControllerContext
{
HttpContext = httpContext
};
controller.TempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
return controller;
}
private static Mock<IPlatformSettingsService> CreatePlatformSettings()
{
var settings = new Mock<IPlatformSettingsService>();
settings.Setup(x => x.GetAsync(It.IsAny<string>())).ReturnsAsync((string?)null);
return settings;
}
private static ApplicationDbContext CreateContext()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
return new ApplicationDbContext(options);
}
}