diff --git a/plugins/article_import/app/overrides/controllers/articles_controller_override.rb b/plugins/article_import/app/overrides/controllers/articles_controller_override.rb index 43e9773b..7777064e 100644 --- a/plugins/article_import/app/overrides/controllers/articles_controller_override.rb +++ b/plugins/article_import/app/overrides/controllers/articles_controller_override.rb @@ -1,18 +1,20 @@ -ArticlesController.class_eval do - def parse_upload - uploaded_file = params[:articles]['file'] or raise I18n.t('articles.controller.parse_upload.no_file') - type = params[:articles]['type'] - options = { filename: uploaded_file.original_filename } - options[:outlist_absent] = (params[:articles]['outlist_absent'] == '1') - options[:convert_units] = (params[:articles]['convert_units'] == '1') - options[:update_category] = (params[:articles]['update_category'] == '1') +if FoodsoftArticleImport.enabled? + ArticlesController.class_eval do + def parse_upload + uploaded_file = params[:articles]['file'] or raise I18n.t('articles.controller.parse_upload.no_file') + type = params[:articles]['type'] + options = { filename: uploaded_file.original_filename } + options[:outlist_absent] = (params[:articles]['outlist_absent'] == '1') + options[:convert_units] = (params[:articles]['convert_units'] == '1') + options[:update_category] = (params[:articles]['update_category'] == '1') - @updated_article_pairs, @outlisted_articles, @new_articles = @supplier.sync_from_file uploaded_file.tempfile, type, options - if @updated_article_pairs.empty? && @outlisted_articles.empty? && @new_articles.empty? - redirect_to supplier_articles_path(@supplier), :notice => I18n.t('articles.controller.parse_upload.notice') + @updated_article_pairs, @outlisted_articles, @new_articles = @supplier.sync_from_file uploaded_file.tempfile, type, options + if @updated_article_pairs.empty? && @outlisted_articles.empty? && @new_articles.empty? + redirect_to supplier_articles_path(@supplier), :notice => I18n.t('articles.controller.parse_upload.notice') + end + @ignored_article_count = 0 + rescue => error + redirect_to upload_supplier_articles_path(@supplier), :alert => I18n.t('errors.general_msg', :msg => error.message) end - @ignored_article_count = 0 - rescue => error - redirect_to upload_supplier_articles_path(@supplier), :alert => I18n.t('errors.general_msg', :msg => error.message) end -end +end \ No newline at end of file diff --git a/plugins/article_import/app/overrides/models/article_override.rb b/plugins/article_import/app/overrides/models/article_override.rb index 2018a4e7..5ca177ad 100644 --- a/plugins/article_import/app/overrides/models/article_override.rb +++ b/plugins/article_import/app/overrides/models/article_override.rb @@ -1,37 +1,39 @@ -Article.class_eval do - def unequal_attributes(new_article, options = {}) - # try to convert different units when desired - if options[:convert_units] == false - new_price = nil - new_unit_quantity = nil - else - new_price, new_unit_quantity = convert_units(new_article) - end - if new_price && new_unit_quantity - new_unit = self.unit - else - new_price = new_article.price - new_unit_quantity = new_article.unit_quantity - new_unit = new_article.unit - end +if FoodsoftArticleImport.enabled? + Article.class_eval do + def unequal_attributes(new_article, options = {}) + # try to convert different units when desired + if options[:convert_units] == false + new_price = nil + new_unit_quantity = nil + else + new_price, new_unit_quantity = convert_units(new_article) + end + if new_price && new_unit_quantity + new_unit = self.unit + else + new_price = new_article.price + new_unit_quantity = new_article.unit_quantity + new_unit = new_article.unit + end - attribute_hash = { - :name => [self.name, new_article.name], - :manufacturer => [self.manufacturer, new_article.manufacturer.to_s], - :origin => [self.origin, new_article.origin], - :unit => [self.unit, new_unit], - :price => [self.price.to_f.round(2), new_price.to_f.round(2)], - :tax => [self.tax, new_article.tax], - :deposit => [self.deposit.to_f.round(2), new_article.deposit.to_f.round(2)], - # take care of different num-objects. - :unit_quantity => [self.unit_quantity.to_s.to_f, new_unit_quantity.to_s.to_f], - :note => [self.note.to_s, new_article.note.to_s] - } - if options[:update_category] == true - new_article_category = new_article.article_category - attribute_hash[:article_category] = [self.article_category, new_article_category] unless new_article_category.blank? - end + attribute_hash = { + :name => [self.name, new_article.name], + :manufacturer => [self.manufacturer, new_article.manufacturer.to_s], + :origin => [self.origin, new_article.origin], + :unit => [self.unit, new_unit], + :price => [self.price.to_f.round(2), new_price.to_f.round(2)], + :tax => [self.tax, new_article.tax], + :deposit => [self.deposit.to_f.round(2), new_article.deposit.to_f.round(2)], + # take care of different num-objects. + :unit_quantity => [self.unit_quantity.to_s.to_f, new_unit_quantity.to_s.to_f], + :note => [self.note.to_s, new_article.note.to_s] + } + if options[:update_category] == true + new_article_category = new_article.article_category + attribute_hash[:article_category] = [self.article_category, new_article_category] unless new_article_category.blank? + end - Article.compare_attributes(attribute_hash) + Article.compare_attributes(attribute_hash) + end end -end +end \ No newline at end of file diff --git a/plugins/article_import/app/overrides/models/supplier_override.rb b/plugins/article_import/app/overrides/models/supplier_override.rb index 504bc26d..62885aac 100644 --- a/plugins/article_import/app/overrides/models/supplier_override.rb +++ b/plugins/article_import/app/overrides/models/supplier_override.rb @@ -1,51 +1,53 @@ -Supplier.class_eval do - # Synchronise articles with spreadsheet. - # - # @param file [File] Spreadsheet file to parse - # @param options [Hash] Options passed to {FoodsoftArticleImport#parse} except when listed here. - # @option options [Boolean] :outlist_absent Set to +true+ to remove articles not in spreadsheet. - # @option options [Boolean] :convert_units Omit or set to +true+ to keep current units, recomputing unit quantity and price. - def sync_from_file(file, type, options = {}) - all_order_numbers = [] - updated_article_pairs, outlisted_articles, new_articles = [], [], [] - custom_codes_path = File.join(Rails.root, "config", "custom_codes.yml") - opts = options.except(:convert_units, :outlist_absent) - custom_codes_file_path = custom_codes_path if File.exist?(custom_codes_path) - FoodsoftArticleImport.parse(file, custom_file_path: custom_codes_file_path, type: type, **opts) do |new_attrs, status, line| - article = articles.undeleted.where(order_number: new_attrs[:order_number]).first +if FoodsoftArticleImport.enabled? + Supplier.class_eval do + # Synchronise articles with spreadsheet. + # + # @param file [File] Spreadsheet file to parse + # @param options [Hash] Options passed to {FoodsoftArticleImport#parse} except when listed here. + # @option options [Boolean] :outlist_absent Set to +true+ to remove articles not in spreadsheet. + # @option options [Boolean] :convert_units Omit or set to +true+ to keep current units, recomputing unit quantity and price. + def sync_from_file(file, type, options = {}) + all_order_numbers = [] + updated_article_pairs, outlisted_articles, new_articles = [], [], [] + custom_codes_path = File.join(Rails.root, "config", "custom_codes.yml") + opts = options.except(:convert_units, :outlist_absent) + custom_codes_file_path = custom_codes_path if File.exist?(custom_codes_path) + FoodsoftArticleImport.parse(file, custom_file_path: custom_codes_file_path, type: type, **opts) do |new_attrs, status, line| + article = articles.undeleted.where(order_number: new_attrs[:order_number]).first - if new_attrs[:article_category].present? && options[:update_category] - new_attrs[:article_category] = ArticleCategory.find_match(new_attrs[:article_category]) || ArticleCategory.create_or_find_by!(name: new_attrs[:article_category]) - else - new_attrs[:article_category] = nil - end - - new_attrs[:tax] ||= FoodsoftConfig[:tax_default] - new_article = articles.build(new_attrs) - if status.nil? - if article.nil? - new_articles << new_article + if new_attrs[:article_category].present? && options[:update_category] + new_attrs[:article_category] = ArticleCategory.find_match(new_attrs[:article_category]) || ArticleCategory.create_or_find_by!(name: new_attrs[:article_category]) else - unequal_attributes = article.unequal_attributes(new_article, options.slice(:convert_units, :update_category)) - unless unequal_attributes.empty? - article.attributes = unequal_attributes - updated_article_pairs << [article, unequal_attributes] - end + new_attrs[:article_category] = nil end - elsif status == :outlisted && article.present? - outlisted_articles << article - # stop when there is a parsing error - elsif status.is_a? String - # @todo move I18n key to model - raise I18n.t('articles.model.error_parse', :msg => status, :line => line.to_s) + new_attrs[:tax] ||= FoodsoftConfig[:tax_default] + new_article = articles.build(new_attrs) + if status.nil? + if article.nil? + new_articles << new_article + else + unequal_attributes = article.unequal_attributes(new_article, options.slice(:convert_units, :update_category)) + unless unequal_attributes.empty? + article.attributes = unequal_attributes + updated_article_pairs << [article, unequal_attributes] + end + end + elsif status == :outlisted && article.present? + outlisted_articles << article + + # stop when there is a parsing error + elsif status.is_a? String + # @todo move I18n key to model + raise I18n.t('articles.model.error_parse', :msg => status, :line => line.to_s) + end + + all_order_numbers << article.order_number if article end - - all_order_numbers << article.order_number if article + if options[:outlist_absent] + outlisted_articles += articles.undeleted.where.not(order_number: all_order_numbers + [nil]) + end + [updated_article_pairs, outlisted_articles, new_articles] end - if options[:outlist_absent] - outlisted_articles += articles.undeleted.where.not(order_number: all_order_numbers + [nil]) - end - [updated_article_pairs, outlisted_articles, new_articles] end end diff --git a/plugins/article_import/lib/foodsoft_article_import/engine.rb b/plugins/article_import/lib/foodsoft_article_import/engine.rb index 49c54bab..a2eee118 100644 --- a/plugins/article_import/lib/foodsoft_article_import/engine.rb +++ b/plugins/article_import/lib/foodsoft_article_import/engine.rb @@ -6,7 +6,7 @@ module FoodsoftArticleImport end end def default_foodsoft_config(cfg) - cfg[:use_article_import] = true + cfg[:use_article_import] = false end end end diff --git a/plugins/article_import/spec/app_config.yml b/plugins/article_import/spec/app_config.yml new file mode 100644 index 00000000..e31af571 --- /dev/null +++ b/plugins/article_import/spec/app_config.yml @@ -0,0 +1,34 @@ +# Minimal Foodsoft configuration +# +# Without those settings, Foodsoft may not even work. +# This file is used when running tests. When plugins would modify foodsoft behaviour +# and they are enabled in the sample configuration, there is stable base to test with. + +default: &defaults + multi_coop_install: false + use_self_service: true + default_scope: 'f' + + name: FC Minimal + + # true by default to keep compat with older installations, but test with false here + use_nick: false + use_article_import: true + + price_markup: 5 + + # do we really need the following ones? + tax_default: 6.0 + email_sender: noreply@minimal.test + + host: localhost + + +development: + <<: *defaults + +test: + <<: *defaults + +production: + <<: *defaults diff --git a/plugins/article_import/spec/fixtures/bnn_file01.bnn b/plugins/article_import/spec/fixtures/bnn_file01.bnn new file mode 100644 index 00000000..b75b63cf --- /dev/null +++ b/plugins/article_import/spec/fixtures/bnn_file01.bnn @@ -0,0 +1,5 @@ +BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1 +29932;;;;4280001958081;4280001958203;Walnoten (ongeroosterd);bio;;;med;;GR;C%;DE-?KO-001;120;1302;10;55;;1;;1;1 kg;1;N;930190;99260;;1,41;;;;1;;;4,49;2,34;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;28,571;; +28391;;;;4280001958081;4280001958203;Pijnboompitten;dem;;;med;;GR;C%;DE-?KO-001;120;1302;10;55;;1;;1;100 g;10;N;930190;99260;;1,41;;;;1;;;5,56;2.89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;Kg;28,571;; +1829;;;;4280001958081;4280001958203;Appelsap (verpakt);;;;med;;GR;C%;DE-?KO-001;120;1302;10;55;;1;4x250 ml;10;4x250 ml;10;N;930190;99260;;3,21;;;;1;;;4,49;2.89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;ml;28,571;; +177813;;;;4280001958081;4280001958203;Tomaten;bio;;;med;;GR;C%;DE-?KO-001;120;1302;10;55;;1;;1;500 g;20;N;930190;99260;;1,20;;;;1;;;4,49;2.89;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;g;28,571;; \ No newline at end of file diff --git a/plugins/article_import/spec/fixtures/bnn_file_02.bnn b/plugins/article_import/spec/fixtures/bnn_file_02.bnn new file mode 100644 index 00000000..e3dba5bb --- /dev/null +++ b/plugins/article_import/spec/fixtures/bnn_file_02.bnn @@ -0,0 +1,2 @@ +BNN;3;0;Naturkost Nord, Hamburg;T;Angebot Nr. 0922;EUR;20220905;20221001;20220825;837;1 +1;;;;4280001958081;4280001958203;Tomatoes;organic;;;med;;GR;C%;DE-?KO-001;120;1302;10;55;;1;;20;500 g;1;N;930190;99260;;1,41;;;;1;;;4,49;1,20;J;;2;3;;;;;;;;;;;;;;;;;;;A;;;;;g;28,571;; \ No newline at end of file diff --git a/plugins/article_import/spec/fixtures/odin_file_01.xml b/plugins/article_import/spec/fixtures/odin_file_01.xml new file mode 100644 index 00000000..3b60e83e --- /dev/null +++ b/plugins/article_import/spec/fixtures/odin_file_01.xml @@ -0,0 +1,273 @@ + + + +1039 +1.08 +Estafette Associatie C.V. +Geldermalsen + + +8719325207668 +Walnoten (ongeroosterd) +Nucli rose + +0 +0 +0 +1 +kg +Stuk +0 +Het warme woud +bio + + +NL + +6 +1017515 +29932 +10 +Actief +druiven* +0 +0 +2 +2 +0 +0 +0 +2 +2 +0 +2 +0 +2 +0 +2 +2 +2 +2 +1 +0 +2 +0 +2 +2 + + + +0 +0 +0 +0 +1 + +2 +0 + +adviesprijs +2022-08-18 +2.34 +7.95 + + + +8719325207668 +Pijnboompitten +Nucli rose + +0 +0 +0 +100 +g +Stuk +0 +NELEMAN +dem + + +TR + +6 +1017515 +28391 +10 +Actief +druiven* +0 +0 +2 +2 +0 +0 +0 +2 +2 +0 +2 +0 +2 +0 +2 +2 +2 +2 +1 +0 +2 +0 +2 +2 + + + +0 +0 +0 +0 +1 + +2 +0 + +adviesprijs +2022-08-18 +5.56 +7.95 + + + +8719325207668 +Appelsap (verpakt) +Nucli rose + +0 +0 +0 +4x250 +ml +Stuk +0.4 +Appelgaarde + + + +DE + +6 +1017515 +1829 +10 +Actief +druiven* +0 +0 +2 +2 +0 +0 +0 +2 +2 +0 +2 +0 +2 +0 +2 +2 +2 +2 +1 +0 +2 +0 +2 +2 + + + +0 +0 +0 +0 +1 + +2 +0 + +adviesprijs +2022-08-18 +3.21 +7.95 + + + +8719325207668 +Tomaten +Nucli rose + +0 +0 +0 +500 +g +Stuk +0 +De röde hof +bio + + +DE + +6 +1017515 +177813 +20 +Actief +druiven* +0 +0 +2 +2 +0 +0 +0 +2 +2 +0 +2 +0 +2 +0 +2 +2 +2 +2 +1 +0 +2 +0 +2 +2 + + + +0 +0 +0 +0 +1 + +2 +0 + +adviesprijs +2022-08-18 +1.2 +7.95 + + + \ No newline at end of file diff --git a/plugins/article_import/spec/fixtures/odin_file_02.xml b/plugins/article_import/spec/fixtures/odin_file_02.xml new file mode 100644 index 00000000..c732b4d5 --- /dev/null +++ b/plugins/article_import/spec/fixtures/odin_file_02.xml @@ -0,0 +1,75 @@ + + + +1039 +1.08 +Estafette Associatie C.V. +Geldermalsen + + +8719325207668 +Tomatoes +Nucli rose + +0 +0 +0 +500 +g +Stuk +0 +De röde hof +organic + + +Somewhere, UK + +6 +1017515 +1 +20 +Actief +druiven* +0 +0 +2 +2 +0 +0 +0 +2 +2 +0 +2 +0 +2 +0 +2 +2 +2 +2 +1 +0 +2 +0 +2 +2 + + + +0 +0 +0 +0 +1 + +2 +0 + +adviesprijs +2022-08-18 +1.2 +7.95 + + + \ No newline at end of file diff --git a/plugins/article_import/spec/integration/articles_spec.rb b/plugins/article_import/spec/integration/articles_spec.rb new file mode 100644 index 00000000..0a547515 --- /dev/null +++ b/plugins/article_import/spec/integration/articles_spec.rb @@ -0,0 +1,169 @@ +require_relative '../test_helper' +require_relative '../../../../spec/spec_helper' + +feature ArticlesController do + + let(:user) { create(:user, groups: [create(:workgroup, role_article_meta: true)]) } + let(:supplier) { create(:supplier) } + let!(:article_category) { create(:article_category) } + + before { login user } + + describe ':index', js: true do + before do + login user + visit supplier_articles_path(supplier_id: supplier.id) + end + + it 'can visit supplier articles path' do + expect(page).to have_content(supplier.name) + expect(page).to have_content(I18n.t('articles.index.edit_all')) + end + + it 'can create a new article' do + click_on I18n.t('articles.index.new') + expect(page).to have_selector('form#new_article') + article = build(:article, supplier: supplier, article_category: article_category) + within('#new_article') do + fill_in 'article_name', :with => article.name + fill_in 'article_unit', :with => article.unit + select article.article_category.name, :from => 'article_article_category_id' + fill_in 'article_price', :with => article.price + fill_in 'article_unit_quantity', :with => article.unit_quantity + fill_in 'article_tax', :with => article.tax + fill_in 'article_deposit', :with => article.deposit + # "Element cannot be scrolled into view" error, js as workaround + # find('input[type="submit"]').click + page.execute_script('$("form#new_article").submit();') + end + expect(page).to have_content(article.name) + end + end + + describe ':upload' do + let(:filename) { 'foodsoft_file_02.csv' } + let(:file) { Rails.root.join("spec/fixtures/#{filename}") } + + before do + visit upload_supplier_articles_path(supplier_id: supplier.id) + attach_file 'articles_file', file + end + + Dir.glob('spec/fixtures/foodsoft_file_01.*') do |test_file| + describe "can import articles from #{test_file}" do + let(:file) { Rails.root.join(test_file) } + + it do + find("#articles_type option[value='foodsoft']").select_option + find('input[type="submit"]').click + expect(find("tr:nth-child(1) #new_articles__note").value).to eq "bio ◎" + expect(find("tr:nth-child(2) #new_articles__name").value).to eq "Pijnboompitten" + + 4.times do |i| + all("tr:nth-child(#{i + 1}) select > option")[1].select_option + end + find('input[type="submit"]').click + expect(page).to have_content("Pijnboompitten") + + expect(supplier.articles.count).to eq 4 + end + end + end + + Dir.glob('spec/fixtures/bnn_file_01.*') do |test_file| + describe "can import articles from #{test_file}" do + let(:file) { Rails.root.join(test_file) } + + it do + find("#articles_type option[value='bnn']").select_option + find('input[type="submit"]').click + expect(find("tr:nth-child(1) #new_articles__note").value).to eq "bio" + expect(find("tr:nth-child(1) #new_articles__name").value).to eq "Walnoten (ongeroosterd)" + # set article category + 4.times do |i| + all("tr:nth-child(#{i + 1}) select > option")[1].select_option + end + find('input[type="submit"]').click + + expect(page).to have_content("Pijnboompitten") + + expect(supplier.articles.count).to eq 4 + end + end + end + end + + describe "updates" do + file_paths = ['spec/fixtures/foodsoft_file_02.csv', 'plugins/article_import/spec/fixtures/bnn_file_02.bnn', 'plugins/article_import/spec/fixtures/odin_file_02.xml'] + let(:filename) { 'foodsoft_file_02.csv' } + let(:file) { Rails.root.join("spec/fixtures/#{filename}") } + let(:val) { 'foodsoft' } + let(:type) { %w[foodsoft bnn odin] } + + before do + visit upload_supplier_articles_path(supplier_id: supplier.id) + attach_file 'articles_file', file + find("#articles_type option[value='#{val}']").select_option + end + + file_paths.each_with_index do |test_file, index| + describe "updates article for #{test_file}" do + let(:article) { create(:article, supplier: supplier, name: 'Foobar', order_number: 1, unit: '250 g') } + let(:file) { Rails.root.join(test_file) } + let(:val) { type[index] } + + it do + article.reload + find('input[type="submit"]').click + expect(find("#articles_#{article.id}_name").value).to eq 'Tomatoes' + find('input[type="submit"]').click + article.reload + expect(article.name).to eq 'Tomatoes' + if type[index] == "odin" + expect([article.unit, article.unit_quantity, article.price]).to eq ['500gr', 20, 1.20] + else + expect([article.unit, article.unit_quantity, article.price]).to eq ['500 g', 20, 1.20] + end + end + + it "handles missing data" do + find('input[type="submit"]').click # to overview + find('input[type="submit"]').click # missing category, re-show form + expect(find('tr.alert')).to be_present + expect(supplier.articles.count).to eq 0 + + all("tr select > option")[1].select_option + find('input[type="submit"]').click # now it should succeed + expect(supplier.articles.count).to eq 1 + end + end + + describe "can remove an existing article" do + let!(:article) { create(:article, supplier: supplier, name: 'Foobar', order_number: 99999) } + + it do + check('articles_outlist_absent') + find('input[type="submit"]').click + expect(find("#outlisted_articles_#{article.id}", visible: :all)).to be_present + + all("tr select > option")[1].select_option + find('input[type="submit"]').click + expect(article.reload.deleted?).to be true + end + end + + describe "can convert units when updating" do + let!(:article) { create(:article, supplier: supplier, order_number: 1, unit: '250 g') } + + it do + check('articles_convert_units') + find('input[type="submit"]').click + expect(find("#articles_#{article.id}_name").value).to eq 'Tomatoes' + find('input[type="submit"]').click + article.reload + expect([article.unit, article.unit_quantity, article.price]).to eq ['250 g', 40, 0.6] + end + end + end + end +end diff --git a/plugins/article_import/spec/integration/supplier_spec.rb b/plugins/article_import/spec/integration/supplier_spec.rb new file mode 100644 index 00000000..d80c0d52 --- /dev/null +++ b/plugins/article_import/spec/integration/supplier_spec.rb @@ -0,0 +1,21 @@ +require_relative '../test_helper' +require_relative '../../../../spec/spec_helper' + +describe Supplier do + let(:supplier) { create :supplier } + + context 'syncs from file' do + it 'imports and updates articles' do + article1 = create(:article, supplier: supplier, order_number: 177813, unit: '250 g', price: 0.1) + article2 = create(:article, supplier: supplier, order_number: 12345) + supplier.articles = [article1, article2] + options = { filename: 'foodsoft_file_01.csv' } + options[:outlist_absent] = true + options[:convert_units] = true + updated_article_pairs, outlisted_articles, new_articles = supplier.sync_from_file(Rails.root.join('spec/fixtures/foodsoft_file_01.csv'), 'foodsoft', options) + expect(new_articles.length).to be > 0 + expect(updated_article_pairs.first[1][:name]).to eq 'Tomaten' + expect(outlisted_articles.first).to eq article2 + end + end +end \ No newline at end of file diff --git a/plugins/article_import/spec/spec_helper.rb b/plugins/article_import/spec/spec_helper.rb deleted file mode 100644 index d3e43d53..00000000 --- a/plugins/article_import/spec/spec_helper.rb +++ /dev/null @@ -1,100 +0,0 @@ -# frozen_string_literal: true - -require 'simplecov' -SimpleCov.start -# This file was generated by the `rspec --init` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. -# -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. -# -# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. - config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" - expectations.include_chain_clauses_in_custom_matcher_descriptions = true - end - - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. - config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. - mocks.verify_partial_doubles = true - end - - # This option will default to `:apply_to_host_groups` in RSpec 4 (and will - # have no way to turn it off -- the option exists only for backwards - # compatibility in RSpec 3). It causes shared context metadata to be - # inherited by the metadata hash of host groups and examples, rather than - # triggering implicit auto-inclusion in groups with matching metadata. - config.shared_context_metadata_behavior = :apply_to_host_groups - - # The settings below are suggested to provide a good initial experience - # with RSpec, but feel free to customize to your heart's content. - # # This allows you to limit a spec run to individual examples or groups - # # you care about by tagging them with `:focus` metadata. When nothing - # # is tagged with `:focus`, all examples get run. RSpec also provides - # # aliases for `it`, `describe`, and `context` that include `:focus` - # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - # config.filter_run_when_matching :focus - # - # # Allows RSpec to persist some state between runs in order to support - # # the `--only-failures` and `--next-failure` CLI options. We recommend - # # you configure your source control system to ignore this file. - # config.example_status_persistence_file_path = "spec/examples.txt" - # - # # Limits the available syntax to the non-monkey patched syntax that is - # # recommended. For more details, see: - # # https://relishapp.com/rspec/rspec-core/docs/configuration/zero-monkey-patching-mode - # config.disable_monkey_patching! - # - # # This setting enables warnings. It's recommended, but in some cases may - # # be too noisy due to issues in dependencies. - # config.warnings = true - # - # # Many RSpec users commonly either run the entire suite or an individual - # # file, and it's useful to allow more verbose output when running an - # # individual spec file. - # if config.files_to_run.one? - # # Use the documentation formatter for detailed output, - # # unless a formatter has already been configured - # # (e.g. via a command-line flag). - # config.default_formatter = "doc" - # end - # - # # Print the 10 slowest examples and example groups at the - # # end of the spec run, to help surface which specs are running - # # particularly slow. - # config.profile_examples = 10 - # - # # Run specs in random order to surface order dependencies. If you find an - # # order dependency and want to debug it, you can fix the order by providing - # # the seed, which is printed after each run. - # # --seed 1234 - # config.order = :random - # - # # Seed global randomization in this process using the `--seed` CLI option. - # # Setting this allows you to use `--seed` to deterministically reproduce - # # test failures related to randomization by passing the same `--seed` value - # # as the one that triggered the failure. - # Kernel.srand config.seed -end diff --git a/plugins/article_import/spec/test_helper.rb b/plugins/article_import/spec/test_helper.rb new file mode 100644 index 00000000..527a16d8 --- /dev/null +++ b/plugins/article_import/spec/test_helper.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module TestHelper + ENV["FOODSOFT_APP_CONFIG"] = "plugins/article_import/spec/app_config.yml" +end + +RSpec.configure do |config| + config.include TestHelper, :type => :feature +end