This commit includes all previously untracked backend files: Domain: - Accounts, Attachments, BankConnections, Customers - FiscalYears, Invoices, JournalEntryDrafts - Orders, Products, UserAccess Commands & Handlers: - Full CQRS command structure for all domains Repositories: - PostgreSQL repositories for all read models - Bank transaction and ledger repositories GraphQL: - Input types, scalars, and types for all entities - Mutations and queries Infrastructure: - Banking integration (Enable Banking client) - File storage, Invoicing, Reporting, SAF-T export - Database migrations (003-029) Tests: - Integration tests for GraphQL endpoints - Domain tests - Invoicing and reporting tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
100 lines
3.4 KiB
C#
100 lines
3.4 KiB
C#
using Books.Api.Banking;
|
|
using AwesomeAssertions;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
|
|
namespace Books.Api.Tests.Integration;
|
|
|
|
/// <summary>
|
|
/// Integration tests for Enable Banking API client.
|
|
/// These tests call the real Enable Banking API.
|
|
/// </summary>
|
|
[Trait("Category", "Integration")]
|
|
public class EnableBankingClientTests : IDisposable
|
|
{
|
|
private readonly EnableBankingClient _client;
|
|
private readonly HttpClient _httpClient;
|
|
|
|
public EnableBankingClientTests()
|
|
{
|
|
var options = new EnableBankingOptions
|
|
{
|
|
ApplicationId = "0bafa28d-41ea-4275-a4d5-221a78c72350",
|
|
KeyId = "0bafa28d-41ea-4275-a4d5-221a78c72350",
|
|
PrivateKey = File.ReadAllText(Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
|
"projects/ledger/private.key"))
|
|
};
|
|
|
|
_httpClient = new HttpClient
|
|
{
|
|
BaseAddress = new Uri("https://api.enablebanking.com")
|
|
};
|
|
|
|
_client = new EnableBankingClient(_httpClient, options, NullLogger<EnableBankingClient>.Instance);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_client.Dispose();
|
|
_httpClient.Dispose();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetAspsps_ReturnsDanishBanks()
|
|
{
|
|
// Act
|
|
var banks = await _client.GetAspspsAsync("DK");
|
|
|
|
// Assert
|
|
banks.Should().NotBeEmpty();
|
|
banks.Should().Contain(b => b.Name.Contains("Danske", StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
[Fact(Skip = "Requires redirect URL to be registered in Enable Banking dashboard")]
|
|
public async Task StartAuthorization_WithRegisteredRedirectUrl_ReturnsAuthorizationUrl()
|
|
{
|
|
// Arrange - First get actual bank name from API
|
|
var banks = await _client.GetAspspsAsync("DK");
|
|
var danskeBank = banks.FirstOrDefault(b => b.Name.Contains("Danske", StringComparison.OrdinalIgnoreCase));
|
|
danskeBank.Should().NotBeNull("Danske Bank should exist in available banks");
|
|
|
|
// Note: This redirect URL must be registered in Enable Banking dashboard
|
|
// Configure at: https://enablebanking.com/dashboard
|
|
var redirectUrl = "https://your-registered-url.com/callback";
|
|
var state = Guid.NewGuid().ToString();
|
|
|
|
// Act
|
|
var result = await _client.StartAuthorizationAsync(
|
|
aspspName: danskeBank!.Name,
|
|
redirectUrl: redirectUrl,
|
|
state: state,
|
|
psuType: "personal");
|
|
|
|
// Assert
|
|
result.Should().NotBeNull();
|
|
result.AuthorizationId.Should().NotBeNullOrEmpty();
|
|
result.Url.Should().StartWith("https://");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task StartAuthorization_WithUnregisteredRedirectUrl_ThrowsExpectedError()
|
|
{
|
|
// Arrange
|
|
var banks = await _client.GetAspspsAsync("DK");
|
|
var bank = banks.First();
|
|
|
|
var unregisteredRedirectUrl = "https://unregistered-domain.example.com/callback";
|
|
var state = Guid.NewGuid().ToString();
|
|
|
|
// Act
|
|
var act = async () => await _client.StartAuthorizationAsync(
|
|
aspspName: bank.Name,
|
|
redirectUrl: unregisteredRedirectUrl,
|
|
state: state,
|
|
psuType: "personal");
|
|
|
|
// Assert - Should get REDIRECT_URI_NOT_ALLOWED error (proves API auth works)
|
|
var exception = await act.Should().ThrowAsync<HttpRequestException>();
|
|
exception.Which.Message.Should().Contain("REDIRECT_URI_NOT_ALLOWED");
|
|
}
|
|
}
|