128 lines
7.2 KiB
C#
128 lines
7.2 KiB
C#
using System.Security.Claims;
|
|
using JobTrackerApi.Controllers;
|
|
using JobTrackerApi.Data;
|
|
using JobTrackerApi.Models;
|
|
using JobTrackerApi.Services;
|
|
using JobTrackerApi.Tests.TestSupport;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace JobTrackerApi.Tests;
|
|
|
|
public sealed class CoverLetterThemeEntitlementTests
|
|
{
|
|
[Theory]
|
|
[InlineData("save")]
|
|
[InlineData("preview")]
|
|
[InlineData("restore")]
|
|
public async Task Free_user_cannot_activate_a_premium_version_two_letter_through_any_design_writer(string action)
|
|
{
|
|
var (db, job, controller, _) = await Fixture();
|
|
await using var dispose = db;
|
|
var premium = new CoverLetterDocumentSettings { ThemeId = "executive", DesignVersion = 2 };
|
|
db.CoverLetterVersions.Add(new CoverLetterVersion { OwnerUserId = "owner", JobApplicationId = job.Id, Version = 1,
|
|
Text = "Historical premium", Source = CoverLetterSources.Manual, DocumentSettingsJson = CoverLetterDocumentSettingsJson.Serialize(premium) });
|
|
await db.SaveChangesAsync();
|
|
var response = action switch
|
|
{
|
|
"preview" => (await controller.PreviewCoverLetter(job.Id, new("Reviewed text", premium), default)).Result,
|
|
"restore" => (await controller.RestoreCoverLetter(job.Id, 1, new(job.Version), default)).Result,
|
|
_ => (await controller.SaveCoverLetter(job.Id, new("Reviewed text", "manual", null, job.Version, premium), default)).Result,
|
|
};
|
|
Assert.Equal(403, Assert.IsAssignableFrom<ObjectResult>(response).StatusCode);
|
|
Assert.Null(job.CoverLetterDocumentSettingsJson);
|
|
Assert.Null(job.CoverLetterText);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Shared_service_rejects_premium_design_before_changing_letter_or_history()
|
|
{
|
|
var (db, job, _, service) = await Fixture();
|
|
await using var dispose = db;
|
|
await Assert.ThrowsAsync<CoverLetterThemeAccessException>(() => service.SaveCoverLetterAsync("owner", job.Id, "Unsaved", "manual", null,
|
|
job.Version, default, new() { DesignVersion = 2, ThemeId = "technical" }));
|
|
Assert.Null(job.CoverLetterText);
|
|
Assert.Null(job.CoverLetterDocumentSettingsJson);
|
|
Assert.Empty(db.CoverLetterVersions);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData(1)]
|
|
public async Task Legacy_letter_metadata_remains_editable_and_previewable_for_free_users(int? designVersion)
|
|
{
|
|
var (db, job, controller, _) = await Fixture();
|
|
await using var dispose = db;
|
|
var legacy = new CoverLetterDocumentSettings { ThemeId = "executive", DesignVersion = designVersion };
|
|
Assert.IsType<OkObjectResult>((await controller.PreviewCoverLetter(job.Id, new("Legacy text", legacy), default)).Result);
|
|
Assert.IsType<OkObjectResult>((await controller.SaveCoverLetter(job.Id, new("Legacy text", "manual", null, job.Version, legacy), default)).Result);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Premium_account_can_save_and_preview_a_new_premium_letter_design()
|
|
{
|
|
var (db, job, controller, service) = await Fixture(premium: true);
|
|
await using var dispose = db;
|
|
var design = new CoverLetterDocumentSettings { ThemeId = "technical", DesignVersion = 2 };
|
|
Assert.IsType<OkObjectResult>((await controller.PreviewCoverLetter(job.Id, new("Reviewed text", design), default)).Result);
|
|
Assert.IsType<OkObjectResult>((await controller.SaveCoverLetter(job.Id, new("Reviewed text", "manual", null, job.Version, design), default)).Result);
|
|
Assert.NotNull(await service.RenderSavedCoverLetterAsync("owner", job.Id, job.Version, default));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Downgraded_account_keeps_current_premium_design_but_cannot_switch_to_another_premium_design()
|
|
{
|
|
var (db, job, controller, service) = await Fixture();
|
|
await using var dispose = db;
|
|
var stored = new CoverLetterDocumentSettings { ThemeId = "executive", DesignVersion = 2 };
|
|
job.CoverLetterDocumentSettingsJson = CoverLetterDocumentSettingsJson.Serialize(stored);
|
|
job.CoverLetterText = "Stored premium text";
|
|
await db.SaveChangesAsync();
|
|
Assert.NotNull(await service.GetCoverLetterAsync("owner", job.Id, default));
|
|
Assert.NotNull(await service.RenderSavedCoverLetterAsync("owner", job.Id, job.Version, default));
|
|
Assert.IsType<OkObjectResult>((await controller.PreviewCoverLetter(job.Id, new("Text edit", stored), default)).Result);
|
|
Assert.IsType<OkObjectResult>((await controller.SaveCoverLetter(job.Id, new("Text edit", "manual", null, job.Version, stored), default)).Result);
|
|
var different = new CoverLetterDocumentSettings { ThemeId = "technical", DesignVersion = 2 };
|
|
Assert.Equal(403, Assert.IsAssignableFrom<ObjectResult>((await controller.PreviewCoverLetter(job.Id, new("Text edit", different), default)).Result).StatusCode);
|
|
Assert.Equal(403, Assert.IsAssignableFrom<ObjectResult>((await controller.SaveCoverLetter(job.Id, new("Text edit", "manual", null, job.Version, different), default)).Result).StatusCode);
|
|
Assert.Equal("executive", CoverLetterDocumentSettingsJson.Deserialize(job.CoverLetterDocumentSettingsJson).ThemeId);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Foreign_application_remains_not_found_before_entitlement_checks()
|
|
{
|
|
var (db, job, controller, _) = await Fixture();
|
|
await using var dispose = db;
|
|
job.OwnerUserId = "other";
|
|
await db.SaveChangesAsync();
|
|
var design = new CoverLetterDocumentSettings { ThemeId = "executive", DesignVersion = 2 };
|
|
Assert.IsType<NotFoundResult>((await controller.PreviewCoverLetter(job.Id, new("Foreign", design), default)).Result);
|
|
Assert.IsType<NotFoundResult>((await controller.SaveCoverLetter(job.Id, new("Foreign", "manual", null, job.Version, design), default)).Result);
|
|
}
|
|
|
|
private static async Task<(JobTrackerContext db, JobApplication job, ApplicationAssetsController controller, ApplicationAssetsService service)> Fixture(bool premium = false)
|
|
{
|
|
var db = TestHostFactory.CreateInMemoryDb("owner");
|
|
var user = new ApplicationUser { Id = "owner", UserName = "owner" };
|
|
db.Users.Add(user);
|
|
if (premium)
|
|
{
|
|
db.Roles.Add(new IdentityRole("Premium") { Id = "premium-role" });
|
|
db.UserRoles.Add(new IdentityUserRole<string> { UserId = user.Id, RoleId = "premium-role" });
|
|
}
|
|
var company = new Company { OwnerUserId = user.Id, Name = "Synthetic" };
|
|
var job = new JobApplication { OwnerUserId = user.Id, Company = company, JobTitle = "Synthetic role" };
|
|
db.JobApplications.Add(job);
|
|
await db.SaveChangesAsync();
|
|
var service = new ApplicationAssetsService(db, Mock.Of<ICvVariantService>(), Mock.Of<IApplicationIntelligenceService>());
|
|
var users = TestHostFactory.CreateUserManager();
|
|
users.Setup(manager => manager.GetUserAsync(It.IsAny<ClaimsPrincipal>())).ReturnsAsync(user);
|
|
var controller = new ApplicationAssetsController(users.Object, service, Mock.Of<ISubmittedApplicationPackageService>())
|
|
{ ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext() } };
|
|
return (db, job, controller, service);
|
|
}
|
|
}
|