namespace HrynCo.NotificationService.Services.Tests.EmailProcessing; using System.Text.Json; using HrynCo.NotificationService.Contracts.Messages; using HrynCo.NotificationService.Worker.Services.EmailProcessing; public sealed class SendEmailContractTests { private const string ItemTrackerPayload = """ { "CorrelationContext": { "CorrelationId": "3ec4ad3f-0a8a-49f3-b31d-cdad5d1b95cc", "ReplyTo": "item-tracker.notifications.result" }, "Data": { "ServiceName": "StoreMate-Prod", "TemplateKey": "EmailVerification", "RecipientEmail": "owner@example.com", "RecipientName": "StoreMate Owner", "Variables": { "AppName": "StoreMate", "VerificationUrl": "https://example.invalid/sensitive-token" }, "LanguageCode": "uk" } } """; [Fact] public void PascalCaseItemTrackerPayload_DeserializesWithoutLosingValues() { SendEmailMessage? message = JsonSerializer.Deserialize(ItemTrackerPayload); Assert.NotNull(message); SendEmailMessageValidator.Validate(message); Assert.Equal("3ec4ad3f-0a8a-49f3-b31d-cdad5d1b95cc", message.CorrelationContext.CorrelationId); Assert.Equal("item-tracker.notifications.result", message.CorrelationContext.ReplyTo); Assert.Equal("StoreMate-Prod", message.Data.ServiceName); Assert.Equal("EmailVerification", message.Data.TemplateKey); Assert.Equal("owner@example.com", message.Data.RecipientEmail); Assert.Equal("StoreMate Owner", message.Data.RecipientName); Assert.Equal("uk", message.Data.LanguageCode); Assert.Equal("StoreMate", message.Data.Variables["AppName"]); Assert.Equal( "https://example.invalid/sensitive-token", message.Data.Variables["VerificationUrl"]); } [Fact] public void MissingLanguageCode_IsRejected() { SendEmailMessage? message = JsonSerializer.Deserialize( ItemTrackerPayload.Replace("\"uk\"", "null", StringComparison.Ordinal)); InvalidDataException exception = Assert.Throws( () => SendEmailMessageValidator.Validate(message!)); Assert.Equal("LanguageCode is required.", exception.Message); } }