diff --git a/GroundsForSupport.sln b/GroundsForSupport.sln index 37e03a0..539cc38 100644 --- a/GroundsForSupport.sln +++ b/GroundsForSupport.sln @@ -11,7 +11,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{0AB3BF05 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GroundsForSupport.Server.Tests", "GroundsForSupport.Server.Tests", "{56565355-472A-D7A5-BBD6-5A9243A600D2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GroundsForSupport.API.Tests", "tests\GroundsForSupport.Server.Tests\GroundsForSupport.API.Tests.csproj", "{73D83B11-C5BC-4C4B-82BF-2DCEE689EDDC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GroundsForSupport.Server.Tests", "tests\GroundsForSupport.Server.Tests\GroundsForSupport.Server.Tests.csproj", "{73D83B11-C5BC-4C4B-82BF-2DCEE689EDDC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/GroundsForSupport.Server/Data/ContextOptions.cs b/src/GroundsForSupport.Server/Data/ContextOptions.cs index e4eaacc..1413737 100644 --- a/src/GroundsForSupport.Server/Data/ContextOptions.cs +++ b/src/GroundsForSupport.Server/Data/ContextOptions.cs @@ -4,7 +4,7 @@ namespace GroundsForSupport.Server.Data; internal sealed record ContextOptions { - public string DatabaseFilePath { get; init; } = "GroundsForSupport.db"; + public string DatabaseFilePath { get; init; } = string.Empty; public string GetFullyQualifiedDatabasePath() { return Path.GetFullPath(DatabaseFilePath, AppContext.BaseDirectory); diff --git a/src/GroundsForSupport.Server/GroundsForSupport.Server.csproj b/src/GroundsForSupport.Server/GroundsForSupport.Server.csproj index 74aa631..da4765d 100644 --- a/src/GroundsForSupport.Server/GroundsForSupport.Server.csproj +++ b/src/GroundsForSupport.Server/GroundsForSupport.Server.csproj @@ -16,6 +16,11 @@ + + + + + diff --git a/src/GroundsForSupport.Server/Payments/Endpoints/CreatePaymentIntentEndpoint.cs b/src/GroundsForSupport.Server/Payments/Endpoints/CreatePaymentIntentEndpoint.cs index 0ac607b..ebd0505 100644 --- a/src/GroundsForSupport.Server/Payments/Endpoints/CreatePaymentIntentEndpoint.cs +++ b/src/GroundsForSupport.Server/Payments/Endpoints/CreatePaymentIntentEndpoint.cs @@ -16,7 +16,8 @@ internal static class CreatePaymentIntentEndpoint public static async Task CreatePaymentIntentHandler( Request request, - IStripeService stripeService + IStripeService stripeService, + CancellationToken cancellationToken ) { var validationErrors = request.Validate(new ValidationContext(request)); @@ -32,7 +33,8 @@ internal static class CreatePaymentIntentEndpoint request.Name, request.Amount, request.Message, - request.Email + request.Email, + cancellationToken ); if (isSuccess is false) diff --git a/src/GroundsForSupport.Server/Payments/Stripe/IStripeService.cs b/src/GroundsForSupport.Server/Payments/Stripe/IStripeService.cs index 3481c94..6575709 100644 --- a/src/GroundsForSupport.Server/Payments/Stripe/IStripeService.cs +++ b/src/GroundsForSupport.Server/Payments/Stripe/IStripeService.cs @@ -6,6 +6,7 @@ internal interface IStripeService string name, decimal amount, string? message, - string? email + string? email, + CancellationToken cancellationToken = default ); } \ No newline at end of file diff --git a/src/GroundsForSupport.Server/Payments/Stripe/StripeService.cs b/src/GroundsForSupport.Server/Payments/Stripe/StripeService.cs index 5fb57d4..59498a9 100644 --- a/src/GroundsForSupport.Server/Payments/Stripe/StripeService.cs +++ b/src/GroundsForSupport.Server/Payments/Stripe/StripeService.cs @@ -1,5 +1,3 @@ -using GroundsForSupport.Server.Data; - using Microsoft.Extensions.Options; using Stripe; @@ -15,7 +13,13 @@ internal sealed class StripeService( private readonly StripeClient _client = new(options.Value.ApiKey, httpClient: new SystemNetHttpClient(httpClient)); private readonly ILogger _logger = logger; - public async Task<(bool IsSuccess, Intent Intent)> CreatePaymentIntentAsync(string name, decimal amount, string? message, string? email) + public async Task<(bool IsSuccess, Intent Intent)> CreatePaymentIntentAsync( + string name, + decimal amount, + string? message, + string? email, + CancellationToken cancellationToken = default + ) { try { @@ -40,7 +44,7 @@ internal sealed class StripeService( createOptions.ReceiptEmail = email; } - var intent = await _client.V1.PaymentIntents.CreateAsync(createOptions); + var intent = await _client.V1.PaymentIntents.CreateAsync(createOptions, cancellationToken: cancellationToken); return (true, new Intent(intent.ClientSecret)); } diff --git a/tests/GroundsForSupport.Server.Tests/GroundsForSupport.API.Tests.csproj b/tests/GroundsForSupport.Server.Tests/GroundsForSupport.Server.Tests.csproj similarity index 95% rename from tests/GroundsForSupport.Server.Tests/GroundsForSupport.API.Tests.csproj rename to tests/GroundsForSupport.Server.Tests/GroundsForSupport.Server.Tests.csproj index 31a8799..846c685 100644 --- a/tests/GroundsForSupport.Server.Tests/GroundsForSupport.API.Tests.csproj +++ b/tests/GroundsForSupport.Server.Tests/GroundsForSupport.Server.Tests.csproj @@ -4,7 +4,7 @@ enable enable Exe - GroundsForSupport.API.Tests + GroundsForSupport.Server.Tests net10.0 @@ -29,6 +29,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/GroundsForSupport.Server.Tests/Integration/Infra/TestApi.cs b/tests/GroundsForSupport.Server.Tests/Integration/Infra/TestApi.cs index 5040b23..34890c8 100644 --- a/tests/GroundsForSupport.Server.Tests/Integration/Infra/TestApi.cs +++ b/tests/GroundsForSupport.Server.Tests/Integration/Infra/TestApi.cs @@ -1,7 +1,40 @@ +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; +using GroundsForSupport.Server.Data; +using GroundsForSupport.Server.Payments.Stripe; -namespace GroundsForSupport.API.Tests.Integration.Infra; +using System.Text.Json; +using Microsoft.Extensions.Configuration; +using System.Text; + +namespace GroundsForSupport.Server.Tests.Integration.Infra; public sealed class TestApi : WebApplicationFactory { + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + var contextOptions = new ContextOptions() + { + DatabaseFilePath = "GroundsForSupport.Test.db", + }; + + var stripeOptions = new StripeOptions() + { + ApiKey = "sk_test_12345", + }; + + var contextOptionsJson = JsonSerializer.Serialize(contextOptions); + var stripeOptionsJson = JsonSerializer.Serialize(stripeOptions); + + var configJson = $@"{{ + ""{nameof(ContextOptions)}"": {contextOptionsJson}, + ""{nameof(StripeOptions)}"": {stripeOptionsJson} + }}"; + + var config = new ConfigurationBuilder() + .AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(configJson))) + .Build(); + + builder.UseConfiguration(config); + } } \ No newline at end of file diff --git a/tests/GroundsForSupport.Server.Tests/Integration/PaymentTests.cs b/tests/GroundsForSupport.Server.Tests/Integration/PaymentTests.cs index 9889f4c..dbfbe2a 100644 --- a/tests/GroundsForSupport.Server.Tests/Integration/PaymentTests.cs +++ b/tests/GroundsForSupport.Server.Tests/Integration/PaymentTests.cs @@ -1,7 +1,14 @@ using System.Net; using System.Net.Http.Json; -using GroundsForSupport.API.Tests.Integration.Infra; +using GroundsForSupport.Server.Payments; +using GroundsForSupport.Server.Payments.Stripe; +using GroundsForSupport.Server.Tests.Integration.Infra; + +using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; + +using Moq; [assembly: CaptureConsole] @@ -50,7 +57,26 @@ public sealed class PaymentTests(TestApi api) : IClassFixture [Fact] public async Task CreatePaymentIntent_WhenGivenValidRequest_ItShouldReturnCreated() { - var client = _api.CreateClient(); + var mockStripeService = new Mock(); + + mockStripeService + .Setup(s => s.CreatePaymentIntentAsync( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny() + ) + ) + .ReturnsAsync((true, new Intent("pi_12345_secret_67890"))); + + var api = _api.WithWebHostBuilder( + b => b.ConfigureTestServices( + s => s.AddSingleton(mockStripeService.Object) + ) + ); + + var client = api.CreateClient(); var request = new {