Skip to content

Commit

Permalink
Added product items validation to cart confirmation
Browse files Browse the repository at this point in the history
Order for confirmed cart can't be created when the cart is empty.
  • Loading branch information
grzegorzorwat authored and oskardudycz committed Feb 6, 2023
1 parent 675e73e commit 001a2ea
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 8 deletions.
Expand Up @@ -14,6 +14,10 @@ public class ConfirmShoppingCartFixture: ApiSpecification<Program>, 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(
Expand All @@ -23,26 +27,45 @@ public async Task InitializeAsync()
await CREATED_WITH_DEFAULT_HEADERS(eTag: 1)(openResponse);

ShoppingCartId = openResponse.GetCreatedId<Guid>();

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<ShoppingCartDetails>();
UnitPrice = cartDetails.ProductItems.Single().UnitPrice;
}

public Task DisposeAsync() => Task.CompletedTask;
}

public class ConfirmShoppingCartTests: IClassFixture<ConfirmShoppingCartFixture>
{

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);
Expand All @@ -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<PricedProductItem>(),
ClientId = API.ClientId,
Version = 2,
ProductItems = new List<PricedProductItem>
{
PricedProductItem.Create(
ProductItem.From(API.ProductItem.ProductId, API.ProductItem.Quantity),
API.UnitPrice
)
},
Version = 3,
}));

// API.PublishedExternalEventsOfType<CartFinalized>();
}
}
18 changes: 18 additions & 0 deletions 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<ShoppingCart> build = () => new ShoppingCart();
private Func<ShoppingCart, ShoppingCart>? modify;

public CartBuilder Opened()
{
Expand All @@ -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;
}
Expand Down
Expand Up @@ -16,6 +16,7 @@ public void ForTentativeCart_ShouldSucceed()
var cart = CartBuilder
.Create()
.Opened()
.WithProduct()
.Build();

// When
Expand All @@ -30,4 +31,20 @@ public void ForTentativeCart_ShouldSucceed()
@event.Should().BeOfType<ShoppingCartConfirmed>();
@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<InvalidOperationException>();
}
}
3 changes: 3 additions & 0 deletions Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs
Expand Up @@ -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);
Expand Down

0 comments on commit 001a2ea

Please sign in to comment.