namespace ProtoTest.Demo; using System.Globalization; using System.Net; using global::NUnit.Framework; using Northstar.ProtoTest; using ProtoTest.Core; using ProtoTest.Data; using ProtoTest.Http; using ProtoTest.Messaging; using ProtoTest.NUnit; using ProtoTest.Rest; using ProtoTest.SampleApp.Contracts; using ProtoTest.SampleApp.Domain; using ProtoTest.Web; /// /// The application publishes invoice.paid when an invoice is paid; the test awaits that event on /// its own tap queue. Without a configured broker the capability is absent and the journey skips, so the /// suite stays honest in every environment. /// [Application(NorthstarTargets.Api)] [NorthstarTenant(PlanIds.Growth)] [Auth] [RequiresCapability( ProtoCapabilityKinds.Broker, Reason = "No broker is configured; set ProtoTest:Messaging:RabbitMq:ConnectionString.")] public sealed class MessagingJourney { [ProtoTest] [SignedInAs] public async Task PayingAnInvoicePublishesAnInvoicePaidEvent() { // Arrange: an open invoice. var invoice = await Proto.Context.Data().IssueInvoiceAsync(); // Act: pay it over the API. using var paid = await Proto.Context.Rest() .Body(new PayInvoiceRequest(PaymentMethods.Visa)) .PostAsync("/api/v1/invoices/{invoiceId}/pay", new { invoiceId = invoice.Id }); paid.Should.HaveHttpStatus(HttpStatusCode.OK); // Assert: the application's event arrives, and it is about this invoice. var message = await Proto.Context.Messaging().AwaitAsync( "invoice.paid", candidate => candidate.Payload is not null && candidate.Payload.Contains( invoice.Id.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal), TimeSpan.FromSeconds(15)); Assert.Multiple(() => { Assert.That(message.ContentType, Is.EqualTo("application/json")); Assert.That(message.Payload, Does.Contain($"\"status\":\"{InvoiceStatuses.Paid}\"")); }); } [ProtoTest] [SignedInAs] [LoginAs("owner")] [RequiresCapability( ProtoCapabilityKinds.Server, CapabilityName = "Northstar standalone", Reason = "Paying through the console needs the standalone application.")] [RequiresConsoleBuild] public async Task PayingInTheConsolePublishesAnInvoicePaidEvent() { // Arrange: an open invoice the console can pay. var invoice = await Proto.Context.Data().IssueInvoiceAsync(); // Act: pay it on the console's billing screen. var billing = Proto.Context.Web().Page(); await billing.OpenAsync("/console/billing"); var row = billing.Invoice(invoice.Number); await row.Status.Should.HaveTextAsync("Open", NorthstarConsole.Wait); await row.Pay.ClickAsync(); await row.Status.Should.HaveTextAsync("Paid", NorthstarConsole.Wait); // Assert: the browser payment published the event the test awaits on the broker. var message = await Proto.Context.Messaging().AwaitAsync( "invoice.paid", candidate => candidate.Payload is not null && candidate.Payload.Contains( invoice.Id.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal), TimeSpan.FromSeconds(15)); Assert.Multiple(() => { Assert.That(message.ContentType, Is.EqualTo("application/json")); Assert.That(message.Payload, Does.Contain($"\"status\":\"{InvoiceStatuses.Paid}\"")); }); } }