profileShare

rasmusjy / splitapp-backend-clean-onion

Read-only snapshot

No repository description.

main default branch 429 files Expires Sep 13, 2026, 9:06 AM
AccountApiIntegrationTests.cs 3,877 bytes
1 using System.Net;
2 using System.Net.Http.Headers;
3 using System.Net.Http.Json;
4 using App.DTO.v1.Identity;
5 using FluentAssertions;
6
7 namespace App.Tests.Integration;
8
9 /// <summary>
10 /// HTTP-level integration tests — real ASP.NET pipeline (controllers + auth +
11 /// EF + SQLite), only the network socket is replaced by TestServer.
12 /// </summary>
13 public class AccountApiIntegrationTests : IClassFixture<WebApiTestFactory>
14 {
15 private readonly HttpClient _client;
16
17 private readonly WebApiTestFactory _factory;
18
19 public AccountApiIntegrationTests(WebApiTestFactory factory)
20 {
21 _factory = factory;
22 _client = factory.CreateClient();
23 }
24
25 [Fact]
26 public async Task Register_NewUser_ReturnsJwtAndRefreshToken()
27 {
28 // Arrange
29 var register = new RegisterInfo
30 {
31 Email = $"int-{Guid.NewGuid():N}@test.local",
32 Password = "Test.123!",
33 Firstname = "Integration",
34 Lastname = "Tester"
35 };
36
37 // Act
38 var response = await _client.PostAsJsonAsync(
39 "/api/v1/identity/Account/Register?expiresInSeconds=3600", register);
40
41 // Assert
42 var body = await response.Content.ReadAsStringAsync();
43 response.StatusCode.Should().Be(HttpStatusCode.OK, $"server replied: {body}");
44 var jwt = await response.Content.ReadFromJsonAsync<JWTResponse>();
45 jwt.Should().NotBeNull();
46 jwt!.Jwt.Should().NotBeNullOrEmpty();
47 jwt.RefreshToken.Should().NotBeNullOrEmpty();
48 jwt.FirstName.Should().Be("Integration");
49 }
50
51 [Fact]
52 public async Task Login_AfterRegister_ReturnsJwt()
53 {
54 // Arrange — register first
55 var register = new RegisterInfo
56 {
57 Email = $"int-{Guid.NewGuid():N}@test.local",
58 Password = "Test.123!",
59 Firstname = "Login",
60 Lastname = "Tester"
61 };
62 await _client.PostAsJsonAsync(
63 "/api/v1/identity/Account/Register?expiresInSeconds=3600", register);
64
65 // Act — log in with same credentials
66 var loginResponse = await _client.PostAsJsonAsync(
67 "/api/v1/identity/Account/Login?expiresInSeconds=3600",
68 new LoginInfo { Email = register.Email, Password = register.Password });
69
70 // Assert
71 loginResponse.StatusCode.Should().Be(HttpStatusCode.OK);
72 var jwt = await loginResponse.Content.ReadFromJsonAsync<JWTResponse>();
73 jwt!.Jwt.Should().NotBeNullOrEmpty();
74 }
75
76 [Fact]
77 public async Task GetTrips_WithoutJwt_ReturnsUnauthorized()
78 {
79 // No Authorization header — protected endpoint must reject
80 var response = await _client.GetAsync("/api/v1/Trips");
81
82 response.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
83 }
84
85 [Fact]
86 public async Task GetTrips_WithValidJwt_ReturnsEmptyListForFreshUser()
87 {
88 // Arrange — register, get JWT, attach as Bearer
89 var register = new RegisterInfo
90 {
91 Email = $"int-{Guid.NewGuid():N}@test.local",
92 Password = "Test.123!",
93 Firstname = "Trips",
94 Lastname = "Tester"
95 };
96 var registerResp = await _client.PostAsJsonAsync(
97 "/api/v1/identity/Account/Register?expiresInSeconds=3600", register);
98 var jwt = (await registerResp.Content.ReadFromJsonAsync<JWTResponse>())!.Jwt;
99
100 // Use factory.CreateClient() — that gives an HttpClient pointed at TestServer.
101 // Don't `new HttpClient`, that would try real localhost:80.
102 var authClient = _factory.CreateClient();
103 authClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwt);
104
105 // Act
106 var response = await authClient.GetAsync("/api/v1/Trips");
107
108 // Assert
109 response.StatusCode.Should().Be(HttpStatusCode.OK);
110 }
111 }
112