Skip to content

Commit

Permalink
Added test collection for Marten ECommerce sample
Browse files Browse the repository at this point in the history
Removed redundant retries from ESDB api tests, as we have already long polling in place
  • Loading branch information
oskardudycz committed May 23, 2024
1 parent 6171bb4 commit fe66531
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 122 deletions.
25 changes: 25 additions & 0 deletions Sample/ECommerce/Carts/Carts.Api.Tests/ApiTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Core.Testing;
using Ogooreck.API;
using Xunit;

namespace Carts.Api.Tests;

public class ShoppingCartsApplicationFactory: TestWebApplicationFactory<Program>;

public class ApiFixture: IDisposable
{
public ApiSpecification<Program> API { get; } =
ApiSpecification<Program>.Setup(new ShoppingCartsApplicationFactory());

public void Dispose() =>
API.Dispose();
}

[CollectionDefinition("ApiTests")]
public class DatabaseCollection: ICollectionFixture<ApiFixture>;

[Collection("ApiTests")]
public abstract class ApiTest(ApiFixture fixture)
{
protected readonly ApiSpecification<Program> API = fixture.API;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ namespace Carts.Api.Tests.ShoppingCarts.AddingProduct;

using static ShoppingCartsApi;

public class AddProductTests(ApiSpecification<Program> api): IClassFixture<ApiSpecification<Program>>
public class AddProductTests(ApiFixture fixture): ApiTest(fixture)
{
private readonly ProductItemRequest product = new(Guid.NewGuid(), 1);

[Fact]
[Trait("Category", "Acceptance")]
public Task Post_Should_AddProductItem_To_ShoppingCart() =>
api
API
.Given("Opened Shopping Cart", OpenShoppingCart())
.When(
"Add new product",
Expand All @@ -28,7 +26,8 @@ public Task Post_Should_AddProductItem_To_ShoppingCart() =>
)
.Then(OK)
.And()
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.OpenedShoppingCartId()}"))
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.OpenedShoppingCartId()}"), HEADERS(IF_MATCH(2)))
.Until(RESPONSE_ETAG_IS(2))
.Then(
RESPONSE_BODY<ShoppingCartDetails>((details, ctx) =>
{
Expand All @@ -40,4 +39,6 @@ public Task Post_Should_AddProductItem_To_ShoppingCart() =>
details.Version.Should().Be(2);
})
);

private readonly ProductItemRequest product = new(Guid.NewGuid(), 1);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,13 @@

namespace Carts.Api.Tests.ShoppingCarts.Canceling;

public class CancelShoppingCartTests(ApiSpecification<Program> api): IClassFixture<ApiSpecification<Program>>
public class CancelShoppingCartTests(ApiFixture fixture): ApiTest(fixture)
{
public readonly Guid ClientId = Guid.NewGuid();

[Fact]
[Trait("Category", "Acceptance")]
public Task Delete_Should_Return_OK_And_Cancel_Shopping_Cart() =>
api
.Given(OpenShoppingCart(ClientId))
API
.Given(OpenShoppingCart(clientId))
.When(
"Cancel Shopping Cart",
DELETE,
Expand All @@ -25,7 +23,7 @@ public Task Delete_Should_Return_OK_And_Cancel_Shopping_Cart() =>
)
.Then(OK)
.And()
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.OpenedShoppingCartId()}"))
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.OpenedShoppingCartId()}"), HEADERS(IF_MATCH(2)))
.Until(RESPONSE_ETAG_IS(2))
.Then(
OK,
Expand All @@ -34,7 +32,9 @@ public Task Delete_Should_Return_OK_And_Cancel_Shopping_Cart() =>
details.Id.Should().Be(ctx.OpenedShoppingCartId());
details.Status.Should().Be(ShoppingCartStatus.Canceled);
details.ProductItems.Should().BeEmpty();
details.ClientId.Should().Be(ClientId);
details.ClientId.Should().Be(clientId);
details.Version.Should().Be(2);
}));

