using System.Net; using System.Net.Http.Json; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNetCore.Identity; using Xunit; using IamService.API.Application.Commands.Auth; using IamService.API.Application.Common; using IamService.Domain.AggregatesModel.UserAggregate; namespace IamService.FunctionalTests.Controllers; /// /// EN: Functional tests for AuthController endpoints. /// VI: Functional tests cho các endpoints của AuthController. /// public class AuthControllerTests : IClassFixture { private readonly HttpClient _client; private readonly CustomWebApplicationFactory _factory; public AuthControllerTests(CustomWebApplicationFactory factory) { _factory = factory; _client = factory.CreateClient(new WebApplicationFactoryClientOptions { AllowAutoRedirect = false }); } [Fact] public async Task Register_WithValidData_ShouldReturn201() { // Arrange var request = new RegisterUserCommand( $"test_{Guid.NewGuid()}@example.com", "Password123!", "John", "Doe"); // Act var response = await _client.PostAsJsonAsync("/api/v1/auth/register", request); // Debug: Print response body if not Created if (response.StatusCode != HttpStatusCode.Created) { var body = await response.Content.ReadAsStringAsync(); throw new Exception($"Expected Created, got {response.StatusCode}. Body: {body}"); } // Assert Assert.Equal(HttpStatusCode.Created, response.StatusCode); var result = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(result); Assert.True(result.Success); Assert.NotNull(result.Data); Assert.Equal(request.Email, result.Data.Email); } [Fact] public async Task Register_WithInvalidEmail_ShouldReturn400() { // Arrange var request = new { Email = "invalid-email", Password = "Password123!", FirstName = "John", LastName = "Doe" }; // Act var response = await _client.PostAsJsonAsync("/api/v1/auth/register", request); // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } [Fact] public async Task Register_WithWeakPassword_ShouldReturn400() { // Arrange var request = new { Email = "test@example.com", Password = "weak", FirstName = "John", LastName = "Doe" }; // Act var response = await _client.PostAsJsonAsync("/api/v1/auth/register", request); // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } [Fact] public async Task Register_WithDuplicateEmail_ShouldReturn409() { // Arrange var email = $"duplicate_{Guid.NewGuid()}@example.com"; var request = new RegisterUserCommand(email, "Password123!", "John", "Doe"); // First registration await _client.PostAsJsonAsync("/api/v1/auth/register", request); // Act - Second registration with same email var response = await _client.PostAsJsonAsync("/api/v1/auth/register", request); // Assert Assert.Equal(HttpStatusCode.Conflict, response.StatusCode); } [Fact] public async Task Token_WithValidCredentials_ShouldReturnTokens() { // Arrange - Register user first var email = $"login_{Guid.NewGuid()}@example.com"; var password = "Password123!"; await _client.PostAsJsonAsync("/api/v1/auth/register", new { Email = email, Password = password, FirstName = "Login", LastName = "Test" }); // Activate user (in real scenario, need to verify email first) using var scope = _factory.Services.CreateScope(); var userManager = scope.ServiceProvider.GetRequiredService>(); var user = await userManager.FindByEmailAsync(email); if (user != null) { user.Activate(); await userManager.UpdateAsync(user); } // Act - Login var tokenRequest = new FormUrlEncodedContent(new Dictionary { ["grant_type"] = "password", ["username"] = email, ["password"] = password, ["scope"] = "openid profile email offline_access" }); var response = await _client.PostAsync("/connect/token", tokenRequest); // Assert Assert.Equal(HttpStatusCode.OK, response.StatusCode); var result = await response.Content.ReadFromJsonAsync(); Assert.NotNull(result); Assert.NotEmpty(result.access_token); Assert.Equal("Bearer", result.token_type); } [Fact] public async Task Token_WithInvalidCredentials_ShouldReturn400() { // Arrange var tokenRequest = new FormUrlEncodedContent(new Dictionary { ["grant_type"] = "password", ["username"] = "nonexistent@example.com", ["password"] = "WrongPassword123!", ["scope"] = "openid" }); // Act var response = await _client.PostAsync("/connect/token", tokenRequest); // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } private record TokenResponse( string access_token, string token_type, int expires_in, string? refresh_token, string? scope); }