Files
jobtrackingapp/JobTrackerApi.Tests/EmailDraftPersistenceTests.cs
T
cesnimda 14b396a452
CI and Deploy / test (pull_request) Successful in 4m15s
CI and Deploy / deploy (pull_request) Has been skipped
feat(email): add tenant draft persistence
Add owner-filtered, job-cascading private draft storage with reversible SQLite and MariaDB migration paths. No API or UI exposes draft content yet.
2026-08-10 09:55:16 +02:00

78 lines
3.2 KiB
C#

using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Moq;
using Xunit;
namespace JobTrackerApi.Tests;
public sealed class EmailDraftPersistenceTests
{
[Fact]
public async Task Drafts_are_owner_filtered_and_follow_the_owned_job_lifecycle()
{
await using var connection = new SqliteConnection("Data Source=:memory:");
await connection.OpenAsync();
var options = new DbContextOptionsBuilder<JobTrackerContext>().UseSqlite(connection).Options;
int userOneJobId;
int userTwoJobId;
await using (var seed = Context(options, null))
{
await seed.Database.EnsureCreatedAsync();
var companyOne = new Company { Name = "One", OwnerUserId = "user-1" };
var companyTwo = new Company { Name = "Two", OwnerUserId = "user-2" };
seed.Companies.AddRange(companyOne, companyTwo);
await seed.SaveChangesAsync();
var jobOne = new JobApplication { JobTitle = "Role one", CompanyId = companyOne.Id, OwnerUserId = "user-1" };
var jobTwo = new JobApplication { JobTitle = "Role two", CompanyId = companyTwo.Id, OwnerUserId = "user-2" };
seed.JobApplications.AddRange(jobOne, jobTwo);
await seed.SaveChangesAsync();
userOneJobId = jobOne.Id;
userTwoJobId = jobTwo.Id;
seed.EmailDrafts.AddRange(
Draft("user-1", jobOne.Id, "one@example.test"),
Draft("user-2", jobTwo.Id, "two@example.test"));
await seed.SaveChangesAsync();
}
await using (var userOne = Context(options, "user-1"))
{
var visible = Assert.Single(await userOne.EmailDrafts.AsNoTracking().ToListAsync());
Assert.Equal(userOneJobId, visible.JobApplicationId);
Assert.Equal("one@example.test", visible.To);
var job = await userOne.JobApplications.SingleAsync(item => item.Id == userOneJobId);
userOne.JobApplications.Remove(job);
await userOne.SaveChangesAsync();
}
await using var verify = Context(options, null);
var remaining = Assert.Single(await verify.EmailDrafts.IgnoreQueryFilters().AsNoTracking().ToListAsync());
Assert.Equal("user-2", remaining.OwnerUserId);
Assert.Equal(userTwoJobId, remaining.JobApplicationId);
}
private static EmailDraft Draft(string ownerUserId, int jobApplicationId, string recipient) => new()
{
Id = Guid.NewGuid(),
OwnerUserId = ownerUserId,
JobApplicationId = jobApplicationId,
Provider = "gmail",
To = recipient,
Subject = "Synthetic draft",
BodyText = "Synthetic private draft body.",
ThreadId = "thread-1",
CreatedAtUtc = DateTime.UtcNow,
UpdatedAtUtc = DateTime.UtcNow,
};
private static JobTrackerContext Context(DbContextOptions<JobTrackerContext> options, string? userId)
{
var currentUser = new Mock<ICurrentUserService>();
currentUser.SetupGet(service => service.UserId).Returns(userId);
return new JobTrackerContext(options, currentUser.Object);
}
}