From f169dcda8861cd337186dfd6a8d0fa186cede508 Mon Sep 17 00:00:00 2001 From: Rob H Date: Wed, 26 Jun 2013 16:45:50 +0530 Subject: [PATCH] BPUR: Fix final unstable tests, js concurrency etc. --- .../javascripts/admin/bulk_product_update.js | 75 +++++++++---------- .../spree/admin/products/bulk_edit.html.haml | 2 +- .../admin/bulk_product_update_spec.rb | 2 +- .../unit/bulk_product_update_spec.js | 68 ++++++++++++++--- 4 files changed, 94 insertions(+), 53 deletions(-) diff --git a/app/assets/javascripts/admin/bulk_product_update.js b/app/assets/javascripts/admin/bulk_product_update.js index 2e8dbb8f1d..e524cdc6b6 100644 --- a/app/assets/javascripts/admin/bulk_product_update.js +++ b/app/assets/javascripts/admin/bulk_product_update.js @@ -31,12 +31,13 @@ productsApp.directive('ngTrackProduct', function(){ return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { - var property = attrs.ngTrackProduct; - var clean_value = angular.copy(scope.product[property]); - element.bind('blur', function() { - if (scope.product[property] == clean_value) removeCleanProperty(scope.dirtyProducts, scope.product.id, property); - else addDirtyProperty(scope.dirtyProducts, scope.product.id, property, scope.product[property]); - scope.$apply(scope.displayDirtyProducts()); + var property_name = attrs.ngTrackProduct; + ngModel.$parsers.push(function(viewValue){ + if (ngModel.$dirty) { + addDirtyProperty(scope.dirtyProducts, scope.product.id, property_name, viewValue); + scope.displayDirtyProducts(); + } + return viewValue; }); } } @@ -46,20 +47,16 @@ productsApp.directive('ngTrackVariant', function(){ return { require: 'ngModel', link: function(scope, element, attrs, ngModel) { - var property = attrs.ngTrackVariant; - var clean_value = angular.copy(scope.variant[property]); - element.bind('blur', function() { + var property_name = attrs.ngTrackVariant; + ngModel.$parsers.push(function(viewValue){ var dirtyVariants = {}; if (scope.dirtyProducts.hasOwnProperty(scope.product.id) && scope.dirtyProducts[scope.product.id].hasOwnProperty("variants")) dirtyVariants = scope.dirtyProducts[scope.product.id].variants; - if (scope.variant[property] == clean_value){ - removeCleanProperty(dirtyVariants, scope.variant.id, property); - if (dirtyVariants == {}) removeCleanProperty(scope.dirtyProducts, scope.product.id, "variants"); - } - else { - addDirtyProperty(dirtyVariants, scope.variant.id, property, scope.variant[property]); + if (ngModel.$dirty) { + addDirtyProperty(dirtyVariants, scope.variant.id, property_name, viewValue); addDirtyProperty(scope.dirtyProducts, scope.product.id, "variants", dirtyVariants); + scope.displayDirtyProducts(); } - scope.$apply(scope.displayDirtyProducts()); + return viewValue; }); } } @@ -70,7 +67,7 @@ productsApp.directive('ngToggleVariants',function(){ link: function(scope,element,attrs){ if (scope.displayProperties[scope.product.id].showVariants) { element.removeClass('icon-chevron-right'); element.addClass('icon-chevron-down'); } else { element.removeClass('icon-chevron-down'); element.addClass('icon-chevron-right'); } - element.bind('click', function(){ + element.on('click', function(){ scope.$apply(function(){ if (scope.displayProperties[scope.product.id].showVariants){ scope.displayProperties[scope.product.id].showVariants = false; @@ -120,23 +117,21 @@ productsApp.directive('ngToggleColumnList', function($compile){ }); productsApp.directive('datetimepicker', function ($parse) { - return function (scope, element, attrs) { - // using $parse instead of scope[attrs.datetimepicker] for cases - // where attrs.datetimepicker is 'foo.bar.lol' - $(function(){ - element.datetimepicker({ - dateFormat: 'yy-mm-dd', - timeFormat: 'HH:mm:ss', - stepMinute: 15, - onSelect:function (dateText, inst) { - scope.$apply(function(scope){ - parsed = $parse(attrs.datetimepicker); - parsed.assign(scope, dateText); - }); - } - }); - }); - } + return { + require: 'ngModel', + link: function (scope, element, attrs, ngModel) { + element.datetimepicker({ + dateFormat: 'yy-mm-dd', + timeFormat: 'HH:mm:ss', + stepMinute: 15, + onSelect:function (dateText, inst) { + scope.$apply(function(scope){ + ngModel.$setViewValue(dateText); // Fires ngModel.$parsers + }); + } + }); + } + } }); productsApp.controller('AdminBulkProductsCtrl', function($scope, $timeout, $http, dataFetcher) { @@ -153,15 +148,13 @@ productsApp.controller('AdminBulkProductsCtrl', function($scope, $timeout, $http available_on: { name: 'Available On', visible: true } } - $scope.refreshSuppliers = function(){ + $scope.initialiseData = function(){ dataFetcher('/enterprises/suppliers.json').then(function(data){ $scope.suppliers = data; - }); - }; - - $scope.refreshProducts = function(){ - dataFetcher('/admin/products/bulk_index.json').then(function(data){ - $scope.resetProducts(data); + // Need to have suppliers before we get products so we can match suppliers to product.supplier + dataFetcher('/admin/products/bulk_index.json').then(function(data){ + $scope.resetProducts(data); + }); }); }; diff --git a/app/views/spree/admin/products/bulk_edit.html.haml b/app/views/spree/admin/products/bulk_edit.html.haml index 82b1a8d96b..c028ebf63c 100644 --- a/app/views/spree/admin/products/bulk_edit.html.haml +++ b/app/views/spree/admin/products/bulk_edit.html.haml @@ -11,7 +11,7 @@ %div#new_product(data-hook) -%div{ 'ng-app' => 'bulk_product_update', 'ng-controller' => 'AdminBulkProductsCtrl', 'ng-init' => 'refreshSuppliers(); refreshProducts();' } +%div{ 'ng-app' => 'bulk_product_update', 'ng-controller' => 'AdminBulkProductsCtrl', 'ng-init' => 'initialiseData();' } %div.options Filter Results: %input.search{ 'ng-model' => 'query', :type => 'text', 'placeholder' => 'Search Value' } diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index c2bd923a1d..ad41f2c8c8 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -301,7 +301,7 @@ feature %q{ first("a.delete-product").click page.driver.browser.switch_to.alert.accept - page.should have_selector "a.delete-product" + sleep(0.1) if page.has_selector? "a.delete-product", :count => 3 page.should have_selector "a.delete-product", :count => 2 #page.should have_selector "div.flash.notice", text: "Product has been deleted." diff --git a/spec/javascripts/unit/bulk_product_update_spec.js b/spec/javascripts/unit/bulk_product_update_spec.js index 19286c2408..b6399e81aa 100644 --- a/spec/javascripts/unit/bulk_product_update_spec.js +++ b/spec/javascripts/unit/bulk_product_update_spec.js @@ -200,21 +200,69 @@ describe("AdminBulkProductsCtrl", function(){ ctrl('AdminBulkProductsCtrl', { $scope: scope } ); })); - it("gets a list of suppliers", function(){ + it("gets a list of suppliers and then resets products with a list of data", function(){ httpBackend.expectGET('/enterprises/suppliers.json').respond("list of suppliers"); - scope.refreshSuppliers(); + httpBackend.expectGET('/admin/products/bulk_index.json').respond("list of products"); + spyOn(scope, "resetProducts"); + scope.initialiseData(); httpBackend.flush(); expect(scope.suppliers).toEqual("list of suppliers"); - }); - - it("gets a list of products", function(){ - httpBackend.expectGET('/admin/products/bulk_index.json').respond("list of products"); - scope.refreshProducts(); - httpBackend.flush(); - expect(scope.products).toEqual("list of products"); + expect(scope.resetProducts).toHaveBeenCalledWith("list of products"); }); }); - + + describe("resetting products", function(){ + beforeEach(function(){ + module('bulk_product_update'); + }); + + beforeEach(inject(function($controller,$rootScope) { + scope = $rootScope.$new(); + ctrl = $controller; + + ctrl('AdminBulkProductsCtrl', { $scope: scope } ); + spyOn(scope, "matchSupplier"); + scope.products = {}; + scope.resetProducts( [ { id: 1, name: "P1" }, { id: 3, name: "P2" } ] ); + })); + + it("sets products to the value of 'data'", function(){ + expect(scope.products).toEqual( [ { id: 1, name: "P1" }, { id: 3, name: "P2" } ] ); + }); + + it("resets dirtyProducts",function(){ + expect(scope.dirtyProducts).toEqual({}); + }); + + it("calls match matchSupplier once for each product", function(){ + expect(scope.matchSupplier.calls.length).toEqual(2); + }); + }); + + describe("matching supplier", function(){ + beforeEach(function(){ + module('bulk_product_update'); + }); + + beforeEach(inject(function($controller,$rootScope) { + scope = $rootScope.$new(); + ctrl = $controller; + + ctrl('AdminBulkProductsCtrl', { $scope: scope } ); + })); + + it("changes the supplier of the product to the one which matches it from the suppliers list", function(){ + var s1_s = { id: 1, name: "S1" }; + var s2_s = { id: 2, name: "S2" }; + var s1_p = { id: 1, name: "S1" }; + expect(s1_s == s1_p).not.toEqual(true); + scope.suppliers = [ s1_s, s2_s ]; + var product = { id: 10, supplier: s1_p }; + scope.matchSupplier(product); + expect(product.supplier).toEqual(s1_s); + }); + }); + describe("getting on_hand counts when products have variants", function(){ var p1, p2, p3; beforeEach(function(){