From cf98fcd3b8a7f4e77394a12adc3cff979f812474 Mon Sep 17 00:00:00 2001 From: Nikos Dimitrakopoulos Date: Sun, 21 Apr 2013 14:22:36 +0300 Subject: [PATCH] A first take on phase configuration integration. Refs #15. --- app/models/ability.rb | 25 +- app/models/phase.rb | 8 + test/functional/proposals_controller_test.rb | 1285 +++++++++++++---- .../functional/suggestions_controller_test.rb | 420 ++++-- test/integration/proposal_suggestion_test.rb | 381 +++-- test/integration/proposal_test.rb | 430 ++++-- test/integration/proposal_voting_test.rb | 194 ++- 7 files changed, 2016 insertions(+), 727 deletions(-) diff --git a/app/models/ability.rb b/app/models/ability.rb index e105917..3ac0ffc 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -5,6 +5,7 @@ class Ability # https://github.com/ryanb/cancan/wiki/Defining-Abilities def initialize(user) user ||= User.new + phase = Phase.current # Everyone can :see, :index @@ -22,17 +23,33 @@ def initialize(user) can :see, :my_motivation can [:update], User, :id => user.id - can [:update, :create, :withdraw, :republish, :see_votes], Proposal, :proposer_id => user.id + if phase.new_submissions_allowed? + can [:create], Proposal, :proposer_id => user.id + end + + if phase.submission_editing_allowed? + can [:update], Proposal, :proposer_id => user.id + end + + if phase.submission_withdrawal_allowed? + can [:withdraw, :republish], Proposal, :proposer_id => user.id + end + + can [:see_votes], Proposal, :proposer_id => user.id - can [:create], Suggestion, :author_id => user.id + if phase.new_suggestions_allowed? + can [:create], Suggestion, :author_id => user.id + end if user.moderator? can :update, Suggestion can :see, :moderator_dashboard end - can [:vote], Proposal - cannot [:vote], Proposal, :proposer_id => user.id + if phase.voting_allowed? + can [:vote], Proposal + cannot [:vote], Proposal, :proposer_id => user.id + end end end end diff --git a/app/models/phase.rb b/app/models/phase.rb index ae6befc..c107278 100644 --- a/app/models/phase.rb +++ b/app/models/phase.rb @@ -8,6 +8,8 @@ def self.all [ZERO, ONE, INTERLUDE, TWO, CONFIRMATION, LINEUP] end + attr_accessor :name + attr_accessor :starting_at attr_accessor :ending_at @@ -27,6 +29,7 @@ def self.all alias_method :submission_withdrawal_allowed?, :submission_withdrawal_allowed ZERO = Phase.new.tap do |p| + p.name = "Before the beginning" p.starting_at = DateTime.new(1970, 1, 1) p.ending_at = DateTime.parse('2013-03-28T00:00:00+2') @@ -38,6 +41,7 @@ def self.all end.freeze ONE = Phase.new.tap do |p| + p.name = "Phase 1: Submissions" p.starting_at = DateTime.parse('2013-03-28T00:00:00+2') p.ending_at = DateTime.parse('2013-04-24T00:00:00+3') @@ -49,6 +53,7 @@ def self.all end.freeze INTERLUDE = Phase.new.tap do |p| + p.name = "Interlude" p.starting_at = DateTime.parse('2013-04-24T00:00:00+3') p.ending_at = DateTime.parse('2013-04-29T00:00:00+3') @@ -60,6 +65,7 @@ def self.all end.freeze TWO = Phase.new.tap do |p| + p.name = "Phase 2: Final voting" p.starting_at = DateTime.parse('2013-04-29T00:00:00+3') p.ending_at = DateTime.parse('2013-05-06T00:00:00+3') @@ -71,6 +77,7 @@ def self.all end.freeze CONFIRMATION = Phase.new.tap do |p| + p.name = "Speakers confirmation" p.starting_at = DateTime.parse('2013-05-06T00:00:00+3') p.ending_at = DateTime.parse('2013-05-09T00:00:00+3') @@ -82,6 +89,7 @@ def self.all end.freeze LINEUP = Phase.new.tap do |p| + p.name = "Lineup announcement" p.starting_at = DateTime.parse('2013-05-09T00:00:00+3') p.ending_at = DateTime.parse('2100-01-01T00:00:00+2') diff --git a/test/functional/proposals_controller_test.rb b/test/functional/proposals_controller_test.rb index 4816139..591da68 100644 --- a/test/functional/proposals_controller_test.rb +++ b/test/functional/proposals_controller_test.rb @@ -7,398 +7,1183 @@ def setup @proposal = FactoryGirl.create(:proposal, :proposer => @proposer) end - context 'When visitor' do - context 'on #GET to index' do - setup do - @withdrawn_proposal = FactoryGirl.create(:proposal, :proposer => @proposer, :withdrawn => true) - get :index + context 'Before phase one' do + setup do + Phase.stubs(:current).returns(Phase::ZERO) + end + + context 'When visitor' do + context 'on #GET to index' do + setup do + @withdrawn_proposal = FactoryGirl.create(:proposal, :proposer => @proposer, :withdrawn => true) + get :index + end + + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') end - should respond_with(:success) - should assign_to(:proposals) { [@proposal] } - should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } - should render_template('index') - end + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end - context 'on #GET to show' do - setup do - get :show, :id => @proposal.to_param + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should_not assign_to(:suggestion) + should render_template('show') end - should respond_with(:success) - should assign_to(:proposal) { @proposal } - should_not assign_to(:suggestion) - should render_template('show') - end + context 'on #GET to new' do + setup do + get :new + end - context 'on #GET to new' do - setup do - get :new + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) end - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) - end + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end - context 'on #POST to create' do - setup do - post :create, :proposal => FactoryGirl.attributes_for(:proposal) + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not save proposal" do + assert !assigns(:proposal).persisted? + end end - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) + context 'on #GET to edit' do + setup do + get :edit, :id => @proposal.to_param + end - should "not save proposal" do - assert !assigns(:proposal).persisted? + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) end - end - context 'on #GET to edit' do - setup do - get :edit, :id => @proposal.to_param + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not update proposal" do + assert_not_equal 'Title Updated', @proposal.reload.title + end end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) - end + context 'on #POST to withdraw' do + setup do + post :withdraw, :id => @proposal.to_param + end - context 'on #PUT to update' do - setup do - put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not withdraw proposal" do + assert !@proposal.withdrawn? + end end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) + context 'on #POST to republish' do + setup do + @proposal.withdraw! + post :republish, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not republish proposal" do + assert @proposal.withdrawn? + end + end - should "not update proposal" do - assert_not_equal 'Title Updated', @proposal.reload.title + context 'on #POST to vote' do + [:up, :down, :clear].each do |vote| + context "with :#{vote}" do + setup do + post :vote, :id => @proposal.to_param, :vote => vote.to_s + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not count a vote" do + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end + end + end end end - context 'on #POST to withdraw' do + context 'When viewer is logged in' do setup do - post :withdraw, :id => @proposal.to_param + session[:user_id] = @viewer.id end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) + context 'on #GET to index' do + setup do + get :index + end - should "not withdraw proposal" do - assert !@proposal.withdrawn? + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') end - end - context 'on #POST to republish' do - setup do - @proposal.withdraw! - post :republish, :id => @proposal.to_param + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end + + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should_not assign_to(:suggestion) + should render_template('show') end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) + context 'on #GET to new' do + setup do + get :new + end - should "not republish proposal" do - assert @proposal.withdrawn? + should respond_with(:redirect) end - end - context 'on #POST to vote' do - [:up, :down, :clear].each do |vote| - context "with :#{vote}" do - setup do - post :vote, :id => @proposal.to_param, :vote => vote.to_s - end + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) + should respond_with(:redirect) - should "not count a vote" do - assert_equal 0, @proposal.votes_for - assert_equal 0, @proposal.votes_against - end + should "not save proposal" do + assert !assigns(:proposal).persisted? + end + + should "not send email" do + assert ActionMailer::Base.deliveries.empty? end end - end - end - context 'When viewer is logged in' do - setup do - session[:user_id] = @viewer.id - end + context 'on #GET to edit' do + setup do + get :edit, :id => @proposal.to_param + end - context 'on #GET to index' do - setup do - get :index + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) end - should respond_with(:success) - should assign_to(:proposals) { [@proposal] } - should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } - should render_template('index') - end + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + end - context 'on #GET to show' do - setup do - get :show, :id => @proposal.to_param + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not update proposal" do + assert_not_equal 'Title Updated', @proposal.reload.title + end end - should respond_with(:success) - should assign_to(:proposal) { @proposal } - should assign_to(:suggestion) - should render_template('show') - end + context 'on #POST to withdraw' do + setup do + post :withdraw, :id => @proposal.to_param + end - context 'on #GET to new' do - setup do - get :new + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not withdraw proposal" do + assert !@proposal.withdrawn? + end end - should respond_with(:success) - should render_template('new') - end + context 'on #POST to republish' do + setup do + @proposal.withdraw! + post :republish, :id => @proposal.to_param + end - context 'on #POST to create' do - setup do - post :create, :proposal => FactoryGirl.attributes_for(:proposal) + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not republish proposal" do + assert @proposal.withdrawn? + end end - should respond_with(:redirect) + context 'on #POST to vote' do + context "with :up" do + setup do + post :vote, :id => @proposal.to_param, :vote => 'up' + end - should "save proposal" do - assert assigns(:proposal).persisted? - end + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) - should "assign proposal to user" do - assert_equal @viewer, assigns(:proposal).proposer - end + should "not count an upvote" do + assert_equal 0, @proposal.votes_for + end - should "send email" do - assert !ActionMailer::Base.deliveries.empty? - end - end + should "not count a downvote" do + assert_equal 0, @proposal.votes_against + end + end - context 'on #GET to edit' do - setup do - get :edit, :id => @proposal.to_param - end + context "with :down" do + setup do + post :vote, :id => @proposal.to_param, :vote => 'down' + end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You are not authorized to access this page/) - end + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) - context 'on #PUT to update' do - setup do - put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} - end + should "not count an downvote" do + assert_equal 0, @proposal.votes_for + end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You are not authorized to access this page/) + should "count a downvote" do + assert_equal 0, @proposal.votes_against + end + end + + context "with :clear" do + setup do + @viewer.vote_for(@proposal) + post :vote, :id => @proposal.to_param, :vote => 'clear' + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) - should "not update proposal" do - assert_not_equal 'Title Updated', @proposal.reload.title + should "not neutralize votes" do + assert_equal 1, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end + end end end - context 'on #POST to withdraw' do + context 'When proposer is logged in' do setup do - post :withdraw, :id => @proposal.to_param + session[:user_id] = @proposer.id end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You are not authorized to access this page/) + context 'on #GET to index' do + setup do + get :index + end - should "not withdraw proposal" do - assert !@proposal.withdrawn? + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') end - end - context 'on #POST to republish' do - setup do - @proposal.withdraw! - post :republish, :id => @proposal.to_param + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end + + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should_not assign_to(:suggestion) + should render_template('show') end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You are not authorized to access this page/) + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end + + should respond_with(:redirect) - should "not republish proposal" do - assert @proposal.withdrawn? + should "not save proposal" do + assert !assigns(:proposal).persisted? + end end - end - context 'on #POST to vote' do - context "with :up" do + context 'on #GET to edit' do setup do - post :vote, :id => @proposal.to_param, :vote => 'up' + get :edit, :id => @proposal.to_param end should assign_to(:proposal) { @proposal } should respond_with(:redirect) - should set_the_flash.to(/Thank you for casting your vote. Your vote has been captured!/) + end - should "count an upvote" do - assert_equal 1, @proposal.votes_for + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} end - should "not count a downvote" do - assert_equal 0, @proposal.votes_against + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + + should "update proposal" do + assert_not_equal 'Title Updated', @proposal.reload.title end end - context "with :down" do + context 'on #POST to withdraw' do setup do - post :vote, :id => @proposal.to_param, :vote => 'down' + post :withdraw, :id => @proposal.to_param end should assign_to(:proposal) { @proposal } should respond_with(:redirect) - should set_the_flash.to(/Thank you for casting your vote. Your vote has been captured!/) - - should "not count an downvote" do - assert_equal 0, @proposal.votes_for - end - should "count a downvote" do - assert_equal 1, @proposal.votes_against + should "not withdraw proposal" do + assert !@proposal.reload.withdrawn? end end - context "with :clear" do + context 'on #POST to republish' do setup do - @viewer.vote_for(@proposal) - post :vote, :id => @proposal.to_param, :vote => 'clear' + @proposal.withdraw! + post :republish, :id => @proposal.to_param end should assign_to(:proposal) { @proposal } should respond_with(:redirect) - should set_the_flash.to('Your vote has been cleared. Remember to come back to vote again once you are sure!') - should "neutralize votes" do - assert_equal 0, @proposal.votes_for - assert_equal 0, @proposal.votes_against + should "republish proposal" do + assert @proposal.reload.withdrawn? + end + end + + context 'on #POST to vote' do + [:up, :down, :clear].each do |vote| + context "with :#{vote}" do + setup do + post :vote, :id => @proposal.to_param, :vote => vote.to_s + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not count a vote" do + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end + end end end end end - context 'When proposer is logged in' do + context 'During phase one' do setup do - session[:user_id] = @proposer.id + Phase.stubs(:current).returns(Phase::ONE) end - context 'on #GET to index' do - setup do - get :index + context 'When visitor' do + context 'on #GET to index' do + setup do + @withdrawn_proposal = FactoryGirl.create(:proposal, :proposer => @proposer, :withdrawn => true) + get :index + end + + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') end - should respond_with(:success) - should assign_to(:proposals) { [@proposal] } - should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } - should render_template('index') - end + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end - context 'on #GET to show' do - setup do - get :show, :id => @proposal.to_param + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should_not assign_to(:suggestion) + should render_template('show') end - should respond_with(:success) - should assign_to(:proposal) { @proposal } - should assign_to(:suggestion) - should render_template('show') - end + context 'on #GET to new' do + setup do + get :new + end - context 'on #POST to create' do - setup do - post :create, :proposal => FactoryGirl.attributes_for(:proposal) + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) end - should respond_with(:redirect) + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end + + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) - should "save proposal" do - assert assigns(:proposal).persisted? + should "not save proposal" do + assert !assigns(:proposal).persisted? + end end - should "assign proposal to user" do - assert_equal @proposer, assigns(:proposal).proposer + context 'on #GET to edit' do + setup do + get :edit, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) end - end - context 'on #GET to edit' do - setup do - get :edit, :id => @proposal.to_param + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not update proposal" do + assert_not_equal 'Title Updated', @proposal.reload.title + end end - should assign_to(:proposal) { @proposal } - should respond_with(:success) - should render_template('edit') - end + context 'on #POST to withdraw' do + setup do + post :withdraw, :id => @proposal.to_param + end - context 'on #PUT to update' do - setup do - put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not withdraw proposal" do + assert !@proposal.withdrawn? + end end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) + context 'on #POST to republish' do + setup do + @proposal.withdraw! + post :republish, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not republish proposal" do + assert @proposal.withdrawn? + end + end - should "update proposal" do - assert_equal 'Title Updated', @proposal.reload.title + context 'on #POST to vote' do + [:up, :down, :clear].each do |vote| + context "with :#{vote}" do + setup do + post :vote, :id => @proposal.to_param, :vote => vote.to_s + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not count a vote" do + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end + end + end end end - context 'on #POST to withdraw' do + context 'When viewer is logged in' do setup do - post :withdraw, :id => @proposal.to_param + session[:user_id] = @viewer.id end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/Your proposal has been withdrawn/) + context 'on #GET to index' do + setup do + get :index + end - should "withdraw proposal" do - assert @proposal.reload.withdrawn? + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') end - end - context 'on #POST to republish' do - setup do - @proposal.withdraw! - post :republish, :id => @proposal.to_param + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end + + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should render_template('show') end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/Your proposal has been republished/) + context 'on #GET to new' do + setup do + get :new + end - should "republish proposal" do - assert !@proposal.reload.withdrawn? + should respond_with(:success) + should render_template('new') end - end - context 'on #POST to vote' do - [:up, :down, :clear].each do |vote| - context "with :#{vote}" do - setup do - post :vote, :id => @proposal.to_param, :vote => vote.to_s - end + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end - should assign_to(:proposal) { @proposal } - should respond_with(:redirect) - should set_the_flash.to(/You are not authorized to access this page/) + should respond_with(:redirect) - should "not count a vote" do - assert_equal 0, @proposal.votes_for - assert_equal 0, @proposal.votes_against + should "save proposal" do + assert assigns(:proposal).persisted? + end + + should "assign proposal to user" do + assert_equal @viewer, assigns(:proposal).proposer + end + + should "send email" do + assert !ActionMailer::Base.deliveries.empty? + end + end + + context 'on #GET to edit' do + setup do + get :edit, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + end + + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not update proposal" do + assert_not_equal 'Title Updated', @proposal.reload.title + end + end + + context 'on #POST to withdraw' do + setup do + post :withdraw, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not withdraw proposal" do + assert !@proposal.withdrawn? + end + end + + context 'on #POST to republish' do + setup do + @proposal.withdraw! + post :republish, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not republish proposal" do + assert @proposal.withdrawn? + end + end + + context 'on #POST to vote' do + context "with :up" do + setup do + post :vote, :id => @proposal.to_param, :vote => 'up' + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/Thank you for casting your vote. Your vote has been captured!/) + + should "count an upvote" do + assert_equal 1, @proposal.votes_for + end + + should "not count a downvote" do + assert_equal 0, @proposal.votes_against + end + end + + context "with :down" do + setup do + post :vote, :id => @proposal.to_param, :vote => 'down' + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/Thank you for casting your vote. Your vote has been captured!/) + + should "not count an downvote" do + assert_equal 0, @proposal.votes_for + end + + should "count a downvote" do + assert_equal 1, @proposal.votes_against + end + end + + context "with :clear" do + setup do + @viewer.vote_for(@proposal) + post :vote, :id => @proposal.to_param, :vote => 'clear' + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to('Your vote has been cleared. Remember to come back to vote again once you are sure!') + + should "neutralize votes" do + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end + end + end + end + + context 'When proposer is logged in' do + setup do + session[:user_id] = @proposer.id + end + + context 'on #GET to index' do + setup do + get :index + end + + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') + end + + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end + + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should render_template('show') + end + + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end + + should respond_with(:redirect) + + should "save proposal" do + assert assigns(:proposal).persisted? + end + + should "assign proposal to user" do + assert_equal @proposer, assigns(:proposal).proposer + end + end + + context 'on #GET to edit' do + setup do + get :edit, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:success) + should render_template('edit') + end + + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + + should "update proposal" do + assert_equal 'Title Updated', @proposal.reload.title + end + end + + context 'on #POST to withdraw' do + setup do + post :withdraw, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/Your proposal has been withdrawn/) + + should "withdraw proposal" do + assert @proposal.reload.withdrawn? + end + end + + context 'on #POST to republish' do + setup do + @proposal.withdraw! + post :republish, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/Your proposal has been republished/) + + should "republish proposal" do + assert !@proposal.reload.withdrawn? + end + end + + context 'on #POST to vote' do + [:up, :down, :clear].each do |vote| + context "with :#{vote}" do + setup do + post :vote, :id => @proposal.to_param, :vote => vote.to_s + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not count a vote" do + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end + end + end + end + end + end + + context 'During interlude' do + setup do + Phase.stubs(:current).returns(Phase::INTERLUDE) + end + + context 'When visitor' do + context 'on #GET to index' do + setup do + @withdrawn_proposal = FactoryGirl.create(:proposal, :proposer => @proposer, :withdrawn => true) + get :index + end + + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') + end + + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end + + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should_not assign_to(:suggestion) + should render_template('show') + end + + context 'on #GET to new' do + setup do + get :new + end + + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + end + + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end + + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not save proposal" do + assert !assigns(:proposal).persisted? + end + end + + context 'on #GET to edit' do + setup do + get :edit, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + end + + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not update proposal" do + assert_not_equal 'Title Updated', @proposal.reload.title + end + end + + context 'on #POST to withdraw' do + setup do + post :withdraw, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not withdraw proposal" do + assert !@proposal.withdrawn? + end + end + + context 'on #POST to republish' do + setup do + @proposal.withdraw! + post :republish, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not republish proposal" do + assert @proposal.withdrawn? + end + end + + context 'on #POST to vote' do + [:up, :down, :clear].each do |vote| + context "with :#{vote}" do + setup do + post :vote, :id => @proposal.to_param, :vote => vote.to_s + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "not count a vote" do + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end + end + end + end + end + + context 'When viewer is logged in' do + setup do + session[:user_id] = @viewer.id + end + + context 'on #GET to index' do + setup do + get :index + end + + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') + end + + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end + + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should_not assign_to(:suggestion) + should render_template('show') + end + + context 'on #GET to new' do + setup do + get :new + end + + should respond_with(:redirect) + end + + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end + + should respond_with(:redirect) + + should "not save proposal" do + assert !assigns(:proposal).persisted? + end + end + + context 'on #GET to edit' do + setup do + get :edit, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + end + + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not update proposal" do + assert_not_equal 'Title Updated', @proposal.reload.title + end + end + + context 'on #POST to withdraw' do + setup do + post :withdraw, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not withdraw proposal" do + assert !@proposal.withdrawn? + end + end + + context 'on #POST to republish' do + setup do + @proposal.withdraw! + post :republish, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not republish proposal" do + assert @proposal.withdrawn? + end + end + + context 'on #POST to vote' do + context "with :up" do + setup do + post :vote, :id => @proposal.to_param, :vote => 'up' + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/Thank you for casting your vote. Your vote has been captured!/) + + should "count an upvote" do + assert_equal 1, @proposal.votes_for + end + + should "not count a downvote" do + assert_equal 0, @proposal.votes_against + end + end + + context "with :down" do + setup do + post :vote, :id => @proposal.to_param, :vote => 'down' + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/Thank you for casting your vote. Your vote has been captured!/) + + should "not count an downvote" do + assert_equal 0, @proposal.votes_for + end + + should "count a downvote" do + assert_equal 1, @proposal.votes_against + end + end + + context "with :clear" do + setup do + @viewer.vote_for(@proposal) + post :vote, :id => @proposal.to_param, :vote => 'clear' + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to('Your vote has been cleared. Remember to come back to vote again once you are sure!') + + should "neutralize votes" do + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end + end + end + end + + context 'When proposer is logged in' do + setup do + session[:user_id] = @proposer.id + end + + context 'on #GET to index' do + setup do + get :index + end + + should respond_with(:success) + should assign_to(:proposals) { [@proposal] } + should assign_to(:withdrawn_proposals) { [@withdrawn_proposal] } + should render_template('index') + end + + context 'on #GET to show' do + setup do + get :show, :id => @proposal.to_param + end + + should respond_with(:success) + should assign_to(:proposal) { @proposal } + should_not assign_to(:suggestion) + should render_template('show') + end + + context 'on #POST to create' do + setup do + post :create, :proposal => FactoryGirl.attributes_for(:proposal) + end + + should respond_with(:redirect) + + should "not save proposal" do + assert !assigns(:proposal).persisted? + end + end + + context 'on #GET to edit' do + setup do + get :edit, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + end + + context 'on #PUT to update' do + setup do + put :update, :id => @proposal.to_param, :proposal => {:title => 'Title Updated'} + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + + should "not update proposal" do + assert_not_equal 'Title Updated', @proposal.reload.title + end + end + + context 'on #POST to withdraw' do + setup do + post :withdraw, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/Your proposal has been withdrawn/) + + should "withdraw proposal" do + assert @proposal.reload.withdrawn? + end + end + + context 'on #POST to republish' do + setup do + @proposal.withdraw! + post :republish, :id => @proposal.to_param + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/Your proposal has been republished/) + + should "republish proposal" do + assert !@proposal.reload.withdrawn? + end + end + + context 'on #POST to vote' do + [:up, :down, :clear].each do |vote| + context "with :#{vote}" do + setup do + post :vote, :id => @proposal.to_param, :vote => vote.to_s + end + + should assign_to(:proposal) { @proposal } + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not count a vote" do + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + end end end end diff --git a/test/functional/suggestions_controller_test.rb b/test/functional/suggestions_controller_test.rb index 4200a46..7df343c 100644 --- a/test/functional/suggestions_controller_test.rb +++ b/test/functional/suggestions_controller_test.rb @@ -7,124 +7,71 @@ def setup @proposal = FactoryGirl.create(:proposal, :proposer => @proposer) end - context 'When visitor' do - context 'on #POST to create' do - setup do - post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) - end - - should assign_to(:proposal) { @proposal } - should assign_to(:suggestion) - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) - - should "save suggestion" do - assert !assigns(:suggestion).persisted? - end - end - - context 'on #POST to update' do - setup do - @suggestion = FactoryGirl.create(:suggestion) - put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) - end - - should assign_to(:proposal) { @proposal } - should assign_to(:suggestion) - should respond_with(:redirect) - should set_the_flash.to(/You need to sign in or sign up before continuing/) - - should "not update suggestion" do - assert_equal 1, @suggestion.versions.size - end - end - end - - context 'When viewer' do + context 'During phase one' do setup do - session[:user_id] = @viewer.id + Phase.stubs(:current).returns(Phase::ONE) end - context 'on #POST to create' do - setup do - post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) - end - - should assign_to(:proposal) { @proposal } - should assign_to(:suggestion) - should respond_with(:redirect) - should set_the_flash.to(/Your suggestion has been published/) + context 'When visitor' do + context 'on #POST to create' do + setup do + post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) + end - should "save suggestion" do - assert assigns(:suggestion).persisted? - end + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) - should "send email" do - assert !ActionMailer::Base.deliveries.empty? + should "save suggestion" do + assert !assigns(:suggestion).persisted? + end end - end - context 'on #POST to update' do - setup do - @suggestion = FactoryGirl.create(:suggestion, :author => @viewer) - put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) - end + context 'on #POST to update' do + setup do + @suggestion = FactoryGirl.create(:suggestion) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end - should assign_to(:proposal) { @proposal } - should assign_to(:suggestion) - should respond_with(:redirect) - should set_the_flash.to(/You are not authorized to access this page/) + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) - should "not update suggestion" do - assert_equal 1, @suggestion.versions.size + should "not update suggestion" do + assert_equal 1, @suggestion.versions.size + end end end - end - - context 'When proposer' do - setup do - session[:user_id] = @proposer.id - end - context 'on #POST to create' do + context 'When viewer' do setup do - post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) - end - - should assign_to(:proposal) { @proposal } - should assign_to(:suggestion) - should respond_with(:redirect) - should set_the_flash.to(/Your suggestion has been published/) - - should "save suggestion" do - assert assigns(:suggestion).persisted? + session[:user_id] = @viewer.id end - should "send email" do - assert !ActionMailer::Base.deliveries.empty? - end - end - - context 'on #POST to update' do - context 'own suggestion' do + context 'on #POST to create' do setup do - @suggestion = FactoryGirl.create(:suggestion, :author => @proposer) - put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) end should assign_to(:proposal) { @proposal } should assign_to(:suggestion) should respond_with(:redirect) - should set_the_flash.to(/You are not authorized to access this page/) + should set_the_flash.to(/Your suggestion has been published/) - should "not update suggestion" do - assert_equal 1, @suggestion.versions.size + should "save suggestion" do + assert assigns(:suggestion).persisted? + end + + should "send email" do + assert !ActionMailer::Base.deliveries.empty? end end - context 'someone else suggestion' do + context 'on #POST to update' do setup do - @suggestion = FactoryGirl.create(:suggestion) + @suggestion = FactoryGirl.create(:suggestion, :author => @viewer) put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) end @@ -138,28 +85,24 @@ def setup end end end - end - context 'When moderator' do - setup do - @moderator = FactoryGirl.create(:user, :email => 'moderator@euruko2013.org') - session[:user_id] = @moderator - end + context 'When proposer' do + setup do + session[:user_id] = @proposer.id + end - context 'on #POST to update' do - context 'own suggestion' do + context 'on #POST to create' do setup do - @suggestion = FactoryGirl.create(:suggestion, :author => @moderator) - put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) end should assign_to(:proposal) { @proposal } should assign_to(:suggestion) should respond_with(:redirect) - should set_the_flash.to(/Suggestion has been updated/) + should set_the_flash.to(/Your suggestion has been published/) - should "update suggestion" do - assert_equal 2, @suggestion.versions.size + should "save suggestion" do + assert assigns(:suggestion).persisted? end should "send email" do @@ -167,26 +110,269 @@ def setup end end - context 'someone else suggestion' do - setup do - @suggestion = FactoryGirl.create(:suggestion) - put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + context 'on #POST to update' do + context 'own suggestion' do + setup do + @suggestion = FactoryGirl.create(:suggestion, :author => @proposer) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not update suggestion" do + assert_equal 1, @suggestion.versions.size + end end - should assign_to(:proposal) { @proposal } - should assign_to(:suggestion) - should respond_with(:redirect) - should set_the_flash.to(/Suggestion has been updated/) + context 'someone else suggestion' do + setup do + @suggestion = FactoryGirl.create(:suggestion) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) - should "update suggestion" do - assert_equal 2, @suggestion.versions.size + should "not update suggestion" do + assert_equal 1, @suggestion.versions.size + end end + end + end - should "send email" do - assert !ActionMailer::Base.deliveries.empty? + context 'When moderator' do + setup do + @moderator = FactoryGirl.create(:user, :email => 'moderator@euruko2013.org') + session[:user_id] = @moderator + end + + context 'on #POST to update' do + context 'own suggestion' do + setup do + @suggestion = FactoryGirl.create(:suggestion, :author => @moderator) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/Suggestion has been updated/) + + should "update suggestion" do + assert_equal 2, @suggestion.versions.size + end + + should "send email" do + assert !ActionMailer::Base.deliveries.empty? + end + end + + context 'someone else suggestion' do + setup do + @suggestion = FactoryGirl.create(:suggestion) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/Suggestion has been updated/) + + should "update suggestion" do + assert_equal 2, @suggestion.versions.size + end + + should "send email" do + assert !ActionMailer::Base.deliveries.empty? + end end end + end + end + + [Phase.all - [Phase::ONE]].flatten.each do |phase| + context "During '#{phase.name}'" do + setup do + Phase.stubs(:current).returns(phase) + end + + context 'When visitor' do + context 'on #POST to create' do + setup do + post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + + should "save suggestion" do + assert !assigns(:suggestion).persisted? + end + end + + context 'on #POST to update' do + setup do + @suggestion = FactoryGirl.create(:suggestion) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You need to sign in or sign up before continuing/) + should "not update suggestion" do + assert_equal 1, @suggestion.versions.size + end + end + end + + context 'When viewer' do + setup do + session[:user_id] = @viewer.id + end + + context 'on #POST to create' do + setup do + post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + + should "not save suggestion" do + assert !assigns(:suggestion).persisted? + end + end + + context 'on #POST to update' do + setup do + @suggestion = FactoryGirl.create(:suggestion, :author => @viewer) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not update suggestion" do + assert_equal 1, @suggestion.versions.size + end + end + end + + context 'When proposer' do + setup do + session[:user_id] = @proposer.id + end + + context 'on #POST to create' do + setup do + post :create, :proposal_id => @proposal.to_param, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + + should "not save suggestion" do + assert !assigns(:suggestion).persisted? + end + end + + context 'on #POST to update' do + context 'own suggestion' do + setup do + @suggestion = FactoryGirl.create(:suggestion, :author => @proposer) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not update suggestion" do + assert_equal 1, @suggestion.versions.size + end + end + + context 'someone else suggestion' do + setup do + @suggestion = FactoryGirl.create(:suggestion) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/You are not authorized to access this page/) + + should "not update suggestion" do + assert_equal 1, @suggestion.versions.size + end + end + end + end + + context 'When moderator' do + setup do + @moderator = FactoryGirl.create(:user, :email => 'moderator@euruko2013.org') + session[:user_id] = @moderator + end + + context 'on #POST to update' do + context 'own suggestion' do + setup do + @suggestion = FactoryGirl.create(:suggestion, :author => @moderator) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/Suggestion has been updated/) + + should "update suggestion" do + assert_equal 2, @suggestion.versions.size + end + + should "send email" do + assert !ActionMailer::Base.deliveries.empty? + end + end + + context 'someone else suggestion' do + setup do + @suggestion = FactoryGirl.create(:suggestion) + put :update, :proposal_id => @proposal.to_param, :id => @suggestion.id, :suggestion => FactoryGirl.attributes_for(:suggestion) + end + + should assign_to(:proposal) { @proposal } + should assign_to(:suggestion) + should respond_with(:redirect) + should set_the_flash.to(/Suggestion has been updated/) + + should "update suggestion" do + assert_equal 2, @suggestion.versions.size + end + + should "send email" do + assert !ActionMailer::Base.deliveries.empty? + end + end + end + end + end end end \ No newline at end of file diff --git a/test/integration/proposal_suggestion_test.rb b/test/integration/proposal_suggestion_test.rb index 6cd0dc8..a02fec5 100644 --- a/test/integration/proposal_suggestion_test.rb +++ b/test/integration/proposal_suggestion_test.rb @@ -1,71 +1,76 @@ require "test_helper" class ProposalSuggestionTest < IntegrationTestCase - - context "Given a talk proposal" do - setup do - @proposer = FactoryGirl.create(:user) - @proposal = FactoryGirl.create(:proposal, :proposer => @proposer) - end - - context "a visitor viewing the proposal" do + [Phase::ONE].each do |phase| + context "During '#{phase.name}'" do setup do - visit proposal_path(@proposal) + Phase.stubs(:current).returns(phase) end - should "not be able to suggest anything" do - refute page.has_css?("form[action='#{proposal_suggestions_path(@proposal)}']") - end - - context 'when there are some suggestions already' do + context "Given a talk proposal" do setup do - @other_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :created_at => 2.days.ago, :updated_at => 2.days.ago) + @proposer = FactoryGirl.create(:user) + @proposal = FactoryGirl.create(:proposal, :proposer => @proposer) end - should "be able to subscribe to the rss feed of suggestions to the proposal" do - assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposal_path(@proposal, :format => :rss)}']") - visit proposal_path(@proposal, :format => :rss) - assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] + context "a visitor viewing the proposal" do + setup do + visit proposal_path(@proposal) + end + + should "not be able to suggest anything" do + refute page.has_css?("form[action='#{proposal_suggestions_path(@proposal)}']") + end + + context 'when there are some suggestions already' do + setup do + @other_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :created_at => 2.days.ago, :updated_at => 2.days.ago) + end + + should "be able to subscribe to the rss feed of suggestions to the proposal" do + assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposal_path(@proposal, :format => :rss)}']") + visit proposal_path(@proposal, :format => :rss) + assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] + end + + should 'see the existing suggestions in the feed' do + visit proposal_path(@proposal, :format => :rss) + assert page.has_xpath?('.//item/title', :text => "Suggestion from #{@other_suggestion.author.name} (@#{@other_suggestion.author.github_nickname})") + assert page.has_xpath?('.//item/description', :text => @other_suggestion.body) + end + + should "not be able to edit an existing suggestion of someone else" do + refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, @other_suggestion)}']") + end + end end - should 'see the existing suggestions in the feed' do - visit proposal_path(@proposal, :format => :rss) - assert page.has_xpath?('.//item/title', :text => "Suggestion from #{@other_suggestion.author.name} (@#{@other_suggestion.author.github_nickname})") - assert page.has_xpath?('.//item/description', :text => @other_suggestion.body) - end + context "a logged in user viewing the proposal" do + setup do + @me = FactoryGirl.create(:user) + sign_in @me + visit proposal_path(@proposal) + end - should "not be able to edit an existing suggestion of someone else" do - refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, @other_suggestion)}']") - end - end - end + should "be able to subscribe to the rss feed of suggestions to the proposal" do + assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposal_path(@proposal, :format => :rss)}']") + visit proposal_path(@proposal, :format => :rss) + assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] + end - context "a logged in user viewing the proposal" do - setup do - @me = FactoryGirl.create(:user) - sign_in @me - visit proposal_path(@proposal) - end + should "see a call to action asking for help to develop the proposal" do + assert page.has_content?("Help develop this into a good proposal") + end - should "be able to subscribe to the rss feed of suggestions to the proposal" do - assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposal_path(@proposal, :format => :rss)}']") - visit proposal_path(@proposal, :format => :rss) - assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] - end + should "be able to make a suggestion about the proposal" do + suggest "I think you should focus on the first bit, because that's going to be more interesting to newbies." - should "see a call to action asking for help to develop the proposal" do - assert page.has_content?("Help develop this into a good proposal") - end + assert_page_has_suggestion :body => "I think you should focus on the first bit, because that's going to be more interesting to newbies.", + :author => @me + end - should "be able to make a suggestion about the proposal" do - suggest "I think you should focus on the first bit, because that's going to be more interesting to newbies." - - assert_page_has_suggestion :body => "I think you should focus on the first bit, because that's going to be more interesting to newbies.", - :author => @me - end - - should "be able to make a suggestion about the proposal and preserve the markdown content when displaying it" do - suggest %{ + should "be able to make a suggestion about the proposal and preserve the markdown content when displaying it" do + suggest %{ 1. change the title - it's not really clear 2. put more emphasis on how you'd test your approach 3. cover this gem: http://rubygems.org/gems/sausage-mcmuffin @@ -73,130 +78,222 @@ class ProposalSuggestionTest < IntegrationTestCase Other than that, sounds great! } - within ".suggestions" do - assert page.has_css?("ol li", :text => "change the title - it's not really clear") - assert page.has_css?("ol li", :text => "put more emphasis on how you'd test your approach") - assert page.has_css?("ol li", :text => "cover this gem: http://rubygems.org/gems/sausage-mcmuffin") - assert page.has_css?("ol li a[href='http://rubygems.org/gems/sausage-mcmuffin']", :text => 'http://rubygems.org/gems/sausage-mcmuffin') - assert page.has_css?("p", :text => "Other than that, sounds great!") + within ".suggestions" do + assert page.has_css?("ol li", :text => "change the title - it's not really clear") + assert page.has_css?("ol li", :text => "put more emphasis on how you'd test your approach") + assert page.has_css?("ol li", :text => "cover this gem: http://rubygems.org/gems/sausage-mcmuffin") + assert page.has_css?("ol li a[href='http://rubygems.org/gems/sausage-mcmuffin']", :text => 'http://rubygems.org/gems/sausage-mcmuffin') + assert page.has_css?("p", :text => "Other than that, sounds great!") + end + end + + context 'when there are some suggestions already' do + setup do + @other_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :created_at => 2.days.ago, :updated_at => 2.days.ago) + end + + should "be able to subscribe to the rss feed of suggestions to the proposal" do + assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposal_path(@proposal, :format => :rss)}']") + visit proposal_path(@proposal, :format => :rss) + assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] + end + + should 'see the existing suggestions in the feed' do + visit proposal_path(@proposal, :format => :rss) + assert page.has_xpath?('.//item/title', :text => "Suggestion from #{@other_suggestion.author.name} (@#{@other_suggestion.author.github_nickname})") + assert page.has_xpath?('.//item/description', :text => @other_suggestion.body) + end + + should 'be able to add a new suggestion and see it in the feed at the top' do + suggest "I think you should focus on the first bit, because that's going to be more interesting to newbies." + + visit proposal_path(@proposal, :format => :rss) + + assert page.has_xpath?('.//item[position() = 2]/title', :text => "Suggestion from #{@other_suggestion.author.name} (@#{@other_suggestion.author.github_nickname})") + assert page.has_xpath?('.//item[position() = 2]/description', :text => @other_suggestion.body) + + assert page.has_xpath?('.//item[position() = 1]/title', :text => "Suggestion from #{@me.name} (@#{@me.github_nickname})") + assert page.has_xpath?('.//item[position() = 1]/description', :text => "I think you should focus on the first bit, because that's going to be more interesting to newbies.") + end + + should "not be able to edit an existing suggestion of someone else" do + refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, @other_suggestion)}']") + end + + should "not be able to edit an existing suggestion of their own" do + own_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @me) + visit proposal_path(@proposal) + + refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, own_suggestion)}']") + end + end + + should "anonymise suggestions by the proposer" do + suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) + visit proposal_path(@proposal) + + assert page.has_no_content?(@proposer.name) + assert page.has_content?("The proposal author") + end + + should "not be able to make an empty suggestion" do + suggest "" + i_am_warned_about Suggestion, :body, "can't be blank" + end + + should "be required to provide a substantial suggestion" do + suggest "x"*49 + i_am_warned_about Suggestion, :body, "should be a meaningful contribution or criticism (i.e. at least 50 characters)" + end + + should "not be able to make a '+1' suggestion" do + suggest "+1" + i_am_warned_about Suggestion, :body, "should contain some concrete suggestions about how to develop this proposal" + end + + should "not be able to make a '-1' suggestion" do + suggest "-1" + i_am_warned_about Suggestion, :body, "should contain some concrete suggestions about how to develop this proposal" + end end - end - context 'when there are some suggestions already' do - setup do - @other_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :created_at => 2.days.ago, :updated_at => 2.days.ago) - end + context "a proposer viewing their proposal" do + setup do + sign_in @proposer + visit proposal_path(@proposal) + end - should "be able to subscribe to the rss feed of suggestions to the proposal" do - assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposal_path(@proposal, :format => :rss)}']") - visit proposal_path(@proposal, :format => :rss) - assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] - end + should "see a call to action explaining anonymisation" do + assert page.has_content?("your identity will be masked from other visitors") + end - should 'see the existing suggestions in the feed' do - visit proposal_path(@proposal, :format => :rss) - assert page.has_xpath?('.//item/title', :text => "Suggestion from #{@other_suggestion.author.name} (@#{@other_suggestion.author.github_nickname})") - assert page.has_xpath?('.//item/description', :text => @other_suggestion.body) - end + should "see their suggestions identified as their own" do + suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) + visit proposal_path(@proposal) - should 'be able to add a new suggestion and see it in the feed at the top' do - suggest "I think you should focus on the first bit, because that's going to be more interesting to newbies." + assert page.has_content?("You respond") + end - visit proposal_path(@proposal, :format => :rss) + should "not be able to edit an existing suggestion of their own" do + own_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) + visit proposal_path(@proposal) - assert page.has_xpath?('.//item[position() = 2]/title', :text => "Suggestion from #{@other_suggestion.author.name} (@#{@other_suggestion.author.github_nickname})") - assert page.has_xpath?('.//item[position() = 2]/description', :text => @other_suggestion.body) + refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, own_suggestion)}']") + end - assert page.has_xpath?('.//item[position() = 1]/title', :text => "Suggestion from #{@me.name} (@#{@me.github_nickname})") - assert page.has_xpath?('.//item[position() = 1]/description', :text => "I think you should focus on the first bit, because that's going to be more interesting to newbies.") - end + should "not be able to edit an existing suggestion of someone else" do + other_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal) + visit proposal_path(@proposal) - should "not be able to edit an existing suggestion of someone else" do - refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, @other_suggestion)}']") + refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, other_suggestion)}']") + end end - should "not be able to edit an existing suggestion of their own" do - own_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @me) - visit proposal_path(@proposal) + context "a moderator viewing a proposal with suggestions" do + setup do + @suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :created_at => 2.days.ago, :updated_at => 2.days.ago) + sign_in FactoryGirl.create(:user, :email => 'moderator@euruko2013.org') + visit proposal_path(@proposal) + end - refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, own_suggestion)}']") + should "be able to edit the suggestion" do + assert page.has_css?("form[action='#{proposal_suggestion_path(@proposal, @suggestion)}']") + end end end + end + end - should "anonymise suggestions by the proposer" do - suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) - visit proposal_path(@proposal) - - assert page.has_no_content?(@proposer.name) - assert page.has_content?("The proposal author") + [Phase.all - [Phase::ONE]].flatten.each do |phase| + context "During '#{phase.name}'" do + setup do + Phase.stubs(:current).returns(phase) end - should "not be able to make an empty suggestion" do - suggest "" - i_am_warned_about Suggestion, :body, "can't be blank" - end + context "Given a talk proposal" do + setup do + @proposer = FactoryGirl.create(:user) + @proposal = FactoryGirl.create(:proposal, :proposer => @proposer) + end - should "be required to provide a substantial suggestion" do - suggest "x"*49 - i_am_warned_about Suggestion, :body, "should be a meaningful contribution or criticism (i.e. at least 50 characters)" - end + context "a visitor viewing the proposal" do + setup do + visit proposal_path(@proposal) + end - should "not be able to make a '+1' suggestion" do - suggest "+1" - i_am_warned_about Suggestion, :body, "should contain some concrete suggestions about how to develop this proposal" - end + should "not be able to suggest anything" do + refute page.has_css?("form[action='#{proposal_suggestions_path(@proposal)}']") + end + end - should "not be able to make a '-1' suggestion" do - suggest "-1" - i_am_warned_about Suggestion, :body, "should contain some concrete suggestions about how to develop this proposal" - end - end + context "a logged in user viewing the proposal" do + setup do + @me = FactoryGirl.create(:user) + sign_in @me + visit proposal_path(@proposal) + end - context "a proposer viewing their proposal" do - setup do - sign_in @proposer - visit proposal_path(@proposal) - end + should "not be able to suggest anything" do + refute page.has_css?("form[action='#{proposal_suggestions_path(@proposal)}']") + end - should "see a call to action explaining anonymisation" do - assert page.has_content?("your identity will be masked from other visitors") - end + should "anonymise suggestions by the proposer" do + suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) + visit proposal_path(@proposal) - should "see their suggestions identified as their own" do - suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) - visit proposal_path(@proposal) + assert page.has_no_content?(@proposer.name) + assert page.has_content?("The proposal author") + end + end - assert page.has_content?("You respond") - end + context "a proposer viewing their proposal" do + setup do + sign_in @proposer + visit proposal_path(@proposal) + end - should "not be able to edit an existing suggestion of their own" do - own_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) - visit proposal_path(@proposal) + should "see their suggestions identified as their own" do + suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) + visit proposal_path(@proposal) - refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, own_suggestion)}']") - end + assert page.has_content?("You respond") + end - should "not be able to edit an existing suggestion of someone else" do - other_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal) - visit proposal_path(@proposal) + should "not be able to edit an existing suggestion of their own" do + own_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :author => @proposer) + visit proposal_path(@proposal) - refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, other_suggestion)}']") - end - end + refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, own_suggestion)}']") + end - context "a moderator viewing a proposal with suggestions" do - setup do - @suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :created_at => 2.days.ago, :updated_at => 2.days.ago) - sign_in FactoryGirl.create(:user, :email => 'moderator@euruko2013.org') - visit proposal_path(@proposal) - end + should "not be able to edit an existing suggestion of someone else" do + other_suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal) + visit proposal_path(@proposal) - should "be able to edit the suggestion" do - assert page.has_css?("form[action='#{proposal_suggestion_path(@proposal, @suggestion)}']") + refute page.has_css?("form[action='#{proposal_suggestion_path(@proposal, other_suggestion)}']") + end + end + + context "a moderator viewing a proposal with suggestions" do + setup do + @suggestion = FactoryGirl.create(:suggestion, :proposal => @proposal, :created_at => 2.days.ago, :updated_at => 2.days.ago) + sign_in FactoryGirl.create(:user, :email => 'moderator@euruko2013.org') + visit proposal_path(@proposal) + end + + should "be able to edit the suggestion" do + assert page.has_css?("form[action='#{proposal_suggestion_path(@proposal, @suggestion)}']") + end + end end end end + + ######### + protected + ######### + def suggest(body) fill_in "suggestion[body]", :with => body click_button "Make your suggestion" diff --git a/test/integration/proposal_test.rb b/test/integration/proposal_test.rb index 3b3a077..afcdd78 100644 --- a/test/integration/proposal_test.rb +++ b/test/integration/proposal_test.rb @@ -1,215 +1,337 @@ - require "test_helper" class ProposalTest < IntegrationTestCase + [Phase::ONE].each do |phase| + context "During '#{phase.name}'" do + setup do + Phase.stubs(:current).returns(phase) + end - context "As a visitor to the site" do - should "not see a link to propose a talk" do - visit proposals_path - assert !page.has_content?("Propose talk"), "link to propose talk should not be present!" - end + context "As a visitor to the site" do + should "not see a link to propose a talk" do + visit proposals_path + assert !page.has_content?("Propose talk"), "link to propose talk should not be present!" + end - should "not be able to propose a talk" do - visit new_proposal_path - i_am_asked_to_sign_in - end + should "not be able to propose a talk" do + visit new_proposal_path + i_am_asked_to_sign_in + end - context "given a proposal already exists" do - setup do - @proposal = FactoryGirl.create(:proposal, :title => "Ruby Muby Schmuby") - end + context "given a proposal already exists" do + setup do + @proposal = FactoryGirl.create(:proposal, :title => "Ruby Muby Schmuby") + end - should "be able to see the list of proposals" do - visit proposals_path - assert page.has_css?('ul.proposals') - end + should "be able to see the list of proposals" do + visit proposals_path + assert page.has_css?('ul.proposals') + end - should "be able to subscribe to the rss feed of proposals" do - visit proposals_path - assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposals_path(:format => :rss)}']") - visit proposals_path(:format => :rss) - assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] - assert page.has_xpath?('.//item/title', :text => @proposal.title) - end + should "be able to subscribe to the rss feed of proposals" do + visit proposals_path + assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposals_path(:format => :rss)}']") + visit proposals_path(:format => :rss) + assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] + assert page.has_xpath?('.//item/title', :text => @proposal.title) + end - should "be able to read individual proposals" do - visit proposals_path - click_link "Ruby Muby Schmuby" - assert_page_has_proposal :title => "Ruby Muby Schmuby" - end + should "be able to read individual proposals" do + visit proposals_path + click_link "Ruby Muby Schmuby" + assert_page_has_proposal :title => "Ruby Muby Schmuby" + end - should "not see a link to edit a proposal" do - visit proposals_path - click_link "Ruby Muby Schmuby" - assert !page.has_content?("Edit proposal"), "link to edit proposal should not be present" - end + should "not see a link to edit a proposal" do + visit proposals_path + click_link "Ruby Muby Schmuby" + assert !page.has_content?("Edit proposal"), "link to edit proposal should not be present" + end - should "not be able to edit a proposal" do - visit edit_proposal_path(@proposal) - i_am_asked_to_sign_in - end + should "not be able to edit a proposal" do + visit edit_proposal_path(@proposal) + i_am_asked_to_sign_in + end - should "my page view be tracked" do - assert_difference(lambda { @proposal.impressionist_count }, 1) do - visit proposal_path(@proposal) + should "my page view be tracked" do + assert_difference(lambda { @proposal.impressionist_count }, 1) do + visit proposal_path(@proposal) + end + end end end - end - end - context "Given I am logged in" do - setup do - @user = FactoryGirl.create(:user) - sign_in @user - end + context "Given I am logged in" do + setup do + @user = FactoryGirl.create(:user) + sign_in @user + end - context "and I propose a talk with all the required details" do - setup { propose_talk :title => "My Amazing Talk", :description => 'This talk is amazing.' } - - should "be able to see my proposal on the site" do - visit proposals_path - click_link "My Amazing Talk" - assert_page_has_proposal \ - :title => "My Amazing Talk", - :description => 'This talk is amazing.', - :proposer => @user - assert !page.has_css?('script', text: 'pwned') - end + context "and I propose a talk with all the required details" do + setup { propose_talk :title => "My Amazing Talk", :description => 'This talk is amazing.' } - should "be able to withdraw my proposal" do - visit proposals_path - click_link "My Amazing Talk" - click_link "Withdraw proposal" + should "be able to see my proposal on the site" do + visit proposals_path + click_link "My Amazing Talk" + assert_page_has_proposal \ + :title => "My Amazing Talk", + :description => 'This talk is amazing.', + :proposer => @user + assert !page.has_css?('script', text: 'pwned') + end - assert_proposal_withdrawn "My Amazing Talk" - end + should "be able to withdraw my proposal" do + visit proposals_path + click_link "My Amazing Talk" + click_link "Withdraw proposal" - context "and I withdraw my proposal" do - setup do - visit proposals_path - click_link "My Amazing Talk" - click_link "Withdraw proposal" - end + assert_proposal_withdrawn "My Amazing Talk" + end - should "be able to re-publish my withdrawn proposal" do - visit proposals_path - click_link "My Amazing Talk" - click_link "Re-publish proposal" - assert_proposal_republished - end - end - context "and then edit my proposal" do - setup do - visit proposals_path - click_link "My Amazing Talk" - click_link "Edit proposal" + context "and I withdraw my proposal" do + setup do + visit proposals_path + click_link "My Amazing Talk" + click_link "Withdraw proposal" + end + + should "be able to re-publish my withdrawn proposal" do + visit proposals_path + click_link "My Amazing Talk" + click_link "Re-publish proposal" + assert_proposal_republished + end + end + context "and then edit my proposal" do + setup do + visit proposals_path + click_link "My Amazing Talk" + click_link "Edit proposal" + end + + context "with valid content" do + setup do + fill_in "Title", :with => "My Even More Amazing Talk" + fill_in "Description", :with => "This talk is wildly amazing." + click_button "Update proposal" + end + + should "update the proposal" do + visit proposals_path + click_link "My Even More Amazing Talk" + assert_page_has_proposal \ + :title => "My Even More Amazing Talk", + :description => 'This talk is wildly amazing.', + :proposer => @user + end + end + + context "and remove the title" do + setup do + fill_in "Title", :with => "" + click_button "Update proposal" + end + + should "alert me that the title is required" do + i_am_warned_about Proposal, :title, "can't be blank" + end + end + end end - context "with valid content" do + context "and I propose a talk with markdown-formatted description" do setup do - fill_in "Title", :with => "My Even More Amazing Talk" - fill_in "Description", :with => "This talk is wildly amazing." - click_button "Update proposal" + propose_talk :title => "My Amazing Talk", :description => %{ +# A moment in time + +blah blah blah + }.strip end - should "update the proposal" do + should "be able to see my proposal with a formatted description" do visit proposals_path - click_link "My Even More Amazing Talk" - assert_page_has_proposal \ - :title => "My Even More Amazing Talk", - :description => 'This talk is wildly amazing.', - :proposer => @user + click_link "My Amazing Talk" + within_proposal do + within(".description") do + assert page.has_css?('h1', :text => 'A moment in time') + assert page.has_css?('p', :text => 'blah blah blah') + end + end end end - context "and remove the title" do - setup do - fill_in "Title", :with => "" - click_button "Update proposal" - end + context "and I propose a talk without a title" do + setup { propose_talk :title => nil } should "alert me that the title is required" do i_am_warned_about Proposal, :title, "can't be blank" end end - end - end - context "and I propose a talk with markdown-formatted description" do - setup do - propose_talk :title => "My Amazing Talk", :description => %{ + context "and a proposal from another user exists" do + setup do + @other_persons_proposal = FactoryGirl.create(:proposal, :title => "Another talk") + end + + should "not see a link to edit that proposal" do + visit proposals_path + click_link "Another talk" + assert !page.has_content?("Edit proposal"), "link to edit proposal should not be present" + end + + should "not be able to edit that proposal" do + visit edit_proposal_path(@other_persons_proposal) + i_am_not_authorized + end + end + + context "and there are some proposals (mine and others)" do + setup do + propose_talk :title => "My Amazing Talk", :description => %{ # A moment in time blah blah blah }.strip - end + @other_persons_proposal = FactoryGirl.create(:proposal, :title => "Another talk", :created_at => 3.days.ago) + end - should "be able to see my proposal with a formatted description" do - visit proposals_path - click_link "My Amazing Talk" - within_proposal do - within(".description") do - assert page.has_css?('h1', :text => 'A moment in time') - assert page.has_css?('p', :text => 'blah blah blah') + should "be able to subscribe to the rss feed of proposals" do + visit proposals_path + assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposals_path(:format => :rss)}']") + visit proposals_path(:format => :rss) + assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] end - end - end - end - context "and I propose a talk without a title" do - setup { propose_talk :title => nil } + should 'have my talk and the other talk in the feed, in newest first order' do + visit proposals_path(:format => :rss) + assert page.has_xpath?('.//item[position() = 2]/title', :text => @other_persons_proposal.title) + assert page.has_xpath?('.//item[position() = 1]/title', :text => "My Amazing Talk") + end + + should "be able to see other persons proposal and my page view be tracked" do + assert_difference(lambda { @other_persons_proposal.impressionist_count }, 1) do + visit proposal_path(@other_persons_proposal) + end - should "alert me that the title is required" do - i_am_warned_about Proposal, :title, "can't be blank" + assert_equal 1, @other_persons_proposal.impressionist_count(user_id: @user.id) + end + end end end + end - context "and a proposal from another user exists" do + [Phase.all - [Phase::ONE, Phase::INTERLUDE]].flatten.each do |phase| + context "During '#{phase.name}'" do setup do - @other_persons_proposal = FactoryGirl.create(:proposal, :title => "Another talk") + Phase.stubs(:current).returns(phase) end - should "not see a link to edit that proposal" do - visit proposals_path - click_link "Another talk" - assert !page.has_content?("Edit proposal"), "link to edit proposal should not be present" - end + context "As a visitor to the site" do + should "not see a link to propose a talk" do + visit proposals_path + assert !page.has_content?("Propose talk"), "link to propose talk should not be present!" + end - should "not be able to edit that proposal" do - visit edit_proposal_path(@other_persons_proposal) - i_am_not_authorized - end - end + should "not be able to propose a talk" do + visit new_proposal_path + i_am_asked_to_sign_in + end - context "and there are some proposals (mine and others)" do - setup do - propose_talk :title => "My Amazing Talk", :description => %{ -# A moment in time + context "given a proposal already exists" do + setup do + @proposal = FactoryGirl.create(:proposal, :title => "Ruby Muby Schmuby") + end -blah blah blah - }.strip - @other_persons_proposal = FactoryGirl.create(:proposal, :title => "Another talk", :created_at => 3.days.ago) - end + should "be able to see the list of proposals" do + visit proposals_path + assert page.has_css?('ul.proposals') + end - should "be able to subscribe to the rss feed of proposals" do - visit proposals_path - assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposals_path(:format => :rss)}']") - visit proposals_path(:format => :rss) - assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] - end + should "be able to subscribe to the rss feed of proposals" do + visit proposals_path + assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposals_path(:format => :rss)}']") + visit proposals_path(:format => :rss) + assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] + assert page.has_xpath?('.//item/title', :text => @proposal.title) + end - should 'have my talk and the other talk in the feed, in newest first order' do - visit proposals_path(:format => :rss) - assert page.has_xpath?('.//item[position() = 2]/title', :text => @other_persons_proposal.title) - assert page.has_xpath?('.//item[position() = 1]/title', :text => "My Amazing Talk") + should "be able to read individual proposals" do + visit proposals_path + click_link "Ruby Muby Schmuby" + assert_page_has_proposal :title => "Ruby Muby Schmuby" + end + + should "not see a link to edit a proposal" do + visit proposals_path + click_link "Ruby Muby Schmuby" + assert !page.has_content?("Edit proposal"), "link to edit proposal should not be present" + end + + should "not be able to edit a proposal" do + visit edit_proposal_path(@proposal) + i_am_asked_to_sign_in + end + + should "my page view be tracked" do + assert_difference(lambda { @proposal.impressionist_count }, 1) do + visit proposal_path(@proposal) + end + end + end end - should "be able to see other persons proposal and my page view be tracked" do - assert_difference(lambda { @other_persons_proposal.impressionist_count }, 1) do - visit proposal_path(@other_persons_proposal) + context "Given I am logged in" do + setup do + @user = FactoryGirl.create(:user) + sign_in @user + end + + should "not see a link to propose a talk" do + visit proposals_path + assert !page.has_content?("Propose talk"), "link to propose talk should not be present!" + end + + should "not be able to propose a talk" do + visit new_proposal_path + i_am_not_authorized end - assert_equal 1, @other_persons_proposal.impressionist_count(user_id: @user.id) + context "given a proposal already exists" do + setup do + @proposal = FactoryGirl.create(:proposal, :title => "Ruby Muby Schmuby") + end + + should "be able to see the list of proposals" do + visit proposals_path + assert page.has_css?('ul.proposals') + end + + should "be able to subscribe to the rss feed of proposals" do + visit proposals_path + assert page.has_css?("link[rel='alternate'][type='application/rss+xml'][href$='#{proposals_path(:format => :rss)}']") + visit proposals_path(:format => :rss) + assert_match %r{application/rss\+xml}, page.response_headers['Content-Type'] + assert page.has_xpath?('.//item/title', :text => @proposal.title) + end + + should "be able to read individual proposals" do + visit proposals_path + click_link "Ruby Muby Schmuby" + assert_page_has_proposal :title => "Ruby Muby Schmuby" + end + + should "not see a link to edit a proposal" do + visit proposals_path + click_link "Ruby Muby Schmuby" + assert !page.has_content?("Edit proposal"), "link to edit proposal should not be present" + end + + should "my page view be tracked" do + assert_difference(lambda { @proposal.impressionist_count }, 1) do + visit proposal_path(@proposal) + end + end + end end end end diff --git a/test/integration/proposal_voting_test.rb b/test/integration/proposal_voting_test.rb index 3305155..4ba0afb 100644 --- a/test/integration/proposal_voting_test.rb +++ b/test/integration/proposal_voting_test.rb @@ -1,85 +1,159 @@ require "test_helper" class ProposalVotingTest < IntegrationTestCase - - context "Given a talk proposal" do - setup do - @proposer = FactoryGirl.create(:user) - @proposal = FactoryGirl.create(:proposal, :proposer => @proposer) - end - - context "a visitor viewing the proposal" do + [Phase::ONE, Phase::INTERLUDE].each do |phase| + context "During '#{phase.name}'" do setup do - visit proposal_path(@proposal) + Phase.stubs(:current).returns(phase) end - should "not be able to vote anything" do - refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") - refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") - end - end + context "Given a talk proposal" do + setup do + @proposer = FactoryGirl.create(:user) + @proposal = FactoryGirl.create(:proposal, :proposer => @proposer) + end - context "a logged in user viewing the proposal" do - setup do - @me = FactoryGirl.create(:user) - sign_in @me - visit proposal_path(@proposal) - end + context "a visitor viewing the proposal" do + setup do + visit proposal_path(@proposal) + end - should "see a call to action asking to vote for the proposal" do - assert page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") - assert page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") - end + should "not be able to vote anything" do + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") + end + end + + context "a logged in user viewing the proposal" do + setup do + @me = FactoryGirl.create(:user) + sign_in @me + visit proposal_path(@proposal) + end + + should "see a call to action asking to vote for the proposal" do + assert page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") + assert page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") + end + + should "be able to vote up a proposal" do + vote_up + assert_equal 1, @proposal.votes_for + i_am_alerted 'Thank you for casting your vote. Your vote has been captured!' + end + + should "be able to vote down" do + vote_down + assert_equal 1, @proposal.votes_against + i_am_alerted 'Thank you for casting your vote. Your vote has been captured!' + end + + context 'who has already voted for the proposal' do + setup do + @me.vote_for(@proposal) + visit proposal_path(@proposal) + end + + should "see a message informing me about what I have voted" do + assert page.has_content?('You have already voted up this proposal.') + end + + should "be able to withdraw my vote" do + click_link 'Changed your mind?' + vote_clear + assert_equal 0, @proposal.votes_for + assert_equal 0, @proposal.votes_against + i_am_alerted 'Your vote has been cleared. Remember to come back to vote again once you are sure!' + end + + should "be able to change my mind" do + click_link 'Changed your mind?' + vote_down + assert_equal 0, @proposal.votes_for + assert_equal 1, @proposal.votes_against + i_am_alerted 'Thank you for casting your vote. Your vote has been captured!' + end + end + end + + context "a proposer viewing their proposal" do + setup do + sign_in @proposer + visit proposal_path(@proposal) + end - should "be able to vote up a proposal" do - vote_up - assert_equal 1, @proposal.votes_for - i_am_alerted 'Thank you for casting your vote. Your vote has been captured!' + should "not see a call to action asking to vote for the proposal" do + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") + end + end end + end + end - should "be able to vote down" do - vote_down - assert_equal 1, @proposal.votes_against - i_am_alerted 'Thank you for casting your vote. Your vote has been captured!' + [Phase.all - [Phase::ONE, Phase::INTERLUDE]].flatten.each do |phase| + context "During '#{phase.name}'" do + setup do + Phase.stubs(:current).returns(phase) end - context 'who has already voted for the proposal' do + context "Given a talk proposal" do setup do - @me.vote_for(@proposal) - visit proposal_path(@proposal) + @proposer = FactoryGirl.create(:user) + @proposal = FactoryGirl.create(:proposal, :proposer => @proposer) end - should "see a message informing me about what I have voted" do - assert page.has_content?('You have already voted up this proposal.') - end + context "a visitor viewing the proposal" do + setup do + visit proposal_path(@proposal) + end - should "be able to withdraw my vote" do - click_link 'Changed your mind?' - vote_clear - assert_equal 0, @proposal.votes_for - assert_equal 0, @proposal.votes_against - i_am_alerted 'Your vote has been cleared. Remember to come back to vote again once you are sure!' + should "not be able to vote anything" do + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") + end end - should "be able to change my mind" do - click_link 'Changed your mind?' - vote_down - assert_equal 0, @proposal.votes_for - assert_equal 1, @proposal.votes_against - i_am_alerted 'Thank you for casting your vote. Your vote has been captured!' + context "a logged in user viewing the proposal" do + setup do + @me = FactoryGirl.create(:user) + sign_in @me + visit proposal_path(@proposal) + end + + should "not be able to vote anything" do + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") + end + + context 'who has already voted for the proposal' do + setup do + @me.vote_for(@proposal) + visit proposal_path(@proposal) + end + + should "not see a message informing me about what I have voted" do + assert !page.has_content?('You have already voted up this proposal.') + end + + should "not be able to vote anything" do + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") + end + end end - end - end - context "a proposer viewing their proposal" do - setup do - sign_in @proposer - visit proposal_path(@proposal) - end + context "a proposer viewing their proposal" do + setup do + sign_in @proposer + visit proposal_path(@proposal) + end - should "not see a call to action asking to vote for the proposal" do - refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") - refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") + should "not see a call to action asking to vote for the proposal" do + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :up)}']") + refute page.has_css?("a[href='#{vote_proposal_path(@proposal, :vote => :down)}']") + end + end end end end