From fbba08a17a6f718e1e6ed85e528189042fc9b1da Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 8 Sep 2022 15:59:54 +0200 Subject: [PATCH 01/25] test supplier deletes articles --- spec/models/supplier_spec.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/models/supplier_spec.rb b/spec/models/supplier_spec.rb index 72e870ed..74ef7902 100644 --- a/spec/models/supplier_spec.rb +++ b/spec/models/supplier_spec.rb @@ -3,6 +3,13 @@ require_relative '../spec_helper' describe Supplier do let(:supplier) { create :supplier } + it 'deletes the supplier and its articles' do + supplier = create :supplier, article_count: 3 + supplier.articles.each{ |a| expect(a).to receive(:mark_as_deleted)} + supplier.mark_as_deleted + expect(supplier.deleted?).to be(true) + end + it 'has a unique name' do supplier2 = build :supplier, name: supplier.name expect(supplier2).to be_invalid From 3be6841f6fa006aaea7b83d5b0485f31c42a19ff Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 8 Sep 2022 17:47:07 +0200 Subject: [PATCH 02/25] add home_spec integration test --- spec/integration/home_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 spec/integration/home_spec.rb diff --git a/spec/integration/home_spec.rb b/spec/integration/home_spec.rb new file mode 100644 index 00000000..ec5af29d --- /dev/null +++ b/spec/integration/home_spec.rb @@ -0,0 +1,21 @@ +require_relative '../spec_helper' + +feature HomeController do + let(:user) { create :user } + before { login user } + describe 'my profile' do + before { visit my_profile_path } + + it 'is accessible' do + expect(page).to have_selector 'input[id=user_first_name]' + expect(find_field('user_first_name').value).to eq(user.first_name) + end + + it 'updates first name' do + fill_in 'user_first_name', with: "foo" + click_button('Save') + expect(User.find(user.id).first_name).to eq "foo" + expect(page).to have_selector '.alert-success' + end + end +end \ No newline at end of file From 5e96efe10dcee6f3efd6e790e143ca635785fd33 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 15 Sep 2022 17:23:04 +0200 Subject: [PATCH 03/25] add drone ci --- .drone.yml | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .drone.yml diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..b892af61 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,42 @@ +kind: pipeline +type: docker +name: default + +steps: + - name: build and test + image: circleci/ruby:2.6.9-bullseye-node-browsers-legacy + commands: + - sudo apt install --no-install-recommends -y libmagic-dev + - sudo -E bundle install --path /bundle --without production,development + - sudo -E bundle exec rake foodsoft:setup:stock_config || true + - sudo -E bundle exec rake db:schema:load + - sudo -E bundle exec rake rspec-rerun:spec + + volumes: + - name: gem-cache + path: /bundle + - name: tmp + path: /drone/src/tmp + environment: + RAILS_LOG_TO_STDOUT: true + RAILS_ENV: test + COVERAGE: lcov + DATABASE_URL: mysql2://user:password@mariadb/test?encoding=utf8mb4 + DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL: true + PARALLEL_TEST_PROCESSORS: 15 + +services: + - name: mariadb + image: mariadb + environment: + MYSQL_USER: user + MYSQL_PASSWORD: password + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: password + +volumes: + - name: gem-cache + host: + path: /tmp/cache + - name: tmp + temp: {} From 3ac59d60a973ca484802684ce60cae926511bb5b Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Mon, 26 Sep 2022 16:42:01 +0200 Subject: [PATCH 04/25] WIP adding controller specs base --- spec/controllers/home_controller_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 spec/controllers/home_controller_spec.rb diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb new file mode 100644 index 00000000..86a2547c --- /dev/null +++ b/spec/controllers/home_controller_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe HomeController do + describe "GET profile" do + it 'shows dashboard for logged in user' do + get :my_profile + expect(response).to have_http_status(:success) + end + end +end From 6c1bfe3cec83d0fb9434cb080bd9d89d1618f203 Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Mon, 26 Sep 2022 16:42:33 +0200 Subject: [PATCH 05/25] test Supplier for correct tolerance --- spec/models/supplier_spec.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/spec/models/supplier_spec.rb b/spec/models/supplier_spec.rb index 74ef7902..f918e077 100644 --- a/spec/models/supplier_spec.rb +++ b/spec/models/supplier_spec.rb @@ -3,9 +3,16 @@ require_relative '../spec_helper' describe Supplier do let(:supplier) { create :supplier } + it 'return correct tolerance' do + supplier = create :supplier, articles: create_list(:article, 1, unit_quantity: 1) + expect(supplier.has_tolerance?).to be false + supplier2 = create :supplier, articles: create_list(:article, 1, unit_quantity: 2) + expect(supplier2.has_tolerance?).to be true + end + it 'deletes the supplier and its articles' do supplier = create :supplier, article_count: 3 - supplier.articles.each{ |a| expect(a).to receive(:mark_as_deleted)} + supplier.articles.each{ |a| expect(a).to receive(:mark_as_deleted) } supplier.mark_as_deleted expect(supplier.deleted?).to be(true) end From 3d55c68bad6422821e5d45184f9020548d48a90a Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 26 Sep 2022 20:28:40 +0200 Subject: [PATCH 06/25] supplier_spec: add sync from file test --- spec/models/supplier_spec.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/models/supplier_spec.rb b/spec/models/supplier_spec.rb index f918e077..4f73dd37 100644 --- a/spec/models/supplier_spec.rb +++ b/spec/models/supplier_spec.rb @@ -3,6 +3,21 @@ require_relative '../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"), 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 + it 'return correct tolerance' do supplier = create :supplier, articles: create_list(:article, 1, unit_quantity: 1) expect(supplier.has_tolerance?).to be false From 0dcbf16814d49dbefbec39a7bde745387260dee8 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Tue, 27 Sep 2022 09:45:28 +0200 Subject: [PATCH 07/25] add working home controller test and login_helper --- spec/controllers/home_controller_spec.rb | 10 ++++++++-- spec/spec_helper.rb | 1 + spec/support/spec_test_helper.rb | 25 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 spec/support/spec_test_helper.rb diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb index 86a2547c..be2e9189 100644 --- a/spec/controllers/home_controller_spec.rb +++ b/spec/controllers/home_controller_spec.rb @@ -2,10 +2,16 @@ require 'spec_helper' -describe HomeController do +describe HomeController, type: :controller do + let(:user) { create(:user) } + describe "GET profile" do + before do + login user + end + it 'shows dashboard for logged in user' do - get :my_profile + get :profile, params: { foodcoop: FoodsoftConfig[:default_scope] } expect(response).to have_http_status(:success) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 88dea423..6cd41ded 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -51,6 +51,7 @@ RSpec.configure do |config| # --seed 1234 config.order = "random" + config.include SpecTestHelper, type: :controller config.include SessionHelper, type: :feature # Automatically determine spec from directory structure, see: diff --git a/spec/support/spec_test_helper.rb b/spec/support/spec_test_helper.rb new file mode 100644 index 00000000..d27685b4 --- /dev/null +++ b/spec/support/spec_test_helper.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +# spec/support/spec_test_helper.rb +module SpecTestHelper + def login_admin + login(:admin) + end + + def login(user) + user = User.where(:nick => user.nick).first if user.is_a?(Symbol) + session[:user_id] = user.id + session[:scope] = FoodsoftConfig[:default_scope] # Save scope in session to not allow switching between foodcoops with one account + session[:locale] = user.locale + end + + + def current_user + User.find(session[:user_id]) + end +end + +# spec/spec_helper.rb +RSpec.configure do |config| + config.include SpecTestHelper, :type => :controller +end From 2bcb95349620937b70ae99bd1571c08197031d15 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Wed, 28 Sep 2022 09:33:37 +0200 Subject: [PATCH 08/25] group_order_article_spec: add tolerance test --- spec/models/group_order_article_spec.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/models/group_order_article_spec.rb b/spec/models/group_order_article_spec.rb index ddb9158a..b4888df4 100644 --- a/spec/models/group_order_article_spec.rb +++ b/spec/models/group_order_article_spec.rb @@ -46,7 +46,7 @@ describe GroupOrderArticle do let(:article) { create :article, supplier: order.supplier, unit_quantity: 1 } let(:oa) { order.order_articles.create(:article => article) } let(:goa) { create :group_order_article, group_order: go, order_article: oa } - let!(:goaq) { create :group_order_article_quantity, group_order_article: goa, quantity: 4 } + let!(:goaq) { create :group_order_article_quantity, group_order_article: goa, quantity: 4, tolerance: 6} it 'can calculate the result for the distribution strategy "first order first serve"' do res = goa.calculate_result(2) @@ -55,9 +55,13 @@ describe GroupOrderArticle do it 'can calculate the result for the distribution strategy "no automatic distribution"' do FoodsoftConfig[:distribution_strategy] = FoodsoftConfig::DistributionStrategy::NO_AUTOMATIC_DISTRIBUTION - res = goa.calculate_result(2) expect(res).to eq(quantity: 4, tolerance: 0, total: 4) end + + it 'determines tolerance correctly' do + res = goa.calculate_result(6) + expect(res).to eq(quantity: 4, tolerance: 2, total: 6) + end end end From 9b68f7566504a92e0e3cc2407cacd62e0cbfbeb8 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 29 Sep 2022 13:36:38 +0200 Subject: [PATCH 09/25] group_order_article_spec: add updates quantity tolerance test --- spec/models/group_order_article_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/models/group_order_article_spec.rb b/spec/models/group_order_article_spec.rb index b4888df4..1e7a2d3a 100644 --- a/spec/models/group_order_article_spec.rb +++ b/spec/models/group_order_article_spec.rb @@ -40,6 +40,15 @@ describe GroupOrderArticle do goa.update_quantities(0, 0) expect(GroupOrderArticle.exists?(goa.id)).to be false end + + it 'updates quantity and tolerance' do + goa.update_quantities(2,2) + goa.update_quantities(1,1) + expect(goa.quantity).to eq(1) + expect(goa.tolerance).to eq(1) + goa.update_quantities(1,2) + expect(goa.tolerance).to eq(2) + end end describe 'distribution strategy' do From 6ccf738589da9aab04f19561f57a53227d1baa1b Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Wed, 5 Oct 2022 14:53:13 +0200 Subject: [PATCH 10/25] home controller 100% spec'd --- Gemfile | 1 + Gemfile.lock | 5 + app/controllers/home_controller.rb | 3 +- spec/controllers/home_controller_spec.rb | 191 ++++++++++++++++++++++- spec/integration/home_spec.rb | 32 ++-- 5 files changed, 211 insertions(+), 21 deletions(-) diff --git a/Gemfile b/Gemfile index a46969fc..be499511 100644 --- a/Gemfile +++ b/Gemfile @@ -111,6 +111,7 @@ group :test do gem 'rspec-core' gem 'rspec-rerun' gem 'i18n-spec' + gem 'rails-controller-testing' # code coverage gem 'simplecov', require: false gem 'simplecov-lcov', require: false diff --git a/Gemfile.lock b/Gemfile.lock index e75862a6..14e9478c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -356,6 +356,10 @@ GEM sprockets-rails (>= 2.0.0) rails-assets-listjs (0.2.0.beta.4) railties (>= 3.1) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) @@ -610,6 +614,7 @@ DEPENDENCIES rack-cors rails (~> 5.2) rails-assets-listjs (= 0.2.0.beta.4) + rails-controller-testing rails-i18n rails-settings-cached (= 0.4.3) rails_tokeninput diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 6f677b6b..01567a6e 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -63,8 +63,9 @@ class HomeController < ApplicationController # cancel personal memberships direct from the myProfile-page def cancel_membership + # TODO: membership_id not used anymore? if params[:membership_id] - membership = @current_user.memberships.find!(params[:membership_id]) + membership = @current_user.memberships.find(params[:membership_id]) else membership = @current_user.memberships.find_by_group_id!(params[:group_id]) end diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb index be2e9189..ebe3a8be 100644 --- a/spec/controllers/home_controller_spec.rb +++ b/spec/controllers/home_controller_spec.rb @@ -3,16 +3,197 @@ require 'spec_helper' describe HomeController, type: :controller do - let(:user) { create(:user) } + let(:user) { create :user } - describe "GET profile" do - before do - login user + describe 'GET index' do + describe 'NOT logged in' do + it 'redirects' do + get :profile, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(login_path) + end end - it 'shows dashboard for logged in user' do + describe 'logegd in' do + before { login user } + + it 'assigns tasks' do + get :index, params: { foodcoop: FoodsoftConfig[:default_scope] } + + expect(assigns(:unaccepted_tasks)).not_to be_nil + expect(assigns(:next_tasks)).not_to be_nil + expect(assigns(:unassigned_tasks)).not_to be_nil + expect(response).to render_template('home/index') + end + end + end + + describe 'GET profile' do + before { login user } + + it 'renders dashboard' do get :profile, params: { foodcoop: FoodsoftConfig[:default_scope] } expect(response).to have_http_status(:success) + expect(response).to render_template('home/profile') + end + end + + describe 'GET reference_calculator' do + describe 'with simple user' do + before { login user } + + it 'redirects to home' do + get :reference_calculator, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(root_path) + end + end + + describe 'with ordergroup user' do + let(:og_user) { create :user, :ordergroup } + + before { login og_user } + + it 'renders reference calculator' do + get :reference_calculator, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:success) + expect(response).to render_template('home/reference_calculator') + end + end + end + + describe 'GET update_profile' do + describe 'with simple user' do + let(:unchanged_attributes) { user.attributes.slice('first_name', 'last_name', 'email') } + let(:changed_attributes) { attributes_for :user } + let(:invalid_attributes) { { email: 'e.mail.com'} } + + before { login user } + + it 'renders profile after update with invalid attributes' do + get :update_profile, params: { foodcoop: FoodsoftConfig[:default_scope], user: invalid_attributes } + expect(response).to have_http_status(:success) + expect(response).to render_template('home/profile') + expect(assigns(:current_user).errors.present?).to be true + end + + it 'redirects to profile after update with unchanged attributes' do + get :update_profile, params: { foodcoop: FoodsoftConfig[:default_scope], user: unchanged_attributes } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(my_profile_path) + end + + it 'redirects to profile after update' do + patch :update_profile, params: { foodcoop: FoodsoftConfig[:default_scope], user: changed_attributes } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(my_profile_path) + expect(flash[:notice]).to match(/#{I18n.t('home.changes_saved')}/) + expect(user.reload.attributes.slice(:first_name, :last_name, :email)).to eq(changed_attributes.slice('first_name', 'last_name', 'email')) + end + end + + describe 'with ordergroup user' do + let(:og_user) { create :user, :ordergroup } + let(:unchanged_attributes) { og_user.attributes.slice('first_name', 'last_name', 'email') } + let(:changed_attributes) { unchanged_attributes.merge({ ordergroup: { contact_address: 'new Adress 7' } }) } + + before { login og_user } + + it 'redirects to home after update' do + get :update_profile, params: { foodcoop: FoodsoftConfig[:default_scope], user: changed_attributes } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(my_profile_path) + expect(og_user.reload.ordergroup.contact_address).to eq('new Adress 7') + end + end + end + + describe 'GET ordergroup' do + describe 'with simple user' do + before { login user } + + it 'redirects to home' do + get :ordergroup, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(root_path) + end + end + + describe 'with ordergroup user' do + let(:og_user) { create :user, :ordergroup } + + before { login og_user } + + it 'renders ordergroup' do + get :ordergroup, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:success) + expect(response).to render_template('home/ordergroup') + end + + describe 'assigns sortings' do + let(:fin_trans1) { create :financial_transaction, user: og_user, ordergroup: og_user.ordergroup, note: 'A', amount: 100 } + let(:fin_trans2) { create :financial_transaction, user: og_user, ordergroup: og_user.ordergroup, note: 'B', amount: 200 } + + before do + fin_trans1 + fin_trans2 + end + + it 'by criteria' do + sortings = [ + ['date', [fin_trans1, fin_trans2]], + ['note', [fin_trans1, fin_trans2]], + ['amount', [fin_trans1, fin_trans2]], + ['date_reverse', [fin_trans2, fin_trans1]], + ['note_reverse', [fin_trans2, fin_trans1]], + ['amount_reverse', [fin_trans2, fin_trans1]] + ] + sortings.each do |sorting| + get :ordergroup, params: { foodcoop: FoodsoftConfig[:default_scope], sort: sorting[0] } + expect(response).to have_http_status(:success) + + expect(assigns(:financial_transactions).to_a).to eq(sorting[1]) + end + end + end + end + end + + describe 'GET cancel_membership' do + describe 'with simple user without group' do + before { login user } + + it 'fails' do + expect do + get :cancel_membership, params: { foodcoop: FoodsoftConfig[:default_scope] } + end.to raise_error(ActiveRecord::RecordNotFound) + end + end + + describe 'with ordergroup user' do + let(:fin_user) { create :user, :role_finance } + + before { login fin_user } + + it 'removes user from group' do + membership = fin_user.memberships.first + get :cancel_membership, + params: { foodcoop: FoodsoftConfig[:default_scope], + group_id: fin_user.groups.first.id } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(my_profile_path) + expect(flash[:notice]).to match(/#{I18n.t('home.ordergroup_cancelled', :group => membership.group.name)}/) + end + + it 'removes user membership' do + membership = fin_user.memberships.first + get :cancel_membership, + params: { foodcoop: FoodsoftConfig[:default_scope], + membership_id: membership.id } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(my_profile_path) + expect(flash[:notice]).to match(/#{I18n.t('home.ordergroup_cancelled', :group => membership.group.name)}/) + end end end end diff --git a/spec/integration/home_spec.rb b/spec/integration/home_spec.rb index ec5af29d..ecfa5f7c 100644 --- a/spec/integration/home_spec.rb +++ b/spec/integration/home_spec.rb @@ -1,21 +1,23 @@ require_relative '../spec_helper' feature HomeController do - let(:user) { create :user } - before { login user } - describe 'my profile' do - before { visit my_profile_path } + let(:user) { create :user } - it 'is accessible' do - expect(page).to have_selector 'input[id=user_first_name]' - expect(find_field('user_first_name').value).to eq(user.first_name) - end + before { login user } - it 'updates first name' do - fill_in 'user_first_name', with: "foo" - click_button('Save') - expect(User.find(user.id).first_name).to eq "foo" - expect(page).to have_selector '.alert-success' - end + describe 'my profile' do + before { visit my_profile_path } + + it 'is accessible' do + expect(page).to have_selector 'input[id=user_first_name]' + expect(find_field('user_first_name').value).to eq(user.first_name) end -end \ No newline at end of file + + it 'updates first name' do + fill_in 'user_first_name', with: 'foo' + click_button('Save') + expect(User.find(user.id).first_name).to eq 'foo' + expect(page).to have_selector '.alert-success' + end + end +end From decfba13ec5ed19e4551fcb6051ed257a9eec35f Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Wed, 5 Oct 2022 14:58:16 +0200 Subject: [PATCH 11/25] minor formatting --- spec/controllers/home_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb index ebe3a8be..beb556e0 100644 --- a/spec/controllers/home_controller_spec.rb +++ b/spec/controllers/home_controller_spec.rb @@ -66,7 +66,7 @@ describe HomeController, type: :controller do describe 'with simple user' do let(:unchanged_attributes) { user.attributes.slice('first_name', 'last_name', 'email') } let(:changed_attributes) { attributes_for :user } - let(:invalid_attributes) { { email: 'e.mail.com'} } + let(:invalid_attributes) { { email: 'e.mail.com' } } before { login user } From 6cc9a0bb499f2784fd727f80e39bb239b5aec744 Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Wed, 5 Oct 2022 15:40:14 +0200 Subject: [PATCH 12/25] move test to refactoring branch --- spec/controllers/home_controller_spec.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb index beb556e0..54a97e28 100644 --- a/spec/controllers/home_controller_spec.rb +++ b/spec/controllers/home_controller_spec.rb @@ -184,16 +184,6 @@ describe HomeController, type: :controller do expect(response).to redirect_to(my_profile_path) expect(flash[:notice]).to match(/#{I18n.t('home.ordergroup_cancelled', :group => membership.group.name)}/) end - - it 'removes user membership' do - membership = fin_user.memberships.first - get :cancel_membership, - params: { foodcoop: FoodsoftConfig[:default_scope], - membership_id: membership.id } - expect(response).to have_http_status(:redirect) - expect(response).to redirect_to(my_profile_path) - expect(flash[:notice]).to match(/#{I18n.t('home.ordergroup_cancelled', :group => membership.group.name)}/) - end end end end From 27b84df003afb920fd4bda6a72d6c0dbf79b25a6 Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Wed, 5 Oct 2022 17:53:10 +0200 Subject: [PATCH 13/25] login_controller spec'd --- spec/controllers/login_controller_spec.rb | 67 +++++++++++++++++++++++ spec/factories/invite.rb | 15 +++++ 2 files changed, 82 insertions(+) create mode 100644 spec/controllers/login_controller_spec.rb create mode 100644 spec/factories/invite.rb diff --git a/spec/controllers/login_controller_spec.rb b/spec/controllers/login_controller_spec.rb new file mode 100644 index 00000000..0e795893 --- /dev/null +++ b/spec/controllers/login_controller_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe LoginController, type: :controller do + let(:invite) { create :invite } + + describe 'GET accept_invitation' do + let(:expired_invite) { create :expired_invite } + + describe 'with valid token' do + it 'accepts invitation' do + get :accept_invitation, params: { foodcoop: FoodsoftConfig[:default_scope], token: invite.token } + expect(response).to have_http_status(:success) + expect(response).to render_template('login/accept_invitation') + end + end + + describe 'with invalid token' do + it 'redirects to login' do + get :accept_invitation, params: { foodcoop: FoodsoftConfig[:default_scope], token: invite.token + 'XX' } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(login_url) + expect(flash[:alert]).to match(I18n.t('login.controller.error_invite_invalid')) + end + end + + describe 'with timed out token' do + it 'redirects to login' do + get :accept_invitation, params: { foodcoop: FoodsoftConfig[:default_scope], token: expired_invite.token } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(login_url) + expect(flash[:alert]).to match(I18n.t('login.controller.error_invite_invalid')) + end + end + + describe 'without group' do + it 'redirects to login' do + invite.group.destroy + get :accept_invitation, params: { foodcoop: FoodsoftConfig[:default_scope], token: invite.token } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(login_url) + expect(flash[:alert]).to match(I18n.t('login.controller.error_group_invalid')) + end + end + end + + describe 'POST accept_invitation' do + describe 'with invalid parameters' do + it 'renders accept_invitation view' do + post :accept_invitation, params: { foodcoop: FoodsoftConfig[:default_scope], token: invite.token, user: invite.user.slice('first_name') } + expect(response).to have_http_status(:success) + expect(response).to render_template('login/accept_invitation') + expect(assigns(:user).errors.present?).to be true + end + end + + describe 'with valid parameters' do + it 'redirects to login' do + post :accept_invitation, params: { foodcoop: FoodsoftConfig[:default_scope], token: invite.token, user: invite.user.slice('first_name', 'password') } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(login_url) + expect(flash[:notice]).to match(I18n.t('login.controller.accept_invitation.notice')) + end + end + end +end \ No newline at end of file diff --git a/spec/factories/invite.rb b/spec/factories/invite.rb new file mode 100644 index 00000000..51d48840 --- /dev/null +++ b/spec/factories/invite.rb @@ -0,0 +1,15 @@ +require 'factory_bot' + +FactoryBot.define do + factory :invite do + user { create :user } + group { create :group } + email { Faker::Internet.email } + + factory :expired_invite do + after :create do |invite| + invite.update_column(:expires_at, Time.now.yesterday) + end + end + end +end From fd17f339d4c50fd472f852951c60938e7bec59ac Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 6 Oct 2022 12:27:34 +0200 Subject: [PATCH 14/25] article_spec: add deleted test --- config/environments/test.rb | 6 ++++++ spec/models/article_spec.rb | 5 +++++ spec/models/order_article_spec.rb | 4 ++++ spec/spec_helper.rb | 9 +++++++++ 4 files changed, 24 insertions(+) diff --git a/config/environments/test.rb b/config/environments/test.rb index ccf3767f..86b59a8b 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -47,4 +47,10 @@ Rails.application.configure do # Raises error for missing translations # config.action_view.raise_on_missing_translations = true + + # Enable stdout logger + config.logger = Logger.new(STDOUT) + + # Set log level + config.log_level = :DEBUG end diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 526b5417..8484d713 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -9,6 +9,11 @@ describe Article do expect(article2).to be_invalid end + it 'can be deleted' do + article.mark_as_deleted() + expect(article.deleted?).to be true + end + it 'computes the gross price correctly' do article.deposit = 0 article.tax = 12 diff --git a/spec/models/order_article_spec.rb b/spec/models/order_article_spec.rb index 32b280dc..f8f05c7b 100644 --- a/spec/models/order_article_spec.rb +++ b/spec/models/order_article_spec.rb @@ -4,6 +4,10 @@ describe OrderArticle do let(:order) { create :order, article_count: 1 } let(:oa) { order.order_articles.first } + it 'foo' do + oa.update_article_and_price!() + end + it 'is not ordered by default' do expect(OrderArticle.ordered.count).to eq 0 end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6cd41ded..fbf281da 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -68,6 +68,15 @@ if ENV['COVERAGE'] == 'lcov' SimpleCov.formatters = SimpleCov::Formatter::LcovFormatter end +if ENV['COVERAGE'] == 'html' + require 'simplecov-lcov' + SimpleCov::Formatter::LcovFormatter.config do |c| + c.report_with_single_file = true + c.single_report_path = 'coverage/lcov.html' + end + SimpleCov.formatters = SimpleCov::Formatter::HTMLFormatter +end + # include default foodsoft scope in urls, so that *_path works # https://github.com/rspec/rspec-rails/issues/255 class ActionDispatch::Routing::RouteSet From d010a74e36bba47e45a7532ea3896199543e27da Mon Sep 17 00:00:00 2001 From: viehlieb Date: Thu, 6 Oct 2022 12:42:58 +0200 Subject: [PATCH 15/25] article_controller wip and balancing_controller spec'd --- .../finance/balancing_controller.rb | 4 +- spec/controllers/articles_controller_spec.rb | 37 +++ .../finance/balancing_controller_spec.rb | 212 ++++++++++++++++++ 3 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 spec/controllers/articles_controller_spec.rb create mode 100644 spec/controllers/finance/balancing_controller_spec.rb diff --git a/app/controllers/finance/balancing_controller.rb b/app/controllers/finance/balancing_controller.rb index 09c109f8..2dca6f71 100644 --- a/app/controllers/finance/balancing_controller.rb +++ b/app/controllers/finance/balancing_controller.rb @@ -22,7 +22,7 @@ class Finance::BalancingController < Finance::BaseController when 'order_number_reverse' then @articles.order('articles.order_number DESC') else - @articles + @articles # TODO: We will never get here end render layout: false if request.xhr? @@ -105,6 +105,6 @@ class Finance::BalancingController < Finance::BaseController end redirect_to finance_order_index_url, notice: t('finance.balancing.close_all_direct_with_invoice.notice', count: count) rescue => error - redirect_to finance_order_index_url, alert: t('errors.general_msg', msg: error.message) + redirect_to finance_order_index_url, alert: t('errors.general_msg', msg: error.message) #TODO: this can't be reached end end diff --git a/spec/controllers/articles_controller_spec.rb b/spec/controllers/articles_controller_spec.rb new file mode 100644 index 00000000..79d8f0ac --- /dev/null +++ b/spec/controllers/articles_controller_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ArticlesController, type: :controller do + let(:user) { create :user, :role_article_meta } + + before { login user } + + describe 'GET index' do + let(:article_categoryA) { create :article_category, name: "AAAA" } + let(:article_categoryB) { create :article_category, name: "BBBB" } + let(:articleA) { create :article, name: 'AAAA', note: "AAAA", unit: '250 g', article_category: article_categoryA, availability: false } + let(:articleB) { create :article, name: 'BBBB', note: "BBBB", unit: '500 g', article_category: article_categoryB, availability: true } + let(:supplier) { create :supplier, articles: [articleA, articleB] } + + it 'assigns sorting on articles' do + sortings = [ + ['name', [articleA, articleB]], + ['name_reverse', [articleB, articleA]], + ['unit', [articleA, articleB]], + ['unit_reverse', [articleB, articleA]], + ['article_category', [articleA, articleB]], + ['article_category_reverse', [articleB, articleA]], + ['note', [articleA, articleB]], + ['note_reverse', [articleB, articleA]], + ['availability', [articleA, articleB]], + ['availability_reverse', [articleB, articleA]] + ] + sortings.each do |sorting| + get :index, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, sort: sorting[0] } + expect(response).to have_http_status(:success) + expect(assigns(:articles).to_a).to eq(sorting[1]) + end + end + end +end diff --git a/spec/controllers/finance/balancing_controller_spec.rb b/spec/controllers/finance/balancing_controller_spec.rb new file mode 100644 index 00000000..dbeb262d --- /dev/null +++ b/spec/controllers/finance/balancing_controller_spec.rb @@ -0,0 +1,212 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Finance::BalancingController, type: :controller do + let(:user) { create :user, :role_finance, :role_orders, groups: [create(:ordergroup)] } + + before { login user } + + describe 'GET index' do + let(:order) { create :order } + + it 'renders index page' do + get :index, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:success) + expect(response).to render_template('finance/balancing/index') + end + end + + describe 'new balancing' do + let(:supplier) { create :supplier } + let(:article1) { create :article, name: "AAAA", supplier: supplier, unit_quantity: 1 } + let(:article2) { create :article, name: "AAAB", supplier: supplier, unit_quantity: 1 } + + let(:order) { create :order, supplier: supplier, article_ids: [article1.id, article2.id] } + + let(:go1) { create :group_order, order: order } + let(:go2) { create :group_order, order: order } + let(:oa1) { order.order_articles.find_by_article_id(article1.id) } + let(:oa2) { order.order_articles.find_by_article_id(article2.id) } + let(:oa3) { order2.order_articles.find_by_article_id(article2.id) } + let(:goa1) { create :group_order_article, group_order: go1, order_article: oa1 } + let(:goa2) { create :group_order_article, group_order: go1, order_article: oa2 } + + before do + goa1.update_quantities(3, 0) + goa2.update_quantities(1, 0) + oa1.update_results! + oa2.update_results! + end + + it 'renders new order page' do + get :new, params: { foodcoop: FoodsoftConfig[:default_scope], order_id: order.id } + expect(response).to have_http_status(:success) + expect(response).to render_template('finance/balancing/new') + end + + it 'assigns sorting on articles' do + sortings = [ + ['name', [oa1, oa2]], + ['name_reverse', [oa2, oa1]], + ['order_number', [oa1, oa2]], + ['order_number_reverse', [oa1, oa2]] # just one order + ] + sortings.each do |sorting| + get :new, params: { foodcoop: FoodsoftConfig[:default_scope], order_id: order.id, sort: sorting[0] } + expect(response).to have_http_status(:success) + expect(assigns(:articles).to_a).to eq(sorting[1]) + end + end + end + + describe 'update summary' do + let(:order) { create(:order) } + + it 'shows the summary view' do + get :update_summary, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id }, xhr: true + expect(response).to have_http_status(:success) + expect(response).to render_template('finance/balancing/update_summary') + end + end + + describe 'new_on_order' do + let(:order) { create(:order) } + let(:order_article) { order.order_articles.first } + + # TODO: how to check for js.erb calls? + it 'calls article update' do + get :new_on_order_article_update, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id, order_article_id: order_article.id }, xhr: true + expect(response).not_to render_template(layout: "application") + expect(response).to render_template('finance/balancing/new_on_order_article_update') + end + + it 'calls article create' do + get :new_on_order_article_create, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id, order_article_id: order_article.id }, xhr: true + expect(response).not_to render_template(layout: "application") + expect(response).to render_template('finance/balancing/new_on_order_article_create') + end + end + + describe 'edit_note' do + let(:order) { create(:order) } + + it 'updates order note' do + get :edit_note, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id, order: { note: "Hello" } }, xhr: true + expect(response).to have_http_status(:success) + expect(response).to render_template('finance/balancing/edit_note') + end + end + + describe 'update_note' do + let(:order) { create(:order) } + + it 'updates order note' do + get :update_note, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id, order: { note: "Hello" } }, xhr: true + expect(response).to have_http_status(:success) + end + + it 'redirects to edit note on failed update' do + get :update_note, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id, order: { article_ids: nil } }, xhr: true + expect(response).to have_http_status(:success) + expect(response).to render_template('finance/balancing/edit_note') + end + end + + describe 'transport' do + let(:order) { create(:order) } + + it 'calls the edit transport view' do + get :edit_transport, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id }, xhr: true + expect(response).to have_http_status(:success) + expect(response).to render_template('finance/balancing/edit_transport') + end + + it 'does redirect if order valid' do + get :update_transport, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id, order: { ends: Time.now } }, xhr: true + expect(response).to have_http_status(:redirect) + expect(assigns(:order).errors.count).to eq(0) + expect(response).to redirect_to(new_finance_order_path(order_id: order.id)) + end + + it 'does redirect if order invalid' do + get :update_transport, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id, order: { starts: Time.now + 2, ends: Time.now } }, xhr: true + expect(assigns(:order).errors.count).to eq(1) + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(new_finance_order_path(order_id: order.id)) + end + end + + describe 'confirm' do + let(:order) { create(:order) } + + it 'renders the confirm template' do + get :confirm, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id }, xhr: true + expect(response).to have_http_status(:success) + expect(response).to render_template('finance/balancing/confirm') + end + end + + describe 'close and update account balances' do + let(:order) { create(:order) } + let(:order1) { create(:order, ends: Time.now) } + let(:fft) { create(:financial_transaction_type) } + + it 'does not close order if ends not set' do + get :close, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id, type: fft.id } + expect(assigns(:order).closed?).to be_falsey + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(new_finance_order_url(order_id: order.id)) + end + + it 'closes order' do + get :close, params: { foodcoop: FoodsoftConfig[:default_scope], id: order1.id, type: fft.id } + expect(assigns(:order).closed?).to be_truthy + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(finance_order_index_url) + end + end + + describe 'close direct' do + let(:order) { create(:order) } + + it 'does not close order if already closed' do + order.close_direct!(user) + get :close_direct, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id } + expect(assigns(:order).closed?).to be_truthy + end + + it 'closes order directly' do + get :close_direct, params: { foodcoop: FoodsoftConfig[:default_scope], id: order.id } + expect(assigns(:order).closed?).to be_truthy + end + end + + describe 'close all direct' do + let(:invoice) { create(:invoice) } + let(:invoice1) { create(:invoice) } + let(:order) { create(:order, state: 'finished', ends: Time.now + 2.hours, invoice: invoice) } + let(:order1) { create(:order, state: 'finished', ends: Time.now + 2.hours) } + + before do + order + order1 + end + + it 'does close orders' do + get :close_all_direct_with_invoice, params: { foodcoop: FoodsoftConfig[:default_scope] } + order.reload + expect(order.closed?).to be_truthy + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(finance_order_index_url) + end + + it 'does not close orders when invoice not set' do + get :close_all_direct_with_invoice, params: { foodcoop: FoodsoftConfig[:default_scope] } + order1.reload + expect(order1.closed?).to be_falsey + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(finance_order_index_url) + end + end +end From 8ff44dc71ff223a77e359bc958699be27603d5fe Mon Sep 17 00:00:00 2001 From: viehlieb Date: Thu, 6 Oct 2022 13:08:02 +0200 Subject: [PATCH 16/25] revert debug level und logger to stdout --- config/environments/test.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index 86b59a8b..ccf3767f 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -47,10 +47,4 @@ Rails.application.configure do # Raises error for missing translations # config.action_view.raise_on_missing_translations = true - - # Enable stdout logger - config.logger = Logger.new(STDOUT) - - # Set log level - config.log_level = :DEBUG end From 6cbfed5654d790a6fc45690cf27f10d9f21f896f Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 6 Oct 2022 13:38:42 +0200 Subject: [PATCH 17/25] article_spec: add convert unit tests --- spec/models/article_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 8484d713..2a3b3402 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -14,6 +14,27 @@ describe Article do expect(article.deleted?).to be true end + describe 'convert units' do + it 'returns nil when equal' do expect(article.convert_units(article)).to be nil end + it 'returns false when invalid unit' do + article1 = build :article, supplier: supplier, unit: "invalid" + expect(article.convert_units(article1)).to be false + end + it 'converts from ST to KI' do + article1 = build :article, supplier: supplier, unit: "ST" + article2 = build :article, supplier: supplier, name: "banana 10-12 St", price: 12.34, unit: "KI" + new_price, new_unit_quantity = article1.convert_units(article2) + expect(new_unit_quantity).to eq 10 + expect(new_price).to eq 1.23 + end + it 'converts from g to kg' do + article1 = build :article, supplier: supplier, unit: "kg" + article2 = build :article, supplier: supplier, unit: "g", price: 0.12, unit_quantity: 1500 + new_price, new_unit_quantity = article1.convert_units(article2) + expect(new_unit_quantity).to eq 1.5 + expect(new_price).to eq 120 + end + end it 'computes the gross price correctly' do article.deposit = 0 article.tax = 12 From a71ca3c2dce949f9bee45afcafca94111ac4ca4f Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 6 Oct 2022 13:42:16 +0200 Subject: [PATCH 18/25] article_spec: add changed article test --- spec/models/article_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 2a3b3402..d75c49b6 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -35,6 +35,12 @@ describe Article do expect(new_price).to eq 120 end end + + it 'computes changed article attributes' do # not done yet! + article2 = build :article, supplier: supplier, name: "banana" + expect(article.unequal_attributes(article2)[:name]).to eq "banana" + end + it 'computes the gross price correctly' do article.deposit = 0 article.tax = 12 From 75b0bdf856cbb78ed7655d7774a6cc9bda122294 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 6 Oct 2022 16:08:32 +0200 Subject: [PATCH 19/25] delivery: add delivery test --- spec/factories/delivery.rb | 9 +++++++++ spec/models/delivery_spec.rb | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 spec/factories/delivery.rb create mode 100644 spec/models/delivery_spec.rb diff --git a/spec/factories/delivery.rb b/spec/factories/delivery.rb new file mode 100644 index 00000000..0252064d --- /dev/null +++ b/spec/factories/delivery.rb @@ -0,0 +1,9 @@ +require 'factory_bot' + +FactoryBot.define do + factory :delivery do + supplier { create :supplier } + invoice { create :invoice } + date { Faker::Date.backward(days: 14) } + end +end \ No newline at end of file diff --git a/spec/models/delivery_spec.rb b/spec/models/delivery_spec.rb new file mode 100644 index 00000000..b48449ab --- /dev/null +++ b/spec/models/delivery_spec.rb @@ -0,0 +1,23 @@ +require_relative '../spec_helper' + +describe Delivery do + let(:delivery) { create :delivery } + let(:stock_article) { create :stock_article, price: 3 } + + it 'creates new stock_changes' do + delivery.new_stock_changes = ([ + { + quantity: 1, + stock_article: stock_article + }, + { + quantity: 2, + stock_article: stock_article + } + ]) + + expect(delivery.stock_changes.last[:stock_article_id]).to be stock_article.id + expect(delivery.includes_article?(stock_article)).to be true + expect(delivery.sum(:net)).to eq 9 + end +end From 085e854361958d569fca1fcde5bd6f5d34b27723 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 6 Oct 2022 16:13:10 +0200 Subject: [PATCH 20/25] revert foo --- spec/models/order_article_spec.rb | 4 ---- spec/spec_helper.rb | 9 --------- 2 files changed, 13 deletions(-) diff --git a/spec/models/order_article_spec.rb b/spec/models/order_article_spec.rb index f8f05c7b..32b280dc 100644 --- a/spec/models/order_article_spec.rb +++ b/spec/models/order_article_spec.rb @@ -4,10 +4,6 @@ describe OrderArticle do let(:order) { create :order, article_count: 1 } let(:oa) { order.order_articles.first } - it 'foo' do - oa.update_article_and_price!() - end - it 'is not ordered by default' do expect(OrderArticle.ordered.count).to eq 0 end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index fbf281da..6cd41ded 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -68,15 +68,6 @@ if ENV['COVERAGE'] == 'lcov' SimpleCov.formatters = SimpleCov::Formatter::LcovFormatter end -if ENV['COVERAGE'] == 'html' - require 'simplecov-lcov' - SimpleCov::Formatter::LcovFormatter.config do |c| - c.report_with_single_file = true - c.single_report_path = 'coverage/lcov.html' - end - SimpleCov.formatters = SimpleCov::Formatter::HTMLFormatter -end - # include default foodsoft scope in urls, so that *_path works # https://github.com/rspec/rspec-rails/issues/255 class ActionDispatch::Routing::RouteSet From 030cc195ba96397de054b2da9f7337a7e7bee885 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Fri, 7 Oct 2022 14:04:19 +0200 Subject: [PATCH 21/25] article_controllers almostspec'd --- spec/app_config.yml | 1 + spec/controllers/articles_controller_spec.rb | 274 ++++++++++++++++++- spec/factories/order_article.rb | 8 + spec/fixtures/files/upload_test.csv | 3 + spec/fixtures/upload_test.csv | 3 + 5 files changed, 283 insertions(+), 6 deletions(-) create mode 100644 spec/factories/order_article.rb create mode 100644 spec/fixtures/files/upload_test.csv create mode 100644 spec/fixtures/upload_test.csv diff --git a/spec/app_config.yml b/spec/app_config.yml index 2e146be9..861bded3 100644 --- a/spec/app_config.yml +++ b/spec/app_config.yml @@ -7,6 +7,7 @@ default: &defaults multi_coop_install: false default_scope: 'f' + tax_default: 0 name: FC Minimal diff --git a/spec/controllers/articles_controller_spec.rb b/spec/controllers/articles_controller_spec.rb index 79d8f0ac..2fdee31a 100644 --- a/spec/controllers/articles_controller_spec.rb +++ b/spec/controllers/articles_controller_spec.rb @@ -4,16 +4,19 @@ require 'spec_helper' describe ArticlesController, type: :controller do let(:user) { create :user, :role_article_meta } + let(:article_categoryA) { create :article_category, name: "AAAA" } + let(:article_categoryB) { create :article_category, name: "BBBB" } + let(:articleA) { create :article, name: 'AAAA', note: "AAAA", unit: '250 g', article_category: article_categoryA, availability: false } + let(:articleB) { create :article, name: 'BBBB', note: "BBBB", unit: '500 g', article_category: article_categoryB, availability: true } + let(:articleC) { create :article, name: 'CCCC', note: "CCCC", unit: '500 g', article_category: article_categoryB, availability: true } + + let(:supplier) { create :supplier, articles: [articleA, articleB] } + let(:order) { create :order } + let(:order_article) { create :order_article, order: order, article: articleC } before { login user } describe 'GET index' do - let(:article_categoryA) { create :article_category, name: "AAAA" } - let(:article_categoryB) { create :article_category, name: "BBBB" } - let(:articleA) { create :article, name: 'AAAA', note: "AAAA", unit: '250 g', article_category: article_categoryA, availability: false } - let(:articleB) { create :article, name: 'BBBB', note: "BBBB", unit: '500 g', article_category: article_categoryB, availability: true } - let(:supplier) { create :supplier, articles: [articleA, articleB] } - it 'assigns sorting on articles' do sortings = [ ['name', [articleA, articleB]], @@ -33,5 +36,264 @@ describe ArticlesController, type: :controller do expect(assigns(:articles).to_a).to eq(sorting[1]) end end + + it 'triggers an article csv' do + get :index, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id }, format: :csv + expect(response.header["Content-Type"]).to include("text/csv") + expect(response.body).to include(articleA.unit, articleB.unit) + end + end + + describe "new" do + it 'renders form for a new article' do + get :new, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id }, xhr: true + expect(response).to have_http_status(:success) + end + end + + describe "copy" do + it 'renders form with copy of an article' do + get :copy, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, article_id: articleA.id }, xhr: true + expect(assigns(:article).attributes).to eq(articleA.dup.attributes) + expect(response).to have_http_status(:success) + end + end + # TODO: + + describe "#create" do + it 'creates a new article' do + valid_attributes = articleA.attributes.except("id") + valid_attributes["name"] = "ABAB" + get :create, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, article: valid_attributes }, xhr: true + expect(response).to have_http_status(:success) + end + + it 'fails to create a new article an renders #new' do + get :create, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, article: { id: nil } }, xhr: true + expect(response).to have_http_status(:success) + expect(response).to render_template('articles/new') + end + end + + describe "edit" do + it 'opens form to edit article attributes' do + get :edit, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, id: articleA.id }, xhr: true + expect(response).to have_http_status(:success) + expect(response).to render_template('articles/new') + end + end + + describe "#edit all" do + it 'renders edit_all' do + get :edit_all, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id }, xhr: true + expect(response).to have_http_status(:success) + expect(response).to render_template('articles/edit_all') + end + end + + describe "#update" do + it 'updates article attributes' do + get :update, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, id: articleA.id, article: { unit: "300 g" } }, xhr: true + expect(assigns(:article).unit).to eq("300 g") + expect(response).to have_http_status(:success) + end + + it 'updates article attributes' do + get :update, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, id: articleA.id, article: { name: nil } }, xhr: true + expect(response).to render_template('articles/new') + end + end + + describe "#update_all" do + xit 'updates all articles' do + # never used and controller method bugged + get :update_all, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, articles: [articleA, articleB] } + puts assigns(:articles).count + expect(response).to have_http_status(:success) + end + end + + describe "#update_selected" do + before do + order_article + end + + it 'updates selected articles' do + get :update_selected, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, selected_articles: [articleA.id, articleB.id] } + expect(response).to have_http_status(:redirect) + end + + it 'destroys selected articles' do + get :update_selected, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, selected_articles: [articleA.id, articleB.id], selected_action: "destroy" } + articleA.reload + articleB.reload + expect(articleA.deleted? && articleB.deleted?).to be_truthy + expect(response).to have_http_status(:redirect) + end + + it 'sets availability false on selected articles' do + get :update_selected, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, selected_articles: [articleA.id, articleB.id], selected_action: "setNotAvailable" } + articleA.reload + articleB.reload + expect(articleA.availability || articleB.availability).to be_falsey + expect(response).to have_http_status(:redirect) + end + + it 'sets availability true on selected articles' do + get :update_selected, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, selected_articles: [articleA.id, articleB.id], selected_action: "setAvailable" } + articleA.reload + articleB.reload + expect(articleA.availability && articleB.availability).to be_truthy + expect(response).to have_http_status(:redirect) + end + + it 'fails deletion if one article is in open order' do + get :update_selected, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, selected_articles: [articleA.id, articleC.id], selected_action: "destroy" } + articleA.reload + articleC.reload + expect(articleA.deleted? || articleC.deleted?).to be_falsey + expect(response).to have_http_status(:redirect) + end + end + + describe "#parse_upload" do + let(:file) { fixture_file_upload(Rails.root.join('spec/fixtures/files/upload_test.csv')) } + + before do + file + end + # TODO: Cannot use Rack attributes in controller?? + # #":String + + xit 'updates particles from spreadsheet' do + get :parse_upload, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, articles: { file: file, outlist_absent: "1", convert_units: "1" } } + # {articleA.id => articleA, articleB.id => articleB}} + expect(response).to have_http_status(:redirect) + end + end + + describe "#sync" do + # TODO: double render error in controller + xit 'updates particles from spreadsheet' do + get :sync, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id } + expect(response).to have_http_status(:redirect) + end + end + + describe "#destroy" do + before do + order_article + end + + it 'does not delete article if order open' do + get :destroy, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, id: articleC.id }, xhr: true + expect(assigns(:article).deleted?).to be_falsey + expect(response).to have_http_status(:success) + expect(response).to render_template('articles/destroy') + end + + it 'deletes article if order closed' do + get :destroy, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, id: articleB.id }, xhr: true + expect(assigns(:article).deleted?).to be_truthy + expect(response).to have_http_status(:success) + expect(response).to render_template('articles/destroy') + end + end + + describe "#update_synchronized" do + before do + order_article + articleA + articleB + articleC + end + + it 'deletes articles' do + # TODO: double render error in controller + get :update_synchronized, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, outlisted_articles: { articleA.id => articleA, articleB.id => articleB } } + articleA.reload + articleB.reload + expect(articleA.deleted? && articleB.deleted?).to be_truthy + expect(response).to have_http_status(:redirect) + end + + it 'updates articles' do + get :update_synchronized, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, articles: { articleA.id => { name: "NewNameA" }, articleB.id => { name: "NewNameB" } } } + expect(assigns(:updated_articles).first.name).to eq "NewNameA" + expect(response).to have_http_status(:redirect) + end + + it 'does not update articles if article with same name exists' do + get :update_synchronized, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, articles: { articleA.id => { unit: "2000 g" }, articleB.id => { name: "AAAA" } } } + error_array = [assigns(:updated_articles).first.errors.first, assigns(:updated_articles).last.errors.first] + expect(error_array).to include([:name, "name is already taken"]) + expect(response).to have_http_status(:success) + end + + it 'does update articles if article with same name was deleted before' do + get :update_synchronized, params: { + foodcoop: FoodsoftConfig[:default_scope], + supplier_id: supplier.id, + outlisted_articles: { articleA.id => articleA }, + articles: { + articleA.id => { name: "NewName" }, + articleB.id => { name: "AAAA" } + } + } + error_array = [assigns(:updated_articles).first.errors.first, assigns(:updated_articles).last.errors.first] + expect(error_array.any?).to be_falsey + expect(response).to have_http_status(:redirect) + end + + it 'does not delete articles in open order' do + get :update_synchronized, params: { + foodcoop: FoodsoftConfig[:default_scope], + supplier_id: supplier.id, + outlisted_articles: { articleC.id => articleC } + } + articleC.reload + expect(articleC.deleted?).to be_falsey + expect(response).to have_http_status(:success) + end + + it 'assigns updated article_pairs on error' do + get :update_synchronized, params: { + foodcoop: FoodsoftConfig[:default_scope], + supplier_id: supplier.id, + articles: { articleA.id => { name: "DDDD" } }, + outlisted_articles: { articleC.id => articleC } + } + expect(assigns(:updated_article_pairs).first).to eq([articleA, { name: "DDDD" }]) + articleC.reload + expect(articleC.deleted?).to be_falsey + expect(response).to have_http_status(:success) + end + + it 'updates articles in open order' do + get :update_synchronized, params: { + foodcoop: FoodsoftConfig[:default_scope], + supplier_id: supplier.id, + articles: { articleC.id => { name: "DDDD" } } + } + articleC.reload + expect(articleC.name).to eq "DDDD" + expect(response).to have_http_status(:redirect) + end + end + + describe "#shared" do + let(:shared_supplier) { create :shared_supplier, shared_articles: [shared_article] } + let(:shared_article) { create :shared_article, name: "shared" } + let(:articleS) { create :article, name: 'SSSS', note: "AAAA", unit: '250 g', article_category: article_categoryA, availability: false } + + let(:supplier_with_shared) { create :supplier, articles: [articleS], shared_supplier: shared_supplier } + + it 'renders view with articles' do + get :shared, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier_with_shared.id, q: { name_cont_all: "shared" } }, xhr: true + expect(assigns(:supplier).shared_supplier.shared_articles.any?).to be_truthy + expect(assigns(:articles).any?).to be_truthy + expect(response).to have_http_status(:success) + end end end diff --git a/spec/factories/order_article.rb b/spec/factories/order_article.rb new file mode 100644 index 00000000..99ca8701 --- /dev/null +++ b/spec/factories/order_article.rb @@ -0,0 +1,8 @@ +require 'factory_bot' + +FactoryBot.define do + factory :order_article do + order { create :order } + article { create :article } + end +end diff --git a/spec/fixtures/files/upload_test.csv b/spec/fixtures/files/upload_test.csv new file mode 100644 index 00000000..ac2f59b0 --- /dev/null +++ b/spec/fixtures/files/upload_test.csv @@ -0,0 +1,3 @@ +avail.;Order number;Name;Note;Manufacturer;Origin;Unit;Price (net);VAT;Deposit;Unit quantity;"";"";Category +"";;AAAA;AAAA;;;500 g;25.55;6.0;0.0;1;"";"";AAAA +"";;BBBB;BBBB;;;250 g;12.11;6.0;0.0;2;"";"";BBBB diff --git a/spec/fixtures/upload_test.csv b/spec/fixtures/upload_test.csv new file mode 100644 index 00000000..ac2f59b0 --- /dev/null +++ b/spec/fixtures/upload_test.csv @@ -0,0 +1,3 @@ +avail.;Order number;Name;Note;Manufacturer;Origin;Unit;Price (net);VAT;Deposit;Unit quantity;"";"";Category +"";;AAAA;AAAA;;;500 g;25.55;6.0;0.0;1;"";"";AAAA +"";;BBBB;BBBB;;;250 g;12.11;6.0;0.0;2;"";"";BBBB From d5b710dd9ed186e7a48f985d4205a20dccaccf5d Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Tue, 11 Oct 2022 16:09:18 +0200 Subject: [PATCH 22/25] auth concern spec'd --- .../application_controller_spec.rb | 12 ++ .../controllers/concerns/auth_concern_spec.rb | 185 ++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 spec/controllers/application_controller_spec.rb create mode 100644 spec/controllers/concerns/auth_concern_spec.rb diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb new file mode 100644 index 00000000..eb11200e --- /dev/null +++ b/spec/controllers/application_controller_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ApplicationController, type: :controller do + describe 'current' do + it 'returns current ApplicationController' do + ApplicationController.new.send(:store_controller) + expect(ApplicationController.current).to be_instance_of ApplicationController + end + end +end diff --git a/spec/controllers/concerns/auth_concern_spec.rb b/spec/controllers/concerns/auth_concern_spec.rb new file mode 100644 index 00000000..39ad7b7e --- /dev/null +++ b/spec/controllers/concerns/auth_concern_spec.rb @@ -0,0 +1,185 @@ +# frozen_string_literal: true + +require 'spec_helper' + +class DummyAuthController < ApplicationController; end + +describe 'Auth concern', type: :controller do + + controller DummyAuthController do + # Defining a dummy action for an anynomous controller which inherits from the described class. + def authenticate_blank + authenticate + end + + def authenticate_unknown_group + authenticate('nooby') + end + + def authenticate_pickups + authenticate('pickups') + head :ok unless performed? + end + + def authenticate_finance_or_orders + authenticate('finance_or_orders') + head :ok unless performed? + end + + def try_authenticate_membership_or_admin + authenticate_membership_or_admin + end + + def try_authenticate_or_token + authenticate_or_token('xyz') + head :ok unless performed? + end + end + + # unit testing protected/private methods + describe 'protected/private methods' do + let(:user) { create :user } + + describe '#current_user' do + before { login user } + + describe 'with valid session' do + it "returns current_user" do + subject.session[:user_id] = user.id + subject.params[:foodcoop] = FoodsoftConfig[:default_scope] + expect(subject.send(:current_user)).to eq user + expect(assigns(:current_user)).to eq user + end + end + + describe 'with invalid session' do + it "not returns current_user" do + subject.session[:user_id] = '' + subject.params[:foodcoop] = FoodsoftConfig[:default_scope] + expect(subject.send(:current_user)).to be_nil + expect(assigns(:current_user)).to be_nil + end + end + end + + describe '#deny_access' do + xit "redirects to root_url" do + expect(subject.send(:deny_access)).to redirect_to(root_url) + end + end + + describe '#login' do + it "sets user in session" do + subject.send(:login, user) + expect(subject.session[:user_id]).to eq user.id + expect(subject.session[:scope]).to eq FoodsoftConfig.scope + expect(subject.session[:locale]).to eq user.locale + end + end + + describe '#login_and_redirect_to_return_to' do + xit "redirects to already set target" do + subject.session[:return_to] = my_profile_url + subject.send(:login_and_redirect_to_return_to, user) + expect(subject.session[:return_to]).to be nil + end + end + end + + describe 'authenticate' do + describe 'not logged in' do + it 'does not authenticate' do + routes.draw { get "authenticate_blank" => "dummy_auth#authenticate_blank" } + get :authenticate_blank, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(login_path) + expect(flash[:alert]).to match(I18n.t('application.controller.error_authn')) + end + end + + describe 'logged in' do + let(:user) { create :user } + let(:pickups_user) { create :user, :role_pickups } + let(:finance_user) { create :user, :role_finance } + let(:orders_user) { create :user, :role_orders } + + it 'does not authenticate with unknown group' do + login user + routes.draw { get "authenticate_unknown_group" => "dummy_auth#authenticate_unknown_group" } + get :authenticate_unknown_group, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(root_path) + expect(flash[:alert]).to match(I18n.t('application.controller.error_denied', sign_in: ActionController::Base.helpers.link_to(I18n.t('application.controller.error_denied_sign_in'), login_path))) + end + + it 'does not authenticate with pickups group' do + login pickups_user + routes.draw { get "authenticate_pickups" => "dummy_auth#authenticate_pickups" } + get :authenticate_pickups, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:success) + end + + it 'does not authenticate with finance group' do + login finance_user + routes.draw { get "authenticate_finance_or_orders" => "dummy_auth#authenticate_finance_or_orders" } + get :authenticate_finance_or_orders, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:success) + end + + it 'does not authenticate with orders group' do + login orders_user + routes.draw { get "authenticate_finance_or_orders" => "dummy_auth#authenticate_finance_or_orders" } + get :authenticate_finance_or_orders, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:success) + end + end + end + + describe 'authenticate_membership_or_admin' do + describe 'logged in' do + let(:pickups_user) { create :user, :role_pickups } + let(:workgroup) { create :workgroup } + + it 'redirects with not permitted group' do + group_id = workgroup.id + login pickups_user + routes.draw { get "try_authenticate_membership_or_admin" => "dummy_auth#try_authenticate_membership_or_admin" } + get :try_authenticate_membership_or_admin, params: { foodcoop: FoodsoftConfig[:default_scope], id: group_id } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(root_path) + expect(flash[:alert]).to match(I18n.t('application.controller.error_members_only')) + end + end + end + + describe 'authenticate_or_token' do + describe 'logged in' do + let(:token_verifier) { TokenVerifier.new('xyz') } + let(:token_msg) { token_verifier.generate } + let(:user) { create :user } + + it 'authenticates token' do + login user + routes.draw { get "try_authenticate_or_token" => "dummy_auth#try_authenticate_or_token" } + get :try_authenticate_or_token, params: { foodcoop: FoodsoftConfig[:default_scope], token: token_msg } + expect(response).to_not have_http_status(:redirect) + end + + it 'redirects on faulty token' do + login user + routes.draw { get "try_authenticate_or_token" => "dummy_auth#try_authenticate_or_token" } + get :try_authenticate_or_token, params: { foodcoop: FoodsoftConfig[:default_scope], token: 'abc' } + expect(response).to have_http_status(:redirect) + expect(response).to redirect_to(root_path) + expect(flash[:alert]).to match(I18n.t('application.controller.error_token')) + end + + it 'authenticates current user on empty token' do + login user + routes.draw { get "try_authenticate_or_token" => "dummy_auth#try_authenticate_or_token" } + get :try_authenticate_or_token, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:success) + end + end + end +end \ No newline at end of file From a72495b7415fa7b3c3d8c20de29f05090aea893b Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Wed, 12 Oct 2022 14:11:11 +0200 Subject: [PATCH 23/25] more spec'd --- .../controllers/concerns/auth_concern_spec.rb | 1 - .../finance/base_controller_spec.rb | 30 ++++++++++++++ spec/factories/supplier.rb | 1 + spec/integration/admin_spec.rb | 29 ++++++++++++++ spec/integration/supplier_spec.rb | 39 +++++++++++++++++-- 5 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 spec/controllers/finance/base_controller_spec.rb create mode 100644 spec/integration/admin_spec.rb diff --git a/spec/controllers/concerns/auth_concern_spec.rb b/spec/controllers/concerns/auth_concern_spec.rb index 39ad7b7e..65d7f13e 100644 --- a/spec/controllers/concerns/auth_concern_spec.rb +++ b/spec/controllers/concerns/auth_concern_spec.rb @@ -5,7 +5,6 @@ require 'spec_helper' class DummyAuthController < ApplicationController; end describe 'Auth concern', type: :controller do - controller DummyAuthController do # Defining a dummy action for an anynomous controller which inherits from the described class. def authenticate_blank diff --git a/spec/controllers/finance/base_controller_spec.rb b/spec/controllers/finance/base_controller_spec.rb new file mode 100644 index 00000000..40c80c57 --- /dev/null +++ b/spec/controllers/finance/base_controller_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Finance::BaseController, type: :controller do + let(:user) { create :user, :role_finance, :role_orders, :ordergroup } + + before { login user } + + describe 'GET index' do + let(:fin_trans) { create_list :financial_transaction, 3, user: user, ordergroup: user.ordergroup } + let(:orders) { create_list :order, 2, state: 'finished' } + let(:invoices) { create_list :invoice, 4 } + + before do + fin_trans + orders + invoices + end + + it 'renders index page' do + get :index, params: { foodcoop: FoodsoftConfig[:default_scope] } + expect(response).to have_http_status(:success) + expect(response).to render_template('finance/index') + expect(assigns(:financial_transactions).size).to eq(fin_trans.size) + expect(assigns(:orders).size).to eq(orders.size) + expect(assigns(:unpaid_invoices).size).to eq(invoices.size) + end + end +end \ No newline at end of file diff --git a/spec/factories/supplier.rb b/spec/factories/supplier.rb index 67ba3528..5780dc46 100644 --- a/spec/factories/supplier.rb +++ b/spec/factories/supplier.rb @@ -5,6 +5,7 @@ FactoryBot.define do name { Faker::Company.name.truncate(30) } phone { Faker::PhoneNumber.phone_number } address { Faker::Address.street_address } + email { Faker::Internet.email } transient do article_count { 0 } diff --git a/spec/integration/admin_spec.rb b/spec/integration/admin_spec.rb new file mode 100644 index 00000000..c929a44a --- /dev/null +++ b/spec/integration/admin_spec.rb @@ -0,0 +1,29 @@ +require_relative '../spec_helper' + +feature Admin::BaseController do + let(:admin) { create :admin } + let(:users) { create_list :user, 2 } + let(:workgroups) { create_list :workgroup, 3 } + let(:groups) { create_list :group, 4 } + + before { login admin } + + describe 'base#index' do + before do + users + end + + it 'is accessible with workgroups existing' do + workgroups + visit admin_root_path + expect(page).to have_content(I18n.t('admin.base.index.newest_users')) + expect(page).to have_content(users.first.name) + end + + # TODO: + it 'raising error when groups existing' do + groups + expect{ visit admin_root_path }.to raise_error(ActionView::Template::Error) + end + end +end diff --git a/spec/integration/supplier_spec.rb b/spec/integration/supplier_spec.rb index ea015d06..e4a81a0a 100644 --- a/spec/integration/supplier_spec.rb +++ b/spec/integration/supplier_spec.rb @@ -2,12 +2,11 @@ require_relative '../spec_helper' feature 'supplier' do let(:supplier) { create :supplier } + let(:user) { create :user, groups: [create(:workgroup, role_suppliers: true)] } + + before { login user } describe 'create new' do - let(:user) { create :user, groups: [create(:workgroup, role_suppliers: true)] } - - before { login user } - it 'can be created' do create :supplier_category visit suppliers_path @@ -28,4 +27,36 @@ feature 'supplier' do expect(page).to have_content(supplier.name) end end + + describe 'existing', js: true do + it 'can be shown' do + supplier + visit suppliers_path + click_link supplier.name + expect(page).to have_content(supplier.address) + expect(page).to have_content(supplier.phone) + expect(page).to have_content(supplier.email) + end + + it 'can be updated' do + new_name = Faker::Company.name.truncate(30) + supplier + visit suppliers_path + click_link I18n.t('ui.edit') + fill_in I18n.t('activerecord.attributes.supplier.name'), with: new_name + click_button 'Update Supplier' + expect(supplier.reload.name).to eq new_name + end + + it 'can be destroyed' do + supplier + visit suppliers_path + expect(page).to have_content(supplier.name) + accept_confirm do + click_link I18n.t('ui.delete') + end + expect(page).not_to have_content(supplier.name) + expect(supplier.reload.deleted?).to be true + end + end end From e4a6bdb2e401c2466b75817ca976b55311415448 Mon Sep 17 00:00:00 2001 From: viehlieb Date: Thu, 13 Oct 2022 10:30:34 +0200 Subject: [PATCH 24/25] fix articles controller spec --- spec/controllers/articles_controller_spec.rb | 40 ++++++++++++++++---- spec/spec_helper.rb | 5 ++- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/spec/controllers/articles_controller_spec.rb b/spec/controllers/articles_controller_spec.rb index 2fdee31a..56529200 100644 --- a/spec/controllers/articles_controller_spec.rb +++ b/spec/controllers/articles_controller_spec.rb @@ -12,7 +12,7 @@ describe ArticlesController, type: :controller do let(:supplier) { create :supplier, articles: [articleA, articleB] } let(:order) { create :order } - let(:order_article) { create :order_article, order: order, article: articleC } + before { login user } @@ -68,7 +68,7 @@ describe ArticlesController, type: :controller do expect(response).to have_http_status(:success) end - it 'fails to create a new article an renders #new' do + it 'fails to create a new article and renders #new' do get :create, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier.id, article: { id: nil } }, xhr: true expect(response).to have_http_status(:success) expect(response).to render_template('articles/new') @@ -114,6 +114,7 @@ describe ArticlesController, type: :controller do end describe "#update_selected" do + let(:order_article) { create :order_article, order: order, article: articleC } before do order_article end @@ -157,11 +158,11 @@ describe ArticlesController, type: :controller do end describe "#parse_upload" do - let(:file) { fixture_file_upload(Rails.root.join('spec/fixtures/files/upload_test.csv')) } + # let(:file) { fixture_file_upload(Rails.root.join('spec/fixtures/files/upload_test.csv')) } - before do - file - end + # before do + # file + # end # TODO: Cannot use Rack attributes in controller?? # #":String @@ -182,6 +183,7 @@ describe ArticlesController, type: :controller do end describe "#destroy" do + let(:order_article) { create :order_article, order: order, article: articleC } before do order_article end @@ -202,6 +204,7 @@ describe ArticlesController, type: :controller do end describe "#update_synchronized" do + let(:order_article) { create :order_article, order: order, article: articleC } before do order_article articleA @@ -290,10 +293,33 @@ describe ArticlesController, type: :controller do let(:supplier_with_shared) { create :supplier, articles: [articleS], shared_supplier: shared_supplier } it 'renders view with articles' do - get :shared, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier_with_shared.id, q: { name_cont_all: "shared" } }, xhr: true + get :shared, params: { foodcoop: FoodsoftConfig[:default_scope], supplier_id: supplier_with_shared.id, name_cont_all_joined: "shared" }, xhr: true expect(assigns(:supplier).shared_supplier.shared_articles.any?).to be_truthy expect(assigns(:articles).any?).to be_truthy expect(response).to have_http_status(:success) end end + + describe "#import" do + let(:shared_supplier) { create :shared_supplier, shared_articles: [shared_article] } + let(:shared_article) { create :shared_article, name: "shared" } + + before do + shared_article + article_categoryA + end + + it 'fills form with article details' do + get :import, params: { foodcoop: FoodsoftConfig[:default_scope], article_category_id: article_categoryB.id, direct: "true", supplier_id: supplier.id, shared_article_id: shared_article.id }, xhr: true + expect(assigns(:article).nil?).to be_falsey + expect(response).to have_http_status(:success) + expect(response).to render_template(:create) + end + it 'does redirect to :new if param :direct not set' do + get :import, params: { foodcoop: FoodsoftConfig[:default_scope], article_category_id: article_categoryB.id, supplier_id: supplier.id, shared_article_id: shared_article.id }, xhr: true + expect(assigns(:article).nil?).to be_falsey + expect(response).to have_http_status(:success) + expect(response).to render_template(:new) + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6cd41ded..666ab06f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -21,6 +21,10 @@ Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } RSpec.configure do |config| # We use capybara with webkit, and need database_cleaner + # config.before(:suite) do + # DatabaseCleaner.clean_with(:truncation) + # end + config.before(:each) do DatabaseCleaner.strategy = (RSpec.current_example.metadata[:js] ? :truncation : :transaction) DatabaseCleaner.start @@ -53,7 +57,6 @@ RSpec.configure do |config| config.include SpecTestHelper, type: :controller config.include SessionHelper, type: :feature - # Automatically determine spec from directory structure, see: # https://www.relishapp.com/rspec/rspec-rails/v/3-0/docs/directory-structure config.infer_spec_type_from_file_location! From 9f44b8015d403fd21d8d3a825eb1d582eda12644 Mon Sep 17 00:00:00 2001 From: Tobias Kneuker Date: Thu, 13 Oct 2022 11:46:19 +0200 Subject: [PATCH 25/25] fixxing flaky timestamp --- spec/controllers/home_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb index 54a97e28..5fd086fb 100644 --- a/spec/controllers/home_controller_spec.rb +++ b/spec/controllers/home_controller_spec.rb @@ -132,7 +132,7 @@ describe HomeController, type: :controller do describe 'assigns sortings' do let(:fin_trans1) { create :financial_transaction, user: og_user, ordergroup: og_user.ordergroup, note: 'A', amount: 100 } - let(:fin_trans2) { create :financial_transaction, user: og_user, ordergroup: og_user.ordergroup, note: 'B', amount: 200 } + let(:fin_trans2) { create :financial_transaction, user: og_user, ordergroup: og_user.ordergroup, note: 'B', amount: 200, created_on: Time.now + 1.minute } before do fin_trans1