using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Shogi.BackEnd.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.ConfigureTestServices(services =>
{
// Remove all EF Core and database provider related services
var descriptorsToRemove = services
.Where(d => d.ServiceType.Namespace != null &&
(d.ServiceType.Namespace.StartsWith("Microsoft.EntityFrameworkCore") ||
d.ServiceType == typeof(ApplicationDbContext) ||
d.ServiceType == typeof(DbContextOptions)))
.ToList();
foreach (var descriptor in descriptorsToRemove)
{
services.Remove(descriptor);
}
// Add DbContext with InMemory database
services.AddDbContext(options =>
options.UseInMemoryDatabase("IntegrationTestDb_" + Guid.NewGuid().ToString()));
});
}
public async Task InitializeAsync()
{
this.HttpClient = this.CreateClient();
this.OtherHttpClient = this.CreateClient();
// Ensure the in-memory database is created
using (var scope = this.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService();
await db.Database.EnsureCreatedAsync();
}
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;
}
}