diff --git a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs index feedcf0cb..b1277c591 100644 --- a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs +++ b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs @@ -14,6 +14,10 @@ public class ConfirmShoppingCartFixture: ApiSpecification, IAsyncLifeti public readonly Guid ClientId = Guid.NewGuid(); + public readonly ProductItemRequest ProductItem = new(Guid.NewGuid(), 1); + + public decimal UnitPrice; + public async Task InitializeAsync() { var openResponse = await Send( @@ -23,6 +27,26 @@ public async Task InitializeAsync() await CREATED_WITH_DEFAULT_HEADERS(eTag: 1)(openResponse); ShoppingCartId = openResponse.GetCreatedId(); + + var addResponse = await Send( + new ApiRequest( + POST, + URI($"/api/ShoppingCarts/{ShoppingCartId}/products"), + BODY(new AddProductRequest(ProductItem)), + HEADERS(IF_MATCH(1))) + ); + + await OK(addResponse); + + var getResponse = await Send( + new ApiRequest( + GET_UNTIL(RESPONSE_ETAG_IS(2)), + URI($"/api/ShoppingCarts/{ShoppingCartId}") + ) + ); + + var cartDetails = await getResponse.GetResultFromJson(); + UnitPrice = cartDetails.ProductItems.Single().UnitPrice; } public Task DisposeAsync() => Task.CompletedTask; @@ -30,19 +54,18 @@ public async Task InitializeAsync() public class ConfirmShoppingCartTests: IClassFixture { - private readonly ConfirmShoppingCartFixture API; public ConfirmShoppingCartTests(ConfirmShoppingCartFixture api) => API = api; [Fact] [Trait("Category", "Acceptance")] - public async Task Put_Should_Return_OK_And_Cancel_Shopping_Cart() + public async Task Put_Should_Return_OK_And_Confirm_Shopping_Cart() { await API .Given( URI($"/api/ShoppingCarts/{API.ShoppingCartId}/confirmation"), - HEADERS(IF_MATCH(1)) + HEADERS(IF_MATCH(2)) ) .When(PUT) .Then(OK); @@ -51,18 +74,22 @@ await API .Given( URI($"/api/ShoppingCarts/{API.ShoppingCartId}") ) - .When(GET_UNTIL(RESPONSE_ETAG_IS(2))) + .When(GET_UNTIL(RESPONSE_ETAG_IS(3))) .Then( OK, RESPONSE_BODY(new ShoppingCartDetails { Id = API.ShoppingCartId, Status = ShoppingCartStatus.Confirmed, - ProductItems = new List(), ClientId = API.ClientId, - Version = 2, + ProductItems = new List + { + PricedProductItem.Create( + ProductItem.From(API.ProductItem.ProductId, API.ProductItem.Quantity), + API.UnitPrice + ) + }, + Version = 3, })); - - // API.PublishedExternalEventsOfType(); } } diff --git a/Sample/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs b/Sample/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs index 4fe016d14..09ee2068d 100644 --- a/Sample/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs +++ b/Sample/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs @@ -1,11 +1,16 @@ +using Carts.Pricing; using Carts.ShoppingCarts; +using Carts.ShoppingCarts.Products; +using Carts.Tests.Stubs.Products; using Core.Aggregates; namespace Carts.Tests.Builders; internal class CartBuilder { + private readonly IProductPriceCalculator productPriceCalculator = new FakeProductPriceCalculator(); private Func build = () => new ShoppingCart(); + private Func? modify; public CartBuilder Opened() { @@ -23,11 +28,24 @@ public CartBuilder Opened() return this; } + public CartBuilder WithProduct() + { + var productId = Guid.NewGuid(); + const int quantity = 1; + modify += cart => + { + cart.AddProduct(productPriceCalculator, ProductItem.From(productId, quantity)); + return cart; + }; + return this; + } + public static CartBuilder Create() => new(); public ShoppingCart Build() { var cart = build(); + modify?.Invoke(cart); ((IAggregate)cart).DequeueUncommittedEvents(); return cart; } diff --git a/Sample/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs b/Sample/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs index 058c2d8fb..956e1fb41 100644 --- a/Sample/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs +++ b/Sample/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs @@ -16,6 +16,7 @@ public void ForTentativeCart_ShouldSucceed() var cart = CartBuilder .Create() .Opened() + .WithProduct() .Build(); // When @@ -30,4 +31,20 @@ public void ForTentativeCart_ShouldSucceed() @event.Should().BeOfType(); @event!.CartId.Should().Be(cart.Id); } + + [Fact] + public void ForEmptyCart_ShouldFail() + { + // Given + var emptyCart = CartBuilder + .Create() + .Opened() + .Build(); + + // When + Action confirmAction = () => emptyCart.Confirm(); + + // Then + confirmAction.Should().Throw(); + } } diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs index aebb7dbb5..5a1117367 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs @@ -129,6 +129,9 @@ public void Confirm() if(Status != ShoppingCartStatus.Pending) throw new InvalidOperationException($"Confirming cart in '{Status}' status is not allowed."); + if (ProductItems.Count == 0) + throw new InvalidOperationException($"Confirming empty cart is not allowed."); + var @event = ShoppingCartConfirmed.Create(Id, DateTime.UtcNow); Enqueue(@event);