public async void CreateCreditCard_IStripeServiceThrowsStripeExceptionCardError_AddsErrorToModelState()
        {
            Member member = new Member
            {
                UserId = memberId
            };

            string stripeCardToken = "stripeCardToken";

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<Member>> memberDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<Member> { member }.AsQueryable());
            memberDbSetStub.
                Setup(mdb => mdb.FindAsync(memberId)).
                ReturnsAsync(member);

            dbStub.
                Setup(db => db.Members).
                Returns(memberDbSetStub.Object);

            string stripeErrorMessage = "A card Error Message";

            StripeServiceException exception = new StripeServiceException(stripeErrorMessage, StripeExceptionType.CardError);

            Mock<IStripeService> stripeServiceStub = new Mock<IStripeService>();
            stripeServiceStub.
                Setup(s => s.CreateCreditCard(It.IsAny<Member>(), It.IsAny<string>())).
                Throws(exception);

            Mock<IGuidUserIdGetter> idGetterStub = TestHelpers.GetSetupIUserIdGetterFake(memberId);
            Mock<ControllerContext> contextStub = TestHelpers.GetSetupControllerContextFakeWithUserIdentitySetup();

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object, idGetter: idGetterStub.Object, stripeService: stripeServiceStub.Object);
            controller.ControllerContext = contextStub.Object;

            await controller.CreateCreditCard(stripeCardToken);

            Assert.That(controller.ModelState[ManageController.STRIPE_ISSUES_MODELSTATE_KEY].Errors, Has.Some.Matches<ModelError>(modelError => modelError.ErrorMessage == stripeErrorMessage));
        }
        public async void CreateCreditCard_IStripeServiceThrowsApiKeyException_ReturnsInternalServerError()
        {
            Member member = new Member
            {
                UserId = memberId
            };

            string stripeCardToken = "stripeCardToken";

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<Member>> memberDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<Member> { member }.AsQueryable());
            memberDbSetStub.
                Setup(mdb => mdb.FindAsync(memberId)).
                ReturnsAsync(member);

            dbStub.
                Setup(db => db.Members).
                Returns(memberDbSetStub.Object);

            StripeServiceException exception = new StripeServiceException("message", StripeExceptionType.ApiKeyError);

            Mock<IStripeService> stripeServiceStub = new Mock<IStripeService>();
            stripeServiceStub.
                Setup(s => s.CreateCreditCard(It.IsAny<Member>(), It.IsAny<string>())).
                Throws(exception);

            Mock<IGuidUserIdGetter> idGetterStub = TestHelpers.GetSetupIUserIdGetterFake(memberId);
            Mock<ControllerContext> contextStub = TestHelpers.GetSetupControllerContextFakeWithUserIdentitySetup();

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object, idGetter: idGetterStub.Object, stripeService: stripeServiceStub.Object);
            controller.ControllerContext = contextStub.Object;

            var result = await controller.CreateCreditCard(stripeCardToken) as HttpStatusCodeResult;

            Assert.That(result != null);
            Assert.That(result.StatusCode, Is.GreaterThanOrEqualTo((int)HttpStatusCode.InternalServerError));
        }
        public async void CreateCreditCard_IStripeServiceThrowsStripeException_RedirectsToManageCreditCard()
        {
            Member member = new Member
            {
                UserId = memberId
            };

            string stripeCardToken = "stripeCardToken";

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<Member>> memberDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<Member> { member }.AsQueryable());
            memberDbSetStub.
                Setup(mdb => mdb.FindAsync(memberId)).
                ReturnsAsync(member);

            dbStub.
                Setup(db => db.Members).
                Returns(memberDbSetStub.Object);

            StripeServiceException exception = new StripeServiceException("message", StripeExceptionType.UnknownError);

            Mock<IStripeService> stripeServiceStub = new Mock<IStripeService>();
            stripeServiceStub.
                Setup(s => s.CreateCreditCard(It.IsAny<Member>(), It.IsAny<string>())).
                Throws(exception);

            Mock<IGuidUserIdGetter> idGetterStub = TestHelpers.GetSetupIUserIdGetterFake(memberId);
            Mock<ControllerContext> contextStub = TestHelpers.GetSetupControllerContextFakeWithUserIdentitySetup();

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object, idGetter: idGetterStub.Object, stripeService: stripeServiceStub.Object);
            controller.ControllerContext = contextStub.Object;

            var result = await controller.CreateCreditCard(stripeCardToken) as RedirectToRouteResult;

            Assert.That(result != null);
            Assert.That(result.RouteValues["Action"], Is.EqualTo(nameof(controller.ManageCreditCards)));
        }
        public void CreateCreditCard_IStripeServiceThrowsStripeException_HandlesException()
        {
            Member member = new Member
            {
                UserId = memberId
            };

            string stripeCardToken = "stripeCardToken";

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            Mock<DbSet<Member>> memberDbSetStub = TestHelpers.GetFakeAsyncDbSet(new List<Member> { member }.AsQueryable());
            memberDbSetStub.
                Setup(mdb => mdb.FindAsync(memberId)).
                ReturnsAsync(member);

            dbStub.
                Setup(db => db.Members).
                Returns(memberDbSetStub.Object);

            StripeServiceException exception = new StripeServiceException("message", StripeExceptionType.UnknownError);

            Mock<IStripeService> stripeServiceStub = new Mock<IStripeService>();
            stripeServiceStub.
                Setup(s => s.CreateCreditCard(It.IsAny<Member>(), It.IsAny<string>())).
                Throws(exception);

            Mock<IGuidUserIdGetter> idGetterStub = TestHelpers.GetSetupIUserIdGetterFake(memberId);
            Mock<ControllerContext> contextStub = TestHelpers.GetSetupControllerContextFakeWithUserIdentitySetup();

            ManageController controller = CreateManageController(veilDataAccess: dbStub.Object, idGetter: idGetterStub.Object, stripeService: stripeServiceStub.Object);
            controller.ControllerContext = contextStub.Object;

            Assert.That(async () => await controller.CreateCreditCard(stripeCardToken), Throws.Nothing);
        }
        public async void NewBillingInfo_StripeExceptionApiKeyError_ReturnsInternalServerErrorCode()
        {
            Member currentMember = member;
            string cardToken = "cardToken";
            string stripeErrorMessage = "A card error message";

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            SetupVeilDataAccessWithCarts(dbStub, GetCartsListContainingCartWithNewAndUsed());
            SetupVeilDataAccessWithMember(dbStub, currentMember);
            Mock<ControllerContext> contextStub = GetControllerContextWithSessionSetupToReturn(validNotSavedShippingDetails);

            StripeServiceException exception = new StripeServiceException(stripeErrorMessage, StripeExceptionType.ApiKeyError);

            Mock<IStripeService> stripeServiceMock = new Mock<IStripeService>();
            stripeServiceMock.
                Setup(s => s.CreateCreditCard(It.IsAny<Member>(), It.IsAny<string>())).
                Throws(exception);

            CheckoutController controller = CreateCheckoutController(dbStub.Object, context: contextStub.Object, stripeService: stripeServiceMock.Object);

            var result = await controller.NewBillingInfo(cardToken, saveCard: true) as HttpStatusCodeResult;

            Assert.That(result != null);
            Assert.That(result.StatusCode, Is.GreaterThanOrEqualTo((int)HttpStatusCode.InternalServerError));
        }
        public async void NewBillingInfo_StripeException_RedisplaysBillingInfo()
        {
            Member currentMember = member;
            string cardToken = "cardToken";
            string stripeErrorMessage = "A card error message";

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            SetupVeilDataAccessWithCarts(dbStub, GetCartsListContainingCartWithNewAndUsed());
            SetupVeilDataAccessWithMember(dbStub, currentMember);
            Mock<ControllerContext> contextStub = GetControllerContextWithSessionSetupToReturn(validNotSavedShippingDetails);

            StripeServiceException exception = new StripeServiceException(stripeErrorMessage, StripeExceptionType.CardError);

            Mock<IStripeService> stripeServiceMock = new Mock<IStripeService>();
            stripeServiceMock.
                Setup(s => s.CreateCreditCard(It.IsAny<Member>(), It.IsAny<string>())).
                Throws(exception);

            CheckoutController controller = CreateCheckoutController(dbStub.Object, context: contextStub.Object, stripeService: stripeServiceMock.Object);

            var result = await controller.NewBillingInfo(cardToken, saveCard: true) as RedirectToRouteResult;

            Assert.That(result != null);
            Assert.That(result.RouteValues["Action"], Is.EqualTo(nameof(CheckoutController.BillingInfo)));
            Assert.That(result.RouteValues["Controller"], Is.Null);
        }
        public async void NewBillingInfo_StripeExceptionCardError_AddsCardErrorMessageToAlertMessages()
        {
            Member currentMember = member;
            string cardToken = "cardToken";
            string stripeErrorMessage = "A card error message";

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            SetupVeilDataAccessWithCarts(dbStub, GetCartsListContainingCartWithNewAndUsed());
            SetupVeilDataAccessWithMember(dbStub, currentMember);
            Mock<ControllerContext> contextStub = GetControllerContextWithSessionSetupToReturn(validNotSavedShippingDetails);

            StripeServiceException exception = new StripeServiceException(stripeErrorMessage, StripeExceptionType.CardError);

            Mock<IStripeService> stripeServiceMock = new Mock<IStripeService>();
            stripeServiceMock.
                Setup(s => s.CreateCreditCard(It.IsAny<Member>(), It.IsAny<string>())).
                Throws(exception);

            CheckoutController controller = CreateCheckoutController(dbStub.Object, context: contextStub.Object, stripeService: stripeServiceMock.Object);

            await controller.NewBillingInfo(cardToken, saveCard: true);

            Assert.That(controller.TempData[AlertHelper.ALERT_MESSAGE_KEY], Has.Some.Matches<AlertMessage>(am => am.Message == stripeErrorMessage));
        }
        public async void NewBillingInfo_SaveCard_CallsStripeServiceCreateCardWithMemberCustomerIdAndPassedCardToken()
        {
            Member currentMember = member;
            string cardToken = "cardToken";

            Mock<IVeilDataAccess> dbStub = TestHelpers.GetVeilDataAccessFake();
            SetupVeilDataAccessWithCarts(dbStub, GetCartsListContainingCartWithNewAndUsed());
            SetupVeilDataAccessWithMember(dbStub, currentMember);
            Mock<ControllerContext> contextStub = GetControllerContextWithSessionSetupToReturn(validNotSavedShippingDetails);

            StripeServiceException exception = new StripeServiceException("message", StripeExceptionType.UnknownError);

            Mock<IStripeService> stripeServiceMock = new Mock<IStripeService>();
            stripeServiceMock.
                Setup(s => s.CreateCreditCard(It.IsAny<Member>(), It.IsAny<string>())).
                Throws(exception). // Throw exception to end test early as we have the knowledge we need
                Verifiable();

            CheckoutController controller = CreateCheckoutController(dbStub.Object, context: contextStub.Object, stripeService: stripeServiceMock.Object);

            await controller.NewBillingInfo(cardToken, saveCard: true);

            Assert.That(
                () => 
                    stripeServiceMock.Verify(s => s.CreateCreditCard(currentMember, cardToken),
                    Times.Once),
                Throws.Nothing);
        }