Merge branch 'tests-rspec' into master-spec

This commit is contained in:
wvengen 2013-09-10 11:37:05 +02:00
commit e20898c5ee
28 changed files with 786 additions and 13 deletions

14
.travis.yml Normal file
View file

@ -0,0 +1,14 @@
language: ruby
rvm:
- 1.9.3
services:
- redis-server
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
before_script:
- "bundle exec rake foodsoft:setup:stock_config"
- "mysql -e 'create database foodsoft_test;'"
- 'printf "test:\n adapter: mysql2\n database: foodsoft_test\n username: travis\n encoding: utf8\n" >config/database.yml'
- 'bundle exec rake db:schema:load RAILS_ENV=test'
script: bundle exec rake spec

24
Gemfile
View file

@ -54,10 +54,6 @@ group :development do
gem 'binding_of_caller' gem 'binding_of_caller'
# gem "rails-i18n-debug" # gem "rails-i18n-debug"
# Re-enable rails benchmarker/profiler
gem 'ruby-prof'
gem 'test-unit'
# Get infos when not using proper eager loading # Get infos when not using proper eager loading
gem 'bullet' gem 'bullet'
@ -71,3 +67,23 @@ group :development do
# Avoid having content-length warnings # Avoid having content-length warnings
gem 'thin' gem 'thin'
end end
group :development, :test do
gem 'ruby-prof'
end
group :test do
gem 'rspec-rails'
gem 'factory_girl_rails', '~> 4.0'
gem 'faker'
# version requirements to avoid problem http://stackoverflow.com/questions/18114544
gem 'capybara', '~> 2.1.0'
# webkit and poltergeist don't seem to work yet
gem 'selenium-webdriver', '~> 2.35.1'
gem 'database_cleaner'
gem 'simplecov', require: false
# need to include rspec components before i18n-spec or rake fails in test environment
gem 'rspec-core'
gem 'rspec-expectations'
gem 'i18n-spec'
end

View file