private readonly Guid clientId = Guid.NewGuid();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ namespace Carts.Api.Tests.ShoppingCarts.Confirming;

using static ShoppingCartsApi;

public class ConfirmShoppingCartTests(ApiSpecification<Program> api): IClassFixture<ApiSpecification<Program>>
public class ConfirmShoppingCartTests(ApiFixture fixture): ApiTest(fixture)
{
[Fact]
[Trait("Category", "Acceptance")]
public Task Put_Should_Return_OK_And_Confirm_Shopping_Cart() =>
api
API
.Given(
"Shopping Cart with Product Item",
OpenShoppingCart(ClientId),
AddProductItem(ProductItem, ifMatch: 1)
OpenShoppingCart(clientId),
AddProductItem(productItem, ifMatch: 1)
)
.When(
PUT,
Expand All @@ -28,8 +28,8 @@ public Task Put_Should_Return_OK_And_Confirm_Shopping_Cart() =>
)
.Then(OK)
.And()
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.OpenedShoppingCartId()}"))
.Until(RESPONSE_ETAG_IS(3), 10)
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.OpenedShoppingCartId()}"), HEADERS(IF_MATCH(3)))
.Until(RESPONSE_ETAG_IS(3))
.Then(
OK,
RESPONSE_BODY<ShoppingCartDetails>((details, ctx) =>
Expand All @@ -38,14 +38,14 @@ public Task Put_Should_Return_OK_And_Confirm_Shopping_Cart() =>
details.Status.Should().Be(ShoppingCartStatus.Confirmed);
details.ProductItems.Count.Should().Be(1);
details.ProductItems.Single().ProductItem.Should()
.Be(Carts.ShoppingCarts.Products.ProductItem.From(ProductItem.ProductId, ProductItem.Quantity));
details.ClientId.Should().Be(ClientId);
.Be(Carts.ShoppingCarts.Products.ProductItem.From(productItem.ProductId, productItem.Quantity));
details.ClientId.Should().Be(clientId);
details.Version.Should().Be(3);
}));

// API.PublishedExternalEventsOfType<CartFinalized>();

private readonly Guid ClientId = Guid.NewGuid();
private readonly Guid clientId = Guid.NewGuid();

private readonly ProductItemRequest ProductItem = new(Guid.NewGuid(), 1);
private readonly ProductItemRequest productItem = new(Guid.NewGuid(), 1);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,30 @@

namespace Carts.Api.Tests.ShoppingCarts.Opening;

public class OpenShoppingCartTests(ApiSpecification<Program> api): IClassFixture<ApiSpecification<Program>>
public class OpenShoppingCartTests(ApiFixture fixture): ApiTest(fixture)
{
[Fact]
public Task Post_ShouldReturn_CreatedStatus_With_CartId() =>
api.Scenario(
api.Given()
.When(
POST,
URI("/api/ShoppingCarts/"),
BODY(new OpenShoppingCartRequest(ClientId))
)
.Then(CREATED_WITH_DEFAULT_HEADERS(eTag: 1)),
response =>
api.Given()
.When(GET, URI($"/api/ShoppingCarts/{response.GetCreatedId()}"))
.Until(RESPONSE_ETAG_IS(1), 10)
.Then(
OK,
RESPONSE_BODY<ShoppingCartDetails>(details =>
{
details.Id.Should().Be(response.GetCreatedId<Guid>());
details.Status.Should().Be(ShoppingCartStatus.Pending);
details.ProductItems.Should().BeEmpty();
details.ClientId.Should().Be(ClientId);
details.Version.Should().Be(1);
}))
);
API.Given()
.When(
POST,
URI("/api/ShoppingCarts/"),
BODY(new OpenShoppingCartRequest(ClientId))
)
.Then(CREATED_WITH_DEFAULT_HEADERS(eTag: 1))
.And()
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.GetCreatedId()}"), HEADERS(IF_MATCH(1)))
.Until(RESPONSE_ETAG_IS(1))
.Then(
OK,
RESPONSE_BODY<ShoppingCartDetails>((details, ctx) =>
{
details.Id.Should().Be(ctx.GetCreatedId<Guid>());
details.Status.Should().Be(ShoppingCartStatus.Pending);
details.ProductItems.Should().BeEmpty();
details.ClientId.Should().Be(ClientId);
details.Version.Should().Be(1);
}));

