tests(infra,api): refactor to allow further config of TestApi
This commit is contained in:
+1
-2
@@ -81,7 +81,6 @@ dotnet_remove_unnecessary_suppression_exclusions = none
|
|||||||
|
|
||||||
# analyzer settings
|
# analyzer settings
|
||||||
dotnet_diagnostic.IDE0058.severity = none
|
dotnet_diagnostic.IDE0058.severity = none
|
||||||
dotnet_diagnostic.IDE0053.severity = when_on_single_line:suggestion
|
|
||||||
dotnet_diagnostic.IDE0100.severity = none
|
dotnet_diagnostic.IDE0100.severity = none
|
||||||
dotnet_diagnostic.CA1515.severity = none
|
dotnet_diagnostic.CA1515.severity = none
|
||||||
dotnet_diagnostic.CA1848.severity = none
|
dotnet_diagnostic.CA1848.severity = none
|
||||||
@@ -95,7 +94,7 @@ csharp_style_var_when_type_is_apparent = true:suggestion
|
|||||||
csharp_style_expression_bodied_accessors = true:silent
|
csharp_style_expression_bodied_accessors = true:silent
|
||||||
csharp_style_expression_bodied_constructors = false:silent
|
csharp_style_expression_bodied_constructors = false:silent
|
||||||
csharp_style_expression_bodied_indexers = true:silent
|
csharp_style_expression_bodied_indexers = true:silent
|
||||||
csharp_style_expression_bodied_lambdas = true:suggestion
|
csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion
|
||||||
csharp_style_expression_bodied_local_functions = false:silent
|
csharp_style_expression_bodied_local_functions = false:silent
|
||||||
csharp_style_expression_bodied_methods = false:silent
|
csharp_style_expression_bodied_methods = false:silent
|
||||||
csharp_style_expression_bodied_operators = false:silent
|
csharp_style_expression_bodied_operators = false:silent
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ internal sealed class HttpRequestBuilder
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HttpRequestBuilder New() => new();
|
public static HttpRequestBuilder New()
|
||||||
|
{
|
||||||
|
return new();
|
||||||
|
}
|
||||||
|
|
||||||
public HttpRequestBuilder WithMethod(HttpMethod method)
|
public HttpRequestBuilder WithMethod(HttpMethod method)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ namespace FiscalOS.API.Tests.Infra;
|
|||||||
|
|
||||||
public class TestApi : WebApplicationFactory<Program>
|
public class TestApi : WebApplicationFactory<Program>
|
||||||
{
|
{
|
||||||
|
private readonly List<Action<IWebHostBuilder>> _additionalConfigs = [];
|
||||||
|
|
||||||
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
protected override void ConfigureWebHost(IWebHostBuilder builder)
|
||||||
{
|
{
|
||||||
base.ConfigureWebHost(builder);
|
base.ConfigureWebHost(builder);
|
||||||
@@ -25,5 +27,71 @@ public class TestApi : WebApplicationFactory<Program>
|
|||||||
|
|
||||||
c.AddSingleton<IKeyRing>(TestKeyRing.From);
|
c.AddSingleton<IKeyRing>(TestKeyRing.From);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
using FiscalOS.Core.Queuing;
|
||||||
|
using FiscalOS.Infra.Transactions.Plaid;
|
||||||
|
|
||||||
using Account = FiscalOS.Core.Accounts.Account;
|
using Account = FiscalOS.Core.Accounts.Account;
|
||||||
using Institution = FiscalOS.Core.Accounts.Institution;
|
using Institution = FiscalOS.Core.Accounts.Institution;
|
||||||
|
|
||||||
@@ -31,7 +34,6 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
["PlaidInstitutionId"] = ["The PlaidInstitutionId field is required."],
|
["PlaidInstitutionId"] = ["The PlaidInstitutionId field is required."],
|
||||||
["PlaidAccountId"] = ["The PlaidAccountId field is required."],
|
["PlaidAccountId"] = ["The PlaidAccountId field is required."],
|
||||||
["PlaidAccountName"] = ["The PlaidAccountName field is required."],
|
["PlaidAccountName"] = ["The PlaidAccountName field is required."],
|
||||||
["AccountCurrencyCode"] = ["The AccountCurrencyCode field is required."],
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +126,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Add_WhenCalledWithPlaidInstitutionIdThatHasNotBeenAdded_ItShouldReturn400WithProblemDetails()
|
public async Task Add_WhenCalledWithPlaidInstitutionIdThatHasNotBeenAdded_ItShouldReturn400WithProblemDetails()
|
||||||
{
|
{
|
||||||
var user = await ExecuteAsync(static async (context, ct, sp) =>
|
var user = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
@@ -161,7 +163,7 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Add_WhenCalledWithPlaidAccountIdThatHasAlreadyBeenAdded_ItShouldReturn409WithProblemDetails()
|
public async Task Add_WhenCalledWithPlaidAccountIdThatHasAlreadyBeenAdded_ItShouldReturn409WithProblemDetails()
|
||||||
{
|
{
|
||||||
var (user, institution, account) = await ExecuteAsync(static async (context, ct, sp) =>
|
var (user, institution, account) = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
@@ -212,7 +214,18 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Add_WhenCalledWithNewAccount_ItShouldReturn200()
|
public async Task Add_WhenCalledWithNewAccount_ItShouldReturn200()
|
||||||
{
|
{
|
||||||
var (user, institution) = await ExecuteAsync(async (context, ct, sp) =>
|
var mockQueue = new Mock<IAsyncQueue<SyncUpdatesQueueItem>>();
|
||||||
|
|
||||||
|
await using var testApi = Api
|
||||||
|
.WithAdditionalConfig(whb =>
|
||||||
|
{
|
||||||
|
whb.ConfigureTestServices(s =>
|
||||||
|
{
|
||||||
|
s.AddSingleton(mockQueue.Object);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var (user, institution) = await testApi.ExecuteAsync(async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
@@ -256,11 +269,13 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
})
|
})
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var response = await Client.SendAsync(request, TestContext.Current.CancellationToken);
|
var client = testApi.CreateClient();
|
||||||
|
|
||||||
|
var response = await client.SendAsync(request, TestContext.Current.CancellationToken);
|
||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
|
||||||
var updatedUser = await ExecuteAsync(
|
var updatedUser = await testApi.ExecuteAsync(
|
||||||
async (context, ct) => await context.Set<User>()
|
async (context, ct) => await context.Set<User>()
|
||||||
.Include(u => u.Accounts)
|
.Include(u => u.Accounts)
|
||||||
.ThenInclude(a => a.Metadata)
|
.ThenInclude(a => a.Metadata)
|
||||||
@@ -279,12 +294,9 @@ public class AddTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
((PlaidAccountMetadata)a.Metadata).PlaidName == newAccountName
|
((PlaidAccountMetadata)a.Metadata).PlaidName == newAccountName
|
||||||
);
|
);
|
||||||
|
|
||||||
updatedUser.Accounts.First()
|
mockQueue.Verify(m => m.EnqueueAsync(
|
||||||
.Balances.Should().ContainSingle(
|
It.IsAny<SyncUpdatesQueueItem>(),
|
||||||
b => b.AccountId == updatedUser.Accounts.First().Id &&
|
It.IsAny<CancellationToken>()
|
||||||
b.Current == expectedBalance &&
|
), Times.Once());
|
||||||
b.Available == expectedBalance &&
|
|
||||||
b.CurrencyCode == expectedCurrencyCode
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ public class LoginTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Login_WhenUserExistsButPasswordIsIncorrect_ItShouldReturn401WithProblemDetails()
|
public async Task Login_WhenUserExistsButPasswordIsIncorrect_ItShouldReturn401WithProblemDetails()
|
||||||
{
|
{
|
||||||
await ExecuteAsync(static async (context, ct, sp) =>
|
await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
@@ -70,7 +70,7 @@ public class LoginTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Login_WhenUserExistsAndPasswordIsCorrect_ItShouldReturn200WithJwtTokenAndSetRefreshCookie()
|
public async Task Login_WhenUserExistsAndPasswordIsCorrect_ItShouldReturn200WithJwtTokenAndSetRefreshCookie()
|
||||||
{
|
{
|
||||||
await ExecuteAsync(static async (context, ct, sp) =>
|
await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Refresh_WhenCalledWithTokenBelongingToDifferentUser_ItShouldReturn403WithProblemDetails()
|
public async Task Refresh_WhenCalledWithTokenBelongingToDifferentUser_ItShouldReturn403WithProblemDetails()
|
||||||
{
|
{
|
||||||
var (users, refreshToken) = await ExecuteAsync(static async (context, ct, sp) =>
|
var (users, refreshToken) = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
|
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
|
||||||
@@ -61,7 +61,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
|
|
||||||
await response.Should().BeProblemDetails(HttpStatusCode.Forbidden);
|
await response.Should().BeProblemDetails(HttpStatusCode.Forbidden);
|
||||||
|
|
||||||
var unrevokedTokensCountForUser2 = await ExecuteAsync(
|
var unrevokedTokensCountForUser2 = await Api.ExecuteAsync(
|
||||||
async (context, ct) => await context.Set<RefreshToken>()
|
async (context, ct) => await context.Set<RefreshToken>()
|
||||||
.Include(t => t.User)
|
.Include(t => t.User)
|
||||||
.Where(t => t.UserId == users[1].Id && t.Revoked == false)
|
.Where(t => t.UserId == users[1].Id && t.Revoked == false)
|
||||||
@@ -75,7 +75,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Refresh_WhenCalledWithRevokedRefreshToken_ItShouldReturn400WithProblemDetails()
|
public async Task Refresh_WhenCalledWithRevokedRefreshToken_ItShouldReturn400WithProblemDetails()
|
||||||
{
|
{
|
||||||
var (user, refreshToken) = await ExecuteAsync(static async (context, ct, sp) =>
|
var (user, refreshToken) = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
|
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
|
||||||
@@ -108,7 +108,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Refresh_WhenCalledWithExpiredRefreshToken_ItShouldReturn400WithProblemDetails()
|
public async Task Refresh_WhenCalledWithExpiredRefreshToken_ItShouldReturn400WithProblemDetails()
|
||||||
{
|
{
|
||||||
var (user, refreshToken) = await ExecuteAsync(static async (context, ct, sp) =>
|
var (user, refreshToken) = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
|
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
|
||||||
@@ -142,7 +142,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[InlineData(-5)]
|
[InlineData(-5)]
|
||||||
public async Task Refresh_WhenCalledWithValidRefreshTokenAndExpiredOrNotExpiredAccessToken_ItShouldReturn200WithNewTokensAndSetRefreshCookie(int accessTokenExpiresAtOffset)
|
public async Task Refresh_WhenCalledWithValidRefreshTokenAndExpiredOrNotExpiredAccessToken_ItShouldReturn200WithNewTokensAndSetRefreshCookie(int accessTokenExpiresAtOffset)
|
||||||
{
|
{
|
||||||
var (user, refreshToken) = await ExecuteAsync(static async (context, ct, sp) =>
|
var (user, refreshToken) = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
|
var tokenGenerator = sp.GetRequiredService<ITokenGenerator>();
|
||||||
@@ -174,7 +174,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
response.Should().HaveSetCookieHeader("fiscalos_refresh_cookie");
|
response.Should().HaveSetCookieHeader("fiscalos_refresh_cookie");
|
||||||
await response.Should().BeJsonContentOfType<API.Auth.Refresh.Response>(HttpStatusCode.OK);
|
await response.Should().BeJsonContentOfType<API.Auth.Refresh.Response>(HttpStatusCode.OK);
|
||||||
|
|
||||||
var oldRefreshTokenInDb = await ExecuteAsync(
|
var oldRefreshTokenInDb = await Api.ExecuteAsync(
|
||||||
async (context, ct) => await context.Set<RefreshToken>()
|
async (context, ct) => await context.Set<RefreshToken>()
|
||||||
.Include(t => t.User)
|
.Include(t => t.User)
|
||||||
.Where(t => t.UserId == user.Id && t.Token == refreshToken.Token && t.Revoked == true)
|
.Where(t => t.UserId == user.Id && t.Token == refreshToken.Token && t.Revoked == true)
|
||||||
@@ -184,7 +184,7 @@ public class RefreshTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
|
|
||||||
oldRefreshTokenInDb.Should().NotBeNull();
|
oldRefreshTokenInDb.Should().NotBeNull();
|
||||||
|
|
||||||
var newRefreshTokenInDb = await ExecuteAsync(
|
var newRefreshTokenInDb = await Api.ExecuteAsync(
|
||||||
async (context, ct) => await context.Set<RefreshToken>()
|
async (context, ct) => await context.Set<RefreshToken>()
|
||||||
.Include(t => t.User)
|
.Include(t => t.User)
|
||||||
.Where(t => t.UserId == user.Id && t.Revoked == false && t.Token != refreshToken.Token)
|
.Where(t => t.UserId == user.Id && t.Revoked == false && t.Token != refreshToken.Token)
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public class ConnectTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Connect_WhenCalledWithPlaidInstitutionIdThatIsAlreadyConnected_ItShouldReturn409WithProblemDetails()
|
public async Task Connect_WhenCalledWithPlaidInstitutionIdThatIsAlreadyConnected_ItShouldReturn409WithProblemDetails()
|
||||||
{
|
{
|
||||||
var (user, institution) = await ExecuteAsync(static async (context, ct, sp) =>
|
var (user, institution) = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
@@ -136,7 +136,7 @@ public class ConnectTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
{
|
{
|
||||||
var plaidInstitutionId = "ins_109508";
|
var plaidInstitutionId = "ins_109508";
|
||||||
|
|
||||||
var (user, publicToken) = await ExecuteAsync(async (context, ct, sp) =>
|
var (user, publicToken) = await Api.ExecuteAsync(async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var plaidClient = sp.GetRequiredService<PlaidClient>();
|
var plaidClient = sp.GetRequiredService<PlaidClient>();
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
@@ -171,7 +171,7 @@ public class ConnectTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
|
||||||
var updatedUser = await ExecuteAsync(
|
var updatedUser = await Api.ExecuteAsync(
|
||||||
async (context, ct) => await context.Set<User>()
|
async (context, ct) => await context.Set<User>()
|
||||||
.Include(u => u.Institutions)
|
.Include(u => u.Institutions)
|
||||||
.ThenInclude(i => i.Metadata)
|
.ThenInclude(i => i.Metadata)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class GetAvailableTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetAvailable_WhenCalledWithNonExistentInstitutionId_ItShouldReturn404WithProblemDetails()
|
public async Task GetAvailable_WhenCalledWithNonExistentInstitutionId_ItShouldReturn404WithProblemDetails()
|
||||||
{
|
{
|
||||||
var user = await ExecuteAsync(static async (context, ct, sp) =>
|
var user = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
@@ -65,7 +65,7 @@ public class GetAvailableTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task GetAvailable_WhenCalledWithConnectedInstitution_ItShouldReturn200WithAvailableAccounts()
|
public async Task GetAvailable_WhenCalledWithConnectedInstitution_ItShouldReturn200WithAvailableAccounts()
|
||||||
{
|
{
|
||||||
var (user, institution, expectedAccounts) = await ExecuteAsync(static async (context, ct, sp) =>
|
var (user, institution, expectedAccounts) = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class GetTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Get_WhenCalledByUser_ItShouldReturn200WithListOfInstitutions()
|
public async Task Get_WhenCalledByUser_ItShouldReturn200WithListOfInstitutions()
|
||||||
{
|
{
|
||||||
var (user, institution) = await ExecuteAsync(static async (context, ct, sp) =>
|
var (user, institution) = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class LinkTests(TestApi testApi) : IntegrationTest(testApi)
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Link_WhenCalledWithUserWhoExists_ItShouldReturnLinkToken()
|
public async Task Link_WhenCalledWithUserWhoExists_ItShouldReturnLinkToken()
|
||||||
{
|
{
|
||||||
var user = await ExecuteAsync(static async (context, ct, sp) =>
|
var user = await Api.ExecuteAsync(static async (context, ct, sp) =>
|
||||||
{
|
{
|
||||||
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
var passwordHasher = sp.GetRequiredService<IPasswordHasher>();
|
||||||
var encryptor = sp.GetRequiredService<IEncryptor>();
|
var encryptor = sp.GetRequiredService<IEncryptor>();
|
||||||
|
|||||||
@@ -2,51 +2,17 @@ namespace FiscalOS.API.Tests.Integration;
|
|||||||
|
|
||||||
public abstract class IntegrationTest(TestApi testApi) : IClassFixture<TestApi>, IAsyncLifetime
|
public abstract class IntegrationTest(TestApi testApi) : IClassFixture<TestApi>, IAsyncLifetime
|
||||||
{
|
{
|
||||||
public HttpClient Client => testApi.CreateClient();
|
protected TestApi Api => testApi;
|
||||||
|
protected HttpClient Client => testApi.CreateClient();
|
||||||
|
|
||||||
public async ValueTask InitializeAsync()
|
public async ValueTask InitializeAsync()
|
||||||
{
|
{
|
||||||
await ExecuteAsync(static async (context, ct) =>
|
await Api.EnsureDbCreatedAsync();
|
||||||
{
|
|
||||||
await context.Database.EnsureCreatedAsync(ct);
|
|
||||||
}, TestContext.Current.CancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task ExecuteAsync(Func<DbContext, CancellationToken, Task> action, CancellationToken ct)
|
|
||||||
{
|
|
||||||
await using var scope = testApi.Services.CreateAsyncScope();
|
|
||||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
||||||
await action(context, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task ExecuteAsync(Func<DbContext, CancellationToken, IServiceProvider, Task> action, CancellationToken ct)
|
|
||||||
{
|
|
||||||
await using var scope = testApi.Services.CreateAsyncScope();
|
|
||||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
||||||
await action(context, ct, scope.ServiceProvider);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task<T> ExecuteAsync<T>(Func<DbContext, CancellationToken, Task<T>> action, CancellationToken ct)
|
|
||||||
{
|
|
||||||
await using var scope = testApi.Services.CreateAsyncScope();
|
|
||||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
||||||
return await action(context, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task<T> ExecuteAsync<T>(Func<DbContext, CancellationToken, IServiceProvider, Task<T>> action, CancellationToken ct)
|
|
||||||
{
|
|
||||||
await using var scope = testApi.Services.CreateAsyncScope();
|
|
||||||
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
||||||
return await action(context, ct, scope.ServiceProvider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
public async ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
await ExecuteAsync(static async (context, ct) =>
|
await Api.EnsureDbDeletedAsync();
|
||||||
{
|
|
||||||
await context.Database.EnsureDeletedAsync(ct);
|
|
||||||
}, TestContext.Current.CancellationToken);
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,4 @@ namespace FiscalOS.Infra.Tests.Unit;
|
|||||||
|
|
||||||
public class PlaidTransactionSyncerTests
|
public class PlaidTransactionSyncerTests
|
||||||
{
|
{
|
||||||
private readonly Mock<ILogger<PlaidTransactionSyncer>> _mockSyncer = new();
|
|
||||||
private
|
|
||||||
private readonly PlaidTransactionSyncer _sut;
|
|
||||||
|
|
||||||
public PlaidTransactionSyncer()
|
|
||||||
{
|
|
||||||
_sut = PlaidTransactionSyncer.From();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user