Merge pull request #113 from ChrisBr/feature_tests

tests
This commit is contained in:
Christian Bruckmayer 2014-05-13 15:54:18 +02:00
commit e8b9c26778
19 changed files with 606 additions and 44 deletions

View file

@ -76,6 +76,8 @@ group :development, :test do
gem 'rspec', '>= 3.0.0.beta'
gem 'rspec-rails', '>= 3.0.0.beta'
gem 'capybara'
gem 'database_cleaner'
gem 'capybara-webkit'
gem 'shoulda'
end

View file

@ -55,6 +55,9 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
capybara-webkit (1.1.0)
capybara (~> 2.0, >= 2.0.2)
json
celluloid (0.15.2)
timers (~> 1.1.0)
celluloid-io (0.15.0)
@ -81,6 +84,7 @@ GEM
thor
d3_rails (3.4.6)
railties (>= 3.1.0)
database_cleaner (1.2.0)
devise (3.2.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
@ -308,9 +312,11 @@ DEPENDENCIES
bootstrap-sass
cancan
capybara
capybara-webkit
cocoon
coveralls
d3_rails
database_cleaner
devise
factory_girl_rails
formtastic (~> 2.3.0.rc3)

View file

@ -27,9 +27,15 @@ class Admin::ConferenceController < ApplicationController
def update
@conference = Conference.find_by(short_title: params[:id])
@conference.update_attributes(params[:conference])
flash[:notice] = "Updated Conference"
redirect_to(admin_conference_path(:id => @conference.short_title), :notice => 'Conference was successfully updated.')
short_title = @conference.short_title
if @conference.update_attributes(params[:conference])
redirect_to(admin_conference_path(id: @conference.short_title),
notice: 'Conference was successfully updated.')
else
errors = @conference.errors.full_messages.join('! ')
redirect_to(admin_conference_path(id: short_title),
flash: { error: "Conference update failed. #{errors}" })
end
end
def show
@ -37,7 +43,7 @@ class Admin::ConferenceController < ApplicationController
@conference = Conference.find_by(short_title: params[:id])
respond_to do |format|
format.html
format.json { render :json => @conference.to_json }
format.json { render json: @conference.to_json }
end
end
end

View file

@ -9,7 +9,8 @@ class ApplicationController < ActionController::Base
end
def after_sign_in_path_for(resource)
if not session[:return_to].start_with?(user_registration_path)
if session[:return_to] &&
!session[:return_to].start_with?(user_registration_path)
logger.debug "Returning to #{session[:return_to]}"
session[:return_to]
else

View file

@ -14,14 +14,14 @@ class User < ActiveRecord::Base
accepts_nested_attributes_for :person
accepts_nested_attributes_for :roles
before_save :setup_role
before_create :setup_role
before_create :create_person
delegate :last_name, :first_name, :public_name, to: :person
def role?(role)
Rails.logger.debug("Checking role in user")
return !!self.roles.find_by_name(role.to_s.camelize)
!!roles.find_by_name(role.to_s.downcase.camelize)
end
def get_roles
@ -29,13 +29,8 @@ class User < ActiveRecord::Base
end
def setup_role
if self.id == 1
self.role_ids = [3]
end
if self.role_ids.empty?
self.role_ids = [1]
end
roles << Role.find_by(name: 'Admin') if User.count == 0
roles << Role.find_by(name: 'Participant') if roles.empty?
end
def popup_details
@ -54,9 +49,9 @@ class User < ActiveRecord::Base
end
private
def create_person
# TODO Search people for existing email address, add to their account
build_person(:email => self.email) if person.nil?
true
end
def create_person
# TODO Search people for existing email address, add to their account
build_person(email: email) if person.nil?
true
end
end

View file

@ -47,8 +47,8 @@
%span.caret
.dropdown-menu{:style => "padding: 17px;"}
= form_tag user_session_path do
= text_field_tag 'user[email]'
= password_field_tag 'user[password]'
= text_field_tag 'user[email]', nil, id: 'user_email_dd'
= password_field_tag 'user[password]', nil, id: 'user_password_dd'
%label.checkbox
= check_box_tag 'user[remember_me]'
Remember me

View file

@ -14,7 +14,7 @@ development:
# Do not set this db to the same as development or production.
test:
adapter: sqlite3
database: ":memory:"
database: db/test.sqlite3
pool: 5
timeout: 5000

View file

@ -0,0 +1,244 @@
require 'spec_helper'
describe Admin::ConferenceController do
# It is necessary to use bang version of let to build roles before user
let!(:organizer_role) { create(:organizer_role) }
let!(:participant_role) { create(:participant_role) }
let!(:admin_role) { create(:admin_role) }
let(:conference) { create(:conference) }
let(:admin) { create(:admin) }
let(:organizer) { create(:organizer) }
let(:participant) { create(:participant) }
shared_examples 'access as administration or organizer' do
describe 'PATCH #update' do
context 'valid attributes' do
it 'locates the requested conference' do
patch :update, id: conference.short_title, conference:
attributes_for(:conference, title: 'Example Con')
expect(assigns(:conference)).to eq(conference)
end
it 'changes conference attributes' do
patch :update, id: conference.short_title, conference:
attributes_for(:conference, title: 'Example Con',
short_title: 'ExCon')
conference.reload
expect(conference.title).to eq('Example Con')
expect(conference.short_title).to eq('ExCon')
end
it 'redirects to the updated conference' do
patch :update, id: conference.short_title, conference:
attributes_for(:conference, title: 'Example Con')
expect(response).to redirect_to admin_conference_path(
conference.short_title)
end
end
context 'invalid attributes' do
it 'does not change conference attributes' do
patch :update, id: conference.short_title, conference:
attributes_for(:conference, title: 'Example Con',
short_title: nil)
conference.reload
expect(flash[:error]).to eq("Conference update failed. Short title can't be blank")
expect(conference.title).to eq('The dog and pony show')
expect(conference.short_title).to eq('dps14')
end
it 're-renders the #show template' do
patch :update, id: conference.short_title, conference:
attributes_for(:conference, title: 'Example Con',
short_title: nil)
expect(flash[:error]).to eq("Conference update failed. Short title can't be blank")
expect(response).to redirect_to admin_conference_path(
conference.short_title)
end
end
end
describe 'POST #create' do
context 'with valid attributes' do
it 'saves the conference to the database' do
expected = expect do
post :create, conference:
attributes_for(:conference, short_title: 'dps15')
end
expected.to change { Conference.count }.by 1
end
it 'redirects to conference#show' do
post :create, conference:
attributes_for(:conference, short_title: 'dps15')
expect(response).to redirect_to admin_conference_path(
assigns[:conference].short_title)
end
end
context 'with invalid attributes' do
it 'does not save the conference to the database' do
expected = expect do
post :create, conference:
attributes_for(:conference, short_title: nil)
end
expected.to_not change { Conference.count }
end
it 're-renders the new template' do
post :create, conference:
attributes_for(:conference, short_title: nil)
expect(response).to redirect_to new_admin_conference_path
end
end
context 'with duplicate conference short title' do
it 'does not save the conference to the database' do
conference
expected = expect do
post :create, conference:
attributes_for(:conference)
end
expected.to_not change { Conference.count }
end
it 're-renders the new template' do
conference
post :create, conference: attributes_for(:conference)
expect(response).to redirect_to new_admin_conference_path
end
end
end
describe 'GET #show' do
it 'assigns the requested conference to conference' do
get :show, id: conference.short_title
expect(assigns(:conference)).to eq conference
end
it 'renders the show template' do
get :show, id: conference.short_title
expect(response).to render_template :show
end
end
describe 'GET #index' do
context 'with more than 0 conferences' do
it 'populates an array with conferences' do
con2 = create(:conference, short_title: 'dps15',
title: 'The dog and pony show 2015')
get :index
expect(assigns(:conferences)).to match_array([conference, con2])
end
it 'renders the index template' do
conference
get :index
expect(response).to render_template :index
end
end
context 'no conferences' do
it 'redirect to new conference' do
get :index
expect(response).to redirect_to(redirect_to new_admin_conference_path)
end
end
end
describe 'GET #new' do
it 'assigns a new conference to conference' do
get :new
expect(assigns(:conference)).to be_a_new(Conference)
end
it 'renders the :new template' do
get :new
expect(response).to render_template :new
end
end
end
describe 'administrator access' do
before(:each) do
sign_in(admin)
end
it_behaves_like 'access as administration or organizer'
end
describe 'organizer access' do
before(:each) do
sign_in(organizer)
end
it_behaves_like 'access as administration or organizer'
end
shared_examples 'access as participant or guest' do |success_path|
describe 'GET #show' do
it 'requires admin privileges' do
get :show, id: conference.short_title
expect(response).to redirect_to(send(success_path))
end
end
describe 'GET #index' do
it 'requires admin privileges' do
get :index
expect(response).to redirect_to(send(success_path))
end
end
describe 'GET #new' do
it 'requires admin privileges' do
get :new
expect(response).to redirect_to(send(success_path))
end
end
describe 'POST #create' do
it 'requires admin privileges' do
post :create, conference: attributes_for(:conference,
short_title: 'ExCon')
expect(response).to redirect_to(send(success_path))
end
end
describe 'PATCH #update' do
it 'requires admin privileges' do
patch :update, id: conference.short_title,
conference: attributes_for(:conference,
short_title: 'ExCon')
expect(response).to redirect_to(send(success_path))
end
end
end
describe 'participant access' do
before(:each) do
sign_in(participant)
end
it_behaves_like 'access as participant or guest', :root_path
end
describe 'guest access' do
it_behaves_like 'access as participant or guest', :new_user_session_path
end
end

View file

@ -0,0 +1,10 @@
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
factory :event_type do
title 'Example Event Type'
length 30
minimum_abstract_length 0
maximum_abstract_length 500
end
end

16
spec/factories/role.rb Normal file
View file

@ -0,0 +1,16 @@
FactoryGirl.define do
factory :role do
factory :admin_role do
name 'Admin'
end
factory :organizer_role do
name 'Organizer'
end
factory :participant_role do
name 'Participant'
end
end
end

View file

@ -6,5 +6,17 @@ FactoryGirl.define do
password 'changeme'
password_confirmation 'changeme'
confirmed_at Time.now
factory :participant do
after(:create) { |user| user.role_ids = create(:participant_role).id }
end
factory :admin do
after(:create) { |user| user.role_ids = create(:admin_role).id }
end
factory :organizer do
after(:create) { |user| user.role_ids = create(:organizer_role).id }
end
end
end

View file

@ -0,0 +1,116 @@
require 'spec_helper'
feature Conference do
# It is necessary to use bang version of let to build roles before user
let!(:organizer_role) { create(:organizer_role) }
let!(:participant_role) { create(:participant_role) }
let!(:admin_role) { create(:admin_role) }
shared_examples 'add and update conference' do |user|
scenario 'adds a new conference', feature: true, js: true do
expected_count = Conference.count + 1
sign_in create(user)
visit new_admin_conference_path
fill_in 'conference_title', with: 'Example Con'
fill_in 'conference_short_title', with: 'ExCon'
fill_in 'conference_social_tag', with: 'ExCon'
select('(GMT+01:00) Berlin', from: 'conference[timezone]')
page.execute_script("$('#conference-start-datepicker').val('21/12/2014')")
page.execute_script("$('#conference-end-datepicker').val('24/12/2014')")
click_button 'Create Conference'
expect(page.find('#flash_notice').text).
to eq('Conference was successfully created.')
expect(Conference.count).to eq(expected_count)
end
scenario 'update conference', feature: true, js: true do
conference = create(:conference)
expected_count = Conference.count
sign_in create(user)
visit admin_conference_path(conference.short_title)
fill_in 'conference_title', with: 'New Con'
fill_in 'conference_short_title', with: 'NewCon'
fill_in 'conference_social_tag', with: 'NewCon'
click_button 'Update Conference'
expect(page.find('#flash_notice').text).
to eq('Conference was successfully updated.')
conference.reload
expect(conference.title).to eq('New Con')
expect(conference.short_title).to eq('NewCon')
expect(conference.social_tag).to eq('NewCon')
expect(Conference.count).to eq(expected_count)
end
end
shared_examples 'venue' do |user|
scenario 'adds and updates venue' do
conference = create(:conference)
sign_in create(user)
visit admin_conference_venue_info_path(conference_id: conference.short_title)
expect(page.find("//*[@id='venue_submit_action']").text).to eq('Update Venue')
fill_in 'venue_name', with: 'Example University'
fill_in 'venue_address', with: 'Example Street 42 \n 12345 Example City \n Germany'
fill_in 'venue_website', with: 'www.example.com'
fill_in 'venue_description',
with: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam' \
'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,' \
'sed diam voluptua.'
click_button 'Update Venue'
expect(page.find('#flash_notice').text).
to eq('Venue was successfully updated.')
venue = Conference.find(conference.id).venue
expect(venue.name).to eq('Example University')
expect(venue.address).to eq('Example Street 42 \n 12345 Example City \n Germany')
expect(venue.website).to eq('www.example.com')
expect(venue.description).to eq('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam' \
'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,' \
'sed diam voluptua.')
fill_in 'venue_name', with: 'Example University new'
fill_in 'venue_address', with: 'Example Street 42 \n 12345 Example City \n Germany new'
fill_in 'venue_website', with: 'www.example.com new'
fill_in 'venue_description',
with: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam' \
'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,' \
'sed diam voluptua. new'
click_button 'Update Venue'
expect(page.find('#flash_notice').text).
to eq('Venue was successfully updated.')
venue.reload
expect(venue.name).to eq('Example University new')
expect(venue.address).to eq('Example Street 42 \n 12345 Example City \n Germany new')
expect(venue.website).to eq('www.example.com new')
expect(venue.description).to eq('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam' \
'nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,' \
'sed diam voluptua. new')
end
end
describe 'admin' do
it_behaves_like 'add and update conference', :admin
it_behaves_like 'venue', :admin
end
describe 'organizer' do
it_behaves_like 'add and update conference', :organizer
it_behaves_like 'venue', :organizer
end
end

View file

@ -0,0 +1,56 @@
require 'spec_helper'
feature Event do
# It is necessary to use bang version of let to build roles before user
let!(:organizer_role) { create(:organizer_role) }
let!(:participant_role) { create(:participant_role) }
let!(:admin_role) { create(:admin_role) }
shared_examples 'participant' do |user|
scenario 'submitts a new proposal and updates account', feature: true, js: true do
expected_count = Event.count + 1
conference = create(:conference)
conference.call_for_papers = create(:call_for_papers)
conference.event_types = [create(:event_type)]
sign_in create(user)
visit conference_proposal_index_path(conference.short_title)
click_link 'New Proposal'
fill_in 'event_title', with: 'Example Proposal'
fill_in 'event_subtitle', with: 'Example Proposal Subtitle'
select('Example Event Type', from: 'event[event_type_id]')
fill_in 'event_abstract', with: 'Lorem ipsum abstract'
fill_in 'event_description', with: 'Lorem ipsum description'
select('YouTube', from: 'event[media_type]')
fill_in 'event_media_id', with: '123456'
fill_in 'person_biography', with: 'Lorem ipsum biography'
fill_in 'person_public_name', with: 'Example User'
click_button 'Submit Session'
expect(current_path).to eq(edit_user_registration_path)
fill_in 'user_person_attributes_first_name', with: 'Example'
fill_in 'user_person_attributes_last_name', with: 'User'
click_button 'Update'
expect(page.find('#flash_notice').text).
to eq('You updated your account successfully.')
expect(Event.count).to eq(expected_count)
end
end
describe 'participant' do
it_behaves_like 'participant', :participant
it_behaves_like 'participant', :organizer
it_behaves_like 'participant', :admin
end
end

View file

@ -52,6 +52,11 @@ describe Conference do
describe '#user_registered?' do
# It is necessary to use bang version of let to build roles before user
let!(:organizer_role) { create(:organizer_role) }
let!(:participant_role) { create(:participant_role) }
let!(:admin_role) { create(:admin_role) }
let(:user) { create(:user) }
context 'user not registered' do

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

@ -0,0 +1,68 @@
require 'spec_helper'
describe User do
# It is necessary to use bang version of let to build roles before user
let!(:organizer_role) { create(:organizer_role) }
let!(:participant_role) { create(:participant_role) }
let!(:admin_role) { create(:admin_role) }
let!(:admin) { create(:user) }
it 'returns the correct role' do
participant = create(:user, email: 'participant@example.de')
expect(admin.roles.first).to eq(admin_role)
expect(participant.roles.first).to eq(participant_role)
end
it 'returns the correct roles' do
roles = [organizer_role.id, participant_role.id, admin_role.id]
user_with_all_roles = create(:user, email: 'participant@example.de')
user_with_all_roles.role_ids = roles
user_with_all_roles.save
expect(user_with_all_roles.roles.length).to eq(3)
expect(user_with_all_roles.roles[0]).to eq(participant_role)
expect(user_with_all_roles.roles[1]).to eq(organizer_role)
expect(user_with_all_roles.roles[2]).to eq(admin_role)
end
describe '#role?' do
shared_examples '#role?' do |user, role, expected|
it "returns #{expected} for #{role}" do
user_obj = create(user, email: 'e@example.com')
expect(user_obj.role?(role)).to be expected
expect(user_obj.role?(role.downcase)).to be expected
expect(user_obj.role?(role.upcase)).to be expected
expect(user_obj.role?(role.downcase.capitalize)).to be expected
end
end
context 'admin' do
it_behaves_like '#role?', :admin, 'orgAnizer', false
it_behaves_like '#role?', :admin, 'adMin', true
it_behaves_like '#role?', :admin, 'partiCipant', false
it 'assigns first user admin role' do
expect(admin.role?('Admin')).to be true
expect(admin.role_ids).to match_array([admin_role.id])
end
end
context 'participant' do
it_behaves_like '#role?', :participant, 'orgAnizer', false
it_behaves_like '#role?', :participant, 'adMin', false
it_behaves_like '#role?', :participant, 'partiCipant', true
it 'assigns second user participant role' do
participant = create(:user, email: 'participant@example.de')
expect(participant.role_ids).to match_array([participant_role.id])
end
end
context 'organizer' do
it_behaves_like '#role?', :organizer, 'orgAnizer', true
it_behaves_like '#role?', :organizer, 'adMin', false
it_behaves_like '#role?', :organizer, 'partiCipant', false
end
end
end

View file

@ -1,13 +1,8 @@
require 'coveralls'
Coveralls.wear!('rails')
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
if Rails.configuration.database_configuration['test']['database'] == ':memory:'
load "#{Rails.root}/db/schema.rb"
load "#{Rails.root}/db/seeds.rb"
end
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
@ -18,12 +13,7 @@ require 'rspec/rails'
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.maintain_test_schema!
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
RSpec.configure do |config|
# ## Mock Framework
@ -40,17 +30,26 @@ RSpec.configure do |config|
# 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
config.use_transactional_fixtures = 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.order = 'random'
# Include factory_girls syntax
config.include FactoryGirl::Syntax::Methods
# Enables devise sign_in function
config.include Devise::TestHelpers, type: :controller
# Use capybara-webkit as default javascript driver
Capybara.javascript_driver = :webkit
# Includes support/login_macros for feature tests
config.include LoginMacros, type: :feature
# As we start from scratch in April 2014, let's forbid the old :should syntax
config.expect_with :rspec do |c|
c.syntax = :expect

View file

@ -0,0 +1,22 @@
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end

View file

@ -0,0 +1,11 @@
module LoginMacros
def sign_in(user)
visit new_user_session_path
fill_in 'user_email', with: user.email
fill_in 'user_password', with: user.password
find(:xpath, "//div[@id='content']//input[@name='commit']").click
expect(page.has_content?('Signed in successfully')).to be true
end
end

View file

@ -1,7 +0,0 @@
RSpec.configure do |config|
config.before(:suite) do
load "#{Rails.root}/db/seeds.rb"
end
end