@ -62,6 +62,14 @@ GEM
net-ssh-gateway (>= 1.1.0) net-ssh-gateway (>= 1.1.0)
capistrano-ext (1.2.1) capistrano-ext (1.2.1)
capistrano (>= 1.0.0) capistrano (>= 1.0.0)
capybara (2.1.0)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
childprocess (0.3.9)
ffi (~> 1.0, >= 1.0.11)
chronic (0.9.0) chronic (0.9.0)
client_side_validations (3.1.4) client_side_validations (3.1.4)
coderay (1.0.8) coderay (1.0.8)
@ -74,6 +82,8 @@ GEM
coffee-script-source (1.3.3) coffee-script-source (1.3.3)
commonjs (0.2.6) commonjs (0.2.6)
daemons (1.1.9) daemons (1.1.9)
database_cleaner (0.7.1)
diff-lcs (1.2.4)
erubis (2.7.0) erubis (2.7.0)
eventmachine (1.0.3) eventmachine (1.0.3)
exception_notification (2.6.1) exception_notification (2.6.1)
@ -81,6 +91,14 @@ GEM
execjs (1.4.0) execjs (1.4.0)
multi_json (~> 1.0) multi_json (~> 1.0)
expression_parser (0.9.0) expression_parser (0.9.0)
factory_girl (4.2.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.2.1)
factory_girl (~> 4.2.0)
railties (>= 3.0.0)
faker (1.1.2)
i18n (~> 0.5)
ffi (1.9.0)
haml (3.1.7) haml (3.1.7)
haml-rails (0.3.5) haml-rails (0.3.5)
actionpack (>= 3.1, < 4.1) actionpack (>= 3.1, < 4.1)
@ -92,9 +110,13 @@ GEM
highline (1.6.19) highline (1.6.19)
hike (1.2.3) hike (1.2.3)
i18n (0.6.1) i18n (0.6.1)
i18n-spec (0.4.0)
iso
inherited_resources (1.3.1) inherited_resources (1.3.1)
has_scope (~> 0.5.0) has_scope (~> 0.5.0)
responders (~> 0.6) responders (~> 0.6)
iso (0.2.0)
i18n
journey (1.0.4) journey (1.0.4)
jquery-rails (2.1.3) jquery-rails (2.1.3)
railties (>= 3.1.0, < 5.0) railties (>= 3.1.0, < 5.0)
@ -128,8 +150,9 @@ GEM
activesupport (~> 3.1) activesupport (~> 3.1)
polyamorous (~> 0.5.0) polyamorous (~> 0.5.0)
mime-types (1.21) mime-types (1.21)
mini_portile (0.5.1)
mono_logger (1.1.0) mono_logger (1.1.0)
multi_json (1.7.6) multi_json (1.7.9)
mysql2 (0.3.11) mysql2 (0.3.11)
net-scp (1.1.1) net-scp (1.1.1)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
@ -138,6 +161,8 @@ GEM
net-ssh (2.6.7) net-ssh (2.6.7)
net-ssh-gateway (1.2.0) net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5) net-ssh (>= 2.6.5)
nokogiri (1.6.0)
mini_portile (~> 0.5.0)
pdf-reader (1.2.0) pdf-reader (1.2.0)
Ascii85 (~> 1.0.0) Ascii85 (~> 1.0.0)
hashery (~> 2.0) hashery (~> 2.0)
@ -190,8 +215,20 @@ GEM
redis-namespace (~> 1.2) redis-namespace (~> 1.2)
sinatra (>= 0.9.2) sinatra (>= 0.9.2)
vegas (~> 0.1.2) vegas (~> 0.1.2)
ruby-prof (0.11.2) rspec-core (2.14.2)
rspec-expectations (2.14.0)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.1)
rspec-rails (2.14.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
ruby-prof (0.13.0)
ruby-rc4 (0.1.5) ruby-rc4 (0.1.5)
rubyzip (0.9.9)
sass (3.2.1) sass (3.2.1)
sass-rails (3.2.5) sass-rails (3.2.5)
railties (~> 3.2.0) railties (~> 3.2.0)
@ -200,6 +237,11 @@ GEM
select2-rails (3.4.2) select2-rails (3.4.2)
sass-rails sass-rails
thor (~> 0.14) thor (~> 0.14)
selenium-webdriver (2.35.1)
childprocess (>= 0.2.5)
multi_json (~> 1.0)
rubyzip (< 1.0.0)
websocket (~> 1.0.4)
simple-navigation (3.9.0) simple-navigation (3.9.0)
activesupport (>= 2.3.2) activesupport (>= 2.3.2)
simple-navigation-bootstrap (0.0.4) simple-navigation-bootstrap (0.0.4)
@ -207,6 +249,10 @@ GEM
simple_form (2.1.0) simple_form (2.1.0)
actionpack (~> 3.0) actionpack (~> 3.0)
activemodel (~> 3.0) activemodel (~> 3.0)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
simplecov-html (0.7.1)
sinatra (1.3.6) sinatra (1.3.6)
rack (~> 1.4) rack (~> 1.4)
rack-protection (~> 1.3) rack-protection (~> 1.3)
@ -220,7 +266,6 @@ GEM
rack (~> 1.0) rack (~> 1.0)
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.6) sqlite3 (1.3.6)
test-unit (2.5.3)
therubyracer (0.10.2) therubyracer (0.10.2)
libv8 (~> 3.3.10) libv8 (~> 3.3.10)
thin (1.5.1) thin (1.5.1)
@ -245,12 +290,15 @@ GEM
uniform_notifier (1.1.1) uniform_notifier (1.1.1)
vegas (0.1.11) vegas (0.1.11)
rack (>= 1.0.0) rack (>= 1.0.0)
websocket (1.0.7)
whenever (0.8.1) whenever (0.8.1)
activesupport (>= 2.3.4) activesupport (>= 2.3.4)
chronic (>= 0.6.3) chronic (>= 0.6.3)
wikicloth (0.8.0) wikicloth (0.8.0)
builder builder
expression_parser expression_parser
xpath (2.0.0)
nokogiri (~> 1.3)
PLATFORMS PLATFORMS
ruby ruby
@ -264,11 +312,16 @@ DEPENDENCIES
bullet bullet
capistrano (= 2.13.5) capistrano (= 2.13.5)
capistrano-ext capistrano-ext
capybara (~> 2.1.0)
client_side_validations client_side_validations
coffee-rails (~> 3.2.1) coffee-rails (~> 3.2.1)
daemons daemons
database_cleaner
exception_notification exception_notification
factory_girl_rails (~> 4.0)
faker
haml-rails haml-rails
i18n-spec
inherited_resources inherited_resources
jquery-rails jquery-rails
kaminari kaminari
@ -281,14 +334,18 @@ DEPENDENCIES
rails (~> 3.2.9) rails (~> 3.2.9)
rails-settings-cached (= 0.2.4) rails-settings-cached (= 0.2.4)
resque resque
rspec-core
rspec-expectations
rspec-rails
ruby-prof ruby-prof
sass-rails (~> 3.2.3) sass-rails (~> 3.2.3)
select2-rails select2-rails
selenium-webdriver (~> 2.35.1)
simple-navigation simple-navigation
simple-navigation-bootstrap simple-navigation-bootstrap
simple_form simple_form
simplecov
sqlite3 sqlite3
test-unit
therubyracer therubyracer
thin thin
twitter-bootstrap-rails twitter-bootstrap-rails

