Files
jobtrackingapp/JobTrackerApi.Tests/EmailStatusClassifierTests.cs
T
cesnimda ae3505b877 feat: deterministic email-driven status suggestions
New EmailStatusClassifier scans a message subject/body for outcome
signals (interview invite, offer, rejection) and suggests a canonical
pipeline status. Priority-ordered so a rejection that mentions the prior
interview still classifies as Rejected. Deterministic - no AI - so it is
instant, reproducible, and safe.

- GET /api/jobapplications/{id}/status-suggestion reads the job's latest
  inbound correspondence (incl. Gmail imports) and suggests a forward
  status move, suppressed when already in/past that stage
- always human-confirmed via the existing PATCH .../status
- 7 classifier unit tests + 2 endpoint integration tests; backend green (133)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 03:48:32 +02:00

62 lines
2.1 KiB
C#

using JobTrackerApi.Services;
using Xunit;
namespace JobTrackerApi.Tests;
public sealed class EmailStatusClassifierTests
{
[Fact]
public void Detects_rejection()
{
var s = EmailStatusClassifier.Classify("Your application", "Thank you for your time. Unfortunately, we have decided not to proceed with your application.");
Assert.NotNull(s);
Assert.Equal("Rejected", s!.SuggestedStatus);
}
[Fact]
public void Detects_offer()
{
var s = EmailStatusClassifier.Classify("Great news", "We are pleased to offer you the position of Backend Engineer.");
Assert.NotNull(s);
Assert.Equal("Offer", s!.SuggestedStatus);
}
[Fact]
public void Detects_interview_invite()
{
var s = EmailStatusClassifier.Classify("Next steps", "We would like to invite you to interview next week. What is your availability for a call?");
Assert.NotNull(s);
Assert.Equal("Interview", s!.SuggestedStatus);
}
[Fact]
public void Rejection_wins_over_interview_mention()
{
// A rejection email that references the interview the candidate had must classify as Rejected.
var s = EmailStatusClassifier.Classify(
"Update on your application",
"Thank you for taking the time to interview with us. Unfortunately, we will not be moving forward.");
Assert.NotNull(s);
Assert.Equal("Rejected", s!.SuggestedStatus);
}
[Fact]
public void Weak_interview_cue_is_low_confidence()
{
var s = EmailStatusClassifier.Classify("Coding challenge", "Please complete this take-home assessment.");
Assert.NotNull(s);
Assert.Equal("Interview", s!.SuggestedStatus);
Assert.Equal("low", s.Confidence);
}
[Fact]
public void Returns_null_for_neutral_email()
{
Assert.Null(EmailStatusClassifier.Classify("Re: question", "Thanks for the info, that answers my question about the parking."));
}
[Fact]
public void Handles_empty_input()
=> Assert.Null(EmailStatusClassifier.Classify(null, null));
}