using JobTrackerApi.Models;
using JobTrackerApi.Services;
using Xunit;
namespace JobTrackerApi.Tests;
// Regression safety net for the renderer ahead of the theme-extraction work in
// career-workspace-implementation-roadmap.md Phase F3. The renderer had zero test coverage;
// these tests lock in "renders without throwing, is deterministic, and contains the content it
// was given" for every shipped template so a future refactor (or accidental edit) that changes
// output is caught immediately.
public sealed class CvTemplateRendererTests
{
private static readonly string[] AllTemplateIds = { "ats-minimal", "harvard", "auckland", "edinburgh", "monarch", "fjord" };
private readonly CvTemplateRenderer _renderer = new();
private static TailoredCvDocument SampleDocument(string templateId) => new()
{
TemplateId = templateId,
Headline = "Senior Backend Engineer",
Summary = { "Builds reliable distributed systems." },
SelectedSkills = { "C#", ".NET", "SQL" },
Experience =
{
new TailoredCvExperienceItem
{
Title = "Backend Engineer",
Company = "Acme Corp",
Start = "2020",
End = "Present",
IsCurrent = true,
Bullets = { "Shipped the payments service." },
},
},
Education =
{
new TailoredCvEducationItem { Qualification = "BSc Computer Science", Institution = "Example University" },
},
};
[Theory]
[MemberData(nameof(TemplateIds))]
public void Render_produces_html_containing_candidate_and_content(string templateId)
{
var result = _renderer.Render(SampleDocument(templateId), templateId, "Jamie Rivera", "Backend Engineer", "Acme Corp");
Assert.Equal(templateId, result.TemplateId);
Assert.Contains("Jamie Rivera", result.Html);
Assert.Contains("Acme Corp", result.Html);
Assert.Contains("Shipped the payments service.", result.Html);
Assert.Contains("", result.Html);
}
[Theory]
[MemberData(nameof(TemplateIds))]
public void Render_is_deterministic_for_identical_input(string templateId)
{
var a = _renderer.Render(SampleDocument(templateId), templateId, "Jamie Rivera", "Backend Engineer", "Acme Corp");
var b = _renderer.Render(SampleDocument(templateId), templateId, "Jamie Rivera", "Backend Engineer", "Acme Corp");
Assert.Equal(a.Html, b.Html);
}
[Fact]
public void Unknown_template_id_falls_back_to_ats_minimal()
{
var result = _renderer.Render(SampleDocument("unknown"), "not-a-real-template", "Jamie Rivera", "Backend Engineer", null);
Assert.Equal("ats-minimal", result.TemplateId);
}
[Fact]
public void Html_encodes_user_supplied_content_to_prevent_injection()
{
var document = SampleDocument("ats-minimal");
document.Summary[0] = "";
var result = _renderer.Render(document, "ats-minimal", "Jamie Rivera", "Backend Engineer", null);
Assert.DoesNotContain("", result.Html);
Assert.Contains("<script>", result.Html);
}
public static IEnumerable