littleshop/LittleShop.Tests/Integration/OrdersWithVariantsTests.cs
SysAdmin 5138242a99 Fix SilverPay payment integration JSON serialization
- Changed JSON naming policy from CamelCase to SnakeCaseLower for SilverPay API compatibility
- Fixed field name from 'fiat_amount' to 'amount' in request body
- Used unique payment ID instead of order ID to avoid duplicate external_id conflicts
- Modified SilverPayApiResponse to handle string amounts from API
- Added [JsonIgnore] attributes to computed properties to prevent JSON serialization conflicts
- Fixed test compilation errors (mock service and enum casting issues)
- Updated SilverPay endpoint to http://10.0.0.52:8001/

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-22 04:38:28 +01:00

373 lines
12 KiB
C#

using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using FluentAssertions;
using LittleShop.DTOs;
using LittleShop.Models;
using LittleShop.Tests.Infrastructure;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace LittleShop.Tests.Integration;
public class OrdersWithVariantsTests : IClassFixture<TestWebApplicationFactory>
{
private readonly HttpClient _client;
private readonly TestWebApplicationFactory _factory;
public OrdersWithVariantsTests(TestWebApplicationFactory factory)
{
_factory = factory;
_client = _factory.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false
});
}
[Fact]
public async Task CreateOrder_WithVariants_ShouldStoreVariantInfo()
{
// Arrange
var product = await CreateProductWithVariants();
var orderRequest = new CreateOrderDto
{
IdentityReference = "test_user_" + Guid.NewGuid(),
ShippingName = "John Doe",
ShippingAddress = "123 Test St",
ShippingCity = "Test City",
ShippingPostCode = "TE1 1ST",
ShippingCountry = "United Kingdom",
Items = new List<CreateOrderItemDto>
{
new()
{
ProductId = product.Id,
Quantity = 1,
SelectedVariant = "Red"
},
new()
{
ProductId = product.Id,
Quantity = 2,
SelectedVariant = "Blue"
}
}
};
// Act
var response = await _client.PostAsJsonAsync("/api/orders", orderRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Created);
var order = await response.Content.ReadFromJsonAsync<OrderDto>();
order.Should().NotBeNull();
order!.Items.Should().HaveCount(2);
order.Items.Should().Contain(i => i.SelectedVariant == "Red" && i.Quantity == 1);
order.Items.Should().Contain(i => i.SelectedVariant == "Blue" && i.Quantity == 2);
}
[Fact]
public async Task CreateOrder_WithMultiBuy_ShouldApplyMultiBuyPricing()
{
// Arrange
var product = await CreateProductWithMultiBuys();
var multiBuy = product.MultiBuys.First(mb => mb.Quantity == 3);
var orderRequest = new CreateOrderDto
{
IdentityReference = "test_user_" + Guid.NewGuid(),
ShippingName = "Jane Doe",
ShippingAddress = "456 Test Ave",
ShippingCity = "Test Town",
ShippingPostCode = "TT2 2ST",
ShippingCountry = "United Kingdom",
Items = new List<CreateOrderItemDto>
{
new()
{
ProductId = product.Id,
ProductMultiBuyId = multiBuy.Id,
Quantity = 3
}
}
};
// Act
var response = await _client.PostAsJsonAsync("/api/orders", orderRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Created);
var order = await response.Content.ReadFromJsonAsync<OrderDto>();
order.Should().NotBeNull();
order!.Items.Should().HaveCount(1);
var item = order.Items.First();
item.Quantity.Should().Be(3);
item.ProductMultiBuyId.Should().Be(multiBuy.Id);
item.UnitPrice.Should().Be(multiBuy.PricePerUnit);
item.TotalPrice.Should().Be(multiBuy.Price);
}
[Fact]
public async Task CreateOrder_WithMultiBuyAndVariant_ShouldStoreBoth()
{
// Arrange
var product = await CreateProductWithMultiBuysAndVariants();
var multiBuy = product.MultiBuys.First(mb => mb.Quantity == 2);
var orderRequest = new CreateOrderDto
{
IdentityReference = "test_user_" + Guid.NewGuid(),
ShippingName = "Bob Smith",
ShippingAddress = "789 Test Rd",
ShippingCity = "Testville",
ShippingPostCode = "TV3 3ST",
ShippingCountry = "United Kingdom",
Items = new List<CreateOrderItemDto>
{
new()
{
ProductId = product.Id,
ProductMultiBuyId = multiBuy.Id,
Quantity = 2,
SelectedVariant = "Vanilla"
}
}
};
// Act
var response = await _client.PostAsJsonAsync("/api/orders", orderRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Created);
var order = await response.Content.ReadFromJsonAsync<OrderDto>();
order.Should().NotBeNull();
var item = order.Items.First();
item.ProductMultiBuyId.Should().Be(multiBuy.Id);
item.SelectedVariant.Should().Be("Vanilla");
item.Quantity.Should().Be(2);
}
[Fact]
public async Task CreateOrder_MixedItems_ShouldCalculateTotalCorrectly()
{
// Arrange
var regularProduct = await CreateRegularProduct();
var variantProduct = await CreateProductWithVariants();
var multiBuyProduct = await CreateProductWithMultiBuys();
var multiBuy = multiBuyProduct.MultiBuys.First(mb => mb.Quantity == 3);
var orderRequest = new CreateOrderDto
{
IdentityReference = "test_user_" + Guid.NewGuid(),
ShippingName = "Alice Johnson",
ShippingAddress = "321 Mixed St",
ShippingCity = "Complex City",
ShippingPostCode = "CC4 4ST",
ShippingCountry = "United Kingdom",
Items = new List<CreateOrderItemDto>
{
// Regular product
new()
{
ProductId = regularProduct.Id,
Quantity = 2
},
// Product with variant
new()
{
ProductId = variantProduct.Id,
Quantity = 1,
SelectedVariant = "Blue"
},
// Product with multi-buy
new()
{
ProductId = multiBuyProduct.Id,
ProductMultiBuyId = multiBuy.Id,
Quantity = 3
}
}
};
// Act
var response = await _client.PostAsJsonAsync("/api/orders", orderRequest);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Created);
var order = await response.Content.ReadFromJsonAsync<OrderDto>();
order.Should().NotBeNull();
order!.Items.Should().HaveCount(3);
// Verify total calculation
var expectedTotal = (regularProduct.Price * 2) +
variantProduct.Price +
multiBuy.Price;
order.TotalAmount.Should().Be(expectedTotal);
}
[Fact]
public async Task GetOrder_ShouldIncludeVariantAndMultiBuyInfo()
{
// Arrange
var product = await CreateProductWithMultiBuysAndVariants();
var multiBuy = product.MultiBuys.First();
var orderRequest = new CreateOrderDto
{
IdentityReference = "test_user_" + Guid.NewGuid(),
ShippingName = "Test User",
ShippingAddress = "Test Address",
ShippingCity = "Test City",
ShippingPostCode = "TE1 1ST",
ShippingCountry = "United Kingdom",
Items = new List<CreateOrderItemDto>
{
new()
{
ProductId = product.Id,
ProductMultiBuyId = multiBuy.Id,
Quantity = multiBuy.Quantity,
SelectedVariant = "Chocolate"
}
}
};
var createResponse = await _client.PostAsJsonAsync("/api/orders", orderRequest);
var createdOrder = await createResponse.Content.ReadFromJsonAsync<OrderDto>();
// Act
var getResponse = await _client.GetAsync($"/api/orders/by-identity/{orderRequest.IdentityReference}/{createdOrder!.Id}");
// Assert
getResponse.StatusCode.Should().Be(HttpStatusCode.OK);
var retrievedOrder = await getResponse.Content.ReadFromJsonAsync<OrderDto>();
retrievedOrder.Should().NotBeNull();
var item = retrievedOrder!.Items.First();
item.ProductMultiBuyId.Should().Be(multiBuy.Id);
item.SelectedVariant.Should().Be("Chocolate");
}
private async Task<ProductDto> CreateRegularProduct()
{
var category = await CreateTestCategory();
var productDto = new CreateProductDto
{
Name = "Regular Product",
Description = "A regular product without variants",
Price = 15.00m,
CategoryId = category.Id,
Weight = 1.0m,
WeightUnit = LittleShop.Enums.ProductWeightUnit.Kilograms
};
var response = await _client.PostAsJsonAsync("/api/admin/products", productDto);
response.EnsureSuccessStatusCode();
return (await response.Content.ReadFromJsonAsync<ProductDto>())!;
}
private async Task<ProductDto> CreateProductWithVariants()
{
var product = await CreateRegularProduct();
// Add variants
var variants = new[] { "Red", "Blue", "Green" };
foreach (var variantName in variants)
{
var variantDto = new CreateProductVariantDto
{
ProductId = product.Id,
Name = variantName,
VariantType = "Color",
StockLevel = 100
};
await _client.PostAsJsonAsync($"/api/admin/products/{product.Id}/variants", variantDto);
}
// Refresh product to get variants
var response = await _client.GetAsync($"/api/catalog/products/{product.Id}");
return (await response.Content.ReadFromJsonAsync<ProductDto>())!;
}
private async Task<ProductDto> CreateProductWithMultiBuys()
{
var product = await CreateRegularProduct();
// Add multi-buys
var multiBuys = new[]
{
new CreateProductMultiBuyDto
{
ProductId = product.Id,
Name = "Twin Pack",
Quantity = 2,
Price = 25.00m
},
new CreateProductMultiBuyDto
{
ProductId = product.Id,
Name = "Triple Pack",
Quantity = 3,
Price = 35.00m
}
};
foreach (var multiBuyDto in multiBuys)
{
await _client.PostAsJsonAsync($"/api/admin/products/{product.Id}/multibuys", multiBuyDto);
}
// Refresh product to get multi-buys
var response = await _client.GetAsync($"/api/catalog/products/{product.Id}");
return (await response.Content.ReadFromJsonAsync<ProductDto>())!;
}
private async Task<ProductDto> CreateProductWithMultiBuysAndVariants()
{
var product = await CreateProductWithMultiBuys();
// Add variants
var variants = new[] { "Vanilla", "Chocolate", "Strawberry" };
foreach (var variantName in variants)
{
var variantDto = new CreateProductVariantDto
{
ProductId = product.Id,
Name = variantName,
VariantType = "Flavor",
StockLevel = 50
};
await _client.PostAsJsonAsync($"/api/admin/products/{product.Id}/variants", variantDto);
}
// Refresh product
var response = await _client.GetAsync($"/api/catalog/products/{product.Id}");
return (await response.Content.ReadFromJsonAsync<ProductDto>())!;
}
private async Task<CategoryDto> CreateTestCategory()
{
var categoryDto = new CreateCategoryDto
{
Name = "Test Category " + Guid.NewGuid(),
Description = "Test category for integration tests"
};
var response = await _client.PostAsJsonAsync("/api/admin/categories", categoryDto);
response.EnsureSuccessStatusCode();
return (await response.Content.ReadFromJsonAsync<CategoryDto>())!;
}
}