using Books.Api.EventFlow.Repositories;
using Books.Api.Tests.Helpers;
using Books.Api.Tests.Infrastructure;
using AwesomeAssertions;
using Microsoft.Extensions.DependencyInjection;
namespace Books.Api.Tests.GraphQL;
///
/// Integration tests for JournalEntryDraft (Kassekladde) GraphQL operations.
///
[Trait("Category", "Integration")]
public class JournalEntryDraftGraphQLTests(TestWebApplicationFactory factory)
: IntegrationTestBase(factory)
{
#region Create Draft Tests
[Fact]
public async Task Mutation_CreateJournalEntryDraft_CreatesSuccessfully()
{
// Arrange
var graphqlClient = new GraphQLTestClient(Client);
var companyId = await CreateCompanyAsync(graphqlClient, "Draft Test Company");
// Act
var response = await graphqlClient.MutateAsync("""
mutation CreateDraft($input: CreateJournalEntryDraftInput!) {
createJournalEntryDraft(input: $input) {
id
companyId
name
status
createdBy
}
}
""",
new
{
input = new
{
companyId,
name = "Januar Udgifter"
}
});
// Assert
response.EnsureNoErrors();
response.Data.Should().NotBeNull();
response.Data!.CreateJournalEntryDraft.Should().NotBeNull();
response.Data.CreateJournalEntryDraft!.Name.Should().Be("Januar Udgifter");
response.Data.CreateJournalEntryDraft.Status.Should().Be("active");
response.Data.CreateJournalEntryDraft.CompanyId.Should().Be(companyId);
response.Data.CreateJournalEntryDraft.Id.Should().StartWith("journalentrydraft-");
}
[Fact]
public async Task Mutation_CreateJournalEntryDraft_FailsWithoutCompanyHeader()
{
// Arrange
var graphqlClient = new GraphQLTestClient(Client);
// Note: We're NOT setting X-Company-Id header
// Act
var response = await graphqlClient.MutateAsync("""
mutation CreateDraft($input: CreateJournalEntryDraftInput!) {
createJournalEntryDraft(input: $input) {
id
}
}
""",
new
{
input = new
{
companyId = "some-company-id",
name = "Test Draft"
}
});
// Assert
response.HasErrors.Should().BeTrue();
}
[Fact]
public async Task Mutation_CreateJournalEntryDraft_FailsWithEmptyName()
{
// Arrange
var graphqlClient = new GraphQLTestClient(Client);
var companyId = await CreateCompanyAsync(graphqlClient, "Empty Name Test Company");
// Act
var response = await graphqlClient.MutateAsync("""
mutation CreateDraft($input: CreateJournalEntryDraftInput!) {
createJournalEntryDraft(input: $input) {
id
}
}
""",
new
{
input = new
{
companyId,
name = " " // Whitespace only
}
});
// Assert
response.HasErrors.Should().BeTrue();
var errorInfo = string.Join(" ", response.Errors!.Select(e =>
e.Message + " " + (e.Extensions?.GetValueOrDefault("details")?.ToString() ?? "")));
errorInfo.Should().Contain("Draft name is required");
}
#endregion
#region Update Draft Tests
[Fact]
public async Task Mutation_UpdateJournalEntryDraft_UpdatesSuccessfully()
{
// Arrange
var graphqlClient = new GraphQLTestClient(Client);
var companyId = await CreateCompanyAsync(graphqlClient, "Update Draft Test Company");
var draftId = await CreateDraftAsync(graphqlClient, companyId, "Original Name");
// Wait for eventual consistency
await Eventually.GetAsync(async () =>
{
var repo = GetService();
return await repo.GetByIdAsync(draftId);
});
// Act
var response = await graphqlClient.MutateAsync("""
mutation UpdateDraft($input: UpdateJournalEntryDraftInput!) {
updateJournalEntryDraft(input: $input) {
id
name
documentDate
description
lines {
lineNumber
accountId
debitAmount
creditAmount
description
}
}
}
""",
new
{
input = new
{
id = draftId,
name = "Updated Name",
documentDate = "2025-01-15",
description = "Test beskrivelse",
lines = new[]
{
new { lineNumber = 1, accountId = (string?)null, debitAmount = 1000m, creditAmount = 0m, description = "Debet linje" },
new { lineNumber = 2, accountId = (string?)null, debitAmount = 0m, creditAmount = 1000m, description = "Kredit linje" }
}
}
});
// Assert
response.EnsureNoErrors();
response.Data!.UpdateJournalEntryDraft!.Name.Should().Be("Updated Name");
response.Data.UpdateJournalEntryDraft.Description.Should().Be("Test beskrivelse");
response.Data.UpdateJournalEntryDraft.Lines.Should().HaveCount(2);
response.Data.UpdateJournalEntryDraft.Lines![0].DebitAmount.Should().Be(1000m);
response.Data.UpdateJournalEntryDraft.Lines[1].CreditAmount.Should().Be(1000m);
}
[Fact]
public async Task Mutation_UpdateJournalEntryDraft_FailsForNonExistentDraft()
{
// Arrange
var graphqlClient = new GraphQLTestClient(Client);
var companyId = await CreateCompanyAsync(graphqlClient, "Non-existent Draft Company");
var nonExistentId = $"journalentrydraft-{Guid.NewGuid():D}";
// Act
var response = await graphqlClient.MutateAsync("""
mutation UpdateDraft($input: UpdateJournalEntryDraftInput!) {
updateJournalEntryDraft(input: $input) {
id
}
}
""",
new
{
input = new
{
id = nonExistentId,
name = "Test",
lines = Array.Empty