2026-02-01 04:27:06 -06:00
|
|
|
namespace FiscalOS.API.Tests.Infra;
|
|
|
|
|
|
|
|
|
|
public class TestApi : WebApplicationFactory<Program>
|
|
|
|
|
{
|
2026-03-08 09:15:45 -05:00
|
|
|
private readonly List<Action<IWebHostBuilder>> _additionalConfigs = [];
|
|
|
|
|
|
2026-02-01 04:27:06 -06:00
|
|
|
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
|
|
|
|
{
|
|
|
|
|
base.ConfigureWebHost(builder);
|
|
|
|
|
|
|
|
|
|
builder.ConfigureLogging(static c => c.ClearProviders());
|
2026-02-01 08:07:23 -06:00
|
|
|
|
2026-02-12 20:49:12 -06:00
|
|
|
builder.ConfigureAppConfiguration(static c =>
|
|
|
|
|
{
|
|
|
|
|
var testConfigPath = Path.Combine(AppContext.BaseDirectory, "appsettings.Test.json");
|
|
|
|
|
c.AddJsonFile(testConfigPath, optional: false);
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-01 08:07:23 -06:00
|
|
|
builder.ConfigureTestServices(static c =>
|
|
|
|
|
{
|
2026-02-03 11:34:58 -06:00
|
|
|
c.AddSingleton(Options.Create(new AppDbContextOptions()
|
2026-02-01 08:07:23 -06:00
|
|
|
{
|
|
|
|
|
DatabaseFilePath = $"{Guid.NewGuid()}.db",
|
2026-02-03 11:34:58 -06:00
|
|
|
}));
|
2026-02-01 08:07:23 -06:00
|
|
|
|
2026-02-03 11:34:58 -06:00
|
|
|
c.AddSingleton(Options.Create(JwtTokenBuilder.DefaultJwtOptions));
|
2026-02-06 06:48:34 -06:00
|
|
|
|
|
|
|
|
c.AddSingleton<IKeyRing>(TestKeyRing.From);
|
2026-02-01 08:07:23 -06:00
|
|
|
});
|
2026-03-08 09:15:45 -05:00
|
|
|
|
|
|
|
|
foreach (var config in _additionalConfigs)
|
|
|
|
|
{
|
|
|
|
|
config(builder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TestApi WithAdditionalConfig(Action<IWebHostBuilder> configuration)
|
|
|
|
|
{
|
|
|
|
|
var newApi = new TestApi();
|
|
|
|
|
|
|
|
|
|
newApi._additionalConfigs.AddRange(_additionalConfigs);
|
|
|
|
|
newApi._additionalConfigs.Add(configuration);
|
|
|
|
|
|
|
|
|
|
return newApi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task ExecuteAsync(Func<DbContext, CancellationToken, Task> action, CancellationToken ct)
|
|
|
|
|
{
|
|
|
|
|
await using var scope = Services.CreateAsyncScope();
|
|
|
|
|
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
|
|
|
await action(context, ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task ExecuteAsync(Func<DbContext, CancellationToken, IServiceProvider, Task> action, CancellationToken ct)
|
|
|
|
|
{
|
|
|
|
|
await using var scope = Services.CreateAsyncScope();
|
|
|
|
|
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
|
|
|
await action(context, ct, scope.ServiceProvider);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<T> ExecuteAsync<T>(Func<DbContext, CancellationToken, Task<T>> action, CancellationToken ct)
|
|
|
|
|
{
|
|
|
|
|
await using var scope = Services.CreateAsyncScope();
|
|
|
|
|
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
|
|
|
return await action(context, ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<T> ExecuteAsync<T>(Func<DbContext, CancellationToken, IServiceProvider, Task<T>> action, CancellationToken ct)
|
|
|
|
|
{
|
|
|
|
|
await using var scope = Services.CreateAsyncScope();
|
|
|
|
|
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
|
|
|
return await action(context, ct, scope.ServiceProvider);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task EnsureDbCreatedAsync()
|
|
|
|
|
{
|
|
|
|
|
await ExecuteAsync(static async (context, ct) =>
|
|
|
|
|
{
|
|
|
|
|
await context.Database.EnsureCreatedAsync(ct);
|
|
|
|
|
}, TestContext.Current.CancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task EnsureDbDeletedAsync()
|
|
|
|
|
{
|
|
|
|
|
await ExecuteAsync(static async (context, ct) =>
|
|
|
|
|
{
|
|
|
|
|
await context.Database.EnsureDeletedAsync(ct);
|
|
|
|
|
}, TestContext.Current.CancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override async ValueTask DisposeAsync()
|
|
|
|
|
{
|
|
|
|
|
await EnsureDbDeletedAsync();
|
|
|
|
|
await base.DisposeAsync();
|
|
|
|
|
GC.SuppressFinalize(this);
|
2026-02-01 04:27:06 -06:00
|
|
|
}
|
|
|
|
|
}
|