# Copyright:: (c) Autotelik Media Ltd 2011 # Author :: Tom Statter # Date :: Summer 2011 # # License:: MIT - Free, OpenSource # # Details:: Specification for Spree aspect of datashift gem. # # Provides Loaders and rake tasks specifically tailored for uploading or exporting # Spree Products, associations and Images # require File.dirname(__FILE__) + '/spec_helper' require 'spree_helper' require 'product_loader' include DataShift describe 'SpreeLoader' do before(:all) do SpecHelper::before_all_spree end before(:each) do begin include SpecHelper extend SpecHelper before_each_spree @Product_klass.count.should == 0 @Taxon_klass.count.should == 0 @Variant_klass.count.should == 0 MethodDictionary.clear MethodDictionary.find_operators( @Product_klass ) # want to test both lookup and dynamic creation - this Taxonomy should be found, rest created root = @Taxonomy_klass.create( :name => 'Paintings' ) t = @Taxon_klass.new( :name => 'Landscape' ) t.taxonomy = root t.save @Taxon_klass.count.should == 2 @product_loader = DataShift::SpreeHelper::ProductLoader.new rescue => e puts e.inspect puts e.backtrace end end it "should process a simple .xls spreadsheet" do @zone_klass.delete_all loader = ExcelLoader.new(@zone_klass) loader.perform_load( SpecHelper::spree_fixture('SpreeZoneExample.xls') ) loader.loaded_count.should == @zone_klass.count end it "should process a simple csv file" do @zone_klass.delete_all loader = CsvLoader.new(@zone_klass) loader.perform_load( SpecHelper::spree_fixture('SpreeZoneExample.csv') ) loader.loaded_count.should == @zone_klass.count end # Loader should perform identically regardless of source, whether csv, .xls etc it "should load basic Products .xls via Spree loader" do test_basic_product('SpreeProductsSimple.xls') end it "should load basic Products from .csv via Spree loader", :csv => true do test_basic_product('SpreeProductsSimple.csv') end it "should raise an error for missing file" do lambda { test_basic_product('SpreeProductsSimple.txt') }.should raise_error BadFile end it "should raise an error for unsupported file types" do lambda { test_basic_product('SpreeProductsDefaults.yml') }.should raise_error UnsupportedFileType end def test_basic_product( source ) @product_loader.perform_load( SpecHelper::spree_fixture(source), :mandatory => ['sku', 'name', 'price'] ) @Product_klass.count.should == 3 @product_loader.failed_objects.size.should == 0 @product_loader.loaded_objects.size.should == 3 @product_loader.loaded_count.should == @Product_klass.count p = @Product_klass.first p.sku.should == "SIMPLE_001" p.price.should == 345.78 p.name.should == "Simple Product for AR Loader" p.description.should == "blah blah" p.cost_price.should == 320.00 p.option_types.should have_exactly(1).items p.option_types.should have_exactly(1).items p.count_on_hand.should == 12 @Product_klass.last.count_on_hand.should == 23 end it "should support default values for Spree Products loader" do @expected_time = Time.now.to_s(:db) @product_loader.set_default_value('available_on', @expected_time) @product_loader.set_default_value('cost_price', 1.0 ) @product_loader.set_default_value('meta_description', 'super duper meta desc.' ) @product_loader.set_default_value('meta_keywords', 'techno dubstep d&b' ) @product_loader.set_prefix('sku', 'SPEC_') test_default_values end it "should support default values from config for Spree Products loader" do @product_loader.configure_from( SpecHelper::spree_fixture('SpreeProductsDefaults.yml') ) @product_loader.set_prefix('sku', 'SPEC_') test_default_values end def test_default_values @product_loader.perform_load( SpecHelper::spree_fixture('SpreeProductsMandatoryOnly.xls'), :mandatory => ['sku', 'name', 'price'] ) @Product_klass.count.should == 3 @product_loader.failed_objects.size.should == 0 @product_loader.loaded_objects.size.should == 3 p = @Product_klass.first p.sku.should == "SPEC_SIMPLE_001" @Product_klass.all { |p| p.sku.should.include "SPEC_" p.cost_price = 1.0 p.available_on.should == @expected_time p.meta_description.should == 'super duper meta desc.' p.meta_keywords.should == 'techno dubstep d&b' } end # Operation and results should be identical when loading multiple associations # if using either single column embedded syntax, or one column per entry. it "should load Products and create Variants from single column" do test_variants_creation('SpreeProducts.xls') end it "should load Products and create Variants from multiple column", :fail => true do test_variants_creation('SpreeProductsMultiColumn.xls') end def test_variants_creation( source ) @Product_klass.count.should == 0 @Variant_klass.count.should == 0 @product_loader.perform_load( SpecHelper::spree_fixture(source), :mandatory => ['sku', 'name', 'price'] ) expected_multi_column_variants end def expected_multi_column_variants # 3 MASTER products, 11 VARIANTS @Product_klass.count.should == 3 @Variant_klass.count.should == 14 p = @Product_klass.first p.sku.should == "DEMO_001" p.sku.should == "DEMO_001" p.price.should == 399.99 p.description.should == "blah blah" p.cost_price.should == 320.00 @Product_klass.all.select {|m| m.is_master.should == true } # mime_type:jpeg mime_type:PDF mime_type:PNG p.variants.should have_exactly(3).items p.option_types.should have_exactly(1).items # mime_type p.option_types[0].name.should == "mime_type" p.option_types[0].presentation.should == "Mime type" @Variant_klass.all[1].sku.should == "DEMO_001_0" @Variant_klass.all[1].price.should == 399.99 # V1 v1 = p.variants[0] v1.sku.should == "DEMO_001_0" v1.price.should == 399.99 v1.count_on_hand.should == 12 v1.option_values.should have_exactly(1).items # mime_type: jpeg v1.option_values[0].name.should == "jpeg" v2 = p.variants[1] v2.count_on_hand.should == 6 v2.option_values.should have_exactly(1).items # mime_type: jpeg v2.option_values[0].name.should == "PDF" v2.option_values[0].option_type.should_not be_nil v2.option_values[0].option_type.position.should == 0 v3 = p.variants[2] v3.count_on_hand.should == 7 v3.option_values.should have_exactly(1).items # mime_type: jpeg v3.option_values[0].name.should == "PNG" @Variant_klass.last.price.should == 50.34 @Variant_klass.last.count_on_hand.should == 18 @product_loader.failed_objects.size.should == 0 end ################## ### PROPERTIES ### ################## # Operation and results should be identical when loading multiple associations # if using either single column embedded syntax, or one column per entry. it "should load Products and multiple Properties from single column", :props => true do test_properties_creation( 'SpreeProducts.xls' ) end it "should load Products and multiple Properties from multiple column", :props => true do test_properties_creation( 'SpreeProductsMultiColumn.xls' ) end def test_properties_creation( source ) # want to test both lookup and dynamic creation - this Prop should be found, rest created @Property_klass.create( :name => 'test_pp_001', :presentation => 'Test PP 001' ) @Property_klass.count.should == 1 @product_loader.perform_load( SpecHelper::spree_fixture(source), :mandatory => ['sku', 'name', 'price'] ) expected_multi_column_properties end def expected_multi_column_properties # 3 MASTER products, 11 VARIANTS @Product_klass.count.should == 3 @Variant_klass.count.should == 14 @Product_klass.first.properties.should have_exactly(1).items p3 = @Product_klass.all.last p3.properties.should have_exactly(3).items p3.properties.should include @Property_klass.find_by_name('test_pp_002') # Test the optional text value got set on assigned product property p3.product_properties.select {|p| p.value == 'Example free value' }.should have_exactly(1).items end ############## ### TAXONS ### ############## # Operation and results should be identical when loading multiple associations # if using either single column embedded syntax, or one column per entry. it "should load Products and multiple Taxons from single column", :taxons => true do test_taxon_creation( 'SpreeProducts.xls' ) end it "should load Products and multiple Taxons from multiple columns", :taxons => true do test_taxon_creation( 'SpreeProductsMultiColumn.xls' ) end def test_taxon_creation( source ) # we want to test both find and find_or_create so should already have an object # for find @Taxonomy_klass.count.should == 1 @Taxon_klass.count.should == 2 @product_loader.perform_load( SpecHelper::spree_fixture(source), :mandatory => ['sku', 'name', 'price'] ) expected_multi_column_taxons end def expected_multi_column_taxons #puts @Taxonomy_klass.all.collect( &:name).inspect #puts @Taxon_klass.all.collect( &:name).inspect # Paintings already existed and had 1 child Taxon (Landscape) # 2 nested Taxon (Paintings>Nature>Seascape) created under it so expect Taxonomy : # WaterColour # Oils # Paintings >Nature>Seascape + >Landscape # Drawings @Taxonomy_klass.count.should == 4 @Taxon_klass.count.should == 7 @Product_klass.first.taxons.should have_exactly(2).items @Product_klass.last.taxons.should have_exactly(2).items p2 = @Variant_klass.find_by_sku("DEMO_002").product # Paintings Oils Paintings>Nature>Seascape # ["Nature", "Paintings", "Seascape"] #puts p2.taxons.collect(&:name).inspect p2.taxons.should have_exactly(4).items p2.taxons.collect(&:name).sort.should == ['Nature','Oils','Paintings','Seascape'] paint_parent = @Taxonomy_klass.find_by_name('Paintings') puts paint_parent.taxons.collect(&:name).sort.inspect paint_parent.taxons.should have_exactly(4).items # 3 children + all Taxonomies have a root Taxon paint_parent.taxons.collect(&:name).sort.should == ['Landscape','Nature','Paintings','Seascape'] tn = @Taxon_klass.find_by_name('Nature') # child with children ts = @Taxon_klass.find_by_name('Seascape') # last child ts.should_not be_nil tn.should_not be_nil p2.taxons.collect( &:id ).should include(ts.id) p2.taxons.collect( &:id ).should include(tn.id) tn.parent.id.should == paint_parent.root.id ts.parent.id.should == tn.id tn.children.should have_exactly(1).items ts.children.should have_exactly(0).items end # REPEAT THE WHOLE TEST SUITE VIA CSV it "should load Products from single column csv as per .xls" do test_variants_creation('SpreeProducts.csv') expected_multi_column_properties expected_multi_column_taxons end it "should load Products from multiple column csv as per .xls", :blah => true do test_variants_creation('SpreeProductsMultiColumn.csv') expected_multi_column_properties expected_multi_column_taxons end it "should raise exception when mandatory columns missing from .xls", :ex => true do expect {@product_loader.perform_load($SpreeNegativeFixturePath + '/SpreeProdMissManyMandatory.xls', :mandatory => ['sku', 'name', 'price'] )}.to raise_error(DataShift::MissingMandatoryError) end it "should raise exception when single mandatory column missing from .xls", :ex => true do expect {@product_loader.perform_load($SpreeNegativeFixturePath + '/SpreeProdMiss1Mandatory.xls', :mandatory => 'sku' )}.to raise_error(DataShift::MissingMandatoryError) end it "should raise exception when mandatory columns missing from .csv", :ex => true do expect {@product_loader.perform_load($SpreeNegativeFixturePath + '/SpreeProdMissManyMandatory.csv', :mandatory => ['sku', 'name', 'price'] )}.to raise_error(DataShift::MissingMandatoryError) end it "should raise exception when single mandatory column missing from .csv", :ex => true do expect {@product_loader.perform_load($SpreeNegativeFixturePath + '/SpreeProdMiss1Mandatory.csv', :mandatory => 'sku' )}.to raise_error(DataShift::MissingMandatoryError) end end