tests(api): add integration test for happy path when logging in
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
using FiscalOS.Core.Authentication;
|
|
||||||
|
|
||||||
namespace FiscalOS.API.Login;
|
namespace FiscalOS.API.Login;
|
||||||
|
|
||||||
internal static class Endpoint
|
internal static class Endpoint
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ internal sealed record Response
|
|||||||
{
|
{
|
||||||
public string AccessToken { get; init; }
|
public string AccessToken { get; init; }
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
private Response()
|
||||||
|
{
|
||||||
|
AccessToken = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
private Response(string accessToken)
|
private Response(string accessToken)
|
||||||
{
|
{
|
||||||
AccessToken = accessToken;
|
AccessToken = accessToken;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
global using System.ComponentModel.DataAnnotations;
|
global using System.ComponentModel.DataAnnotations;
|
||||||
|
global using System.Text.Json.Serialization;
|
||||||
|
|
||||||
global using FiscalOS.API.Login;
|
global using FiscalOS.API.Login;
|
||||||
|
global using FiscalOS.Core.Authentication;
|
||||||
global using FiscalOS.Infra.Data;
|
global using FiscalOS.Infra.Data;
|
||||||
global using FiscalOS.Infra.DependencyInjection;
|
global using FiscalOS.Infra.DependencyInjection;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using FiscalOS.Core.Data;
|
|
||||||
|
|
||||||
namespace FiscalOS.Infra.Data;
|
namespace FiscalOS.Infra.Data;
|
||||||
|
|
||||||
public sealed class AppDbContext(IOptions<AppDbContextOptions> ctxOptions) : DbContext
|
public sealed class AppDbContext(IOptions<AppDbContextOptions> ctxOptions) : DbContext
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ global using System.Security.Cryptography;
|
|||||||
global using System.Text;
|
global using System.Text;
|
||||||
|
|
||||||
global using FiscalOS.Core.Authentication;
|
global using FiscalOS.Core.Authentication;
|
||||||
|
global using FiscalOS.Core.Data;
|
||||||
global using FiscalOS.Core.Identity;
|
global using FiscalOS.Core.Identity;
|
||||||
global using FiscalOS.Infra.Authentication;
|
global using FiscalOS.Infra.Authentication;
|
||||||
global using FiscalOS.Infra.Data;
|
global using FiscalOS.Infra.Data;
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
using FiscalOS.Infra.Authentication;
|
||||||
|
|
||||||
namespace FiscalOS.API.Tests.Infra;
|
namespace FiscalOS.API.Tests.Infra;
|
||||||
|
|
||||||
public class TestApi : WebApplicationFactory<Program>
|
public class TestApi : WebApplicationFactory<Program>
|
||||||
@@ -10,12 +14,22 @@ public class TestApi : WebApplicationFactory<Program>
|
|||||||
|
|
||||||
builder.ConfigureTestServices(static c =>
|
builder.ConfigureTestServices(static c =>
|
||||||
{
|
{
|
||||||
var opts = Options.Create(new AppDbContextOptions()
|
var dbOpts = Options.Create(new AppDbContextOptions()
|
||||||
{
|
{
|
||||||
DatabaseFilePath = $"{Guid.NewGuid()}.db",
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
using FiscalOS.Core.Authentication;
|
|
||||||
using FiscalOS.Core.Identity;
|
|
||||||
|
|
||||||
namespace FiscalOS.API.Tests.Integration;
|
namespace FiscalOS.API.Tests.Integration;
|
||||||
|
|
||||||
public class LoginTests(TestApi testApi) : IntegrationTest(testApi)
|
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 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);
|
res.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||||
|
|
||||||
var problem = await res.Content.ReadFromJsonAsync<ValidationProblemDetails>(TestContext.Current.CancellationToken);
|
var problem = await res.Content.ReadFromJsonAsync<ValidationProblemDetails>(TestContext.Current.CancellationToken);
|
||||||
@@ -63,6 +57,38 @@ public class LoginTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
|
|
||||||
res.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
|
res.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Login_WhenUserExistsAndPasswordIsCorrect_ItShouldReturn200WithJwtToken()
|
||||||
|
{
|
||||||
|
await ExecuteDbContextAsync(static async (context, sp) =>
|
||||||
|
{
|
||||||
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
|
|
||||||
|
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<Login.Response>(TestContext.Current.CancellationToken);
|
||||||
|
|
||||||
|
content!.AccessToken.Should().NotBeNullOrEmpty();
|
||||||
|
|
||||||
|
res.Headers.TryGetValues("Set-Cookie", out var cookies).Should().BeTrue();
|
||||||
|
|
||||||
|
cookies.Should().NotBeNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ global using System.Net;
|
|||||||
global using System.Net.Http.Json;
|
global using System.Net.Http.Json;
|
||||||
|
|
||||||
global using FiscalOS.API.Tests.Infra;
|
global using FiscalOS.API.Tests.Infra;
|
||||||
|
global using FiscalOS.Core.Authentication;
|
||||||
|
global using FiscalOS.Core.Identity;
|
||||||
global using FiscalOS.Infra.Data;
|
global using FiscalOS.Infra.Data;
|
||||||
|
|
||||||
global using Microsoft.AspNetCore.Hosting;
|
global using Microsoft.AspNetCore.Hosting;
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
using System.Globalization;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace FiscalOS.Infra.Tests.Unit;
|
namespace FiscalOS.Infra.Tests.Unit;
|
||||||
|
|
||||||
public class TokenGeneratorTests
|
public class TokenGeneratorTests
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
global using System.Globalization;
|
||||||
global using System.IdentityModel.Tokens.Jwt;
|
global using System.IdentityModel.Tokens.Jwt;
|
||||||
|
global using System.Security.Cryptography;
|
||||||
|
|
||||||
global using AwesomeAssertions.Primitives;
|
global using AwesomeAssertions.Primitives;
|
||||||
|
|
||||||
global using FiscalOS.Core.Identity;
|
global using FiscalOS.Core.Identity;
|
||||||
|
|||||||
Reference in New Issue
Block a user