diff --git a/spec/javascripts/unit/bulk_product_update_spec.js b/spec/javascripts/unit/bulk_product_update_spec.js deleted file mode 100644 index 7cd8fc98ac..0000000000 --- a/spec/javascripts/unit/bulk_product_update_spec.js +++ /dev/null @@ -1,481 +0,0 @@ -describe("filtering products", function(){ - it("accepts an object or an array and only returns an array", function(){ - expect( filterSubmitProducts( [] ) ).toEqual([]); - expect( filterSubmitProducts( {} ) ).toEqual([]); - expect( filterSubmitProducts( { 1: { id: 1, name: "lala" } } ) ).toEqual( [ { id: 1, name: "lala" } ] ); - expect( filterSubmitProducts( [ { id: 1, name: "lala" } ] ) ).toEqual( [ { id: 1, name: "lala" } ] ); - expect( filterSubmitProducts( 1 ) ).toEqual([]); - expect( filterSubmitProducts( "2" ) ).toEqual([]); - expect( filterSubmitProducts( null ) ).toEqual([]); - }); - - it("only returns products which have an id property", function(){ - expect( filterSubmitProducts( [ { id: 1, name: "p1" }, { notanid: 2, name: "p2"} ] ) ).toEqual( [ { id: 1, name: "p1" } ]); - }); - - it("does not return a product object for products which have no propeties other than an id", function(){ - expect( filterSubmitProducts( [ { id: 1, someunwantedproperty: "something" }, { id: 2, name: "p2"} ] ) ).toEqual( [ { id: 2, name: "p2" } ]); - }); - - it("does not return an on_hand count when a product has variants", function(){ - var testProduct = { - id: 1, - on_hand: 5, - variants: [ { - id: 1, - on_hand: 5, - price: 12.0 - } ] - }; - expect( filterSubmitProducts( [ testProduct ] ) ).toEqual( [ { - id: 1, - variants_attributes: [ { - id: 1, - on_hand: 5, - price: 12.0 - } ] - } ] ); - }); - - it("returns variants as variants_attributes", function(){ - var testProduct = { - id: 1, - variants: [ { - id: 1, - on_hand: 5, - price: 12.0 - } ] - }; - expect( filterSubmitProducts( [ testProduct ] ) ).toEqual( [ { - id: 1, - variants_attributes: [ { - id: 1, - on_hand: 5, - price: 12.0 - } ] - } ] ); - }); - - it("ignores variants without an id, and those for which deleted_at is not null", function(){ - var testProduct = { - id: 1, - variants: [ { - id: 1, - on_hand: 3, - price: 5.0 - }, - { - on_hand: 1, - price: 15.0 - }, - { - id: 2, - on_hand: 2, - deleted_at: new Date(), - price: 20.0 - } ] - }; - expect( filterSubmitProducts( [ testProduct ] ) ).toEqual( [ { - id: 1, - variants_attributes: [ { - id: 1, - on_hand: 3, - price: 5.0 - } ] - } ] ); - }); - - it("does not return variants_attributes property if variants is an empty array", function(){ - var testProduct = { - id: 1, - price: 10, - variants: [] - }; - expect( filterSubmitProducts( [ testProduct ] ) ).toEqual( [ { - id: 1, - price: 10 - } ] ); - }); - - // TODO Not an exhaustive test, is there a better way to do this? - it("only returns properties the properties of products which ought to be updated", function(){ - var testProduct = { - id: 1, - name: "TestProduct", - description: "", - available_on: new Date(), - deleted_at: null, - permalink: null, - meta_description: null, - meta_keywords: null, - tax_category_id: null, - shipping_category_id: null, - created_at: null, - updated_at: null, - count_on_hand: 0, - supplier_id: 5, - supplier: { id: 5, name: "Supplier 1" }, - group_buy: null, - group_buy_unit_size: null, - on_demand: false, - variants: [ { - id: 1, - on_hand: 2, - price: 10.0 - } ] - }; - - expect(filterSubmitProducts( [ testProduct ] ) ).toEqual([ - { - id: 1, - name: "TestProduct", - supplier_id: 5, - available_on: new Date(), - variants_attributes: [ { - id: 1, - on_hand: 2, - price: 10.0 - } ] - } ] - ); - }); -}); - -describe("Maintaining a live record of dirty products and properties", function(){ - describe("adding product properties to the dirtyProducts object", function(){ // Applies to both products and variants - it("adds the product and the property to the list if property is dirty", function(){ - var dirtyProducts = { }; - addDirtyProperty(dirtyProducts, 1, "name", "Product 1"); - - expect(dirtyProducts).toEqual( { 1: { id: 1, name: "Product 1" } } ); - }); - - it("adds the relevant property to a product that is already in the list but which does not yet possess it if the property is dirty", function(){ - var dirtyProducts = { 1: { id: 1, notaname: "something" } }; - addDirtyProperty(dirtyProducts, 1, "name", "Product 3"); - - expect(dirtyProducts).toEqual( { 1: { id: 1, notaname: "something", name: "Product 3" } } ); - }); - - it("changes the relevant property of a product that is already in the list if the property is dirty", function(){ - var dirtyProducts = { 1: { id: 1, name: "Product 1" } }; - addDirtyProperty(dirtyProducts, 1, "name", "Product 2"); - - expect(dirtyProducts).toEqual( { 1: { id: 1, name: "Product 2" } } ); - }); - }); - - describe("removing properties of products which are clean", function(){ - it("removes the relevant property from a product if the property is clean and the product has that property", function(){ - var dirtyProducts = { 1: { id: 1, someProperty: "something", name: "Product 1" } }; - removeCleanProperty(dirtyProducts, 1, "name", "Product 1"); - - expect(dirtyProducts).toEqual( { 1: { id: 1, someProperty: "something" } } ); - }); - - it("removes the product from dirtyProducts if the property is clean and by removing an existing property on an id is left", function(){ - var dirtyProducts = { 1: { id: 1, name: "Product 1" } }; - removeCleanProperty(dirtyProducts, 1, "name", "Product 1"); - - expect(dirtyProducts).toEqual( { } ); - }); - }); -}); - -describe("AdminBulkProductsCtrl", function(){ - describe("loading data upon initialisation", function(){ - ctrl = null; - scope = null; - httpBackend = null; - - beforeEach(function(){ - module('bulk_product_update'); - }); - - beforeEach(inject(function($controller,$rootScope,$httpBackend) { - scope = $rootScope.$new(); - ctrl = $controller; - httpBackend = $httpBackend; - - ctrl('AdminBulkProductsCtrl', { $scope: scope } ); - })); - - it("gets a list of suppliers and then resets products with a list of data", function(){ - httpBackend.expectGET('/api/users/authorise_api?token=api_key').respond( { "success": "Use of API Authorised" } ); - httpBackend.expectGET('/api/enterprises/managed?template=bulk_index&q[is_primary_producer_eq]=true').respond("list of suppliers"); - httpBackend.expectGET('/api/products/managed?template=bulk_index;page=1;per_page=500').respond("list of products"); - spyOn(scope, "resetProducts"); - scope.initialise('api_key'); - httpBackend.flush(); - expect(scope.suppliers).toEqual("list of suppliers"); - expect(scope.resetProducts).toHaveBeenCalledWith("list of products"); - expect(scope.spree_api_key_ok).toEqual(true); - }); - }); - - 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(){ - beforeEach(function(){ - module('bulk_product_update'); - }); - - beforeEach(inject(function($controller,$rootScope) { - scope = $rootScope.$new(); - ctrl = $controller; - - ctrl('AdminBulkProductsCtrl', { $scope: scope } ); - })); - - var p1, p2, p3; - beforeEach(function(){ - p1 = { variants: { 1: { id: 1, on_hand: 1 }, 2: { id: 2, on_hand: 2 }, 3: { id: 3, on_hand: 3 } } }; - p2 = { variants: { 4: { id: 4, not_on_hand: 1 }, 5: { id: 5, on_hand: 2 }, 6: { id: 6, on_hand: 3 } } }; - p3 = { not_variants: { 7: { id: 7, on_hand: 1 }, 8: { id: 8, on_hand: 2 } }, variants: { 9: { id: 9, on_hand: 3 } } }; - }); - - it("sums variant on_hand properties", function(){ - expect(scope.onHand(p1)).toEqual(6); - }); - - it("ignores items in variants without an on_hand property (adds 0)", function(){ - expect(scope.onHand(p2)).toEqual(5); - }); - - it("ignores on_hand properties of objects in arrays which are not named 'variants' (adds 0)", function(){ - expect(scope.onHand(p3)).toEqual(3); - }); - - it("returns 'error' if not given an object with a variants property that is an object", function(){ - expect( scope.onHand([]) ).toEqual('error'); - expect( scope.onHand( { not_variants: [] } ) ).toEqual('error'); - }); - }); - - describe("submitting products to be updated", function(){ - ctrl = null; - scope = null; - timeout = null; - httpBackend = null; - - beforeEach(function(){ - module('bulk_product_update'); - }); - - beforeEach(inject(function($controller,$rootScope,$timeout,$httpBackend) { - scope = $rootScope.$new(); - ctrl = $controller; - timeout = $timeout; - httpBackend = $httpBackend; - })); - - describe("preparing products for submit",function(){ - beforeEach(function(){ - ctrl('AdminBulkProductsCtrl', { $scope: scope } ); - spyOn(window, "filterSubmitProducts").andReturn( [ { id: 1, value: 3 }, { id: 2, value: 4 } ] ); - spyOn(scope, "updateProducts"); - scope.dirtyProducts = { 1: { id: 1 }, 2: { id: 2 } }; - scope.prepareProductsForSubmit(); - }); - - it("filters returned dirty products", function(){ - expect(filterSubmitProducts).toHaveBeenCalledWith( { 1: { id: 1 }, 2: { id: 2 } } ); - }); - - it("sends dirty and filtered objects to submitProducts()", function(){ - expect(scope.updateProducts).toHaveBeenCalledWith( [ { id: 1, value: 3 }, { id: 2, value: 4 } ] ); - }); - }); - - describe("updating products",function(){ - beforeEach(function(){ - ctrl('AdminBulkProductsCtrl', { $scope: scope, $timeout: timeout } ); - }); - - it("submits products to be updated with a http post request to /admin/products/bulk_update", function(){ - httpBackend.expectPOST('/admin/products/bulk_update').respond("list of products"); - scope.updateProducts("list of products"); - httpBackend.flush(); - }); - - it("runs displaySuccess() when post returns success",function(){ - spyOn(scope, "displaySuccess"); - scope.products = [ { id: 1, name: "P1" }, { id: 2, name: "P2" } ]; - httpBackend.expectPOST('/admin/products/bulk_update').respond(200, [ { id: 1, name: "P1" }, { id: 2, name: "P2" } ] ); - scope.updateProducts("list of dirty products"); - httpBackend.flush(); - expect(scope.displaySuccess).toHaveBeenCalled(); - }); - - it("runs displayFailure() when post return data does not match $scope.products",function(){ - spyOn(scope, "displayFailure"); - scope.products = "current list of products"; - httpBackend.expectPOST('/admin/products/bulk_update').respond(200, "returned list of products"); - scope.updateProducts("updated list of products"); - httpBackend.flush(); - expect(scope.displayFailure).toHaveBeenCalled(); - }); - - it("runs displayFailure() when post returns error",function(){ - spyOn(scope, "displayFailure"); - scope.products = "updated list of products"; - httpBackend.expectPOST('/admin/products/bulk_update').respond(404, "updated list of products"); - scope.updateProducts("updated list of products"); - httpBackend.flush(); - expect(scope.displayFailure).toHaveBeenCalled(); - }); - }); - }); - - describe("deleting products",function(){ - beforeEach(function(){ - ctrl('AdminBulkProductsCtrl', { $scope: scope } ); - }); - - it("deletes products with a http delete request to /api/products/id", function(){ - spyOn(window, "confirm").andReturn(true); - scope.products = [ { id: 9, permalink_live: "apples" }, { id: 13, permalink_live: "oranges" } ]; - scope.dirtyProducts = {}; - httpBackend.expectDELETE('/api/products/13').respond(200, "data"); - scope.deleteProduct(scope.products[1]); - httpBackend.flush(); - }); - - it("removes the specified product from both scope.products and scope.dirtyProducts (if it exists there)", function(){ - spyOn(window, "confirm").andReturn(true); - scope.products = [ { id: 9, permalink_live: "apples" }, { id: 13, permalink_live: "oranges" } ]; - scope.dirtyProducts = { 9: { id: 9, someProperty: "something" }, 13: { id: 13, name: "P1" } }; - httpBackend.expectDELETE('/api/products/13').respond(200, "data"); - scope.deleteProduct(scope.products[1]); - httpBackend.flush(); - expect(scope.products).toEqual( [ { id: 9, permalink_live: "apples" } ] ); - expect(scope.dirtyProducts).toEqual( { 9: { id: 9, someProperty: "something" } } ); - }); - }); - - describe("deleting variants",function(){ - beforeEach(function(){ - ctrl('AdminBulkProductsCtrl', { $scope: scope } ); - }); - - it("deletes variants with a http delete request to /api/products/product_id/variants/(variant_id)", function(){ - spyOn(window, "confirm").andReturn(true); - scope.products = [ { id: 9, permalink_live: "apples", variants: [ { id: 3, price: 12 } ] }, { id: 13, permalink_live: "oranges" } ]; - httpBackend.expectDELETE('/api/products/9/variants/3').respond(200, "data"); - scope.deleteVariant(scope.products[0],scope.products[0].variants[0]); - httpBackend.flush(); - }); - - it("removes the specified variant from both the variants object and scope.dirtyProducts (if it exists there)", function(){ - spyOn(window, "confirm").andReturn(true); - scope.products = [ { id: 9, permalink_live: "apples", variants: [ { id: 3, price: 12.0 }, { id: 4, price: 6.0 } ] }, { id: 13, permalink_live: "oranges" } ]; - scope.dirtyProducts = { 9: { id: 9, variants: { 3: { id: 3, price: 12.0 }, 4: { id: 4, price: 6.0 } } }, 13: { id: 13, name: "P1" } }; - httpBackend.expectDELETE('/api/products/9/variants/3').respond(200, "data"); - scope.deleteVariant(scope.products[0],scope.products[0].variants[0]); - httpBackend.flush(); - expect(scope.products[0].variants).toEqual( [ { id: 4, price: 6.0 } ] ); - expect(scope.dirtyProducts).toEqual( { 9: { id: 9, variants: { 4: { id: 4, price: 6.0 } } }, 13: { id: 13, name: "P1" } } ); - }); - }); - - describe("cloning products",function(){ - beforeEach(function(){ - ctrl('AdminBulkProductsCtrl', { $scope: scope } ); - }); - - it("clones products using a http get request to /admin/products/(permalink)/clone.json", function(){ - scope.products = [ { id: 13, permalink_live: "oranges" } ]; - httpBackend.expectGET('/admin/products/oranges/clone.json').respond(200, { product: { id: 17, name: "new_product" } } ); - httpBackend.expectGET('/api/products/17?template=bulk_show').respond(200, [ { id: 17, name: "new_product" } ] ); - scope.cloneProduct(scope.products[0]); - httpBackend.flush(); - }); - - it("adds the newly created product to scope.products and matches supplier", function(){ - spyOn(scope, "matchSupplier").andCallThrough(); - scope.products = [ { id: 13, permalink_live: "oranges" } ]; - httpBackend.expectGET('/admin/products/oranges/clone.json').respond(200, { product: { id: 17, name: "new_product", supplier: { id: 6 }, variants: [ { id: 3, name: "V1" } ] } } ); - httpBackend.expectGET('/api/products/17?template=bulk_show').respond(200, { id: 17, name: "new_product", supplier: { id: 6 }, variants: [ { id: 3, name: "V1" } ] } ); - scope.cloneProduct(scope.products[0]); - httpBackend.flush(); - expect(scope.matchSupplier).toHaveBeenCalledWith( { id: 17, name: "new_product", supplier: { id: 6 }, variants: [ { id: 3, name: "V1" } ] } ); - expect(scope.products).toEqual( [ { id: 13, permalink_live: "oranges" }, { id: 17, name: "new_product", supplier: { id: 6 }, variants: [ { id: 3, name: "V1" } ] } ] ); - }); - }); -}); - -describe("converting arrays of objects with ids to an object with ids as keys", function(){ - it("returns an object", function(){ - var array = []; - expect(toObjectWithIDKeys(array)).toEqual({}); - }); - - it("adds each object in the array provided with an id to the returned object with the id as its key", function(){ - var array = [ { id: 1 }, { id: 3 } ]; - expect(toObjectWithIDKeys(array)).toEqual({ 1: { id: 1 }, 3: { id: 3 } } ); - }); - - it("ignores items which are not objects and those which do not possess ids", function(){ - var array = [ { id: 1 }, "not an object", { notanid: 3 } ]; - expect(toObjectWithIDKeys(array)).toEqual({ 1: { id: 1 } } ); - }); - - it("sends arrays with the key 'variants' to itself", function(){ - spyOn(window, "toObjectWithIDKeys").andCallThrough(); - var array = [ { id: 1, variants: [ { id: 17 } ] }, { id: 2, variants: { 12: { id: 12 } } } ]; - var products = toObjectWithIDKeys(array); - expect(products["1"].variants).toEqual( { 17: { id: 17 } } ); - expect(toObjectWithIDKeys).toHaveBeenCalledWith( [ { id: 17 } ] ); - expect(toObjectWithIDKeys).not.toHaveBeenCalledWith( { 12: { id: 12 } } ); - }); -}); \ No newline at end of file diff --git a/spec/javascripts/unit/bulk_product_update_spec.js.coffee b/spec/javascripts/unit/bulk_product_update_spec.js.coffee new file mode 100644 index 0000000000..49f10ac076 --- /dev/null +++ b/spec/javascripts/unit/bulk_product_update_spec.js.coffee @@ -0,0 +1,778 @@ +describe "filtering products", -> + it "accepts an object or an array and only returns an array", -> + expect(filterSubmitProducts([])).toEqual [] + expect(filterSubmitProducts({})).toEqual [] + expect(filterSubmitProducts(1: + id: 1 + name: "lala" + )).toEqual [ + id: 1 + name: "lala" + ] + expect(filterSubmitProducts([ + id: 1 + name: "lala" + ])).toEqual [ + id: 1 + name: "lala" + ] + expect(filterSubmitProducts(1)).toEqual [] + expect(filterSubmitProducts("2")).toEqual [] + expect(filterSubmitProducts(null)).toEqual [] + + it "only returns products which have an id property", -> + expect(filterSubmitProducts([ + { + id: 1 + name: "p1" + } + { + notanid: 2 + name: "p2" + } + ])).toEqual [ + id: 1 + name: "p1" + ] + + it "does not return a product object for products which have no propeties other than an id", -> + expect(filterSubmitProducts([ + { + id: 1 + someunwantedproperty: "something" + } + { + id: 2 + name: "p2" + } + ])).toEqual [ + id: 2 + name: "p2" + ] + + it "does not return an on_hand count when a product has variants", -> + testProduct = + id: 1 + on_hand: 5 + variants: [ + id: 1 + on_hand: 5 + price: 12.0 + ] + + expect(filterSubmitProducts([testProduct])).toEqual [ + id: 1 + variants_attributes: [ + id: 1 + on_hand: 5 + price: 12.0 + ] + ] + + it "returns variants as variants_attributes", -> + testProduct = + id: 1 + variants: [ + id: 1 + on_hand: 5 + price: 12.0 + ] + + expect(filterSubmitProducts([testProduct])).toEqual [ + id: 1 + variants_attributes: [ + id: 1 + on_hand: 5 + price: 12.0 + ] + ] + + it "ignores variants without an id, and those for which deleted_at is not null", -> + testProduct = + id: 1 + variants: [ + { + id: 1 + on_hand: 3 + price: 5.0 + } + { + on_hand: 1 + price: 15.0 + } + { + id: 2 + on_hand: 2 + deleted_at: new Date() + price: 20.0 + } + ] + + expect(filterSubmitProducts([testProduct])).toEqual [ + id: 1 + variants_attributes: [ + id: 1 + on_hand: 3 + price: 5.0 + ] + ] + + it "does not return variants_attributes property if variants is an empty array", -> + testProduct = + id: 1 + price: 10 + variants: [] + + expect(filterSubmitProducts([testProduct])).toEqual [ + id: 1 + price: 10 + ] + + + # TODO Not an exhaustive test, is there a better way to do this? + it "only returns properties the properties of products which ought to be updated", -> + testProduct = + id: 1 + name: "TestProduct" + description: "" + available_on: new Date() + deleted_at: null + permalink: null + meta_description: null + meta_keywords: null + tax_category_id: null + shipping_category_id: null + created_at: null + updated_at: null + count_on_hand: 0 + supplier_id: 5 + supplier: + id: 5 + name: "Supplier 1" + + group_buy: null + group_buy_unit_size: null + on_demand: false + variants: [ + id: 1 + on_hand: 2 + price: 10.0 + ] + + expect(filterSubmitProducts([testProduct])).toEqual [ + id: 1 + name: "TestProduct" + supplier_id: 5 + available_on: new Date() + variants_attributes: [ + id: 1 + on_hand: 2 + price: 10.0 + ] + ] + + +describe "Maintaining a live record of dirty products and properties", -> + describe "adding product properties to the dirtyProducts object", -> # Applies to both products and variants + it "adds the product and the property to the list if property is dirty", -> + dirtyProducts = {} + addDirtyProperty dirtyProducts, 1, "name", "Product 1" + expect(dirtyProducts).toEqual 1: + id: 1 + name: "Product 1" + + + it "adds the relevant property to a product that is already in the list but which does not yet possess it if the property is dirty", -> + dirtyProducts = 1: + id: 1 + notaname: "something" + + addDirtyProperty dirtyProducts, 1, "name", "Product 3" + expect(dirtyProducts).toEqual 1: + id: 1 + notaname: "something" + name: "Product 3" + + + it "changes the relevant property of a product that is already in the list if the property is dirty", -> + dirtyProducts = 1: + id: 1 + name: "Product 1" + + addDirtyProperty dirtyProducts, 1, "name", "Product 2" + expect(dirtyProducts).toEqual 1: + id: 1 + name: "Product 2" + + + + describe "removing properties of products which are clean", -> + it "removes the relevant property from a product if the property is clean and the product has that property", -> + dirtyProducts = 1: + id: 1 + someProperty: "something" + name: "Product 1" + + removeCleanProperty dirtyProducts, 1, "name", "Product 1" + expect(dirtyProducts).toEqual 1: + id: 1 + someProperty: "something" + + + it "removes the product from dirtyProducts if the property is clean and by removing an existing property on an id is left", -> + dirtyProducts = 1: + id: 1 + name: "Product 1" + + removeCleanProperty dirtyProducts, 1, "name", "Product 1" + expect(dirtyProducts).toEqual {} + + + +describe "AdminBulkProductsCtrl", -> + ctrl = scope = timeout = httpBackend = null + + beforeEach -> + module "bulk_product_update" + beforeEach inject(($controller, $timeout, $rootScope, $httpBackend) -> + scope = $rootScope.$new() + ctrl = $controller + timeout = $timeout + httpBackend = $httpBackend + ) + + describe "loading data upon initialisation", -> + beforeEach -> + ctrl "AdminBulkProductsCtrl", + $scope: scope + + it "gets a list of suppliers and then resets products with a list of data", -> + httpBackend.expectGET("/api/users/authorise_api?token=api_key").respond success: "Use of API Authorised" + httpBackend.expectGET("/api/enterprises/managed?template=bulk_index&q[is_primary_producer_eq]=true").respond "list of suppliers" + httpBackend.expectGET("/api/products/managed?template=bulk_index;page=1;per_page=500").respond "list of products" + spyOn scope, "resetProducts" + scope.initialise "api_key" + httpBackend.flush() + expect(scope.suppliers).toEqual "list of suppliers" + expect(scope.resetProducts).toHaveBeenCalledWith "list of products" + expect(scope.spree_api_key_ok).toEqual true + + + describe "resetting products", -> + beforeEach -> + 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'", -> + expect(scope.products).toEqual [ + { + id: 1 + name: "P1" + } + { + id: 3 + name: "P2" + } + ] + + it "resets dirtyProducts", -> + expect(scope.dirtyProducts).toEqual {} + + it "calls match matchSupplier once for each product", -> + expect(scope.matchSupplier.calls.length).toEqual 2 + + + describe "matching supplier", -> + beforeEach -> + ctrl "AdminBulkProductsCtrl", + $scope: scope + + it "changes the supplier of the product to the one which matches it from the suppliers list", -> + s1_s = + id: 1 + name: "S1" + + s2_s = + id: 2 + name: "S2" + + s1_p = + id: 1 + name: "S1" + + expect(s1_s is s1_p).not.toEqual true + scope.suppliers = [ + s1_s + s2_s + ] + product = + id: 10 + supplier: s1_p + + scope.matchSupplier product + expect(product.supplier).toEqual s1_s + + + describe "getting on_hand counts when products have variants", -> + beforeEach -> + ctrl "AdminBulkProductsCtrl", + $scope: scope + + p1 = undefined + p2 = undefined + p3 = undefined + beforeEach -> + p1 = variants: + 1: + id: 1 + on_hand: 1 + + 2: + id: 2 + on_hand: 2 + + 3: + id: 3 + on_hand: 3 + + p2 = variants: + 4: + id: 4 + not_on_hand: 1 + + 5: + id: 5 + on_hand: 2 + + 6: + id: 6 + on_hand: 3 + + p3 = + not_variants: + 7: + id: 7 + on_hand: 1 + + 8: + id: 8 + on_hand: 2 + + variants: + 9: + id: 9 + on_hand: 3 + + it "sums variant on_hand properties", -> + expect(scope.onHand(p1)).toEqual 6 + + it "ignores items in variants without an on_hand property (adds 0)", -> + expect(scope.onHand(p2)).toEqual 5 + + it "ignores on_hand properties of objects in arrays which are not named 'variants' (adds 0)", -> + expect(scope.onHand(p3)).toEqual 3 + + it "returns 'error' if not given an object with a variants property that is an object", -> + expect(scope.onHand([])).toEqual "error" + expect(scope.onHand(not_variants: [])).toEqual "error" + + + describe "submitting products to be updated", -> + describe "preparing products for submit", -> + beforeEach -> + ctrl "AdminBulkProductsCtrl", + $scope: scope + + spyOn(window, "filterSubmitProducts").andReturn [ + { + id: 1 + value: 3 + } + { + id: 2 + value: 4 + } + ] + spyOn scope, "updateProducts" + scope.dirtyProducts = + 1: + id: 1 + + 2: + id: 2 + + scope.prepareProductsForSubmit() + + it "filters returned dirty products", -> + expect(filterSubmitProducts).toHaveBeenCalledWith + 1: + id: 1 + + 2: + id: 2 + + + it "sends dirty and filtered objects to submitProducts()", -> + expect(scope.updateProducts).toHaveBeenCalledWith [ + { + id: 1 + value: 3 + } + { + id: 2 + value: 4 + } + ] + + + describe "updating products", -> + beforeEach -> + ctrl "AdminBulkProductsCtrl", + $scope: scope + $timeout: timeout + + it "submits products to be updated with a http post request to /admin/products/bulk_update", -> + httpBackend.expectPOST("/admin/products/bulk_update").respond "list of products" + scope.updateProducts "list of products" + httpBackend.flush() + + it "runs displaySuccess() when post returns success", -> + spyOn scope, "displaySuccess" + scope.products = [ + { + id: 1 + name: "P1" + } + { + id: 2 + name: "P2" + } + ] + httpBackend.expectPOST("/admin/products/bulk_update").respond 200, [ + { + id: 1 + name: "P1" + } + { + id: 2 + name: "P2" + } + ] + scope.updateProducts "list of dirty products" + httpBackend.flush() + expect(scope.displaySuccess).toHaveBeenCalled() + + it "runs displayFailure() when post return data does not match $scope.products", -> + spyOn scope, "displayFailure" + scope.products = "current list of products" + httpBackend.expectPOST("/admin/products/bulk_update").respond 200, "returned list of products" + scope.updateProducts "updated list of products" + httpBackend.flush() + expect(scope.displayFailure).toHaveBeenCalled() + + it "runs displayFailure() when post returns error", -> + spyOn scope, "displayFailure" + scope.products = "updated list of products" + httpBackend.expectPOST("/admin/products/bulk_update").respond 404, "updated list of products" + scope.updateProducts "updated list of products" + httpBackend.flush() + expect(scope.displayFailure).toHaveBeenCalled() + + + + describe "deleting products", -> + beforeEach -> + ctrl "AdminBulkProductsCtrl", + $scope: scope + + it "deletes products with a http delete request to /api/products/id", -> + spyOn(window, "confirm").andReturn true + scope.products = [ + { + id: 9 + permalink_live: "apples" + } + { + id: 13 + permalink_live: "oranges" + } + ] + scope.dirtyProducts = {} + httpBackend.expectDELETE("/api/products/13").respond 200, "data" + scope.deleteProduct scope.products[1] + httpBackend.flush() + + it "removes the specified product from both scope.products and scope.dirtyProducts (if it exists there)", -> + spyOn(window, "confirm").andReturn true + scope.products = [ + { + id: 9 + permalink_live: "apples" + } + { + id: 13 + permalink_live: "oranges" + } + ] + scope.dirtyProducts = + 9: + id: 9 + someProperty: "something" + + 13: + id: 13 + name: "P1" + + httpBackend.expectDELETE("/api/products/13").respond 200, "data" + scope.deleteProduct scope.products[1] + httpBackend.flush() + expect(scope.products).toEqual [ + id: 9 + permalink_live: "apples" + ] + expect(scope.dirtyProducts).toEqual 9: + id: 9 + someProperty: "something" + + + + describe "deleting variants", -> + beforeEach -> + scope = {} + ctrl "AdminBulkProductsCtrl", + $scope: scope + + + it "deletes variants with a http delete request to /api/products/product_id/variants/(variant_id)", -> + spyOn(window, "confirm").andReturn true + scope.products = [ + { + id: 9 + permalink_live: "apples" + variants: [ + id: 3 + price: 12 + ] + } + { + id: 13 + permalink_live: "oranges" + } + ] + scope.dirtyProducts = {} + httpBackend.expectDELETE("/api/products/9/variants/3").respond 200, "data" + scope.deleteVariant scope.products[0], scope.products[0].variants[0] + httpBackend.flush() + + it "removes the specified variant from both the variants object and scope.dirtyProducts (if it exists there)", -> + spyOn(window, "confirm").andReturn true + scope.products = [ + { + id: 9 + permalink_live: "apples" + variants: [ + { + id: 3 + price: 12.0 + } + { + id: 4 + price: 6.0 + } + ] + } + { + id: 13 + permalink_live: "oranges" + } + ] + scope.dirtyProducts = + 9: + id: 9 + variants: + 3: + id: 3 + price: 12.0 + + 4: + id: 4 + price: 6.0 + + 13: + id: 13 + name: "P1" + + httpBackend.expectDELETE("/api/products/9/variants/3").respond 200, "data" + scope.deleteVariant scope.products[0], scope.products[0].variants[0] + httpBackend.flush() + expect(scope.products[0].variants).toEqual [ + id: 4 + price: 6.0 + ] + expect(scope.dirtyProducts).toEqual + 9: + id: 9 + variants: + 4: + id: 4 + price: 6.0 + + 13: + id: 13 + name: "P1" + + + + describe "cloning products", -> + beforeEach -> + ctrl "AdminBulkProductsCtrl", + $scope: scope + + + it "clones products using a http get request to /admin/products/(permalink)/clone.json", -> + scope.products = [ + id: 13 + permalink_live: "oranges" + ] + httpBackend.expectGET("/admin/products/oranges/clone.json").respond 200, + product: + id: 17 + name: "new_product" + + httpBackend.expectGET("/api/products/17?template=bulk_show").respond 200, [ + id: 17 + name: "new_product" + ] + scope.cloneProduct scope.products[0] + httpBackend.flush() + + it "adds the newly created product to scope.products and matches supplier", -> + spyOn(scope, "matchSupplier").andCallThrough() + scope.products = [ + id: 13 + permalink_live: "oranges" + ] + httpBackend.expectGET("/admin/products/oranges/clone.json").respond 200, + product: + id: 17 + name: "new_product" + supplier: + id: 6 + + variants: [ + id: 3 + name: "V1" + ] + + httpBackend.expectGET("/api/products/17?template=bulk_show").respond 200, + id: 17 + name: "new_product" + supplier: + id: 6 + + variants: [ + id: 3 + name: "V1" + ] + + scope.cloneProduct scope.products[0] + httpBackend.flush() + expect(scope.matchSupplier).toHaveBeenCalledWith + id: 17 + name: "new_product" + supplier: + id: 6 + + variants: [ + id: 3 + name: "V1" + ] + + expect(scope.products).toEqual [ + { + id: 13 + permalink_live: "oranges" + } + { + id: 17 + name: "new_product" + supplier: + id: 6 + + variants: [ + id: 3 + name: "V1" + ] + } + ] + + + +describe "converting arrays of objects with ids to an object with ids as keys", -> + it "returns an object", -> + array = [] + expect(toObjectWithIDKeys(array)).toEqual {} + + it "adds each object in the array provided with an id to the returned object with the id as its key", -> + array = [ + { + id: 1 + } + { + id: 3 + } + ] + expect(toObjectWithIDKeys(array)).toEqual + 1: + id: 1 + + 3: + id: 3 + + + it "ignores items which are not objects and those which do not possess ids", -> + array = [ + { + id: 1 + } + "not an object" + { + notanid: 3 + } + ] + expect(toObjectWithIDKeys(array)).toEqual 1: + id: 1 + + + it "sends arrays with the key 'variants' to itself", -> + spyOn(window, "toObjectWithIDKeys").andCallThrough() + array = [ + { + id: 1 + variants: [id: 17] + } + { + id: 2 + variants: + 12: + id: 12 + } + ] + products = toObjectWithIDKeys(array) + expect(products["1"].variants).toEqual 17: + id: 17 + + expect(toObjectWithIDKeys).toHaveBeenCalledWith [id: 17] + expect(toObjectWithIDKeys).not.toHaveBeenCalledWith {12: {id: 12}}