Merge branch '8_increase_test_coverage' into rails_upgrade_tryout
This commit is contained in:
commit
85270e70cf
28 changed files with 1327 additions and 10 deletions
42
.drone.yml
Normal file
42
.drone.yml
Normal file
|
@ -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: {}
|
1
Gemfile
1
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
|
||||
|
|
|
@ -360,6 +360,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)
|
||||
|
@ -614,6 +618,7 @@ DEPENDENCIES
|
|||
rack-cors
|
||||
rails (~> 6.1)
|
||||
rails-assets-listjs (= 0.2.0.beta.4)
|
||||
rails-controller-testing
|
||||
rails-i18n
|
||||
rails-settings-cached (= 0.4.3)
|
||||
rails_tokeninput
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
default: &defaults
|
||||
multi_coop_install: false
|
||||
default_scope: 'f'
|
||||
tax_default: 0
|
||||
|
||||
name: FC Minimal
|
||||
|
||||
|
|
12
spec/controllers/application_controller_spec.rb
Normal file
12
spec/controllers/application_controller_spec.rb
Normal file
|
@ -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
|
325
spec/controllers/articles_controller_spec.rb
Normal file
325
spec/controllers/articles_controller_spec.rb
Normal file
|
@ -0,0 +1,325 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
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 }
|
||||
|
||||
|
||||
before { login user }
|
||||
|
||||
describe 'GET index' do
|
||||
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
|
||||
|
||||
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 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')
|
||||
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
|
||||
let(:order_article) { create :order_article, order: order, article: articleC }
|
||||
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??
|
||||
# #<NoMethodError: undefined method `original_filename' for
|
||||
# "#<Rack::Test::UploadedFile:0x00005575cef1d238>":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
|
||||
let(:order_article) { create :order_article, order: order, article: articleC }
|
||||
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
|
||||
let(:order_article) { create :order_article, order: order, article: articleC }
|
||||
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, 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
|
184
spec/controllers/concerns/auth_concern_spec.rb
Normal file
184
spec/controllers/concerns/auth_concern_spec.rb
Normal file
|
@ -0,0 +1,184 @@
|
|||
# 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
|
212
spec/controllers/finance/balancing_controller_spec.rb
Normal file
212
spec/controllers/finance/balancing_controller_spec.rb
Normal file
|
@ -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
|
30
spec/controllers/finance/base_controller_spec.rb
Normal file
30
spec/controllers/finance/base_controller_spec.rb
Normal file
|
@ -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
|
189
spec/controllers/home_controller_spec.rb
Normal file
189
spec/controllers/home_controller_spec.rb
Normal file
|
@ -0,0 +1,189 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe HomeController, type: :controller do
|
||||
let(:user) { create :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
|
||||
|
||||
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, created_on: Time.now + 1.minute }
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
67
spec/controllers/login_controller_spec.rb
Normal file
67
spec/controllers/login_controller_spec.rb
Normal file
|
@ -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
|
9
spec/factories/delivery.rb
Normal file
9
spec/factories/delivery.rb
Normal file
|
@ -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
|
15
spec/factories/invite.rb
Normal file
15
spec/factories/invite.rb
Normal file
|
@ -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
|
8
spec/factories/order_article.rb
Normal file
8
spec/factories/order_article.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
require 'factory_bot'
|
||||
|
||||
FactoryBot.define do
|
||||
factory :order_article do
|
||||
order { create :order }
|
||||
article { create :article }
|
||||
end
|
||||
end
|
|
@ -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 }
|
||||
|
|
3
spec/fixtures/files/upload_test.csv
vendored
Normal file
3
spec/fixtures/files/upload_test.csv
vendored
Normal file
|
@ -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
|
|
3
spec/fixtures/upload_test.csv
vendored
Normal file
3
spec/fixtures/upload_test.csv
vendored
Normal file
|
@ -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
|
|
29
spec/integration/admin_spec.rb
Normal file
29
spec/integration/admin_spec.rb
Normal file
|
@ -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
|
23
spec/integration/home_spec.rb
Normal file
23
spec/integration/home_spec.rb
Normal file
|
@ -0,0 +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 }
|
||||
|
||||
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
|
|
@ -2,12 +2,11 @@ require_relative '../spec_helper'
|
|||
|
||||
feature 'supplier' do
|
||||
let(:supplier) { create :supplier }
|
||||
|
||||
describe 'create new' do
|
||||
let(:user) { create :user, groups: [create(:workgroup, role_suppliers: true)] }
|
||||
|
||||
before { login user }
|
||||
|
||||
describe 'create new' do
|
||||
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
|
||||
|
|
|
@ -9,6 +9,38 @@ 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
|
||||
|
||||
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 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
|
||||
|
|
23
spec/models/delivery_spec.rb
Normal file
23
spec/models/delivery_spec.rb
Normal file
|
@ -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
|
|
@ -40,13 +40,22 @@ 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
|
||||
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 +64,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
|
||||
|
|
|
@ -3,6 +3,35 @@ 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
|
||||
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.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
|
||||
|
|
|
@ -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
|
||||
|
@ -51,8 +55,8 @@ 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:
|
||||
# https://www.relishapp.com/rspec/rspec-rails/v/3-0/docs/directory-structure
|
||||
config.infer_spec_type_from_file_location!
|
||||
|
|
25
spec/support/spec_test_helper.rb
Normal file
25
spec/support/spec_test_helper.rb
Normal file
|
@ -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
|
Loading…
Reference in a new issue