public readonly Guid ClientId = Guid.NewGuid();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,79 +10,74 @@

namespace Carts.Api.Tests.ShoppingCarts.RemovingProduct;

public class RemoveProductFixture: ApiSpecification<Program>, IAsyncLifetime
{
public Guid ShoppingCartId { get; private set; }

public readonly Guid ClientId = Guid.NewGuid();

public readonly ProductItemRequest ProductItem = new(Guid.NewGuid(), 10);

public decimal UnitPrice;

public async Task InitializeAsync()
{
var cartDetails = await Given()
.When(POST, URI("/api/ShoppingCarts"), BODY(new OpenShoppingCartRequest(ClientId)))
.Then(CREATED_WITH_DEFAULT_HEADERS(eTag: 1))
.And()
.When(
POST,
URI(ctx => $"/api/ShoppingCarts/{ctx.GetCreatedId()}/products"),
BODY(new AddProductRequest(ProductItem)),
HEADERS(IF_MATCH(1))
)
.Then(OK)
.And()
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.GetCreatedId()}"))
.Until(RESPONSE_ETAG_IS(2))
.Then(OK)
.GetResponseBody<ShoppingCartDetails>();

ShoppingCartId = cartDetails.Id;
UnitPrice = cartDetails.ProductItems.Single().UnitPrice;
}

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

public class RemoveProductTests(RemoveProductFixture api): IClassFixture<RemoveProductFixture>
public class RemoveProductTests(ApiFixture fixture): ApiTest(fixture), IAsyncLifetime
{
[Fact]
[Trait("Category", "Acceptance")]
public Task Delete_Should_Return_OK_And_Cancel_Shopping_Cart() =>
api
API
.Given()
.When(
DELETE,
URI(
$"/api/ShoppingCarts/{api.ShoppingCartId}/products/{api.ProductItem.ProductId}?quantity={RemovedCount}&unitPrice={api.UnitPrice.ToString(CultureInfo.InvariantCulture)}"),
$"/api/ShoppingCarts/{ShoppingCartId}/products/{productItem.ProductId}?quantity={RemovedCount}&unitPrice={unitPrice.ToString(CultureInfo.InvariantCulture)}"),
HEADERS(IF_MATCH(2))
)
.Then(NO_CONTENT)
.And()
.When(GET, URI($"/api/ShoppingCarts/{api.ShoppingCartId}"))
.When(GET, URI($"/api/ShoppingCarts/{ShoppingCartId}"), HEADERS(IF_MATCH(3)))
.Until(RESPONSE_ETAG_IS(3))
.Then(
OK,
RESPONSE_BODY<ShoppingCartDetails>(details =>
{
details.Id.Should().Be(api.ShoppingCartId);
details.Id.Should().Be(ShoppingCartId);
details.Status.Should().Be(ShoppingCartStatus.Pending);
details.ProductItems.Should().HaveCount(1);
var productItem = details.ProductItems.Single();
productItem.Should().BeEquivalentTo(
PricedProductItem.Create(
ProductItem.From
(
api.ProductItem.ProductId!.Value,
api.ProductItem.Quantity!.Value - RemovedCount
this.productItem.ProductId!.Value,
this.productItem.Quantity!.Value - RemovedCount
),
api.UnitPrice
unitPrice
));
details.ClientId.Should().Be(api.ClientId);
details.ClientId.Should().Be(clientId);
details.Version.Should().Be(3);
}));

private readonly int RemovedCount = 5;

