mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-04 02:31:33 +00:00
Convert bulk product update spec to coffeescript
This commit is contained in:
@@ -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 } } );
|
||||
});
|
||||
});
|
||||
778
spec/javascripts/unit/bulk_product_update_spec.js.coffee
Normal file
778
spec/javascripts/unit/bulk_product_update_spec.js.coffee
Normal file
@@ -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}}
|
||||
Reference in New Issue
Block a user