401 fix (#408)
* transfer basket on login * review page * unit tests for TransferBasketAsync
This commit is contained in:
@@ -59,11 +59,22 @@ namespace Microsoft.eShopWeb.ApplicationCore.Services
|
|||||||
{
|
{
|
||||||
Guard.Against.NullOrEmpty(anonymousId, nameof(anonymousId));
|
Guard.Against.NullOrEmpty(anonymousId, nameof(anonymousId));
|
||||||
Guard.Against.NullOrEmpty(userName, nameof(userName));
|
Guard.Against.NullOrEmpty(userName, nameof(userName));
|
||||||
var basketSpec = new BasketWithItemsSpecification(anonymousId);
|
var anonymousBasketSpec = new BasketWithItemsSpecification(anonymousId);
|
||||||
var basket = (await _basketRepository.FirstOrDefaultAsync(basketSpec));
|
var anonymousBasket = await _basketRepository.FirstOrDefaultAsync(anonymousBasketSpec);
|
||||||
if (basket == null) return;
|
if (anonymousBasket == null) return;
|
||||||
basket.SetNewBuyerId(userName);
|
var userBasketSpec = new BasketWithItemsSpecification(userName);
|
||||||
await _basketRepository.UpdateAsync(basket);
|
var userBasket = await _basketRepository.FirstOrDefaultAsync(userBasketSpec);
|
||||||
|
if (userBasket == null)
|
||||||
|
{
|
||||||
|
userBasket = new Basket(userName);
|
||||||
|
await _basketRepository.AddAsync(userBasket);
|
||||||
|
}
|
||||||
|
foreach (var item in anonymousBasket.Items)
|
||||||
|
{
|
||||||
|
userBasket.AddItem(item.CatalogItemId, item.UnitPrice, item.Quantity);
|
||||||
|
}
|
||||||
|
await _basketRepository.UpdateAsync(userBasket);
|
||||||
|
await _basketRepository.DeleteAsync(anonymousBasket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
using Microsoft.eShopWeb.Infrastructure.Identity;
|
using Microsoft.eShopWeb.Infrastructure.Identity;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account
|
namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account
|
||||||
{
|
{
|
||||||
@@ -18,11 +19,13 @@ namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account
|
|||||||
{
|
{
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
private readonly ILogger<LoginModel> _logger;
|
private readonly ILogger<LoginModel> _logger;
|
||||||
|
private readonly IBasketService _basketService;
|
||||||
|
|
||||||
public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
|
public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger, IBasketService basketService)
|
||||||
{
|
{
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_basketService = basketService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BindProperty]
|
[BindProperty]
|
||||||
@@ -78,6 +81,7 @@ namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account
|
|||||||
if (result.Succeeded)
|
if (result.Succeeded)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("User logged in.");
|
_logger.LogInformation("User logged in.");
|
||||||
|
await TransferAnonymousBasketToUserAsync(Input.Email);
|
||||||
return LocalRedirect(returnUrl);
|
return LocalRedirect(returnUrl);
|
||||||
}
|
}
|
||||||
if (result.RequiresTwoFactor)
|
if (result.RequiresTwoFactor)
|
||||||
@@ -99,5 +103,15 @@ namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account
|
|||||||
// If we got this far, something failed, redisplay form
|
// If we got this far, something failed, redisplay form
|
||||||
return Page();
|
return Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task TransferAnonymousBasketToUserAsync(string userName)
|
||||||
|
{
|
||||||
|
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
|
||||||
|
{
|
||||||
|
var anonymousId = Request.Cookies[Constants.BASKET_COOKIENAME];
|
||||||
|
await _basketService.TransferBasketAsync(anonymousId, userName);
|
||||||
|
Response.Cookies.Delete(Constants.BASKET_COOKIENAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@page
|
@page
|
||||||
@model CheckoutModel
|
@model CheckoutModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Checkout Complete";
|
ViewData["Title"] = "Checkout";
|
||||||
}
|
}
|
||||||
<section class="esh-catalog-hero">
|
<section class="esh-catalog-hero">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@@ -10,7 +10,77 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Thanks for your Order!</h1>
|
<h1>Review</h1>
|
||||||
|
@if (Model.BasketModel.Items.Any())
|
||||||
|
{
|
||||||
|
<form asp-page="Checkout" method="post">
|
||||||
|
<article class="esh-basket-titles row">
|
||||||
|
<br />
|
||||||
|
<section class="esh-basket-title col-xs-3">Product</section>
|
||||||
|
<section class="esh-basket-title col-xs-3 hidden-lg-down"></section>
|
||||||
|
<section class="esh-basket-title col-xs-2">Price</section>
|
||||||
|
<section class="esh-basket-title col-xs-2">Quantity</section>
|
||||||
|
<section class="esh-basket-title col-xs-2">Cost</section>
|
||||||
|
</article>
|
||||||
|
<div class="esh-catalog-items row">
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
@for (int i = 0; i < Model.BasketModel.Items.Count; i++)
|
||||||
|
{
|
||||||
|
var item = Model.BasketModel.Items[i];
|
||||||
|
<article class="esh-basket-items row">
|
||||||
|
<div>
|
||||||
|
<section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down">
|
||||||
|
<img class="esh-basket-image" src="@item.PictureUrl" />
|
||||||
|
</section>
|
||||||
|
<section class="esh-basket-item esh-basket-item--middle col-xs-3">@item.ProductName</section>
|
||||||
|
<section class="esh-basket-item esh-basket-item--middle col-xs-2">$ @item.UnitPrice.ToString("N2")</section>
|
||||||
|
<section class="esh-basket-item esh-basket-item--middle col-xs-2">
|
||||||
|
<input type="hidden" name="@("Items[" + i + "].Id")" value="@item.Id" />
|
||||||
|
<input type="hidden" name="@("Items[" + i + "].Quantity")" value="@item.Quantity" />
|
||||||
|
@item.Quantity
|
||||||
|
</section>
|
||||||
|
<section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-xs-2">$ @Math.Round(item.Quantity * item.UnitPrice, 2).ToString("N2")</section>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
<a asp-page="/Index">Continue Shopping...</a>
|
</div>
|
||||||
|
</article>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<article class="esh-basket-titles esh-basket-titles--clean row">
|
||||||
|
<section class="esh-basket-title col-xs-10"></section>
|
||||||
|
<section class="esh-basket-title col-xs-2">Total</section>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="esh-basket-items row">
|
||||||
|
<section class="esh-basket-item col-xs-10"></section>
|
||||||
|
<section class="esh-basket-item esh-basket-item--mark col-xs-2">$ @Model.BasketModel.Total().ToString("N2")</section>
|
||||||
|
</article>
|
||||||
|
|
||||||
|
<article class="esh-basket-items row">
|
||||||
|
<section class="esh-basket-item col-xs-7"></section>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<section class="esh-basket-item col-xs-1">
|
||||||
|
<a asp-page="Index" class="btn esh-basket-checkout text-white">[ Back ]</a>
|
||||||
|
</section>
|
||||||
|
<section class="esh-basket-item col-xs-push-7 col-xs-4 text-right">
|
||||||
|
<input type="submit" class="btn esh-basket-checkout" value="[ Pay Now ]" />
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<h3 class="esh-catalog-items row">
|
||||||
|
Basket is empty.
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<section class="esh-basket-item">
|
||||||
|
<a asp-page="/Index" class="btn esh-basket-checkout text-white">[ Continue Shopping..]</a>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
@@ -14,6 +15,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Microsoft.eShopWeb.Web.Pages.Basket
|
namespace Microsoft.eShopWeb.Web.Pages.Basket
|
||||||
{
|
{
|
||||||
|
[Authorize]
|
||||||
public class CheckoutModel : PageModel
|
public class CheckoutModel : PageModel
|
||||||
{
|
{
|
||||||
private readonly IBasketService _basketService;
|
private readonly IBasketService _basketService;
|
||||||
@@ -40,13 +42,7 @@ namespace Microsoft.eShopWeb.Web.Pages.Basket
|
|||||||
|
|
||||||
public async Task OnGet()
|
public async Task OnGet()
|
||||||
{
|
{
|
||||||
if (HttpContext.Request.Query.ContainsKey(Constants.BASKET_ID))
|
await SetBasketModelAsync();
|
||||||
{
|
|
||||||
var basketId = int.Parse(HttpContext.Request.Query[Constants.BASKET_ID]);
|
|
||||||
await _basketService.TransferBasketAsync(Request.Cookies[Constants.BASKET_COOKIENAME], User.Identity.Name);
|
|
||||||
await _orderService.CreateOrderAsync(basketId, new Address("123 Main St.", "Kent", "OH", "United States", "44240"));
|
|
||||||
await _basketService.DeleteBasketAsync(basketId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnPost(IEnumerable<BasketItemViewModel> items)
|
public async Task<IActionResult> OnPost(IEnumerable<BasketItemViewModel> items)
|
||||||
@@ -72,7 +68,7 @@ namespace Microsoft.eShopWeb.Web.Pages.Basket
|
|||||||
return RedirectToPage("/Basket/Index");
|
return RedirectToPage("/Basket/Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
return RedirectToPage();
|
return RedirectToPage("Success");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetBasketModelAsync()
|
private async Task SetBasketModelAsync()
|
||||||
|
|||||||
@@ -71,16 +71,7 @@
|
|||||||
asp-page-handler="Update">
|
asp-page-handler="Update">
|
||||||
[ Update ]
|
[ Update ]
|
||||||
</button>
|
</button>
|
||||||
@{
|
<a asp-page="./Checkout" class="btn esh-basket-checkout">[ Checkout ]</a>
|
||||||
var data = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ Constants.BASKET_ID, Model.BasketModel.Id.ToString() },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
<input type="submit" asp-page="Checkout"
|
|
||||||
class="btn esh-basket-checkout"
|
|
||||||
asp-all-route-data=data
|
|
||||||
value="[ Checkout ]" name="action" />
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
17
src/Web/Pages/Basket/Success.cshtml
Normal file
17
src/Web/Pages/Basket/Success.cshtml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
@page
|
||||||
|
@model SuccessModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Checkout Complete";
|
||||||
|
}
|
||||||
|
|
||||||
|
<section class="esh-catalog-hero">
|
||||||
|
<div class="container">
|
||||||
|
<img class="esh-catalog-title" src="~/images/main_banner_text.png" />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<h1>Thanks for your Order!</h1>
|
||||||
|
|
||||||
|
<a asp-page="/Index">Continue Shopping...</a>
|
||||||
|
</div>
|
||||||
19
src/Web/Pages/Basket/Success.cshtml.cs
Normal file
19
src/Web/Pages/Basket/Success.cshtml.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopWeb.Web.Pages.Basket
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
public class SuccessModel : PageModel
|
||||||
|
{
|
||||||
|
public void OnGet()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
<PackageReference Include="BuildBundlerMinifier" Version="2.9.406" Condition="'$(Configuration)'=='Release'" PrivateAssets="All" />
|
<PackageReference Include="BuildBundlerMinifier" Version="2.9.406" Condition="'$(Configuration)'=='Release'" PrivateAssets="All" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.5.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.5.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.4" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.2" />
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.3" />
|
||||||
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.76" />
|
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.76" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.4.1" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.4.1" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.4.1" />
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="5.4.1" />
|
||||||
|
|||||||
@@ -46,3 +46,5 @@
|
|||||||
.esh-basket-checkout:hover {
|
.esh-basket-checkout:hover {
|
||||||
background-color: #4a760f;
|
background-color: #4a760f;
|
||||||
transition: all 0.35s; }
|
transition: all 0.35s; }
|
||||||
|
.esh-basket-checkout:visited {
|
||||||
|
color: #FFFFFF; }
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
.esh-basket{min-height:80vh;}.esh-basket-titles{padding-bottom:1rem;padding-top:2rem;}.esh-basket-titles--clean{padding-bottom:0;padding-top:0;}.esh-basket-title{text-transform:uppercase;}.esh-basket-items--border{border-bottom:1px solid #eee;padding:.5rem 0;}.esh-basket-items--border:last-of-type{border-color:transparent;}.esh-basket-items-margin-left1{margin-left:1px;}.esh-basket-item{font-size:1rem;font-weight:300;}.esh-basket-item--middle{line-height:8rem;}@media screen and (max-width:1024px){.esh-basket-item--middle{line-height:1rem;}}.esh-basket-item--mark{color:#00a69c;}.esh-basket-image{height:8rem;}.esh-basket-input{line-height:1rem;width:100%;}.esh-basket-checkout{background-color:#83d01b;border:0;border-radius:0;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s;}.esh-basket-checkout:hover{background-color:#4a760f;transition:all .35s;}
|
.esh-basket{min-height:80vh;}.esh-basket-titles{padding-bottom:1rem;padding-top:2rem;}.esh-basket-titles--clean{padding-bottom:0;padding-top:0;}.esh-basket-title{text-transform:uppercase;}.esh-basket-items--border{border-bottom:1px solid #eee;padding:.5rem 0;}.esh-basket-items--border:last-of-type{border-color:transparent;}.esh-basket-items-margin-left1{margin-left:1px;}.esh-basket-item{font-size:1rem;font-weight:300;}.esh-basket-item--middle{line-height:8rem;}@media screen and (max-width:1024px){.esh-basket-item--middle{line-height:1rem;}}.esh-basket-item--mark{color:#00a69c;}.esh-basket-image{height:8rem;}.esh-basket-input{line-height:1rem;width:100%;}.esh-basket-checkout{background-color:#83d01b;border:0;border-radius:0;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s;}.esh-basket-checkout:hover{background-color:#4a760f;transition:all .35s;}.esh-basket-checkout:visited{color:#fff;}
|
||||||
@@ -82,6 +82,10 @@
|
|||||||
background-color: $color-secondary-darker;
|
background-color: $color-secondary-darker;
|
||||||
transition: all $animation-speed-default;
|
transition: all $animation-speed-default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:visited {
|
||||||
|
color: $color-foreground-brighter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
using Microsoft.eShopWeb.ApplicationCore.Services;
|
using Ardalis.Specification;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Services;
|
||||||
|
using Microsoft.eShopWeb.ApplicationCore.Specifications;
|
||||||
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@@ -7,6 +14,17 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Services.BasketServiceTes
|
|||||||
{
|
{
|
||||||
public class TransferBasket
|
public class TransferBasket
|
||||||
{
|
{
|
||||||
|
private readonly string _nonexistentAnonymousBasketBuyerId = "nonexistent-anonymous-basket-buyer-id";
|
||||||
|
private readonly string _existentAnonymousBasketBuyerId = "existent-anonymous-basket-buyer-id";
|
||||||
|
private readonly string _nonexistentUserBasketBuyerId = "newuser@microsoft.com";
|
||||||
|
private readonly string _existentUserBasketBuyerId = "testuser@microsoft.com";
|
||||||
|
private readonly Mock<IAsyncRepository<Basket>> _mockBasketRepo;
|
||||||
|
|
||||||
|
public TransferBasket()
|
||||||
|
{
|
||||||
|
_mockBasketRepo = new Mock<IAsyncRepository<Basket>>();
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ThrowsGivenNullAnonymousId()
|
public async Task ThrowsGivenNullAnonymousId()
|
||||||
{
|
{
|
||||||
@@ -22,5 +40,66 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Services.BasketServiceTes
|
|||||||
|
|
||||||
await Assert.ThrowsAsync<ArgumentNullException>(async () => await basketService.TransferBasketAsync("abcdefg", null));
|
await Assert.ThrowsAsync<ArgumentNullException>(async () => await basketService.TransferBasketAsync("abcdefg", null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokesBasketRepositoryFirstOrDefaultAsyncOnceIfAnonymousBasketNotExists()
|
||||||
|
{
|
||||||
|
var anonymousBasket = null as Basket;
|
||||||
|
var userBasket = new Basket(_existentUserBasketBuyerId);
|
||||||
|
_mockBasketRepo.SetupSequence(x => x.FirstOrDefaultAsync(It.IsAny<BasketWithItemsSpecification>()))
|
||||||
|
.ReturnsAsync(anonymousBasket)
|
||||||
|
.ReturnsAsync(userBasket);
|
||||||
|
var basketService = new BasketService(_mockBasketRepo.Object, null);
|
||||||
|
await basketService.TransferBasketAsync(_nonexistentAnonymousBasketBuyerId, _existentUserBasketBuyerId);
|
||||||
|
_mockBasketRepo.Verify(x => x.FirstOrDefaultAsync(It.IsAny<BasketWithItemsSpecification>()), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TransferAnonymousBasketItemsWhilePreservingExistingUserBasketItems()
|
||||||
|
{
|
||||||
|
var anonymousBasket = new Basket(_existentAnonymousBasketBuyerId);
|
||||||
|
anonymousBasket.AddItem(1, 10, 1);
|
||||||
|
anonymousBasket.AddItem(3, 55, 7);
|
||||||
|
var userBasket = new Basket(_existentUserBasketBuyerId);
|
||||||
|
userBasket.AddItem(1, 10, 4);
|
||||||
|
userBasket.AddItem(2, 99, 3);
|
||||||
|
_mockBasketRepo.SetupSequence(x => x.FirstOrDefaultAsync(It.IsAny<BasketWithItemsSpecification>()))
|
||||||
|
.ReturnsAsync(anonymousBasket)
|
||||||
|
.ReturnsAsync(userBasket);
|
||||||
|
var basketService = new BasketService(_mockBasketRepo.Object, null);
|
||||||
|
await basketService.TransferBasketAsync(_nonexistentAnonymousBasketBuyerId, _existentUserBasketBuyerId);
|
||||||
|
_mockBasketRepo.Verify(x => x.UpdateAsync(userBasket), Times.Once);
|
||||||
|
Assert.Equal(3, userBasket.Items.Count);
|
||||||
|
Assert.Contains(userBasket.Items, x => x.CatalogItemId == 1 && x.UnitPrice == 10 && x.Quantity == 5);
|
||||||
|
Assert.Contains(userBasket.Items, x => x.CatalogItemId == 2 && x.UnitPrice == 99 && x.Quantity == 3);
|
||||||
|
Assert.Contains(userBasket.Items, x => x.CatalogItemId == 3 && x.UnitPrice == 55 && x.Quantity == 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task RemovesAnonymousBasketAfterUpdatingUserBasket()
|
||||||
|
{
|
||||||
|
var anonymousBasket = new Basket(_existentAnonymousBasketBuyerId);
|
||||||
|
var userBasket = new Basket(_existentUserBasketBuyerId);
|
||||||
|
_mockBasketRepo.SetupSequence(x => x.FirstOrDefaultAsync(It.IsAny<BasketWithItemsSpecification>()))
|
||||||
|
.ReturnsAsync(anonymousBasket)
|
||||||
|
.ReturnsAsync(userBasket);
|
||||||
|
var basketService = new BasketService(_mockBasketRepo.Object, null);
|
||||||
|
await basketService.TransferBasketAsync(_nonexistentAnonymousBasketBuyerId, _existentUserBasketBuyerId);
|
||||||
|
_mockBasketRepo.Verify(x => x.UpdateAsync(userBasket), Times.Once);
|
||||||
|
_mockBasketRepo.Verify(x => x.DeleteAsync(anonymousBasket), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreatesNewUserBasketIfNotExists()
|
||||||
|
{
|
||||||
|
var anonymousBasket = new Basket(_existentAnonymousBasketBuyerId);
|
||||||
|
var userBasket = null as Basket;
|
||||||
|
_mockBasketRepo.SetupSequence(x => x.FirstOrDefaultAsync(It.IsAny<BasketWithItemsSpecification>()))
|
||||||
|
.ReturnsAsync(anonymousBasket)
|
||||||
|
.ReturnsAsync(userBasket);
|
||||||
|
var basketService = new BasketService(_mockBasketRepo.Object, null);
|
||||||
|
await basketService.TransferBasketAsync(_existentAnonymousBasketBuyerId, _nonexistentUserBasketBuyerId);
|
||||||
|
_mockBasketRepo.Verify(x => x.AddAsync(It.Is<Basket>(x => x.BuyerId == _nonexistentUserBasketBuyerId)), Times.Once);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user