private Guid ShoppingCartId { get; set; }
private readonly Guid clientId = Guid.NewGuid();
private readonly ProductItemRequest productItem = new(Guid.NewGuid(), 10);
private decimal unitPrice;
private const int RemovedCount = 5;

public async Task InitializeAsync()
{
var cartDetails = await API
.Given()
.When(POST, URI("/api/ShoppingCarts"), BODY(new OpenShoppingCartRequest(clientId)))
.Then(CREATED_WITH_DEFAULT_HEADERS(eTag: 1))
.And()
.When(
POST,
URI(ctx => $"/api/ShoppingCarts/{ctx.GetCreatedId()}/products"),
BODY(new AddProductRequest(productItem)),
HEADERS(IF_MATCH(1))
)
.Then(OK)
.And()
.When(GET, URI(ctx => $"/api/ShoppingCarts/{ctx.GetCreatedId()}"), HEADERS(IF_MATCH(2)))
.Until(RESPONSE_ETAG_IS(2))
.Then(OK)
.GetResponseBody<ShoppingCartDetails>();

ShoppingCartId = cartDetails.Id;
unitPrice = cartDetails.ProductItems.Single().UnitPrice;
}

public Task DisposeAsync() => Task.CompletedTask;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

namespace Carts.Api.Controllers;

using static ETagExtensions;

[Route("api/[controller]")]
public class ShoppingCartsController(
ICommandBus commandBus,
Expand Down Expand Up @@ -62,9 +64,9 @@ [FromBody] AddProductRequest? request
[HttpDelete("{id}/products/{productId}")]
public async Task<IActionResult> RemoveProduct(
Guid id,
[FromRoute]Guid? productId,
[FromQuery]int? quantity,
[FromQuery]decimal? unitPrice
[FromRoute] Guid? productId,
[FromQuery] int? quantity,
[FromQuery] decimal? unitPrice
)
{
var command = ShoppingCarts.RemovingProduct.RemoveProduct.Create(
Expand Down Expand Up @@ -94,7 +96,6 @@ public async Task<IActionResult> ConfirmCart(Guid id)
}



[HttpDelete("{id}")]
public async Task<IActionResult> CancelCart(Guid id)
{
Expand All @@ -108,27 +109,32 @@ public async Task<IActionResult> CancelCart(Guid id)
}

[HttpGet("{id}")]
public async Task<ShoppingCartDetails> Get(Guid id)
public async Task<ShoppingCartDetails> Get(Guid id, [FromIfMatchHeader] string? eTag)
{
var result = await queryBus.Query<GetCartById, ShoppingCartDetails>(GetCartById.For(id));
var result = await queryBus.Query<GetCartById, ShoppingCartDetails>(
GetCartById.From(id, eTag != null ? ToExpectedVersion(eTag) : null)
);

Response.TrySetETagResponseHeader(result.Version);

return result;
}

[HttpGet]
public async Task<PagedListResponse<ShoppingCartShortInfo>> Get([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20)
public async Task<PagedListResponse<ShoppingCartShortInfo>> Get([FromQuery] int pageNumber = 1,
[FromQuery] int pageSize = 20)
{
var pagedList = await queryBus.Query<GetCarts, IPagedList<ShoppingCartShortInfo>>(GetCarts.Create(pageNumber, pageSize));
var pagedList =
await queryBus.Query<GetCarts, IPagedList<ShoppingCartShortInfo>>(GetCarts.Create(pageNumber, pageSize));

return pagedList.ToResponse();
}

[HttpGet("{id}/history")]
public async Task<PagedListResponse<ShoppingCartHistory>> GetHistory(Guid id)
{
var pagedList = await queryBus.Query<GetCartHistory, IPagedList<ShoppingCartHistory>>(GetCartHistory.Create(id));
var pagedList =
await queryBus.Query<GetCartHistory, IPagedList<ShoppingCartHistory>>(GetCartHistory.Create(id));

return pagedList.ToResponse();
}
Expand Down
Loading

0 comments on commit fe66531

Please sign in to comment.