using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Npgsql; using Tiku.Application.Auth; using Tiku.Domain.Identity; using Tiku.Domain.Tenancy; using Tiku.Infrastructure.Persistence; namespace Tiku.IntegrationTests.Api; public sealed class ApiTestFactory(IWechatOAuthClient? wechatOAuthClient = null) : WebApplicationFactory { private readonly string databaseName = Guid.NewGuid().ToString(); protected override void ConfigureWebHost(Microsoft.AspNetCore.Hosting.IWebHostBuilder builder) { builder.ConfigureServices(services => { foreach (var descriptor in services .Where(descriptor => descriptor.ServiceType == typeof(NpgsqlDataSource) || descriptor.ServiceType == typeof(DbContextOptions) || descriptor.ServiceType.FullName?.Contains(nameof(TikuDbContext), StringComparison.Ordinal) == true) .ToArray()) { services.Remove(descriptor); } services.AddDbContext(options => options.UseInMemoryDatabase(databaseName)); if (wechatOAuthClient is not null) { services.AddSingleton(wechatOAuthClient); } }); } public async Task SeedAsync(params object[] entities) { using var scope = Services.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); dbContext.AddRange(entities); await dbContext.SaveChangesAsync(); } public async Task SeedActiveSessionAsync( Guid userId, Guid? tenantId = null, string tokenHash = "integration-test-token-hash") { var resolvedTenantId = tenantId ?? Guid.NewGuid(); await SeedAsync( new Tenant { Id = resolvedTenantId, Slug = resolvedTenantId.ToString("N"), Name = "Test Tenant" }, new User { Id = userId, Phone = "13800000000" }, new AuthSession { Id = Guid.NewGuid(), TenantId = resolvedTenantId, UserId = userId, TokenHash = tokenHash, Provider = "test", ExpiresAt = DateTimeOffset.UtcNow.AddHours(1) }); using var scope = Services.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); return await dbContext.AuthSessions .Where(session => session.UserId == userId) .Select(session => session.Id) .SingleAsync(); } }