From 0ce97cdec84c7b35c7b3988f79b28166ce456645 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Mon, 2 Feb 2026 13:33:23 -0600 Subject: [PATCH] tests(api): add integration test for happy path when logging in --- src/FiscalOS.API/Login/Endpoint.cs | 2 - src/FiscalOS.API/Login/Response.cs | 6 +++ src/FiscalOS.API/Usings.cs | 2 + src/FiscalOS.Infra/Data/AppDbContext.cs | 2 - src/FiscalOS.Infra/Usings.cs | 1 + tests/FiscalOS.API.Tests/Infra/TestApi.cs | 18 ++++++++- .../Integration/LoginTests.cs | 38 ++++++++++++++++--- tests/FiscalOS.API.Tests/Usings.cs | 2 + .../Unit/TokenGeneratorTests.cs | 3 -- tests/FiscalOS.Infra.Tests/Usings.cs | 5 ++- 10 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/FiscalOS.API/Login/Endpoint.cs b/src/FiscalOS.API/Login/Endpoint.cs index 3f85d9c..211e240 100644 --- a/src/FiscalOS.API/Login/Endpoint.cs +++ b/src/FiscalOS.API/Login/Endpoint.cs @@ -1,5 +1,3 @@ -using FiscalOS.Core.Authentication; - namespace FiscalOS.API.Login; internal static class Endpoint diff --git a/src/FiscalOS.API/Login/Response.cs b/src/FiscalOS.API/Login/Response.cs index 93965e9..0a8115c 100644 --- a/src/FiscalOS.API/Login/Response.cs +++ b/src/FiscalOS.API/Login/Response.cs @@ -4,6 +4,12 @@ internal sealed record Response { public string AccessToken { get; init; } + [JsonConstructor] + private Response() + { + AccessToken = string.Empty; + } + private Response(string accessToken) { AccessToken = accessToken; diff --git a/src/FiscalOS.API/Usings.cs b/src/FiscalOS.API/Usings.cs index 3edd5b1..2116758 100644 --- a/src/FiscalOS.API/Usings.cs +++ b/src/FiscalOS.API/Usings.cs @@ -1,6 +1,8 @@ global using System.ComponentModel.DataAnnotations; +global using System.Text.Json.Serialization; global using FiscalOS.API.Login; +global using FiscalOS.Core.Authentication; global using FiscalOS.Infra.Data; global using FiscalOS.Infra.DependencyInjection; diff --git a/src/FiscalOS.Infra/Data/AppDbContext.cs b/src/FiscalOS.Infra/Data/AppDbContext.cs index 3975671..1858447 100644 --- a/src/FiscalOS.Infra/Data/AppDbContext.cs +++ b/src/FiscalOS.Infra/Data/AppDbContext.cs @@ -1,5 +1,3 @@ -using FiscalOS.Core.Data; - namespace FiscalOS.Infra.Data; public sealed class AppDbContext(IOptions ctxOptions) : DbContext diff --git a/src/FiscalOS.Infra/Usings.cs b/src/FiscalOS.Infra/Usings.cs index a462788..9a6d388 100644 --- a/src/FiscalOS.Infra/Usings.cs +++ b/src/FiscalOS.Infra/Usings.cs @@ -4,6 +4,7 @@ global using System.Security.Cryptography; global using System.Text; global using FiscalOS.Core.Authentication; +global using FiscalOS.Core.Data; global using FiscalOS.Core.Identity; global using FiscalOS.Infra.Authentication; global using FiscalOS.Infra.Data; diff --git a/tests/FiscalOS.API.Tests/Infra/TestApi.cs b/tests/FiscalOS.API.Tests/Infra/TestApi.cs index 8ee18b4..d854123 100644 --- a/tests/FiscalOS.API.Tests/Infra/TestApi.cs +++ b/tests/FiscalOS.API.Tests/Infra/TestApi.cs @@ -1,3 +1,7 @@ +using System.Security.Cryptography; + +using FiscalOS.Infra.Authentication; + namespace FiscalOS.API.Tests.Infra; public class TestApi : WebApplicationFactory @@ -10,12 +14,22 @@ public class TestApi : WebApplicationFactory builder.ConfigureTestServices(static c => { - var opts = Options.Create(new AppDbContextOptions() + var dbOpts = Options.Create(new AppDbContextOptions() { DatabaseFilePath = $"{Guid.NewGuid()}.db", }); - c.AddSingleton(opts); + c.AddSingleton(dbOpts); + + var jwtOpts = Options.Create(new JwtOptions() + { + Issuer = "TestIssuer", + Audience = "TestAudience", + Secret = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32)), + ExpiryInMinutes = 5, + }); + + c.AddSingleton(jwtOpts); }); } } \ No newline at end of file diff --git a/tests/FiscalOS.API.Tests/Integration/LoginTests.cs b/tests/FiscalOS.API.Tests/Integration/LoginTests.cs index 17b8bb1..5b5582e 100644 --- a/tests/FiscalOS.API.Tests/Integration/LoginTests.cs +++ b/tests/FiscalOS.API.Tests/Integration/LoginTests.cs @@ -1,6 +1,3 @@ -using FiscalOS.Core.Authentication; -using FiscalOS.Core.Identity; - namespace FiscalOS.API.Tests.Integration; public class LoginTests(TestApi testApi) : IntegrationTest(testApi) @@ -17,9 +14,6 @@ public class LoginTests(TestApi testApi) : IntegrationTest(testApi) var res = await Client.PostAsJsonAsync("/login", req, TestContext.Current.CancellationToken); - var content = await res.Content.ReadAsStringAsync(TestContext.Current.CancellationToken); - Console.WriteLine(content); - res.StatusCode.Should().Be(HttpStatusCode.BadRequest); var problem = await res.Content.ReadFromJsonAsync(TestContext.Current.CancellationToken); @@ -63,6 +57,38 @@ public class LoginTests(TestApi testApi) : IntegrationTest(testApi) res.StatusCode.Should().Be(HttpStatusCode.Unauthorized); } + + [Fact] + public async Task Login_WhenUserExistsAndPasswordIsCorrect_ItShouldReturn200WithJwtToken() + { + await ExecuteDbContextAsync(static async (context, sp) => + { + var passwordHasher = sp.GetRequiredService(); + + context.Add(User.From("Stevan", passwordHasher.Hash("@Password1"))); + + await context.SaveChangesAsync(TestContext.Current.CancellationToken); + }); + + var req = new + { + username = "Stevan", + password = "@Password1", + }; + + var res = await Client.PostAsJsonAsync("/login", req, TestContext.Current.CancellationToken); + + res.StatusCode.Should().Be(HttpStatusCode.OK); + + + var content = await res.Content.ReadFromJsonAsync(TestContext.Current.CancellationToken); + + content!.AccessToken.Should().NotBeNullOrEmpty(); + + res.Headers.TryGetValues("Set-Cookie", out var cookies).Should().BeTrue(); + + cookies.Should().NotBeNull(); + } } diff --git a/tests/FiscalOS.API.Tests/Usings.cs b/tests/FiscalOS.API.Tests/Usings.cs index aa25f2f..d10c88a 100644 --- a/tests/FiscalOS.API.Tests/Usings.cs +++ b/tests/FiscalOS.API.Tests/Usings.cs @@ -2,6 +2,8 @@ global using System.Net; global using System.Net.Http.Json; global using FiscalOS.API.Tests.Infra; +global using FiscalOS.Core.Authentication; +global using FiscalOS.Core.Identity; global using FiscalOS.Infra.Data; global using Microsoft.AspNetCore.Hosting; diff --git a/tests/FiscalOS.Infra.Tests/Unit/TokenGeneratorTests.cs b/tests/FiscalOS.Infra.Tests/Unit/TokenGeneratorTests.cs index 1f23d9a..c308f3d 100644 --- a/tests/FiscalOS.Infra.Tests/Unit/TokenGeneratorTests.cs +++ b/tests/FiscalOS.Infra.Tests/Unit/TokenGeneratorTests.cs @@ -1,6 +1,3 @@ -using System.Globalization; -using System.Security.Cryptography; - namespace FiscalOS.Infra.Tests.Unit; public class TokenGeneratorTests diff --git a/tests/FiscalOS.Infra.Tests/Usings.cs b/tests/FiscalOS.Infra.Tests/Usings.cs index 2e623ad..fe94bed 100644 --- a/tests/FiscalOS.Infra.Tests/Usings.cs +++ b/tests/FiscalOS.Infra.Tests/Usings.cs @@ -1,8 +1,11 @@ +global using System.Globalization; global using System.IdentityModel.Tokens.Jwt; +global using System.Security.Cryptography; + global using AwesomeAssertions.Primitives; global using FiscalOS.Core.Identity; global using FiscalOS.Infra.Authentication; global using FiscalOS.Infra.Tests.Assertions; -global using Microsoft.Extensions.Options; +global using Microsoft.Extensions.Options; \ No newline at end of file