using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Shogi.Identity; using System.Net.Http.Json; using System.Text.Json; namespace Shogi.AcceptanceTests.TestSetup; /// /// Integration test fixture using WebApplicationFactory for in-process testing. /// public class AatTestFixture : WebApplicationFactory, IAsyncLifetime { protected static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web); private const string TestPassword = "TestPassword123!"; public HttpClient HttpClient { get; private set; } = null!; public HttpClient OtherHttpClient { get; private set; } = null!; protected override void ConfigureWebHost(IWebHostBuilder builder) { builder.UseEnvironment("Development"); builder.ConfigureServices(services => { // Remove the existing DbContext registration var descriptor = services.SingleOrDefault( d => d.ServiceType == typeof(DbContextOptions)); if (descriptor != null) { services.Remove(descriptor); } // Add in-memory database for testing services.AddDbContext(options => { options.UseInMemoryDatabase("IntegrationTestDb_" + Guid.NewGuid().ToString()); }); // Ensure the database is created and seeded var sp = services.BuildServiceProvider(); using var scope = sp.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); db.Database.EnsureCreated(); }); } public async Task InitializeAsync() { this.HttpClient = this.CreateClient(); this.OtherHttpClient = this.CreateClient(); await this.SetupTestAccountsAndLogin(); } private async Task SetupTestAccountsAndLogin() { // Register and login first test account await RegisterAndLogin(this.HttpClient, "aat-account@test.com", TestPassword); // Register and login second test account await RegisterAndLogin(this.OtherHttpClient, "aat-account-2@test.com", TestPassword); } private static async Task RegisterAndLogin(HttpClient client, string email, string password) { // Try to register (may already exist) await client.PostAsJsonAsync( new Uri("register", UriKind.Relative), new { email, password }, options: SerializerOptions); // Login var loginResponse = await client.PostAsJsonAsync( new Uri("login", UriKind.Relative), new { email, password }, options: SerializerOptions); if (loginResponse.IsSuccessStatusCode) { var tokenResponse = await loginResponse.Content.ReadFromJsonAsync(SerializerOptions); if (tokenResponse?.AccessToken != null) { client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokenResponse.AccessToken); } } } async Task IAsyncLifetime.DisposeAsync() { this.HttpClient?.Dispose(); this.OtherHttpClient?.Dispose(); await base.DisposeAsync(); } private class LoginResponse { public string AccessToken { get; set; } = string.Empty; } }