View file

@ -1,5 +1,6 @@
FoodSoft FoodSoft
========= =========
[![Build Status](https://travis-ci.org/foodcoops/foodsoft.png?branch=tests-rspec)](https://travis-ci.org/foodcoops/foodsoft)
[![Code Climate](https://codeclimate.com/github/foodcoops/foodsoft.png)](https://codeclimate.com/github/foodcoops/foodsoft) [![Code Climate](https://codeclimate.com/github/foodcoops/foodsoft.png)](https://codeclimate.com/github/foodcoops/foodsoft)
[![Dependency Status](https://gemnasium.com/foodcoops/foodsoft.png)](https://gemnasium.com/foodcoops/foodsoft) [![Dependency Status](https://gemnasium.com/foodcoops/foodsoft.png)](https://gemnasium.com/foodcoops/foodsoft)

View file

@ -13,11 +13,9 @@ class Supplier < ActiveRecord::Base
:delivery_days, :order_howto, :note, :shared_supplier_id, :min_order_quantity :delivery_days, :order_howto, :note, :shared_supplier_id, :min_order_quantity
validates :name, :presence => true, :length => { :in => 4..30 } validates :name, :presence => true, :length => { :in => 4..30 }
validates :phone, :presence => true, :length => { :in => 8..20 } validates :phone, :presence => true, :length => { :in => 8..25 }
validates :address, :presence => true, :length => { :in => 8..50 } validates :address, :presence => true, :length => { :in => 8..50 }
validates_length_of :order_howto, :note, maximum: 250 validates_length_of :order_howto, :note, maximum: 250
validates_length_of :phone, :in => 8..20
validates_length_of :address, :in => 8..50
validate :uniqueness_of_name validate :uniqueness_of_name
scope :undeleted, -> { where(deleted_at: nil) } scope :undeleted, -> { where(deleted_at: nil) }

View file

@ -12,7 +12,7 @@
.well.well-small .well.well-small
%h3= t('.notes_and_journal') %h3= t('.notes_and_journal')
#note #note
- unless @order.note.empty? - unless @order.note.blank?
= simple_format @order.note = simple_format @order.note
- else - else
%p= t('.comment_on_transaction') %p= t('.comment_on_transaction')

View file

@ -38,6 +38,15 @@ namespace :foodsoft do
puts yellow "All done! Your foodcoft should be running smoothly." puts yellow "All done! Your foodcoft should be running smoothly."
start_server start_server
end end
namespace :setup do
desc "Initialize stock configuration"
task :stock_config do
setup_app_config
setup_development
setup_secret_token
end
end
end end
def setup_bundler def setup_bundler

3
lib/tasks/rspec.rake Normal file
View file

@ -0,0 +1,3 @@
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
task :default => :spec

20
spec/factories/article.rb Normal file
View file

@ -0,0 +1,20 @@
require 'factory_girl'
FactoryGirl.define do
factory :article do
sequence(:name) { |n| Faker::Lorem.words(rand(2..4)).join(' ') + " ##{n}" }
unit { Faker::Unit.unit }
price { rand(2600) / 100 }
tax { [6, 21].sample }
deposit { rand(10) < 8 ? 0 : [0.0, 0.80, 1.20, 12.00].sample }
unit_quantity { rand(5) < 3 ? 1 : rand(1..20) }
#supplier_id
article_category { FactoryGirl.create :article_category }
end
factory :article_category do
sequence(:name) { |n| Faker::Lorem.characters(rand(2..12)) + " ##{n}" }
end
end

View file

@ -0,0 +1,10 @@
require 'factory_girl'
FactoryGirl.define do
# requires order
factory :group_order do
ordergroup { FactoryGirl.create(:user, groups: [FactoryGirl.create(:ordergroup)]).ordergroup }
end
end

View file

@ -0,0 +1,9 @@
require 'factory_girl'
FactoryGirl.define do
# requires order_article
factory :group_order_article do
end
end

31
spec/factories/order.rb Normal file
View file

@ -0,0 +1,31 @@
require 'factory_girl'
FactoryGirl.define do
factory :order do
starts { Time.now }
supplier { FactoryGirl.create :supplier, article_count: (article_count.nil? ? true : article_count) }
article_ids { supplier.articles.map(&:id) unless supplier.nil? }
ignore do
article_count true
end
# for an order from stock; need to add articles
factory :stock_order do
supplier_id 0
# article_ids needs to be supplied
end
# In the order's after_save callback order articles are created, so
# until the order is saved, these articles do not yet exist.
after :create do |order|
order.reload
end
end
# requires order and article
factory :order_article do
end
end

View file

@ -0,0 +1,21 @@
require 'factory_girl'
FactoryGirl.define do
factory :supplier do
name { Faker::Company.name.truncate(30) }
phone { Faker::PhoneNumber.phone_number }
address { Faker::Address.street_address }
ignore do
article_count 0
end
after :create do |supplier, evaluator|
article_count = evaluator.article_count
article_count = rand(1..99) if article_count == true
FactoryGirl.create_list :article, article_count, supplier: supplier
end
end
end

36
spec/factories/user.rb Normal file
View file

@ -0,0 +1,36 @@
require 'factory_girl'
FactoryGirl.define do
factory :user do
sequence(:nick) { |n| "user#{n}"}
first_name { Faker::Name.first_name }
email { Faker::Internet.email }
password { new_random_password }
factory :admin do
sequence(:nick) { |n| "admin#{n}" }
first_name 'Administrator'
after :create do |user, evaluator|
FactoryGirl.create :workgroup, role_admin: true, user_ids: [user.id]
end
end
end
factory :group do
sequence(:name) {|n| "Group ##{n}"}
factory :workgroup do
type ''
end
factory :ordergroup do
type 'Ordergroup'
sequence(:name) {|n| "Order group ##{n}"}
# workaround to avoid needing to save the ordergroup
# avoids e.g. error after logging in related to applebar
after :create do |group| Ordergroup.find(group.id).update_stats! end
end
end
end

12
spec/i18n_spec.rb Normal file
View file

@ -0,0 +1,12 @@
require 'spec_helper'
require 'i18n-spec'
Dir.glob('config/locales/*.yml').each do |locale_file|
describe "#{locale_file}" do
it_behaves_like 'a valid locale file', locale_file
# We're currently allowing both German and English as source language
# besides, we're using localeapp, so that it's ok if pull requests
# don't have this - a localapp pull will fix that right away.
#it { expect(locale_file).to be_a_subset_of 'config/locales/en.yml' }
end
end

View file

@ -0,0 +1,55 @@
require 'spec_helper'
describe 'settling an order', :type => :feature do
let(:admin) { FactoryGirl.create :user, groups:[FactoryGirl.create(:workgroup, role_finance: true)] }
let(:supplier) { FactoryGirl.create :supplier }
let(:article) { FactoryGirl.create :article, supplier: supplier, unit_quantity: 1 }
let(:order) { FactoryGirl.create :order, supplier: supplier, article_ids: [article.id] } # need to ref article
let(:go1) { FactoryGirl.create :group_order, order: order }
let(:go2) { FactoryGirl.create :group_order, order: order }
let(:oa) { order.order_articles.find_by_article_id(article.id) }
let(:goa1) { FactoryGirl.create :group_order_article, group_order: go1, order_article: oa }
let(:goa2) { FactoryGirl.create :group_order_article, group_order: go2, order_article: oa }
before do
goa1.update_quantities(3, 0)
goa2.update_quantities(1, 0)
oa.update_results!
order.finish!(admin)
goa1.reload
goa2.reload
end
it 'has correct order result' do
expect(oa.quantity).to eq(4)
expect(oa.tolerance).to eq(0)
expect(goa1.result).to eq(3)
expect(goa2.result).to eq(1)
end
describe :type => :feature, :js => true do
before { login admin }
before { visit new_finance_order_path(order_id: order.id) }
it 'has product ordered visible' do
expect(page).to have_content(article.name)
expect(page).to have_selector("#order_article_#{oa.id}")
end
it 'shows order result' do
click_link article.name
expect(page).to have_selector("#group_order_articles_#{oa.id}")
within("#group_order_articles_#{oa.id}") do
# make sure these ordergroup names are in the list for this product
expect(page).to have_content(go1.ordergroup.name)
expect(page).to have_content(go2.ordergroup.name)
# and that their order results match what we expect
expect(page).to have_selector("#group_order_article_#{goa1.id}_quantity")
expect(find("#group_order_article_#{goa1.id}_quantity").text.to_f).to eq(3)
expect(page).to have_selector("#group_order_article_#{goa2.id}_quantity")
expect(find("#group_order_article_#{goa2.id}_quantity").text.to_f).to eq(1)
end
end
end
end

View file

@ -0,0 +1,57 @@
require 'spec_helper'
describe 'product distribution', :type => :feature do
let(:admin) { FactoryGirl.create :admin }
let(:user_a) { FactoryGirl.create :user, groups: [FactoryGirl.create(:ordergroup)] }
let(:user_b) { FactoryGirl.create :user, groups: [FactoryGirl.create(:ordergroup)] }
let(:supplier) { FactoryGirl.create :supplier }
let(:article) { FactoryGirl.create :article, supplier: supplier, unit_quantity: 5 }
let(:order) { FactoryGirl.create(:order, supplier: supplier, article_ids: [article.id]) }
let(:oa) { order.order_articles.first }
describe :type => :feature do
# make sure users have enough money to order
before do
[user_a, user_b].each do |user|
ordergroup = Ordergroup.find(user.ordergroup.id)
ordergroup.add_financial_transaction! 5000, 'for ordering', admin
end
end
it 'agrees to documented example', :js => true do
# gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will
login user_a
visit new_group_order_path(:order_id => order.id)
2.times { find("[data-increase_quantity='#{oa.id}']").click }
3.times { find("[data-increase_tolerance='#{oa.id}']").click }
find('input[type=submit]').click
expect(page).to have_selector('body')
# gruppe b bestellt 2(0)
login user_b
visit new_group_order_path(:order_id => order.id)
2.times { find("[data-increase_quantity='#{oa.id}']").click }
find('input[type=submit]').click
expect(page).to have_selector('body')
# gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1).
login user_a
visit edit_group_order_path(order.group_order(user_a.ordergroup), :order_id => order.id)
2.times { find("[data-increase_quantity='#{oa.id}']").click }
2.times { find("[data-decrease_tolerance='#{oa.id}']").click }
find('input[type=submit]').click
expect(page).to have_selector('body')
# die zuteilung
order.finish!(admin)
oa.reload
# Endstand: insg. Bestellt wurden 6(1)
expect(oa.quantity).to eq(6)
expect(oa.tolerance).to eq(1)
# Gruppe a bekommt 3 einheiten.
goa_a = oa.group_order_articles.joins(:group_order).where(:group_orders => {:ordergroup_id => user_a.ordergroup.id}).first
expect(goa_a.result).to eq(3)
# gruppe b bekommt 2 einheiten.
goa_b = oa.group_order_articles.joins(:group_order).where(:group_orders => {:ordergroup_id => user_b.ordergroup.id}).first
expect(goa_b.result).to eq(2)
end
end
end

View file

@ -0,0 +1,21 @@
require 'spec_helper'
describe 'the session', :type => :feature do
let(:user) { FactoryGirl.create :user }
describe 'login page', :type => :feature do
it 'is accesible' do
get login_path
expect(response).to be_success
end
it 'logs me in' do
login user
expect(page).to_not have_selector('.alert-error')
end
it 'does not log me in with wrong password' do
login user.nick, 'XX'+user.password
expect(page).to have_selector('.alert-error')
end
end
end

View file

@ -0,0 +1,63 @@
require 'spec_helper'
describe 'supplier', :type => :feature do
let(:supplier) { FactoryGirl.create :supplier }
describe :type => :feature, :js => true do
let(:user) { FactoryGirl.create :user, groups:[FactoryGirl.create(:workgroup, role_suppliers: true)] }
before { login user }
it 'can be created' do
visit suppliers_path
click_on I18n.t('suppliers.index.action_new')
supplier = FactoryGirl.build :supplier
within('#new_supplier') do
fill_in 'supplier_name', :with => supplier.name
fill_in 'supplier_address', :with => supplier.address
fill_in 'supplier_phone', :with => supplier.phone
find('input[type="submit"]').click
end
expect(page).to have_content(supplier.name)
end
it 'is included in supplier list' do
supplier
visit suppliers_path
expect(page).to have_content(supplier.name)
end
end
describe :type => :feature, :js => true do
let(:article_category) { FactoryGirl.create :article_category }
let(:user) { FactoryGirl.create :user, groups:[FactoryGirl.create(:workgroup, role_article_meta: true)] }
before { login user }
it 'can visit supplier articles path' do
visit supplier_articles_path(supplier)
expect(page).to have_content(supplier.name)
expect(page).to have_content(I18n.t('articles.index.edit_all'))
end
it 'can create a new article' do
article_category.save!
visit supplier_articles_path(supplier)
click_on I18n.t('articles.index.new')
expect(page).to have_selector('form#new_article')
article = FactoryGirl.build :article, supplier: supplier, article_category: article_category
within('#new_article') do
fill_in 'article_name', :with => article.name
fill_in 'article_unit', :with => article.unit
select article.article_category.name, :from => 'article_article_category_id'
fill_in 'article_price', :with => article.price
fill_in 'article_unit_quantity', :with => article.unit_quantity
fill_in 'article_tax', :with => article.tax
fill_in 'article_deposit', :with => article.deposit
# "Element cannot be scrolled into view" error, js as workaround
#find('input[type="submit"]').click
page.execute_script('$("form#new_article").submit();')
end
expect(page).to have_content(article.name)
end
end
end

View file

@ -0,0 +1,47 @@
require 'spec_helper'
describe Article do
let(:supplier) { FactoryGirl.create :supplier }
let(:article) { FactoryGirl.create :article, supplier: supplier }
it 'has a unique name' do
article2 = FactoryGirl.build :article, supplier: supplier, name: article.name
expect(article2).to be_invalid
end
it 'computes the gross price correctly' do
article.deposit = 0
article.tax = 12
expect(article.gross_price).to eq((article.price * 1.12).round(2))
article.deposit = 1.20
expect(article.gross_price).to eq(((article.price + 1.20) * 1.12).round(2))
end
it 'gross price >= net price' do
expect(article.gross_price).to be >= article.price
end
it 'fc-price >= gross price' do
if article.gross_price > 0
expect(article.fc_price).to be > article.gross_price
else
expect(article.fc_price).to be >= article.gross_price
end
end
it 'knows when it is deleted' do
expect(supplier.deleted?).to be_false
supplier.mark_as_deleted
expect(supplier.deleted?).to be_true
end
it 'keeps a price history' do
expect(article.article_prices.all.map(&:price)).to eq([article.price])
oldprice = article.price
sleep 1 # so that the new price really has a later creation time
article.price += 1
article.save!
expect(article.article_prices.all.map(&:price)).to eq([article.price, oldprice])
end
end

View file

@ -0,0 +1,48 @@
require 'spec_helper'
describe GroupOrderArticle do
let(:user) { FactoryGirl.create :user, groups: [FactoryGirl.create(:ordergroup)] }
let(:order) { FactoryGirl.create(:order).reload }
let(:go) { FactoryGirl.create :group_order, order: order, ordergroup: user.ordergroup }
let(:goa) { FactoryGirl.create :group_order_article, group_order: go, order_article: order.order_articles.first }
it 'has zero quantity by default' do expect(goa.quantity).to eq(0) end
it 'has zero tolerance by default' do expect(goa.tolerance).to eq(0) end
it 'has zero result by default' do expect(goa.result).to eq(0) end
it 'is not ordered by default' do expect(GroupOrderArticle.ordered.where(:id => goa.id).exists?).to be_false end
it 'has zero total price by default' do expect(goa.total_price).to eq(0) end
describe do
let(:article) { FactoryGirl.create :article, supplier: order.supplier, unit_quantity: 1 }
let(:oa) { order.order_articles.create(:article => article) }
let(:goa) { FactoryGirl.create :group_order_article, group_order: go, order_article: oa }
it 'can be ordered by piece' do
goa.update_quantities(1, 0)
expect(goa.quantity).to eq(1)
expect(goa.tolerance).to eq(0)
end
it 'can be ordered in larger amounts' do
quantity, tolerance = rand(13..99), rand(0..99)
goa.update_quantities(quantity, tolerance)
expect(goa.quantity).to eq(quantity)
expect(goa.tolerance).to eq(tolerance)
end
it 'has a proper total price' do
quantity = rand(1..99)
goa.update_quantities(quantity, 0)
expect(goa.total_price).to eq(quantity * goa.order_article.price.fc_price)
end
it 'can unorder a product' do
goa.update_quantities(rand(1..99), rand(0..99))
goa.update_quantities(0, 0)
expect(goa.quantity).to eq(0)
expect(goa.tolerance).to eq(0)
end
end
end

View file

@ -0,0 +1,25 @@
require 'spec_helper'
describe GroupOrder do
let(:user) { FactoryGirl.create :user, groups: [FactoryGirl.create(:ordergroup)] }
let(:order) { FactoryGirl.create :order }
# the following two tests are currently disabled - https://github.com/foodcoops/foodsoft/issues/158
#it 'needs an order' do
# expect(FactoryGirl.build(:group_order, ordergroup: user.ordergroup)).to be_invalid
#end
#it 'needs an ordergroup' do
# expect(FactoryGirl.build(:group_order, order: order)).to be_invalid
#end
describe do
let(:go) { FactoryGirl.create :group_order, order: order, ordergroup: user.ordergroup }
it 'has zero price initially' do
expect(go.price).to eq(0)
end
end
end

47
spec/models/order_spec.rb Normal file
View file

@ -0,0 +1,47 @@
require 'spec_helper'
describe Order do
it 'needs a supplier' do
expect(FactoryGirl.build(:order, supplier: nil)).to be_invalid
end
it 'needs order articles' do
supplier = FactoryGirl.create :supplier, article_count: 0
expect(FactoryGirl.build(:order, supplier: supplier)).to be_invalid
end
it 'can be created' do
expect(FactoryGirl.build(:order, article_count: 1)).to be_valid
end
describe 'with articles' do
let(:order) { FactoryGirl.create :order }
it 'is open by default' do expect(order).to be_open end
it 'is not finished by default' do expect(order).to_not be_finished end
it 'is not closed by default' do expect(order).to_not be_closed end
it 'has valid order articles' do
order.order_articles.all.each {|oa| expect(oa).to be_valid }
end
it 'can be finished' do
# TODO randomise user
order.finish!(User.first)
expect(order).to_not be_open
expect(order).to be_finished
expect(order).to_not be_closed
end
it 'can be closed' do
# TODO randomise user
order.finish!(User.first)
order.close!(User.first)
expect(order).to_not be_open
expect(order).to be_closed
end
end
end

View file

@ -0,0 +1,16 @@
require 'spec_helper'
describe Supplier do
let(:supplier) { FactoryGirl.create :supplier }
it 'has a unique name' do
supplier2 = FactoryGirl.build :supplier, name: supplier.name
expect(supplier2).to be_invalid
end
it 'has valid articles' do
supplier = FactoryGirl.create :supplier, article_count: true
supplier.articles.all.each {|a| expect(a).to be_valid }
end
end

59
spec/models/user_spec.rb Normal file
View file

@ -0,0 +1,59 @@
require 'spec_helper'
describe User do
it 'is correctly created' do
user = FactoryGirl.create :user,
nick: 'johnnydoe', first_name: 'Johnny', last_name: 'DoeBar',
email: 'johnnydoe@foodcoop.test', phone: '+1234567890'
expect(user.nick).to eq('johnnydoe')
expect(user.first_name).to eq('Johnny')
expect(user.last_name).to eq('DoeBar')
expect(user.name).to eq('Johnny DoeBar')
expect(user.email).to eq('johnnydoe@foodcoop.test')
expect(user.phone).to eq('+1234567890')
end
describe 'does not have the role' do
let(:user) { FactoryGirl.create :user }
it 'admin' do expect(user.role_admin?).to be_false end
it 'finance' do expect(user.role_finance?).to be_false end
it 'article_meta' do expect(user.role_article_meta?).to be_false end
it 'suppliers' do expect(user.role_suppliers?).to be_false end
it 'orders' do expect(user.role_orders?).to be_false end
end
describe do
let(:user) { FactoryGirl.create :user, password: 'blahblah' }
it 'can authenticate with correct password' do
expect(User.authenticate(user.nick, 'blahblah')).to be_true
end
it 'can not authenticate with incorrect password' do
expect(User.authenticate(user.nick, 'foobar')).to be_nil
end
it 'can not set a password without matching confirmation' do
user.password = 'abcdefghij'
user.password_confirmation = 'foobarxyz'
expect(user).to be_invalid
end
it 'can set a password with matching confirmation' do
user.password = 'abcdefghij'
user.password_confirmation = 'abcdefghij'
expect(user).to be_valid
end
it 'has a unique nick' do
expect(FactoryGirl.build(:user, nick: user.nick, email: "x-#{user.email}")).to be_invalid
end
it 'has a unique email' do
expect(FactoryGirl.build(:user, email: "#{user.email}")).to be_invalid
end
end
describe 'admin' do
let(:user) { FactoryGirl.create :admin }
it 'default admin role' do expect(user.role_admin?).to be_true end
end
end

67
spec/spec_helper.rb Normal file
View file

@ -0,0 +1,67 @@
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require 'support/coverage' # needs to be first
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'capybara/rails'
require 'capybara/rspec'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
# ## Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
#config.use_transactional_fixtures = true
# We use capybara with selenium, and need database_cleaner
config.before(:each) do
DatabaseCleaner.strategy = (example.metadata[:js] ? :truncation : :transaction)
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
config.include SessionHelper
end
module Faker
class Unit
class << self
def unit
['kg', '1L', '100ml', 'piece', 'bunch', '500g'].sample
end
end
end
end
# include default foodsoft scope in urls, so that *_path works
ActionDispatch::Integration::Runner.class_eval do
undef default_url_options
def default_url_options(options={})
{foodcoop: FoodsoftConfig.scope}.merge(options)
end
end

14
spec/support/coverage.rb Normal file
View file

@ -0,0 +1,14 @@
# optional test coverage
# needs to be loaded first, e.g. add a require at top of spec_helper
if ENV['COVERAGE']
require 'simplecov'
SimpleCov.start do
add_filter '/spec/'
add_filter '/test/'
add_group 'Models', '/app/models/'
add_group 'Controllers', '/app/controllers/'
add_group 'Helpers', '/app/helpers/'
add_group 'Documents', '/app/documents/'
add_group 'Libraries', '/lib/'
end
end

View file

@ -0,0 +1,17 @@
module SessionHelper
def login(user=nil, password=nil)
visit login_path
user = FactoryGirl.create :user if user.nil?
if user.instance_of? ::User
nick, password = user.nick, user.password
else
nick = user
end
fill_in 'nick', :with => nick
fill_in 'password', :with => password
find('input[type=submit]').click
end
end