using System.Net; using System.Net.Http.Json; using JdeScoping.Api.Models; using JdeScoping.Core.Models; using Microsoft.AspNetCore.Mvc.Testing; using Shouldly; namespace JdeScoping.Api.IntegrationTests; /// /// Integration tests for authentication flow. /// Note: These tests require a running test server with UseFakeAuth=true /// public class AuthenticationTests : IClassFixture { private readonly TestWebApplicationFactory _factory; private readonly HttpClient _client; public AuthenticationTests(TestWebApplicationFactory factory) { _factory = factory; _client = factory.CreateClient(new WebApplicationFactoryClientOptions { HandleCookies = true, AllowAutoRedirect = false }); } [Fact] public async Task FullLoginLogoutFlow_WithCookies() { // Step 1: Login var loginRequest = new LoginRequest { Username = "testuser", Password = "testpass" }; var loginResponse = await _client.PostAsJsonAsync("/api/auth/login", loginRequest); loginResponse.StatusCode.ShouldBe(HttpStatusCode.OK); var user = await loginResponse.Content.ReadFromJsonAsync(); user.ShouldNotBeNull(); user.Username.ShouldBe("testuser"); // Step 2: Verify we can access protected endpoint var meResponse = await _client.GetAsync("/api/auth/me"); meResponse.StatusCode.ShouldBe(HttpStatusCode.OK); var meUser = await meResponse.Content.ReadFromJsonAsync(); meUser.ShouldNotBeNull(); meUser.Username.ShouldBe("testuser"); // Step 3: Logout var logoutResponse = await _client.PostAsync("/api/auth/logout", null); logoutResponse.StatusCode.ShouldBe(HttpStatusCode.OK); // Step 4: Verify protected endpoint returns 401 after logout var afterLogoutResponse = await _client.GetAsync("/api/auth/me"); afterLogoutResponse.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } [Fact] public async Task ProtectedEndpoints_Return401_WithoutAuth() { // Use a fresh client without cookies (using factory to connect to test server) var freshClient = _factory.CreateClient(new WebApplicationFactoryClientOptions { HandleCookies = false, AllowAutoRedirect = false }); // Search endpoints require auth var searchResponse = await freshClient.GetAsync("/api/search"); searchResponse.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); // Auth me endpoint requires auth var meResponse = await freshClient.GetAsync("/api/auth/me"); meResponse.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } [Fact] public async Task ProtectedEndpoints_Work_WithAuthCookie() { // Login first var loginRequest = new LoginRequest { Username = "testuser", Password = "testpass" }; var loginResponse = await _client.PostAsJsonAsync("/api/auth/login", loginRequest); loginResponse.StatusCode.ShouldBe(HttpStatusCode.OK); // Now search endpoint should work var searchResponse = await _client.GetAsync("/api/search"); searchResponse.StatusCode.ShouldBe(HttpStatusCode.OK); } [Fact] public async Task LookupEndpoints_DoNotRequireAuth() { // Use a fresh client without cookies (using factory to connect to test server) var freshClient = _factory.CreateClient(new WebApplicationFactoryClientOptions { HandleCookies = false, AllowAutoRedirect = false }); // Lookup endpoints should work without auth var itemsResponse = await freshClient.GetAsync("/api/lookup/items?q=test"); itemsResponse.StatusCode.ShouldBe(HttpStatusCode.OK); var profitCentersResponse = await freshClient.GetAsync("/api/lookup/profit-centers?q=test"); profitCentersResponse.StatusCode.ShouldBe(HttpStatusCode.OK); var workCentersResponse = await freshClient.GetAsync("/api/lookup/work-centers?q=test"); workCentersResponse.StatusCode.ShouldBe(HttpStatusCode.OK); var operatorsResponse = await freshClient.GetAsync("/api/lookup/operators?q=test"); operatorsResponse.StatusCode.ShouldBe(HttpStatusCode.OK); } }