From 0166400b034ff494523ea930f946a0d1ccad904a Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 6 Jan 2021 11:00:43 +1100 Subject: [PATCH] Guard against invalid quantity input The user can now type anything into the quantity field and some of it may not be valid. These safe guards ensure that the buttons still work even if the quantity is undefined or out of range. Angular guards against the value being out of range but that has other side-effects. We want to be able to de-activate some of Angular's behaviour. --- .../shop_variant_controller.js.coffee | 20 +++++-- .../shop_variant_controller_spec.js.coffee | 54 +++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee index 311dbbc0bc..4b5b3e6a6e 100644 --- a/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee @@ -17,21 +17,33 @@ Darkswarm.controller "ShopVariantCtrl", ($scope, $modal, Cart) -> if item.max_quantity < item.quantity item.quantity = item.max_quantity + $scope.quantity = -> + $scope.variant.line_item.quantity || 0 + + $scope.maxQuantity = -> + $scope.variant.line_item.max_quantity || $scope.sanitizedQuantity() + + $scope.sanitizedQuantity = -> + Math.max(0, Math.min($scope.quantity(), $scope.available())) + + $scope.sanitizedMaxQuantity = -> + Math.max($scope.sanitizedQuantity(), Math.min($scope.maxQuantity(), $scope.available())) + $scope.add = (quantity) -> item = $scope.variant.line_item - item.quantity += quantity + item.quantity = $scope.sanitizedQuantity() + quantity $scope.addMax = (quantity) -> item = $scope.variant.line_item - item.max_quantity += quantity + item.max_quantity = $scope.sanitizedMaxQuantity() + quantity $scope.canAdd = (quantity) -> - wantedQuantity = $scope.variant.line_item.quantity + quantity + wantedQuantity = $scope.sanitizedQuantity() + quantity $scope.quantityValid(wantedQuantity) $scope.canAddMax = (quantity) -> variant = $scope.variant - wantedQuantity = variant.line_item.max_quantity + quantity + wantedQuantity = $scope.sanitizedMaxQuantity() + quantity $scope.quantityValid(wantedQuantity) && variant.line_item.quantity > 0 $scope.available = -> diff --git a/spec/javascripts/unit/darkswarm/controllers/checkout/shop_variant_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/checkout/shop_variant_controller_spec.js.coffee index de350faeb2..c1d459dabf 100644 --- a/spec/javascripts/unit/darkswarm/controllers/checkout/shop_variant_controller_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/controllers/checkout/shop_variant_controller_spec.js.coffee @@ -27,11 +27,29 @@ describe "ShopVariantCtrl", -> scope.add 5 expect(scope.variant.line_item.quantity).toEqual 6 + it "adds to an invalid quantity", -> + scope.$apply -> + scope.variant.line_item.quantity = -5 + scope.add 1 + expect(scope.variant.line_item.quantity).toEqual 1 + + it "adds to an undefined quantity", -> + scope.$apply -> + scope.variant.line_item.quantity = undefined + scope.add 1 + expect(scope.variant.line_item.quantity).toEqual 1 + it "adds to the max quantity", -> scope.addMax 5 expect(scope.variant.line_item.quantity).toEqual 0 expect(scope.variant.line_item.max_quantity).toEqual 5 + it "adds to an undefined max quantity", -> + scope.variant.line_item.quantity = 3 + scope.variant.line_item.max_quantity = undefined + scope.addMax 1 + expect(scope.variant.line_item.max_quantity).toEqual 4 + it "adds to the max quantity to be at least min quantity", -> scope.$apply -> scope.variant.line_item.max_quantity = 2 @@ -74,6 +92,42 @@ describe "ShopVariantCtrl", -> expect(scope.canAdd(2)).toEqual true expect(scope.canAdd(3)).toEqual false + it "denies adding if quantity is too high", -> + scope.variant.on_demand = false + scope.variant.on_hand = 5 + scope.variant.line_item.quantity = 7 + scope.variant.line_item.max_quantity = 7 + + expect(scope.canAdd(1)).toEqual false + expect(scope.canAddMax(1)).toEqual false + + it "allows decrease when quantity is too high", -> + scope.variant.on_demand = false + scope.variant.on_hand = 5 + scope.variant.line_item.quantity = 7 + scope.variant.line_item.max_quantity = 7 + expect(scope.canAdd(-1)).toEqual true + expect(scope.canAddMax(-1)).toEqual true + + it "allows increase when quantity is negative", -> + scope.variant.on_demand = false + scope.variant.on_hand = 5 + scope.variant.line_item.quantity = -3 + scope.variant.line_item.max_quantity = -3 + expect(scope.canAdd(1)).toEqual true + expect(scope.canAddMax(1)).toEqual false + + scope.variant.line_item.quantity = 1 + expect(scope.canAddMax(1)).toEqual true + + it "denies decrease when quantity is negative", -> + scope.variant.on_demand = false + scope.variant.on_hand = 5 + scope.variant.line_item.quantity = -3 + scope.variant.line_item.max_quantity = -3 + expect(scope.canAdd(-1)).toEqual false + expect(scope.canAddMax(-1)).toEqual false + it "denies declaring max quantity before item is in cart", -> expect(scope.canAddMax(1)).toEqual false