diff options
Diffstat (limited to 'spec')
52 files changed, 3911 insertions, 1182 deletions
diff --git a/spec/controllers/admin_censor_rule_controller_spec.rb b/spec/controllers/admin_censor_rule_controller_spec.rb index 4df56a92b..68eaecd6a 100644 --- a/spec/controllers/admin_censor_rule_controller_spec.rb +++ b/spec/controllers/admin_censor_rule_controller_spec.rb @@ -5,76 +5,68 @@ describe AdminCensorRuleController do describe 'GET new' do - it 'returns a successful response' do - get :new - expect(response).to be_success - end + context 'request_id param' do - it 'initializes a new censor rule' do - get :new - expect(assigns[:censor_rule]).to be_new_record - end + before do + @info_request = FactoryGirl.create(:info_request) + get :new, :request_id => @info_request.id, :name_prefix => 'request_' + end - it 'renders the correct template' do - get :new - expect(response).to render_template('new') - end + it 'returns a successful response' do + expect(response).to be_success + end - it 'sets the URL for the form to POST to' do - get :new - expect(assigns[:form_url]).to eq(admin_rule_create_path) - end + it 'initializes a new censor rule' do + expect(assigns[:censor_rule]).to be_new_record + end - context 'info_request_id param' do + it 'renders the correct template' do + expect(response).to render_template('new') + end - it 'finds an info request if the info_request_id param is supplied' do - info_request = FactoryGirl.create(:info_request) - get :new, :info_request_id => info_request.id - expect(assigns[:info_request]).to eq(info_request) + it 'finds an info request if the request_id param is supplied' do + expect(assigns[:info_request]).to eq(@info_request) end it 'associates the info request with the new censor rule' do - info_request = FactoryGirl.create(:info_request) - get :new, :info_request_id => info_request.id - expect(assigns[:censor_rule].info_request).to eq(info_request) + expect(assigns[:censor_rule].info_request).to eq(@info_request) end it 'sets the URL for the form to POST to' do - info_request = FactoryGirl.create(:info_request) - get :new, :info_request_id => info_request.id - expect(assigns[:form_url]).to eq(admin_info_request_censor_rules_path(info_request)) - end - - it 'does not find an info request if no info_request_id param is supplied' do - get :new - expect(assigns[:info_request]).to be_nil + expect(assigns[:form_url]).to eq(admin_request_censor_rules_path(@info_request)) end end context 'user_id param' do + before do + @user = FactoryGirl.create(:user) + get :new, :user_id => @user.id, :name_prefix => 'user_' + end + + it 'returns a successful response' do + expect(response).to be_success + end + + it 'initializes a new censor rule' do + expect(assigns[:censor_rule]).to be_new_record + end + + it 'renders the correct template' do + expect(response).to render_template('new') + end + it 'finds a user if the user_id param is supplied' do - user = FactoryGirl.create(:user) - get :new, :user_id => user.id - expect(assigns[:censor_user]).to eq(user) + expect(assigns[:censor_user]).to eq(@user) end it 'associates the user with the new censor rule' do - user = FactoryGirl.create(:user) - get :new, :user_id => user.id - expect(assigns[:censor_rule].user).to eq(user) + expect(assigns[:censor_rule].user).to eq(@user) end it 'sets the URL for the form to POST to' do - user = FactoryGirl.create(:user) - get :new, :user_id => user.id - expect(assigns[:form_url]).to eq(admin_user_censor_rules_path(user)) - end - - it 'does not find a user if no user_id param is supplied' do - get :new - expect(assigns[:censor_user]).to be_nil + expect(assigns[:form_url]).to eq(admin_user_censor_rules_path(@user)) end end @@ -83,256 +75,292 @@ describe AdminCensorRuleController do describe 'POST create' do - before(:each) do - @censor_rule_params = FactoryGirl.build(:global_censor_rule).serializable_hash - # last_edit_editor gets set in the controller - @censor_rule_params.delete(:last_edit_editor) - end - - it 'sets the last_edit_editor to the current admin' do - post :create, :censor_rule => @censor_rule_params - expect(assigns[:censor_rule].last_edit_editor).to eq('*unknown*') - end + context 'request_id param' do - it 'sets the URL for the form to POST to' do - post :create, :censor_rule => @censor_rule_params - expect(assigns[:form_url]).to eq(admin_rule_create_path) - end + before(:each) do + @censor_rule_params = FactoryGirl.build(:info_request_censor_rule).serializable_hash + # last_edit_editor gets set in the controller + @censor_rule_params.delete(:last_edit_editor) + @info_request = FactoryGirl.create(:info_request) + post :create, :request_id => @info_request.id, + :censor_rule => @censor_rule_params, + :name_prefix => 'request_' + end - context 'info_request_id param' do + it 'sets the last_edit_editor to the current admin' do + expect(assigns[:censor_rule].last_edit_editor).to eq('*unknown*') + end - it 'finds an info request if the info_request_id param is supplied' do - info_request = FactoryGirl.create(:info_request) - post :create, :info_request_id => info_request.id, - :censor_rule => @censor_rule_params - expect(assigns[:info_request]).to eq(info_request) + it 'finds an info request if the request_id param is supplied' do + expect(assigns[:info_request]).to eq(@info_request) end it 'associates the info request with the new censor rule' do - info_request = FactoryGirl.create(:info_request) - post :create, :info_request_id => info_request.id, - :censor_rule => @censor_rule_params - expect(assigns[:censor_rule].info_request).to eq(info_request) + expect(assigns[:censor_rule].info_request).to eq(@info_request) end it 'sets the URL for the form to POST to' do - info_request = FactoryGirl.create(:info_request) - post :create, :info_request_id => info_request.id, - :censor_rule => @censor_rule_params - expect(assigns[:form_url]).to eq(admin_info_request_censor_rules_path(info_request)) + expect(assigns[:form_url]).to eq(admin_request_censor_rules_path(@info_request)) end - it 'does not find an info request if no info_request_id param is supplied' do - post :create, :censor_rule => @censor_rule_params - expect(assigns[:info_request]).to be_nil - end + context 'successfully saving the censor rule' do - end + it 'persists the censor rule' do + post :create, :censor_rule => @censor_rule_params, + :request_id => @info_request.id, + :name_prefix => 'request_' + expect(assigns[:censor_rule]).to be_persisted + end - context 'user_id param' do + it 'confirms the censor rule is created' do + post :create, :censor_rule => @censor_rule_params, + :request_id => @info_request.id, + :name_prefix => 'request_' + msg = 'CensorRule was successfully created.' + expect(flash[:notice]).to eq(msg) + end - it 'finds a user if the user_id param is supplied' do - user = FactoryGirl.create(:user) - post :create, :user_id => user.id, - :censor_rule => @censor_rule_params - expect(assigns[:censor_user]).to eq(user) - end + it 'purges the cache for the info request' do + @controller.should_receive(:expire_for_request). + with(@info_request) - it 'associates the user with the new censor rule' do - user = FactoryGirl.create(:user) - post :create, :user_id => user.id, - :censor_rule => @censor_rule_params - expect(assigns[:censor_rule].user).to eq(user) - end + post :create, :censor_rule => @censor_rule_params, + :request_id => @info_request.id, + :name_prefix => 'request_' + end - it 'sets the URL for the form to POST to' do - user = FactoryGirl.create(:user) - post :create, :user_id => user.id, - :censor_rule => @censor_rule_params - expect(assigns[:form_url]).to eq(admin_user_censor_rules_path(user)) + it 'redirects to the associated info request' do + post :create, :censor_rule => @censor_rule_params, + :request_id => @info_request.id, + :name_prefix => 'request_' + expect(response).to redirect_to( + admin_request_path(assigns[:censor_rule].info_request) + ) + end end - it 'does not find a user if no user_id param is supplied' do - post :create, :censor_rule => @censor_rule_params - expect(assigns[:censor_user]).to be_nil - end + context 'unsuccessfully saving the censor rule' do + + before(:each) do + CensorRule.any_instance.stub(:save).and_return(false) + end + + it 'does not persist the censor rule' do + post :create, :censor_rule => @censor_rule_params, + :request_id => @info_request.id, + :name_prefix => 'request_' + expect(assigns[:censor_rule]).to be_new_record + end + it 'renders the form' do + post :create, :censor_rule => @censor_rule_params, + :request_id => @info_request.id, + :name_prefix => 'request_' + expect(response).to render_template('new') + end + + end end - context 'successfully saving the censor rule' do + context 'user_id param' do before(:each) do - CensorRule.any_instance.stub(:save).and_return(true) + @censor_rule_params = FactoryGirl.build(:user_censor_rule).serializable_hash + # last_edit_editor gets set in the controller + @censor_rule_params.delete(:last_edit_editor) + @user = FactoryGirl.create(:user) + post :create, :user_id => @user.id, + :censor_rule => @censor_rule_params, + :name_prefix => 'user_' end - it 'persists the censor rule' do - pending("This raises an internal error in most cases") - post :create, :censor_rule => @censor_rule_params - expect(assigns[:censor_rule]).to be_persisted + it 'sets the last_edit_editor to the current admin' do + expect(assigns[:censor_rule].last_edit_editor).to eq('*unknown*') end - it 'confirms the censor rule is created' do - pending("This raises an internal error in most cases") - post :create, :censor_rule => @censor_rule_params - msg = 'CensorRule was successfully created.' - expect(flash[:notice]).to eq(msg) + it 'finds a user if the user_id param is supplied' do + expect(assigns[:censor_user]).to eq(@user) end - it 'raises an error after creating the rule' do - expect { - post :create, :censor_rule => @censor_rule_params - }.to raise_error 'internal error' + it 'associates the user with the new censor rule' do + expect(assigns[:censor_rule].user).to eq(@user) end - context 'a CensorRule with an associated InfoRequest' do + it 'sets the URL for the form to POST to' do + expect(assigns[:form_url]).to eq(admin_user_censor_rules_path(@user)) + end - before(:each) do - @censor_rule_params = FactoryGirl.build(:info_request_censor_rule).serializable_hash - # last_edit_editor gets set in the controller - @censor_rule_params.delete(:last_edit_editor) - end + context 'successfully saving the censor rule' do - it 'purges the cache for the info request' do + it 'purges the cache for the info request' do censor_rule = CensorRule.new(@censor_rule_params) - @controller.should_receive(:expire_for_request). - with(censor_rule.info_request) + @controller.should_receive(:expire_requests_for_user). + with(@user) - post :create, :censor_rule => @censor_rule_params + post :create, :censor_rule => @censor_rule_params, + :user_id => @user.id, + :name_prefix => 'user_' end it 'redirects to the associated info request' do - post :create, :censor_rule => @censor_rule_params + post :create, :censor_rule => @censor_rule_params, + :user_id => @user.id, + :name_prefix => 'user_' expect(response).to redirect_to( - admin_request_show_path(assigns[:censor_rule].info_request) + admin_user_path(assigns[:censor_rule].user) ) end end - context 'a CensorRule with an associated User' do + context 'unsuccessfully saving the censor rule' do before(:each) do - @censor_rule_params = FactoryGirl.build(:user_censor_rule).serializable_hash - # last_edit_editor gets set in the controller - @censor_rule_params.delete(:last_edit_editor) + CensorRule.any_instance.stub(:save).and_return(false) end - it 'purges the cache for the info request' do - censor_rule = CensorRule.new(@censor_rule_params) - @controller.should_receive(:expire_requests_for_user). - with(censor_rule.user) - - post :create, :censor_rule => @censor_rule_params + it 'does not persist the censor rule' do + post :create, :censor_rule => @censor_rule_params, + :user_id => @user.id, + :name_prefix => 'user_' + expect(assigns[:censor_rule]).to be_new_record end - it 'redirects to the associated info request' do - post :create, :censor_rule => @censor_rule_params - expect(response).to redirect_to( - admin_user_show_path(assigns[:censor_rule].user) - ) + it 'renders the form' do + post :create, :censor_rule => @censor_rule_params, + :user_id => @user.id, + :name_prefix => 'user_' + expect(response).to render_template('new') end end end - context 'unsuccessfully saving the censor rule' do + end + + describe 'GET edit' do + + context 'a CensorRule with an associated InfoRequest' do before(:each) do - CensorRule.any_instance.stub(:save).and_return(false) + @censor_rule = FactoryGirl.create(:info_request_censor_rule) end - it 'does not persist the censor rule' do - post :create, :censor_rule => @censor_rule_params - expect(assigns[:censor_rule]).to be_new_record + it 'returns a successful response' do + get :edit, :id => @censor_rule.id + expect(response).to be_success end - it 'renders the form' do - post :create, :censor_rule => @censor_rule_params - expect(response).to render_template('new') + it 'renders the correct template' do + get :edit, :id => @censor_rule.id + expect(response).to render_template('edit') + end + + it 'finds the correct censor rule to edit' do + get :edit, :id => @censor_rule.id + expect(assigns[:censor_rule]).to eq(@censor_rule) end end - end + context 'a CensorRule with an associated User' do - describe 'GET edit' do + before(:each) do + @censor_rule = FactoryGirl.create(:user_censor_rule) + end - before(:each) do - @censor_rule = FactoryGirl.create(:global_censor_rule) - end + it 'returns a successful response' do + get :edit, :id => @censor_rule.id + expect(response).to be_success + end - it 'returns a successful response' do - get :edit, :id => @censor_rule.id - expect(response).to be_success - end + it 'renders the correct template' do + get :edit, :id => @censor_rule.id + expect(response).to render_template('edit') + end + + it 'finds the correct censor rule to edit' do + get :edit, :id => @censor_rule.id + expect(assigns[:censor_rule]).to eq(@censor_rule) + end - it 'renders the correct template' do - get :edit, :id => @censor_rule.id - expect(response).to render_template('edit') end - it 'finds the correct censor rule to edit' do - get :edit, :id => @censor_rule.id - expect(assigns[:censor_rule]).to eq(@censor_rule) + context 'when editing a global rule' do + + before(:each) do + @censor_rule = FactoryGirl.create(:global_censor_rule) + end + + it 'shows an error notice' do + get :edit, :id => @censor_rule.id + flash[:notice].should == 'Only user and request censor rules can be edited' + end + + it 'redirects to the admin index' do + get :edit, :id => @censor_rule.id + expect(response).to redirect_to(admin_general_index_path) + end + end end describe 'PUT update' do - before(:each) do - @censor_rule = FactoryGirl.create(:global_censor_rule) - end + context 'a global CensorRule' do - it 'finds the correct censor rule to edit' do - put :update, :id => @censor_rule.id, - :censor_rule => { :text => 'different text' } + before(:each) do + @censor_rule = FactoryGirl.create(:global_censor_rule) + end - expect(assigns[:censor_rule]).to eq(@censor_rule) - end + it 'shows an error notice' do + get :edit, :id => @censor_rule.id + flash[:notice].should == 'Only user and request censor rules can be edited' + end - it 'sets the last_edit_editor to the current admin' do - put :update, :id => @censor_rule.id, - :censor_rule => { :text => 'different text' } + it 'redirects to the admin index' do + get :edit, :id => @censor_rule.id + expect(response).to redirect_to(admin_general_index_path) + end - expect(assigns[:censor_rule].last_edit_editor).to eq('*unknown*') end - context 'successfully saving the censor rule' do + context 'a CensorRule with an associated InfoRequest' do before(:each) do - CensorRule.any_instance.stub(:save).and_return(true) + @censor_rule = FactoryGirl.create(:info_request_censor_rule) end - it 'updates the censor rule' do - pending("This raises an internal error in most cases") + it 'finds the correct censor rule to edit' do put :update, :id => @censor_rule.id, :censor_rule => { :text => 'different text' } - @censor_rule.reload - expect(@censor_rule.text).to eq('different text') + + expect(assigns[:censor_rule]).to eq(@censor_rule) end - it 'confirms the censor rule is updated' do - pending("This raises an internal error in most cases") + it 'sets the last_edit_editor to the current admin' do put :update, :id => @censor_rule.id, :censor_rule => { :text => 'different text' } - msg = 'CensorRule was successfully updated.' - expect(flash[:notice]).to eq(msg) + expect(assigns[:censor_rule].last_edit_editor).to eq('*unknown*') end - it 'raises an error after updating the rule' do - expect { + context 'successfully saving the censor rule' do + + it 'updates the censor rule' do put :update, :id => @censor_rule.id, :censor_rule => { :text => 'different text' } - }.to raise_error 'internal error' - end - - context 'a CensorRule with an associated InfoRequest' do + @censor_rule.reload + expect(@censor_rule.text).to eq('different text') + end - before(:each) do - @censor_rule = FactoryGirl.create(:info_request_censor_rule) + it 'confirms the censor rule is updated' do + put :update, :id => @censor_rule.id, + :censor_rule => { :text => 'different text' } + msg = 'CensorRule was successfully updated.' + expect(flash[:notice]).to eq(msg) end it 'purges the cache for the info request' do @@ -348,87 +376,137 @@ describe AdminCensorRuleController do :censor_rule => { :text => 'different text' } expect(response).to redirect_to( - admin_request_show_path(assigns[:censor_rule].info_request) + admin_request_path(assigns[:censor_rule].info_request) ) end end - context 'a CensorRule with an associated User' do + context 'unsuccessfully saving the censor rule' do before(:each) do - @censor_rule = FactoryGirl.create(:user_censor_rule) + CensorRule.any_instance.stub(:save).and_return(false) end - it 'purges the cache for the info request' do - @controller.should_receive(:expire_requests_for_user). - with(@censor_rule.user) - + it 'does not update the censor rule' do put :update, :id => @censor_rule.id, :censor_rule => { :text => 'different text' } + @censor_rule.reload + expect(@censor_rule.text).to eq('some text to redact') end - it 'redirects to the associated info request' do + it 'renders the form' do put :update, :id => @censor_rule.id, :censor_rule => { :text => 'different text' } - expect(response).to redirect_to( - admin_user_show_path(assigns[:censor_rule].user) - ) + expect(response).to render_template('edit') end - end + end + end - context 'unsuccessfully saving the censor rule' do + context 'a CensorRule with an associated User' do before(:each) do - CensorRule.any_instance.stub(:save).and_return(false) + @censor_rule = FactoryGirl.create(:user_censor_rule) end - it 'does not update the censor rule' do + it 'finds the correct censor rule to edit' do put :update, :id => @censor_rule.id, :censor_rule => { :text => 'different text' } - @censor_rule.reload - expect(@censor_rule.text).to eq('some text to redact') + + expect(assigns[:censor_rule]).to eq(@censor_rule) end - it 'renders the form' do + it 'sets the last_edit_editor to the current admin' do put :update, :id => @censor_rule.id, :censor_rule => { :text => 'different text' } - expect(response).to render_template('edit') + expect(assigns[:censor_rule].last_edit_editor).to eq('*unknown*') + + end + + + context 'successfully saving the censor rule' do + + it 'updates the censor rule' do + put :update, :id => @censor_rule.id, + :censor_rule => { :text => 'different text' } + @censor_rule.reload + expect(@censor_rule.text).to eq('different text') + end + + it 'confirms the censor rule is updated' do + put :update, :id => @censor_rule.id, + :censor_rule => { :text => 'different text' } + msg = 'CensorRule was successfully updated.' + expect(flash[:notice]).to eq(msg) + end + + it 'purges the cache for the info request' do + @controller.should_receive(:expire_requests_for_user). + with(@censor_rule.user) + + put :update, :id => @censor_rule.id, + :censor_rule => { :text => 'different text' } + end + + it 'redirects to the associated info request' do + put :update, :id => @censor_rule.id, + :censor_rule => { :text => 'different text' } + + expect(response).to redirect_to( + admin_user_path(assigns[:censor_rule].user) + ) + end end + context 'unsuccessfully saving the censor rule' do + + before(:each) do + CensorRule.any_instance.stub(:save).and_return(false) + end + + it 'does not update the censor rule' do + put :update, :id => @censor_rule.id, + :censor_rule => { :text => 'different text' } + @censor_rule.reload + expect(@censor_rule.text).to eq('some text to redact') + end + + it 'renders the form' do + put :update, :id => @censor_rule.id, + :censor_rule => { :text => 'different text' } + + expect(response).to render_template('edit') + end + + end + end end describe 'DELETE destroy' do - before(:each) do - @censor_rule = FactoryGirl.create(:global_censor_rule) - end + context 'a global CensorRule' do - it 'finds the correct censor rule to destroy' do - pending("This raises an internal error in most cases") - # TODO: Replace :censor_rule_id with :id - delete :destroy, :censor_rule_id => @censor_rule.id - expect(assigns[:censor_rule]).to eq(@censor_rule) - end + before(:each) do + @censor_rule = FactoryGirl.create(:global_censor_rule) + end - it 'raises an error after destroying the rule' do - expect { - delete :destroy, :censor_rule_id => @censor_rule.id - }.to raise_error 'internal error' - end + it 'shows an error notice' do + get :edit, :id => @censor_rule.id + flash[:notice].should == 'Only user and request censor rules can be edited' + end + + it 'redirects to the admin index' do + get :edit, :id => @censor_rule.id + expect(response).to redirect_to(admin_general_index_path) + end - it 'confirms the censor rule is destroyed in all cases' do - pending("This actually raises an internal error anyway") - delete :destroy, :censor_rule_id => @censor_rule.id - msg = 'CensorRule was successfully destroyed.' - expect(flash[:notice]).to eq(msg) end context 'a CensorRule with an associated InfoRequest' do @@ -437,14 +515,25 @@ describe AdminCensorRuleController do @censor_rule = FactoryGirl.create(:info_request_censor_rule) end + it 'finds the correct censor rule to destroy' do + delete :destroy, :id => @censor_rule.id + expect(assigns[:censor_rule]).to eq(@censor_rule) + end + + it 'confirms the censor rule is destroyed in all cases' do + delete :destroy, :id => @censor_rule.id + msg = 'CensorRule was successfully destroyed.' + expect(flash[:notice]).to eq(msg) + end + it 'purges the cache for the info request' do @controller.should_receive(:expire_for_request).with(@censor_rule.info_request) - delete :destroy, :censor_rule_id => @censor_rule.id + delete :destroy, :id => @censor_rule.id end it 'redirects to the associated info request' do - delete :destroy, :censor_rule_id => @censor_rule.id - expect(response).to redirect_to(admin_request_show_path(@censor_rule.info_request)) + delete :destroy, :id => @censor_rule.id + expect(response).to redirect_to(admin_request_path(@censor_rule.info_request)) end end @@ -455,14 +544,25 @@ describe AdminCensorRuleController do @censor_rule = FactoryGirl.create(:user_censor_rule) end + it 'finds the correct censor rule to destroy' do + delete :destroy, :id => @censor_rule.id + expect(assigns[:censor_rule]).to eq(@censor_rule) + end + + it 'confirms the censor rule is destroyed in all cases' do + delete :destroy, :id => @censor_rule.id + msg = 'CensorRule was successfully destroyed.' + expect(flash[:notice]).to eq(msg) + end + it 'purges the cache for the user' do @controller.should_receive(:expire_requests_for_user).with(@censor_rule.user) - delete :destroy, :censor_rule_id => @censor_rule.id + delete :destroy, :id => @censor_rule.id end it 'redirects to the associated info request' do - delete :destroy, :censor_rule_id => @censor_rule.id - expect(response).to redirect_to(admin_user_show_path(@censor_rule.user)) + delete :destroy, :id => @censor_rule.id + expect(response).to redirect_to(admin_user_path(@censor_rule.user)) end end @@ -474,17 +574,17 @@ end describe AdminCensorRuleController, "when making censor rules from the admin interface" do render_views before { basic_auth_login @request } - + it "should create a censor rule and purge the corresponding request from varnish" do - ir = info_requests(:fancy_dog_request) - post :create, :censor_rule => { + ir = info_requests(:fancy_dog_request) + post :create, :request_id => ir.id, + :name_prefix => 'request_', + :censor_rule => { :text => "meat", :replacement => "tofu", - :last_edit_comment => "none", - :info_request_id => ir + :last_edit_comment => "none" } PurgeRequest.all().first.model_id.should == ir.id end - end diff --git a/spec/controllers/admin_comment_controller_spec.rb b/spec/controllers/admin_comment_controller_spec.rb new file mode 100644 index 000000000..f87231e3b --- /dev/null +++ b/spec/controllers/admin_comment_controller_spec.rb @@ -0,0 +1,66 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe AdminCommentController do + + describe :edit do + + before do + @comment = FactoryGirl.create(:comment) + get :edit, :id => @comment.id + end + + it 'renders the edit template' do + expect(response).to render_template('edit') + end + + it 'gets the comment' do + assigns[:comment].should == @comment + end + + end + + describe :update do + + context 'on valid data submission' do + + before do + @comment = FactoryGirl.create(:comment) + atts = FactoryGirl.attributes_for(:comment, :body => 'I am new') + put :update, :id => @comment.id, :comment => atts + end + + it 'gets the comment' do + assigns[:comment].should == @comment + end + + it 'updates the comment' do + Comment.find(@comment.id).body.should == 'I am new' + end + + it 'logs the update event' do + most_recent_event = Comment.find(@comment.id).info_request_events.last + most_recent_event.event_type.should == 'edit_comment' + most_recent_event.comment_id.should == @comment.id + end + + it 'shows a success notice' do + flash[:notice].should == "Comment successfully updated." + end + + it 'redirects to the request page' do + response.should redirect_to(admin_request_path(@comment.info_request)) + end + end + + context 'on invalid data submission' do + + it 'renders the edit template' do + @comment = FactoryGirl.create(:comment) + put :update, :id => @comment.id, :comment => {:body => ''} + response.should render_template('edit') + end + + end + end + +end diff --git a/spec/controllers/admin_holiday_imports_controller_spec.rb b/spec/controllers/admin_holiday_imports_controller_spec.rb new file mode 100644 index 000000000..dd23a022f --- /dev/null +++ b/spec/controllers/admin_holiday_imports_controller_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe AdminHolidayImportsController do + + describe :new do + + it 'renders the new template' do + get :new + expect(response).to render_template('new') + end + + it 'creates an import' do + get :new + assigns[:holiday_import].should be_instance_of(HolidayImport) + end + + describe 'if the import is valid' do + + it 'populates the import' do + mock_import = mock(HolidayImport, :valid? => true, + :populate => nil) + HolidayImport.stub!(:new).and_return(mock_import) + mock_import.should_receive(:populate) + get :new + end + + end + + end + + describe :create do + + it 'creates an import' do + post :create + assigns[:holiday_import].should be_instance_of(HolidayImport) + end + + describe 'if the import can be saved' do + + before do + mock_import = mock(HolidayImport, :save => true) + HolidayImport.stub!(:new).and_return(mock_import) + post :create + end + + it 'should show a success notice' do + flash[:notice].should == 'Holidays successfully imported' + end + + it 'should redirect to the index' do + response.should redirect_to(admin_holidays_path) + end + + end + + describe 'if the import cannot be saved' do + + before do + mock_import = mock(HolidayImport, :save => false) + HolidayImport.stub!(:new).and_return(mock_import) + post :create + end + + it 'should render the new template' do + expect(response).to render_template('new') + end + + end + + end + + +end diff --git a/spec/controllers/admin_holidays_controller_spec.rb b/spec/controllers/admin_holidays_controller_spec.rb new file mode 100644 index 000000000..21cb51d29 --- /dev/null +++ b/spec/controllers/admin_holidays_controller_spec.rb @@ -0,0 +1,192 @@ +require 'spec_helper' + +describe AdminHolidaysController do + + describe :index do + + before do + @holiday_one = FactoryGirl.create(:holiday, :day => Date.new(2010, 1, 1)) + @holiday_two = FactoryGirl.create(:holiday, :day => Date.new(2011, 2, 2)) + @holiday_three = FactoryGirl.create(:holiday, :day => Date.new(2011, 3, 3)) + end + + it 'gets a hash of holidays keyed by year' do + get :index + assigns(:holidays_by_year)[2010].should include(@holiday_one) + assigns(:holidays_by_year)[2011].should include(@holiday_two) + assigns(:holidays_by_year)[2011].should include(@holiday_three) + end + + it 'gets a list of years with holidays' do + get :index + assigns(:years).should include(2010) + assigns(:years).should include(2011) + end + + it 'renders the index template' do + get :index + expect(response).to render_template('index') + end + + end + + describe :new do + + + describe 'when not using ajax' do + + it 'renders the new template' do + get :new + expect(response).to render_template('new') + end + + end + + describe 'when using ajax' do + + it 'renders the new form partial' do + xhr :get, :new + expect(response).to render_template('new_form') + end + end + + it 'creates a new holiday' do + get :new + assigns[:holiday].should be_instance_of(Holiday) + end + + end + + describe :create do + + before do + @holiday_params = { :description => "New Year's Day", + 'day(1i)' => '2010', + 'day(2i)' => '1', + 'day(3i)' => '1' } + post :create, :holiday => @holiday_params + end + + it 'creates a new holiday' do + assigns(:holiday).description.should == @holiday_params[:description] + assigns(:holiday).day.should == Date.new(2010, 1, 1) + assigns(:holiday).should be_persisted + end + + it 'shows the admin a success message' do + flash[:notice].should == 'Holiday successfully created.' + end + + it 'redirects to the index' do + response.should redirect_to admin_holidays_path + end + + context 'when there are errors' do + + before do + Holiday.any_instance.stub(:save).and_return(false) + post :create, :holiday => @holiday_params + end + + it 'renders the new template' do + expect(response).to render_template('new') + end + end + + end + + describe :edit do + + before do + @holiday = FactoryGirl.create(:holiday) + end + + describe 'when not using ajax' do + + it 'renders the edit template' do + get :edit, :id => @holiday.id + expect(response).to render_template('edit') + end + + end + + describe 'when using ajax' do + + it 'renders the edit form partial' do + xhr :get, :edit, :id => @holiday.id + expect(response).to render_template('edit_form') + end + + end + + it 'gets the holiday in the id param' do + get :edit, :id => @holiday.id + assigns[:holiday].should == @holiday + end + + end + + describe :update do + + before do + @holiday = FactoryGirl.create(:holiday, :day => Date.new(2010, 1, 1), + :description => "Test Holiday") + put :update, :id => @holiday.id, :holiday => { :description => 'New Test Holiday' } + end + + it 'gets the holiday in the id param' do + assigns[:holiday].should == @holiday + end + + it 'updates the holiday' do + holiday = Holiday.find(@holiday.id).description.should == 'New Test Holiday' + end + + it 'shows the admin a success message' do + flash[:notice].should == 'Holiday successfully updated.' + end + + it 'redirects to the index' do + response.should redirect_to admin_holidays_path + end + + context 'when there are errors' do + + before do + Holiday.any_instance.stub(:update_attributes).and_return(false) + put :update, :id => @holiday.id, :holiday => { :description => 'New Test Holiday' } + end + + it 'renders the edit template' do + expect(response).to render_template('edit') + end + end + + end + + describe :destroy do + + before(:each) do + @holiday = FactoryGirl.create(:holiday) + delete :destroy, :id => @holiday.id + end + + it 'finds the holiday to destroy' do + assigns(:holiday).should == @holiday + end + + it 'destroys the holiday' do + assigns(:holiday).should be_destroyed + end + + it 'tells the admin the holiday has been destroyed' do + msg = "Holiday successfully destroyed" + flash[:notice].should == msg + end + + it 'redirects to the index action' do + expect(response).to redirect_to(admin_holidays_path) + end + end + + end diff --git a/spec/controllers/admin_incoming_message_controller_spec.rb b/spec/controllers/admin_incoming_message_controller_spec.rb index 21c744e5b..24a526ca4 100644 --- a/spec/controllers/admin_incoming_message_controller_spec.rb +++ b/spec/controllers/admin_incoming_message_controller_spec.rb @@ -17,19 +17,19 @@ describe AdminIncomingMessageController, "when administering incoming messages" it "destroys the raw email file" do raw_email = @im.raw_email.filepath assert_equal File.exists?(raw_email), true - post :destroy, :incoming_message_id => @im.id + post :destroy, :id => @im.id assert_equal File.exists?(raw_email), false end it 'asks the incoming message to fully destroy itself' do IncomingMessage.stub!(:find).and_return(@im) @im.should_receive(:fully_destroy) - post :destroy, :incoming_message_id => @im.id + post :destroy, :id => @im.id end it 'expires the file cache for the associated info_request' do @controller.should_receive(:expire_for_request).with(@im.info_request) - post :destroy, :incoming_message_id => @im.id + post :destroy, :id => @im.id end end @@ -46,7 +46,7 @@ describe AdminIncomingMessageController, "when administering incoming messages" destination_info_request = info_requests(:naughty_chicken_request) incoming_message = incoming_messages(:useless_incoming_message) @controller.should_receive(:expire_for_request).with(current_info_request) - post :redeliver, :redeliver_incoming_message_id => incoming_message.id, + post :redeliver, :id => incoming_message.id, :url_title => destination_info_request.url_title end @@ -56,7 +56,7 @@ describe AdminIncomingMessageController, "when administering incoming messages" current_info_request = info_requests(:fancy_dog_request) destination_info_request = info_requests(:naughty_chicken_request) incoming_message = incoming_messages(:useless_incoming_message) - post :redeliver, :redeliver_incoming_message_id => incoming_message.id, + post :redeliver, :id => incoming_message.id, :url_title => destination_info_request.url_title end @@ -130,7 +130,7 @@ describe AdminIncomingMessageController, "when administering incoming messages" it 'should redirect to the admin info request view' do make_request - response.should redirect_to admin_request_show_url(@incoming.info_request) + response.should redirect_to admin_request_url(@incoming.info_request) end it 'should show a message that the incoming message has been updated' do diff --git a/spec/controllers/admin_info_request_event_controller_spec.rb b/spec/controllers/admin_info_request_event_controller_spec.rb new file mode 100644 index 000000000..23300a0b8 --- /dev/null +++ b/spec/controllers/admin_info_request_event_controller_spec.rb @@ -0,0 +1,41 @@ +# coding: utf-8 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe AdminInfoRequestEventController do + + describe :update do + + describe 'when handling valid data' do + + before do + @info_request_event = FactoryGirl.create(:info_request_event) + put :update, :id => @info_request_event + end + + it 'gets the info request event' do + assigns[:info_request_event].should == @info_request_event + end + + it 'sets the described and calculated states on the event' do + event = InfoRequestEvent.find(@info_request_event.id) + event.described_state.should == 'waiting_clarification' + event.calculated_state.should == 'waiting_clarification' + end + + it 'shows a success notice' do + flash[:notice].should == 'Old response marked as having been a clarification' + end + + it 'redirects to the request admin page' do + response.should redirect_to(admin_request_url(@info_request_event.info_request)) + end + end + + it 'raises an exception if the event is not a response' do + @info_request_event = FactoryGirl.create(:sent_event) + lambda{ put :update, :id => @info_request_event }.should raise_error + end + + end + +end diff --git a/spec/controllers/admin_outgoing_message_controller_spec.rb b/spec/controllers/admin_outgoing_message_controller_spec.rb index 0dde53b86..a46a077da 100644 --- a/spec/controllers/admin_outgoing_message_controller_spec.rb +++ b/spec/controllers/admin_outgoing_message_controller_spec.rb @@ -79,7 +79,7 @@ describe AdminOutgoingMessageController do it 'should redirect to the admin info request view' do make_request - response.should redirect_to admin_request_show_url(@info_request) + response.should redirect_to admin_request_url(@info_request) end it 'should show a message that the incoming message has been updated' do diff --git a/spec/controllers/admin_public_body_categories_controller_spec.rb b/spec/controllers/admin_public_body_categories_controller_spec.rb index 4c641bd75..1131b3c0b 100644 --- a/spec/controllers/admin_public_body_categories_controller_spec.rb +++ b/spec/controllers/admin_public_body_categories_controller_spec.rb @@ -1,120 +1,268 @@ require 'spec_helper' describe AdminPublicBodyCategoriesController do - context 'when showing the index of categories and headings' do - render_views - it 'shows the index page' do + describe :index do + + it 'responds successfully' do get :index expect(response).to be_success end + + it 'uses the current locale by default' do + get :index + expect(assigns(:locale)).to eq(I18n.locale.to_s) + end + + it 'sets the locale if the show_locale param is passed' do + get :index, :show_locale => 'es' + expect(assigns(:locale)).to eq('es') + end + + it 'finds all category headings' do + PublicBodyHeading.destroy_all + + headings = [FactoryGirl.create(:public_body_heading), + FactoryGirl.create(:public_body_heading)] + + get :index + + expect(assigns(:category_headings)).to eq(headings) + end + + it 'finds all categories without their headings' do + PublicBodyHeading.destroy_all + PublicBodyCategory.destroy_all + + without_heading = FactoryGirl.create(:public_body_category) + + heading = FactoryGirl.create(:public_body_heading) + with_heading = FactoryGirl.create(:public_body_category) + PublicBodyCategoryLink.create!(:public_body_heading_id => heading.id, + :public_body_category_id => with_heading.id) + + + get :index + expect(assigns(:without_heading)).to eq([without_heading]) + end + + it 'renders the index template' do + get :index + expect(response).to render_template('index') + end + end - context 'when showing the form for a new public body category' do - it 'should assign a new public body category to the view' do + describe :new do + + it 'responds successfully' do get :new - assigns[:category].should be_a(PublicBodyCategory) + expect(response).to be_success end - it 'renders the new template' do + it 'builds a new PublicBodyCategory' do get :new - expect(response).to render_template('new') + expect(assigns(:category)).to be_new_record end + it 'builds new translations for all locales' do + get :new + + translations = assigns(:category).translations.map{ |t| t.locale.to_s }.sort + available = I18n.available_locales.map{ |l| l.to_s }.sort + + expect(translations).to eq(available) + end + + it 'renders the new template' do + get :new + expect(response).to render_template('new') + end + end - context 'when creating a public body category' do - it "creates a new public body category in one locale" do - n = PublicBodyCategory.count - post :create, { - :public_body_category => { - :title => 'New Category', - :category_tag => 'new_test_category', - :description => 'New category for testing stuff' - } - } - PublicBodyCategory.count.should == n + 1 + describe :create do + + context 'on success' do + + before(:each) do + PublicBodyCategory.destroy_all + @params = { :category_tag => 'new_test_category', + :translations_attributes => { + 'en' => { :locale => 'en', + :title => 'New Category', + :description => 'New category for testing stuff' } + } } + end + + it 'creates a new category in the default locale' do + PublicBodyCategory.destroy_all + + expect { + post :create, :public_body_category => @params + }.to change{ PublicBodyCategory.count }.from(0).to(1) + end + + it "saves the public body category's heading associations" do + heading = FactoryGirl.create(:public_body_heading) + params = FactoryGirl.attributes_for(:public_body_category) + + post :create, :public_body_category => @params, + :headings => { "heading_#{ heading.id }" => heading.id } + + category = PublicBodyCategory.find_by_title(@params[:translations_attributes]['en'][:title]) + expect(category.public_body_headings).to eq([heading]) + end + + it 'notifies the admin that the category was created' do + post :create, :public_body_category => @params + expect(flash[:notice]).to eq('Category was successfully created.') + end + + it 'redirects to the categories index' do + post :create, :public_body_category => @params + expect(response).to redirect_to(admin_categories_path) + end - category = PublicBodyCategory.find_by_title("New Category") - response.should redirect_to(admin_categories_path) end - it "saves the public body category's heading associations" do - heading = FactoryGirl.create(:public_body_heading) - category_attributes = FactoryGirl.attributes_for(:public_body_category) - post :create, { - :public_body_category => category_attributes, - :headings => {"heading_#{heading.id}" => heading.id} - } - request.flash[:notice].should include('successful') - category = PublicBodyCategory.find_by_title(category_attributes[:title]) - category.public_body_headings.should == [heading] + context 'on success for multiple locales' do + + before(:each) do + PublicBodyCategory.destroy_all + @params = { :category_tag => 'new_test_category', + :translations_attributes => { + 'en' => { :locale => 'en', + :title => 'New Category', + :description => 'New category for testing stuff' }, + 'es' => { :locale => 'es', + :title => 'Mi Nuevo Category', + :description => 'ES Description' } + } } + end + + it 'saves the category' do + expect { + post :create, :public_body_category => @params + }.to change{ PublicBodyCategory.count }.from(0).to(1) + end + + it 'saves the default locale translation' do + post :create, :public_body_category => @params + + category = PublicBodyCategory.find_by_title('New Category') + + I18n.with_locale(:en) do + expect(category.title).to eq('New Category') + end + end + + it 'saves the alternative locale translation' do + post :create, :public_body_category => @params + + category = PublicBodyCategory.find_by_title('New Category') + + I18n.with_locale(:es) do + expect(category.title).to eq('Mi Nuevo Category') + end + end + end - it 'creates a new public body category with multiple locales' do - n = PublicBodyCategory.count - post :create, { - :public_body_category => { - :title => 'New Category', - :category_tag => 'new_test_category', - :description => 'New category for testing stuff', - :translated_versions => [{ :locale => "es", - :title => "Mi Nuevo Category" }] - } - } - PublicBodyCategory.count.should == n + 1 + context 'on failure' do - category = PublicBodyCategory.find_by_title("New Category") - category.translations.map {|t| t.locale.to_s}.sort.should == ["en", "es"] - I18n.with_locale(:en) do - category.title.should == "New Category" + it 'renders the form if creating the record was unsuccessful' do + post :create, :public_body_category => { :title => '' } + expect(response).to render_template('new') end - I18n.with_locale(:es) do - category.title.should == "Mi Nuevo Category" + + it 'is rebuilt with the given params' do + post :create, :public_body_category => { :title => 'Need a description' } + expect(assigns(:category).title).to eq('Need a description') end - response.should redirect_to(admin_categories_path) end - it "renders the form if creating the record was unsuccessful" do - post :create, :public_body_category => { :title => '' } - expect(response).to render_template('new') + context 'on failure for multiple locales' do + + before(:each) do + @params = { :category_tag => 'new_test_category', + :translations_attributes => { + 'en' => { :locale => 'en', + :title => 'Need a description', + :description => nil }, + 'es' => { :locale => 'es', + :title => 'Mi Nuevo Category', + :description => 'ES Description' } + } } + end + + it 'is rebuilt with the default locale translation' do + post :create, :public_body_category => @params + expect(assigns(:category).title).to eq('Need a description') + end + + it 'is rebuilt with the alternative locale translation' do + post :create, :public_body_category => @params + + I18n.with_locale(:es) do + expect(assigns(:category).title).to eq('Mi Nuevo Category') + end + end + end end - context 'when editing a public body category' do + describe :edit do + before do @category = FactoryGirl.create(:public_body_category) I18n.with_locale('es') do @category.title = 'Los category' + @category.description = 'ES Description' @category.save! end end - render_views + it 'responds successfully' do + get :edit, :id => @category.id + expect(response).to be_success + end - it "finds the requested category" do + it 'finds the requested category' do get :edit, :id => @category.id expect(assigns[:category]).to eq(@category) end - it "renders the edit template" do + it 'builds new translations if the body does not already have a translation in the specified locale' do get :edit, :id => @category.id - expect(assigns[:category]).to render_template('edit') + expect(assigns[:category].translations.map(&:locale)).to include(:fr) end - it "edits a public body in another locale" do - get :edit, { :id => @category.id, :locale => :en } + it 'finds the public bodies tagged with the category tag' do + # FIXME: I wanted to call PublicBody.destroy_all here so that we + # have a known DB state, but the constraints were preventing the + # deletion of the fixture data + FactoryGirl.create(:public_body, :tag_string => 'wont_be_found') + + category = FactoryGirl.create(:public_body_category, :category_tag => 'spec') + expected_bodies = [FactoryGirl.create(:public_body, :tag_string => 'spec'), + FactoryGirl.create(:public_body, :tag_string => 'spec')] - # When editing a body, the controller returns all available - # translations - assigns[:category].find_translation_by_locale("es").title.should == 'Los category' - response.should render_template('edit') + get :edit, :id => category.id + + expect(assigns(:tagged_public_bodies).sort).to eq(expected_bodies.sort) end + + it 'renders the edit template' do + get :edit, :id => @category.id + expect(response).to render_template('edit') + end + end - context 'when updating a public body category' do + describe :update do before do @heading = FactoryGirl.create(:public_body_heading) @@ -126,109 +274,389 @@ describe AdminPublicBodyCategoriesController do @tag = @category.category_tag I18n.with_locale('es') do @category.title = 'Los category' + @category.description = 'ES Description' @category.save! end + + @params = { :category_tag => @category.category_tag, + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => @category.title(:en), + :description => @category.description(:en) }, + 'es' => { :id => @category.translation_for(:es).id, + :locale => 'es', + :title => @category.title(:es), + :description => @category.description(:es) } + } } end - render_views + it 'finds the category to update' do + post :update, :id => @category.id, + :public_body_category => @params + expect(assigns(:category)).to eq(@category) + end + + it 'finds the public bodies tagged with the category tag' do + # FIXME: I wanted to call PublicBody.destroy_all here so that we + # have a known DB state, but the constraints were preventing the + # deletion of the fixture data + FactoryGirl.create(:public_body, :tag_string => 'wont_be_found') + + category = FactoryGirl.create(:public_body_category, :category_tag => 'spec') + expected_bodies = [FactoryGirl.create(:public_body, :tag_string => 'spec'), + FactoryGirl.create(:public_body, :tag_string => 'spec')] + + post :update, :id => category.id, + :public_body_category => category.serializable_hash.except(:title, :description) - it "saves edits to a public body category" do - post :update, { :id => @category.id, - :public_body_category => { :title => "Renamed" } } - request.flash[:notice].should include('successful') - pbc = PublicBodyCategory.find(@category.id) - pbc.title.should == "Renamed" + expect(assigns(:tagged_public_bodies)).to eq(expected_bodies) end it "saves edits to a public body category's heading associations" do - @category.public_body_headings.should == [@heading] + # We already have a heading from the before block. Here we're going + # to update to a new heading. heading = FactoryGirl.create(:public_body_heading) - post :update, { :id => @category.id, - :public_body_category => { :title => "Renamed" }, - :headings => {"heading_#{heading.id}" => heading.id} } - request.flash[:notice].should include('successful') - pbc = PublicBodyCategory.find(@category.id) - pbc.public_body_headings.should == [heading] - end - - it "saves edits to a public body category in another locale" do - I18n.with_locale(:es) do - @category.title.should == 'Los category' - post :update, { - :id => @category.id, - :public_body_category => { - :title => "Category", - :translated_versions => { - @category.id => {:locale => "es", - :title => "Renamed"} + + post :update, :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :title => 'Renamed' } } - } - } - request.flash[:notice].should include('successful') + }, + :headings => { "heading_#{ heading.id }" => heading.id } + + category = PublicBodyCategory.find(@category.id) + expect(category.public_body_headings).to eq([heading]) + end + + context 'when the category has associated bodies' do + + it 'does not save edits to category_tag' do + body = FactoryGirl.create(:public_body, :tag_string => @tag) + + post :update, :id => @category.id, + :public_body_category => { :category_tag => 'Renamed' } + + + category = PublicBodyCategory.find(@category.id) + expect(category.category_tag).to eq(@tag) end - pbc = PublicBodyCategory.find(@category.id) - I18n.with_locale(:es) do - pbc.title.should == "Renamed" + it 'notifies the user that the category_tag could not be updated' do + body = FactoryGirl.create(:public_body, :tag_string => @tag) + msg = %Q(There are authorities associated with this category, + so the tag can't be renamed).squish + + post :update, :id => @category.id, + :public_body_category => { :category_tag => 'Renamed' } + + expect(flash[:error]).to eq(msg) end - I18n.with_locale(:en) do - pbc.title.should == "Category" + + it 'renders the edit action' do + body = FactoryGirl.create(:public_body, :tag_string => @tag) + + post :update, :id => @category.id, + :public_body_category => { :category_tag => 'Renamed' } + + expect(response).to render_template('edit') end + end - it "does not save edits to category_tag if the category has associated bodies" do - body = FactoryGirl.create(:public_body, :tag_string => @tag) - post :update, { :id => @category.id, - :public_body_category => { :category_tag => "renamed" } } - - msg = "There are authorities associated with this category, so the tag can't be renamed" - request.flash[:error].should == msg - pbc = PublicBodyCategory.find(@category.id) - pbc.category_tag.should == @tag + context 'on success' do + + before(:each) do + @params = { :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :title => 'Renamed' } + } + } + } + end + + it 'saves edits to a public body category' do + post :update, @params + category = PublicBodyCategory.find(@category.id) + expect(category.title).to eq('Renamed') + end + + it 'notifies the admin that the category was created' do + post :update, @params + expect(flash[:notice]).to eq('Category was successfully updated.') + end + + it 'redirects to the category edit page' do + post :update, @params + expect(response).to redirect_to(edit_admin_category_path(@category)) + end + + it 'saves edits to category_tag if the category has no associated bodies' do + category = FactoryGirl.create(:public_body_category, :category_tag => 'empty') + + post :update, :id => category.id, + :public_body_category => { :category_tag => 'Renamed' } + + category = PublicBodyCategory.find(category.id) + expect(category.category_tag).to eq('Renamed') + end + end + context 'on success for multiple locales' do + + it "saves edits to a public body category in another locale" do + @category.title(:es).should == 'Los category' + post :update, :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => @category.title(:en), + :description => @category.description(:en) }, + 'es' => { :id => @category.translation_for(:es).id, + :locale => 'es', + :title => 'Renamed', + :description => 'ES Description' } + } + } + + category = PublicBodyCategory.find(@category.id) + expect(category.title(:es)).to eq('Renamed') + expect(category.title(:en)).to eq(@category.title(:en)) + end + + it 'adds a new translation' do + @category.translation_for(:es).destroy + @category.reload + + put :update, { + :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => @category.title(:en), + :description => @category.description(:en) }, + 'es' => { :locale => "es", + :title => "Example Public Body Category ES", + :description => @category.description(:es) } + } + } + } + + request.flash[:notice].should include('successful') + + pbc = PublicBodyCategory.find(@category.id) + + I18n.with_locale(:es) do + expect(pbc.title).to eq('Example Public Body Category ES') + end + end + + it 'adds new translations' do + @category.translation_for(:es).destroy + @category.reload + + post :update, { + :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => @category.title(:en), + :description => @category.description(:en) }, + 'es' => { :locale => "es", + :title => "Example Public Body Category ES", + :description => 'ES Description' }, + 'fr' => { :locale => "fr", + :title => "Example Public Body Category FR", + :description => 'FR Description' } + } + } + } + + request.flash[:notice].should include('successful') + + pbc = PublicBodyCategory.find(@category.id) + + I18n.with_locale(:es) do + expect(pbc.title).to eq('Example Public Body Category ES') + end + I18n.with_locale(:fr) do + expect(pbc.title).to eq('Example Public Body Category FR') + end + end + + it 'updates an existing translation and adds a third translation' do + post :update, { + :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => @category.title(:en), + :description => @category.description(:en) }, + # Update existing translation + 'es' => { :id => @category.translation_for(:es).id, + :locale => "es", + :title => "Renamed Example Public Body Category ES", + :description => @category.description }, + # Add new translation + 'fr' => { :locale => "fr", + :title => "Example Public Body Category FR", + :description => @category.description } + } + } + } + + request.flash[:notice].should include('successful') + + pbc = PublicBodyCategory.find(@category.id) + + I18n.with_locale(:es) do + expect(pbc.title).to eq('Renamed Example Public Body Category ES') + end + I18n.with_locale(:fr) do + expect(pbc.title).to eq('Example Public Body Category FR') + end + end + + it "redirects to the edit page after a successful update" do + post :update, :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => @category.title(:en), + :description => @category.description(:en) } + } } + + expect(response).to redirect_to(edit_admin_category_path(@category)) + end - it "save edits to category_tag if the category has no associated bodies" do - category = PublicBodyCategory.create(:title => "Empty Category", :category_tag => "empty", :description => "-") - post :update, { :id => category.id, - :public_body_category => { :category_tag => "renamed" } } - request.flash[:notice].should include('success') - pbc = PublicBodyCategory.find(category.id) - pbc.category_tag.should == "renamed" end - it "redirects to the edit page after a successful update" do - post :update, { :id => @category.id, - :public_body_category => { :title => "Renamed" } } + context 'on failure' do + + it 'renders the form if creating the record was unsuccessful' do + post :update, :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => '', + :description => @category.description(:en) } + } } + expect(response).to render_template('edit') + end + + it 'is rebuilt with the given params' do + post :update, :id => @category.id, + :public_body_category => { + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => 'Need a description', + :description => '' } + } } + expect(assigns(:category).title).to eq('Need a description') + end - expect(response).to redirect_to(edit_admin_category_path(@category)) end - it "re-renders the edit form after an unsuccessful update" do - post :update, { :id => @category.id, - :public_body_category => { :title => '' } } + context 'on failure for multiple locales' do + + before(:each) do + @params = { :category_tag => 'new_test_category', + :translations_attributes => { + 'en' => { :id => @category.translation_for(:en).id, + :locale => 'en', + :title => 'Need a description', + :description => '' }, + 'es' => { :id => @category.translation_for(:es).id, + :locale => 'es', + :title => 'Mi Nuevo Category', + :description => 'ES Description' } + } } + end + + it 'is rebuilt with the default locale translation' do + post :update, :id => @category.id, + :public_body_category => @params + expect(assigns(:category).title(:en)).to eq('Need a description') + end + + it 'is rebuilt with the alternative locale translation' do + post :update, :id => @category.id, + :public_body_category => @params + + I18n.with_locale(:es) do + expect(assigns(:category).title).to eq('Mi Nuevo Category') + end + end - expect(response).to render_template('edit') end end - context 'when destroying a public body category' do - it "destroys empty public body categories" do - pbc = PublicBodyCategory.create(:title => "Empty Category", :category_tag => "empty", :description => "-") - n = PublicBodyCategory.count - post :destroy, { :id => pbc.id } - response.should redirect_to(admin_categories_path) - PublicBodyCategory.count.should == n - 1 + describe :destroy do + + it 'uses the current locale by default' do + category = FactoryGirl.create(:public_body_category) + post :destroy, :id => category.id + expect(assigns(:locale)).to eq(I18n.locale.to_s) end - it "destroys non-empty public body categories" do + it 'sets the locale if the show_locale param is passed' do + category = FactoryGirl.create(:public_body_category) + post :destroy, :id => category.id, :show_locale => 'es' + expect(assigns(:locale)).to eq('es') + end + + it 'destroys empty public body categories' do + PublicBodyCategory.destroy_all + + category = FactoryGirl.create(:public_body_category) + + expect{ + post :destroy, :id => category.id + }.to change{ PublicBodyCategory.count }.from(1).to(0) + end + + it 'destroys non-empty public body categories' do + PublicBodyCategory.destroy_all + + # FIXME: Couldn't create the PublicBodyCategory with a Factory + # because #authorities= doesn't exist? + # undefined method `authorities=' for + # #<PublicBodyCategory:0x7f55cbb84f70> authority = FactoryGirl.create(:public_body) - pbc = PublicBodyCategory.create(:title => "In-Use Category", :category_tag => "empty", :description => "-", :authorities => [authority]) - n = PublicBodyCategory.count - post :destroy, { :id => pbc.id } - response.should redirect_to(admin_categories_path) - PublicBodyCategory.count.should == n - 1 + category = PublicBodyCategory.create(:title => "In-Use Category", + :category_tag => "empty", + :description => "-", + :authorities => [authority]) + + expect{ + post :destroy, :id => category.id + }.to change{ PublicBodyCategory.count }.from(1).to(0) + end + + it 'notifies the admin that the category was destroyed' do + category = FactoryGirl.create(:public_body_category) + post :destroy, :id => category.id + expect(flash[:notice]).to eq('Category was successfully destroyed.') + end + + it 'redirects to the categories index' do + category = FactoryGirl.create(:public_body_category) + post :destroy, :id => category.id + expect(response).to redirect_to(admin_categories_path) end + end end diff --git a/spec/controllers/admin_public_body_controller_spec.rb b/spec/controllers/admin_public_body_controller_spec.rb index f176150da..50a373d9d 100644 --- a/spec/controllers/admin_public_body_controller_spec.rb +++ b/spec/controllers/admin_public_body_controller_spec.rb @@ -39,9 +39,14 @@ end describe AdminPublicBodyController, 'when showing the form for a new public body' do + it 'responds successfully' do + get :new + expect(response).to be_success + end + it 'should assign a new public body to the view' do get :new - assigns[:public_body].should be_a(PublicBody) + expect(assigns(:public_body)).to be_new_record end it "builds new translations for all locales" do @@ -53,6 +58,11 @@ describe AdminPublicBodyController, 'when showing the form for a new public body expect(translations).to eq(available) end + it 'renders the new template' do + get :new + expect(response).to render_template('new') + end + context 'when passed a change request id as a param' do render_views @@ -76,51 +86,127 @@ end describe AdminPublicBodyController, "when creating a public body" do render_views - it "creates a new public body in one locale" do - n = PublicBody.count - post :create, { :public_body => { :name => "New Quango", - :short_name => "", - :tag_string => "blah", - :request_email => 'newquango@localhost', - :last_edit_comment => 'From test code' } } - PublicBody.count.should == n + 1 + context 'on success' do + + before(:each) do + @params = { :public_body => { :name => 'New Quango', + :short_name => 'nq', + :request_email => 'newquango@localhost', + :tag_string => 'spec', + :last_edit_comment => 'From test code' } } + end + + it 'creates a new body in the default locale' do + # FIXME: Can't call PublicBody.destroy_all because database + # database contstraints prevent them being deleted. + existing = PublicBody.count + expected = existing + 1 + expect { + post :create, @params + }.to change{ PublicBody.count }.from(existing).to(expected) + end + + it 'notifies the admin that the body was created' do + post :create, @params + expect(flash[:notice]).to eq('PublicBody was successfully created.') + end + + it 'redirects to the admin page of the body' do + post :create, @params + expect(response).to redirect_to(admin_body_path(assigns(:public_body))) + end - body = PublicBody.find_by_name("New Quango") - response.should redirect_to(:controller=>'admin_public_body', :action=>'show', :id=>body.id) end - it "creates a new public body with multiple locales" do - n = PublicBody.count - post :create, { - :public_body => { :name => "New Quango", - :short_name => "", - :tag_string => "blah", - :request_email => 'newquango@localhost', - :last_edit_comment => 'From test code', - :translations_attributes => { - 'es' => { :locale => "es", - :name => "Mi Nuevo Quango", - :short_name => "", - :request_email => 'newquango@localhost' } - } - } - } - PublicBody.count.should == n + 1 + context 'on success for multiple locales' do + + before(:each) do + @params = { :public_body => { :name => 'New Quango', + :short_name => 'nq', + :request_email => 'newquango@localhost', + :tag_string => 'spec', + :last_edit_comment => 'From test code', + :translations_attributes => { + 'es' => { :locale => 'es', + :name => 'Los Quango' } + } } } + end + + it 'saves the body' do + # FIXME: Can't call PublicBody.destroy_all because database + # database contstraints prevent them being deleted. + existing = PublicBody.count + expected = existing + 1 + expect { + post :create, @params + }.to change{ PublicBody.count }.from(existing).to(expected) + end + + it 'saves the default locale translation' do + post :create, @params + + body = PublicBody.find_by_name('New Quango') + + I18n.with_locale(:en) do + expect(body.name).to eq('New Quango') + end + end + + it 'saves the alternative locale translation' do + post :create, @params + + body = PublicBody.find_by_name('New Quango') + + I18n.with_locale(:es) do + expect(body.name).to eq('Los Quango') + end + end + + end + + context 'on failure' do + + it 'renders the form if creating the record was unsuccessful' do + post :create, :public_body => { :name => '', + :translations_attributes => {} } + expect(response).to render_template('new') + end + + it 'is rebuilt with the given params' do + post :create, :public_body => { :name => '', + :request_email => 'newquango@localhost', + :translations_attributes => {} } + expect(assigns(:public_body).request_email).to eq('newquango@localhost') + end + + end + + context 'on failure for multiple locales' do - body = PublicBody.find_by_name("New Quango") - body.translations.map {|t| t.locale.to_s}.sort.should == ["en", "es"] - I18n.with_locale(:en) do - body.name.should == "New Quango" - body.url_name.should == "new_quango" - body.first_letter.should == "N" + before(:each) do + @params = { :public_body => { :name => '', + :request_email => 'newquango@localhost', + :translations_attributes => { + 'es' => { :locale => 'es', + :name => 'Los Quango' } + } } } end - I18n.with_locale(:es) do - body.name.should == "Mi Nuevo Quango" - body.url_name.should == "mi_nuevo_quango" - body.first_letter.should == "M" + + it 'is rebuilt with the default locale translation' do + post :create, @params + expect(assigns(:public_body)).to_not be_persisted + expect(assigns(:public_body).request_email).to eq('newquango@localhost') + end + + it 'is rebuilt with the alternative locale translation' do + post :create, @params + + expect(assigns(:public_body)).to_not be_persisted + I18n.with_locale(:es) do + expect(assigns(:public_body).name).to eq('Los Quango') + end end - response.should redirect_to(:controller=>'admin_public_body', :action=>'show', :id=>body.id) end context 'when the body is being created as a result of a change request' do @@ -157,10 +243,34 @@ end describe AdminPublicBodyController, "when editing a public body" do render_views - it "edits a public body" do - get :edit, :id => 2 + before do + @body = FactoryGirl.create(:public_body) + I18n.with_locale('es') do + @body.name = 'Los Body' + @body.save! + end + end + + it 'responds successfully' do + get :edit, :id => @body.id + expect(response).to be_success end + it 'finds the requested body' do + get :edit, :id => @body.id + expect(assigns[:public_body]).to eq(@body) + end + + it 'builds new translations if the body does not already have a translation in the specified locale' do + get :edit, :id => @body.id + expect(assigns[:public_body].translations.map(&:locale)).to include(:fr) + end + + it 'renders the edit template' do + get :edit, :id => @body.id + expect(response).to render_template('edit') + end + it "edits a public body in another locale" do get :edit, {:id => 3, :locale => :en} @@ -170,12 +280,6 @@ describe AdminPublicBodyController, "when editing a public body" do response.should render_template('edit') end - it "builds new translations if the body does not already have a translation in the specified locale" do - public_body = FactoryGirl.create(:public_body) - get :edit, :id => public_body.id - expect(assigns[:public_body].translations.map(&:locale)).to include(:fr) - end - context 'when passed a change request id as a param' do render_views @@ -201,159 +305,200 @@ end describe AdminPublicBodyController, "when updating a public body" do render_views - it "saves edits to a public body" do - public_bodies(:humpadink_public_body).name.should == "Department for Humpadinking" - post :update, { :id => 3, :public_body => { :name => "Renamed", - :short_name => "", - :tag_string => "some tags", - :request_email => 'edited@localhost', - :last_edit_comment => 'From test code' } } - request.flash[:notice].should include('successful') - pb = PublicBody.find(public_bodies(:humpadink_public_body).id) - pb.name.should == "Renamed" - end - - it 'adds a new translation' do - pb = public_bodies(:humpadink_public_body) - pb.translation_for(:es).destroy - pb.reload - - post :update, { - :id => pb.id, - :public_body => { - :name => "Department for Humpadinking", - :short_name => "", - :tag_string => "some tags", - :request_email => 'edited@localhost', - :last_edit_comment => 'From test code', - :translations_attributes => { - 'es' => { :locale => "es", - :name => "El Department for Humpadinking", - :short_name => "", - :request_email => 'edited@localhost' } - } - } - } - - request.flash[:notice].should include('successful') - - pb = PublicBody.find(public_bodies(:humpadink_public_body).id) - - I18n.with_locale(:es) do - expect(pb.name).to eq('El Department for Humpadinking') - end - end - - it 'adds new translations' do - pb = public_bodies(:humpadink_public_body) - pb.translation_for(:es).destroy - pb.reload - - post :update, { - :id => pb.id, - :public_body => { - :name => "Department for Humpadinking", - :short_name => "", - :tag_string => "some tags", - :request_email => 'edited@localhost', - :last_edit_comment => 'From test code', - :translations_attributes => { - 'es' => { :locale => "es", - :name => "El Department for Humpadinking", - :short_name => "", - :request_email => 'edited@localhost' }, - 'fr' => { :locale => "fr", - :name => "Le Department for Humpadinking", - :short_name => "", - :request_email => 'edited@localhost' } - } - } - } - - request.flash[:notice].should include('successful') - - pb = PublicBody.find(public_bodies(:humpadink_public_body).id) - - I18n.with_locale(:es) do - expect(pb.name).to eq('El Department for Humpadinking') - end - - I18n.with_locale(:fr) do - expect(pb.name).to eq('Le Department for Humpadinking') - end - end - - it 'updates an existing translation and adds a third translation' do - pb = public_bodies(:humpadink_public_body) - - put :update, { - :id => pb.id, - :public_body => { - :name => "Department for Humpadinking", - :short_name => "", - :tag_string => "some tags", - :request_email => 'edited@localhost', - :last_edit_comment => 'From test code', - :translations_attributes => { - # Update existing translation - 'es' => { :locale => "es", - :name => "Renamed Department for Humpadinking", - :short_name => "", - :request_email => 'edited@localhost' }, - # Add new translation - 'fr' => { :locale => "fr", - :name => "Le Department for Humpadinking", - :short_name => "", - :request_email => 'edited@localhost' } - } - } - } + before do + @body = FactoryGirl.create(:public_body) + I18n.with_locale('es') do + @body.name = 'Los Quango' + @body.save! + end + + @params = { :id => @body.id, + :public_body => { :name => 'Renamed', + :short_name => @body.short_name, + :request_email => @body.request_email, + :tag_string => @body.tag_string, + :last_edit_comment => 'From test code', + :translations_attributes => { + 'es' => { :id => @body.translation_for(:es).id, + :locale => 'es', + :title => @body.name(:es) } + } } } + end + + it 'finds the heading to update' do + post :update, @params + expect(assigns(:heading)).to eq(@heading) + end - request.flash[:notice].should include('successful') + context 'on success' do - pb = PublicBody.find(public_bodies(:humpadink_public_body).id) + it 'saves edits to a public body heading' do + post :update, @params + body = PublicBody.find(@body.id) + expect(body.name).to eq('Renamed') + end - I18n.with_locale(:es) do - expect(pb.name).to eq('Renamed Department for Humpadinking') + it 'notifies the admin that the body was updated' do + post :update, @params + expect(flash[:notice]).to eq('PublicBody was successfully updated.') end - I18n.with_locale(:fr) do - expect(pb.name).to eq('Le Department for Humpadinking') + it 'redirects to the admin body page' do + post :update, @params + expect(response).to redirect_to(admin_body_path(@body)) end end - it "saves edits to a public body in another locale" do - I18n.with_locale(:es) do - pb = PublicBody.find(id=3) - pb.name.should == "El Department for Humpadinking" - post :update, { - :id => 3, - :public_body => { - :name => "Department for Humpadinking", - :short_name => "", - :tag_string => "some tags", - :request_email => 'edited@localhost', - :last_edit_comment => 'From test code', - :translations_attributes => { - 'es' => { :locale => "es", - :name => "Renamed", - :short_name => "", - :request_email => 'edited@localhost' } - } - } - } - request.flash[:notice].should include('successful') + context 'on success for multiple locales' do + + it 'saves edits to a public body heading in another locale' do + @body.name(:es).should == 'Los Quango' + post :update, :id => @body.id, + :public_body => { + :name => @body.name(:en), + :translations_attributes => { + 'es' => { :id => @body.translation_for(:es).id, + :locale => 'es', + :name => 'Renamed' } + } + } + + body = PublicBody.find(@body.id) + expect(body.name(:es)).to eq('Renamed') + expect(body.name(:en)).to eq(@body.name(:en)) end - pb = PublicBody.find(public_bodies(:humpadink_public_body).id) + it 'adds a new translation' do + @body.translation_for(:es).destroy + @body.reload + + put :update, { + :id => @body.id, + :public_body => { + :name => @body.name(:en), + :translations_attributes => { + 'es' => { :locale => "es", + :name => "Example Public Body ES" } + } + } + } + + request.flash[:notice].should include('successful') + + body = PublicBody.find(@body.id) + + I18n.with_locale(:es) do + expect(body.name).to eq('Example Public Body ES') + end + end + + it 'adds new translations' do + @body.translation_for(:es).destroy + @body.reload + + post :update, { + :id => @body.id, + :public_body => { + :name => @body.name(:en), + :translations_attributes => { + 'es' => { :locale => "es", + :name => "Example Public Body ES" }, + 'fr' => { :locale => "fr", + :name => "Example Public Body FR" } + } + } + } + + request.flash[:notice].should include('successful') + + body = PublicBody.find(@body.id) + + I18n.with_locale(:es) do + expect(body.name).to eq('Example Public Body ES') + end + I18n.with_locale(:fr) do + expect(body.name).to eq('Example Public Body FR') + end + end + + it 'updates an existing translation and adds a third translation' do + post :update, { + :id => @body.id, + :public_body => { + :name => @body.name(:en), + :translations_attributes => { + # Update existing translation + 'es' => { :id => @body.translation_for(:es).id, + :locale => "es", + :name => "Renamed Example Public Body ES" }, + # Add new translation + 'fr' => { :locale => "fr", + :name => "Example Public Body FR" } + } + } + } + + request.flash[:notice].should include('successful') + + body = PublicBody.find(@body.id) + + I18n.with_locale(:es) do + expect(body.name).to eq('Renamed Example Public Body ES') + end + I18n.with_locale(:fr) do + expect(body.name).to eq('Example Public Body FR') + end + end + + end + + context 'on failure' do + + it 'renders the form if creating the record was unsuccessful' do + post :update, :id => @body.id, + :public_body => { + :name => '', + :translations_attributes => {} + } + expect(response).to render_template('edit') + end + + it 'is rebuilt with the given params' do + post :update, :id => @body.id, + :public_body => { + :name => '', + :request_email => 'updated@localhost', + :translations_attributes => {} + } + expect(assigns(:public_body).request_email).to eq('updated@localhost') + end + + end - I18n.with_locale(:es) do - expect(pb.name).to eq('Renamed') + context 'on failure for multiple locales' do + + before(:each) do + @params = { :id => @body.id, + :public_body => { :name => '', + :translations_attributes => { + 'es' => { :id => @body.translation_for(:es).id, + :locale => 'es', + :name => 'Mi Nuevo Body' } + } } } + end + + it 'is rebuilt with the default locale translation' do + post :update, @params + expect(assigns(:public_body).name(:en)).to eq('') end - I18n.with_locale(:en) do - expect(pb.name).to eq('Department for Humpadinking') + it 'is rebuilt with the alternative locale translation' do + post :update, @params + + I18n.with_locale(:es) do + expect(assigns(:public_body).name).to eq('Mi Nuevo Body') + end end end @@ -402,7 +547,7 @@ describe AdminPublicBodyController, "when destroying a public body" do it "destroys a public body" do n = PublicBody.count post :destroy, { :id => public_bodies(:forlorn_public_body).id } - response.should redirect_to(:controller=>'admin_public_body', :action=>'list') + response.should redirect_to admin_bodies_path PublicBody.count.should == n - 1 end @@ -416,7 +561,7 @@ describe AdminPublicBodyController, "when assigning public body tags" do n = PublicBody.joins(:translations).where([condition, "en"]).count post :mass_tag_add, { :new_tag => "department", :table_name => "substring" } request.flash[:notice].should == "Added tag to table of bodies." - response.should redirect_to(:action=>'list') + response.should redirect_to admin_bodies_path PublicBody.find_by_tag("department").count.should == n end end diff --git a/spec/controllers/admin_public_body_headings_controller_spec.rb b/spec/controllers/admin_public_body_headings_controller_spec.rb index afbe0fa30..ccdfdecfb 100644 --- a/spec/controllers/admin_public_body_headings_controller_spec.rb +++ b/spec/controllers/admin_public_body_headings_controller_spec.rb @@ -2,161 +2,466 @@ require 'spec_helper' describe AdminPublicBodyHeadingsController do - context 'when showing the form for a new public body category' do - it 'should assign a new public body heading to the view' do + describe :new do + + it 'responds successfully' do get :new - assigns[:heading].should be_a(PublicBodyHeading) + expect(response).to be_success end - it 'renders the new template' do + it 'builds a new PublicBodyHeading' do get :new - expect(response).to render_template('new') + expect(assigns(:heading)).to be_new_record end + + it 'builds new translations for all locales' do + get :new + + translations = assigns(:heading).translations.map{ |t| t.locale.to_s }.sort + available = I18n.available_locales.map{ |l| l.to_s }.sort + + expect(translations).to eq(available) + end + + it 'renders the new template' do + get :new + expect(response).to render_template('new') + end + end - context 'when creating a public body heading' do - it "creates a new public body heading in one locale" do - n = PublicBodyHeading.count - post :create, { - :public_body_heading => { - :name => 'New Heading' - } - } - PublicBodyHeading.count.should == n + 1 - - heading = PublicBodyHeading.find_by_name("New Heading") - response.should redirect_to(admin_categories_path) - end + describe :create do - it 'creates a new public body heading with multiple locales' do - n = PublicBodyHeading.count - post :create, { - :public_body_heading => { - :name => 'New Heading', - :translated_versions => [{ :locale => "es", - :name => "Mi Nuevo Heading" }] - } - } - PublicBodyHeading.count.should == n + 1 - - heading = PublicBodyHeading.find_by_name("New Heading") - heading.translations.map {|t| t.locale.to_s}.sort.should == ["en", "es"] - I18n.with_locale(:en) do - heading.name.should == "New Heading" + context 'on success' do + + before(:each) do + PublicBodyHeading.destroy_all + @params = { :translations_attributes => { + 'en' => { :locale => 'en', + :name => 'New Heading' } + } } end - I18n.with_locale(:es) do - heading.name.should == "Mi Nuevo Heading" + + it 'creates a new heading in the default locale' do + expect { + post :create, :public_body_heading => @params + }.to change{ PublicBodyHeading.count }.from(0).to(1) end - response.should redirect_to(admin_categories_path) - end + it 'notifies the admin that the heading was created' do + post :create, :public_body_heading => @params + expect(flash[:notice]).to eq('Heading was successfully created.') + end + + it 'redirects to the categories index' do + post :create, :public_body_heading => @params + expect(response).to redirect_to(admin_categories_path) + end - it "renders the form if creating the record was unsuccessful" do - post :create, :public_body_heading => { :name => '' } - expect(response).to render_template('new') end - end + context 'on success for multiple locales' do - context 'when editing a public body heading' do - before do - @heading = FactoryGirl.create(:public_body_heading) - end + before(:each) do + PublicBodyHeading.destroy_all + @params = { :translations_attributes => { + 'en' => { :locale => 'en', + :name => 'New Heading' }, + 'es' => { :locale => 'es', + :name => 'Mi Nuevo Heading' } + } } + end - render_views + it 'saves the heading' do + expect { + post :create, :public_body_heading => @params + }.to change{ PublicBodyHeading.count }.from(0).to(1) + end - it "finds the requested heading" do - get :edit, :id => @heading.id - expect(assigns[:heading]).to eq(@heading) - end + it 'saves the default locale translation' do + post :create, :public_body_heading => @params - it "renders the edit template" do - get :edit, :id => @heading.id - expect(assigns[:heading]).to render_template('edit') - end - end + heading = PublicBodyHeading.find_by_name('New Heading') + + I18n.with_locale(:en) do + expect(heading.name).to eq('New Heading') + end + end + + it 'saves the alternative locale translation' do + post :create, :public_body_heading => @params + + heading = PublicBodyHeading.find_by_name('New Heading') + + I18n.with_locale(:es) do + expect(heading.name).to eq('Mi Nuevo Heading') + end + end - context 'when updating a public body heading' do - before do - @heading = FactoryGirl.create(:public_body_heading) - @name = @heading.name end - it "saves edits to a public body heading" do - post :update, { :id => @heading.id, - :public_body_heading => { :name => "Renamed" } } - request.flash[:notice].should include('successful') - found_heading = PublicBodyHeading.find(@heading.id) - found_heading.name.should == "Renamed" + context 'on failure' do + + it 'renders the form if creating the record was unsuccessful' do + post :create, :public_body_heading => { :name => '' } + expect(response).to render_template('new') + end + + it 'is rebuilt with the given params' do + post :create, :public_body_heading => { :name => 'Need a description' } + expect(assigns(:heading).name).to eq('Need a description') + end + end - it "saves edits to a public body heading in another locale" do - I18n.with_locale(:es) do - post :update, { - :id => @heading.id, - :public_body_heading => { - :name => @name, - :translated_versions => { - @heading.id => {:locale => "es", - :name => "Renamed"} - } - } - } - request.flash[:notice].should include('successful') + context 'on failure for multiple locales' do + + before(:each) do + @params = { :translations_attributes => { + 'en' => { :locale => 'en', + :name => 'Need a description' }, + 'es' => { :locale => 'es', + :name => 'Mi Nuevo Heading' } + } } + end + + it 'is rebuilt with the default locale translation' do + post :create, :public_body_heading => @params + expect(assigns(:heading).name).to eq('Need a description') end - heading = PublicBodyHeading.find(@heading.id) - I18n.with_locale(:es) do - heading.name.should == "Renamed" + it 'is rebuilt with the alternative locale translation' do + post :create, :public_body_heading => @params + + I18n.with_locale(:es) do + expect(assigns(:heading).name).to eq('Mi Nuevo Heading') + end end - I18n.with_locale(:en) do - heading.name.should == @name + + end + + end + + describe :edit do + + before do + @heading = FactoryGirl.create(:public_body_heading) + I18n.with_locale('es') do + @heading.name = 'Los heading' + @heading.save! end end - it "redirects to the edit page after a successful update" do - post :update, { :id => @heading.id, - :public_body_heading => { :name => "Renamed" } } + it 'responds successfully' do + get :edit, :id => @heading.id + expect(response).to be_success + end - expect(response).to redirect_to(edit_admin_heading_path(@heading)) + it 'finds the requested heading' do + get :edit, :id => @heading.id + expect(assigns[:heading]).to eq(@heading) end - it "re-renders the edit form after an unsuccessful update" do - post :update, { :id => @heading.id, - :public_body_heading => { :name => '' } } + it 'builds new translations if the body does not already have a translation in the specified locale' do + get :edit, :id => @heading.id + expect(assigns[:heading].translations.map(&:locale)).to include(:fr) + end + it 'renders the edit template' do + get :edit, :id => @heading.id expect(response).to render_template('edit') end end - context 'when destroying a public body heading' do + describe :update do + + before do + @heading = FactoryGirl.create(:public_body_heading) + I18n.with_locale('es') do + @heading.name = 'Los heading' + @heading.save! + end + @params = { :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => @heading.name(:en) }, + 'es' => { :id => @heading.translation_for(:es).id, + :locale => 'es', + :title => @heading.name(:es) } + } } + end + + it 'finds the heading to update' do + post :update, :id => @heading.id, + :public_body_category => @params + expect(assigns(:heading)).to eq(@heading) + end + + context 'on success' do + + before(:each) do + @params = { :id => @heading.id, + :public_body_heading => { + :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :name => 'Renamed' } + } + } + } + end + + it 'saves edits to a public body heading' do + post :update, @params + heading = PublicBodyHeading.find(@heading.id) + expect(heading.name).to eq('Renamed') + end + + it 'notifies the admin that the heading was updated' do + post :update, @params + expect(flash[:notice]).to eq('Heading was successfully updated.') + end + + it 'redirects to the heading edit page' do + post :update, @params + expect(response).to redirect_to(edit_admin_heading_path(@heading)) + end + + end + + context 'on success for multiple locales' do + + it 'saves edits to a public body heading in another locale' do + @heading.name(:es).should == 'Los heading' + post :update, :id => @heading.id, + :public_body_heading => { + :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => @heading.name(:en) }, + 'es' => { :id => @heading.translation_for(:es).id, + :locale => 'es', + :name => 'Renamed' } + } + } + + heading = PublicBodyHeading.find(@heading.id) + expect(heading.name(:es)).to eq('Renamed') + expect(heading.name(:en)).to eq(@heading.name(:en)) + end + + it 'adds a new translation' do + @heading.translation_for(:es).destroy + @heading.reload + + put :update, { + :id => @heading.id, + :public_body_heading => { + :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => @heading.name(:en) }, + 'es' => { :locale => "es", + :name => "Example Public Body Heading ES" } + } + } + } + + request.flash[:notice].should include('successful') + + heading = PublicBodyHeading.find(@heading.id) + + I18n.with_locale(:es) do + expect(heading.name).to eq('Example Public Body Heading ES') + end + end + + it 'adds new translations' do + @heading.translation_for(:es).destroy + @heading.reload + + post :update, { + :id => @heading.id, + :public_body_heading => { + :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => @heading.name(:en) }, + 'es' => { :locale => "es", + :name => "Example Public Body Heading ES" }, + 'fr' => { :locale => "fr", + :name => "Example Public Body Heading FR" } + } + } + } + + request.flash[:notice].should include('successful') + + heading = PublicBodyHeading.find(@heading.id) + + I18n.with_locale(:es) do + expect(heading.name).to eq('Example Public Body Heading ES') + end + I18n.with_locale(:fr) do + expect(heading.name).to eq('Example Public Body Heading FR') + end + end + + it 'updates an existing translation and adds a third translation' do + post :update, { + :id => @heading.id, + :public_body_heading => { + :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => @heading.name(:en) }, + # Update existing translation + 'es' => { :id => @heading.translation_for(:es).id, + :locale => "es", + :name => "Renamed Example Public Body Heading ES" }, + # Add new translation + 'fr' => { :locale => "fr", + :name => "Example Public Body Heading FR" } + } + } + } + + request.flash[:notice].should include('successful') + + heading = PublicBodyHeading.find(@heading.id) + + I18n.with_locale(:es) do + expect(heading.name).to eq('Renamed Example Public Body Heading ES') + end + I18n.with_locale(:fr) do + expect(heading.name).to eq('Example Public Body Heading FR') + end + end + + it "redirects to the edit page after a successful update" do + post :update, :id => @heading.id, + :public_body_heading => { + :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => @heading.name(:en) } + } } + + expect(response).to redirect_to(edit_admin_heading_path(@heading)) + end + + end + + context 'on failure' do + + it 'renders the form if creating the record was unsuccessful' do + post :update, :id => @heading.id, + :public_body_heading => { + :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => '' } + } } + expect(response).to render_template('edit') + end + + it 'is rebuilt with the given params' do + post :update, :id => @heading.id, + :public_body_heading => { + :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => 'Need a description' } + } } + expect(assigns(:heading).name).to eq('Need a description') + end + + end + + context 'on failure for multiple locales' do + + before(:each) do + @params = { :translations_attributes => { + 'en' => { :id => @heading.translation_for(:en).id, + :locale => 'en', + :name => '' }, + 'es' => { :id => @heading.translation_for(:es).id, + :locale => 'es', + :name => 'Mi Nuevo Heading' } + } } + end + + it 'is rebuilt with the default locale translation' do + post :update, :id => @heading.id, + :public_body_heading => @params + expect(assigns(:heading).name(:en)).to eq('') + end + + it 'is rebuilt with the alternative locale translation' do + post :update, :id => @heading.id, + :public_body_heading => @params + + I18n.with_locale(:es) do + expect(assigns(:heading).name).to eq('Mi Nuevo Heading') + end + end + + end + + end + + describe :destroy do + + it 'uses the current locale by default' do + heading = FactoryGirl.create(:public_body_heading) + post :destroy, :id => heading.id + expect(assigns(:locale)).to eq(I18n.locale.to_s) + end - before do - @heading = FactoryGirl.create(:public_body_heading) + it 'sets the locale if the show_locale param is passed' do + heading = FactoryGirl.create(:public_body_heading) + post :destroy, :id => heading.id, :show_locale => 'es' + expect(assigns(:locale)).to eq('es') end - it "destroys a public body heading that has associated categories" do + it 'destroys the public body heading' do + PublicBodyHeading.destroy_all + + heading = FactoryGirl.create(:public_body_heading) + + expect{ + post :destroy, :id => heading.id + }.to change{ PublicBodyHeading.count }.from(1).to(0) + end + + it 'destroys a heading that has associated categories' do + PublicBodyHeading.destroy_all + PublicBodyCategory.destroy_all + + heading = FactoryGirl.create(:public_body_heading) category = FactoryGirl.create(:public_body_category) link = FactoryGirl.create(:public_body_category_link, :public_body_category => category, - :public_body_heading => @heading, + :public_body_heading => heading, :category_display_order => 0) - n = PublicBodyHeading.count - n_links = PublicBodyCategoryLink.count - post :destroy, { :id => @heading.id } - response.should redirect_to(admin_categories_path) - PublicBodyHeading.count.should == n - 1 - PublicBodyCategoryLink.count.should == n_links - 1 + expect{ + post :destroy, :id => heading.id + }.to change{ PublicBodyHeading.count }.from(1).to(0) + end + + it 'notifies the admin that the heading was destroyed' do + heading = FactoryGirl.create(:public_body_heading) + post :destroy, :id => heading.id + expect(flash[:notice]).to eq('Heading was successfully destroyed.') end - it "destroys an empty public body heading" do - n = PublicBodyHeading.count - post :destroy, { :id => @heading.id } - response.should redirect_to(admin_categories_path) - PublicBodyHeading.count.should == n - 1 + it 'redirects to the categories index' do + heading = FactoryGirl.create(:public_body_heading) + post :destroy, :id => heading.id + expect(response).to redirect_to(admin_categories_path) end + end context 'when reordering public body headings' do diff --git a/spec/controllers/admin_raw_email_controller_spec.rb b/spec/controllers/admin_raw_email_controller_spec.rb new file mode 100644 index 000000000..77c57c38b --- /dev/null +++ b/spec/controllers/admin_raw_email_controller_spec.rb @@ -0,0 +1,30 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe AdminRawEmailController do + + describe :show do + + before do + @raw_email = FactoryGirl.create(:incoming_message).raw_email + end + + describe 'html version' do + + it 'renders the show template' do + get :show, :id => @raw_email.id + end + + end + + describe 'text version' do + + it 'sends the email as an RFC-822 attachment' do + get :show, :id => @raw_email.id, :format => 'txt' + response.content_type.should == 'message/rfc822' + response.body.should == @raw_email.data + end + end + + end + +end diff --git a/spec/controllers/admin_request_controller_spec.rb b/spec/controllers/admin_request_controller_spec.rb index 7c5253f49..4eb463963 100644 --- a/spec/controllers/admin_request_controller_spec.rb +++ b/spec/controllers/admin_request_controller_spec.rb @@ -57,12 +57,12 @@ describe AdminRequestController, "when administering requests" do it 'expires the file cache for that request' do info_request = info_requests(:badger_request) @controller.should_receive(:expire_for_request).with(info_request) - get :fully_destroy, { :id => info_request } + get :destroy, { :id => info_request } end it 'uses a different flash message to avoid trying to fetch a non existent user record' do info_request = info_requests(:external_request) - post :fully_destroy, { :id => info_request.id } + post :destroy, { :id => info_request.id } request.flash[:notice].should include('external') end @@ -77,34 +77,6 @@ describe AdminRequestController, "when administering the holding pen" do load_raw_emails_data end - it "shows a rejection reason for an incoming message from an invalid address" do - ir = info_requests(:fancy_dog_request) - ir.allow_new_responses_from = 'authority_only' - ir.handle_rejected_responses = 'holding_pen' - ir.save! - receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "frob@nowhere.com") - get :show_raw_email, :id => InfoRequest.holding_pen_request.get_last_public_response.raw_email.id - response.should contain "Only the authority can reply to this request" - end - - it "guesses a misdirected request" do - ir = info_requests(:fancy_dog_request) - ir.handle_rejected_responses = 'holding_pen' - ir.allow_new_responses_from = 'authority_only' - ir.save! - mail_to = "request-#{ir.id}-asdfg@example.com" - receive_incoming_mail('incoming-request-plain.email', mail_to) - interesting_email = InfoRequest.holding_pen_request.get_last_public_response.raw_email.id - # now we add another message to the queue, which we're not interested in - receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "") - InfoRequest.holding_pen_request.incoming_messages.length.should == 2 - get :show_raw_email, :id => interesting_email - response.should contain "Could not identify the request" - assigns[:info_requests][0].should == ir - end - - - it "shows a suitable default 'your email has been hidden' message" do ir = info_requests(:fancy_dog_request) get :show, :id => ir.id @@ -119,7 +91,7 @@ describe AdminRequestController, "when administering the holding pen" do it "hides requests and sends a notification email that it has done so" do ir = info_requests(:fancy_dog_request) - post :hide_request, :id => ir.id, :explanation => "Foo", :reason => "vexatious" + post :hide, :id => ir.id, :explanation => "Foo", :reason => "vexatious" ir.reload ir.prominence.should == "requester_only" ir.described_state.should == "vexatious" @@ -132,7 +104,7 @@ describe AdminRequestController, "when administering the holding pen" do it 'expires the file cache for the request' do ir = info_requests(:fancy_dog_request) @controller.should_receive(:expire_for_request).with(ir) - post :hide_request, :id => ir.id, :explanation => "Foo", :reason => "vexatious" + post :hide, :id => ir.id, :explanation => "Foo", :reason => "vexatious" end describe 'when hiding an external request' do @@ -153,7 +125,7 @@ describe AdminRequestController, "when administering the holding pen" do end def make_request(params=@default_params) - post :hide_request, params + post :hide, params end it 'should redirect the the admin page for the request' do diff --git a/spec/controllers/admin_track_controller_spec.rb b/spec/controllers/admin_track_controller_spec.rb index f2de6c0d3..d29db4966 100644 --- a/spec/controllers/admin_track_controller_spec.rb +++ b/spec/controllers/admin_track_controller_spec.rb @@ -1,9 +1,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe AdminTrackController, "when administering tracks" do - render_views - - it "shows the list page" do - get :list + + it "shows the index page" do + get :index end end diff --git a/spec/controllers/admin_user_controller_spec.rb b/spec/controllers/admin_user_controller_spec.rb index 8b89506f9..e979355cf 100644 --- a/spec/controllers/admin_user_controller_spec.rb +++ b/spec/controllers/admin_user_controller_spec.rb @@ -2,13 +2,13 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe AdminUserController, "when administering users" do render_views - - it "shows the index/list page" do + + it "shows the index page" do get :index end it "searches for 'bob'" do - get :list, :query => "bob" + get :index, :query => "bob" assigns[:admin_users].should == [ users(:bob_smith_user) ] end @@ -51,7 +51,7 @@ describe AdminUserController do before(:each) do @user = FactoryGirl.create(:user) - request.env["HTTP_REFERER"] = admin_user_show_path(@user) + request.env["HTTP_REFERER"] = admin_user_path(@user) end it 'redirects to the page the admin was previously on' do @@ -61,7 +61,7 @@ describe AdminUserController do :comment_ids => comment.id, :hide_selected => 'hidden' } - response.should redirect_to(admin_user_show_path(@user)) + response.should redirect_to(admin_user_path(@user)) end it 'sets the given comments visibility to hidden' do diff --git a/spec/controllers/general_controller_spec.rb b/spec/controllers/general_controller_spec.rb index 8652d9b17..ae8d4f256 100644 --- a/spec/controllers/general_controller_spec.rb +++ b/spec/controllers/general_controller_spec.rb @@ -102,6 +102,14 @@ describe GeneralController, "when showing the frontpage" do end end + it 'should generate a feed URL for successful requests' do + get :frontpage + assigns[:feed_autodetect].size.should == 1 + successful_request_feed = assigns[:feed_autodetect].first + successful_request_feed[:title].should == 'Successful requests' + end + + it "should render the front page with default language and ignore the browser setting" do config = MySociety::Config.load_default() config['USE_DEFAULT_BROWSER_LANGUAGE'] = false @@ -138,6 +146,35 @@ describe GeneralController, "when showing the frontpage" do end + describe 'when handling logged-in users' do + + before do + @user = FactoryGirl.create(:user) + session[:user_id] = @user.id + end + + it 'should set a time to live on a non "remember me" session' do + get :frontpage + response.body.should match @user.name + session[:ttl].should be_within(1).of(Time.now) + end + + it 'should not set a time to live on a "remember me" session' do + session[:remember_me] = true + get :frontpage + response.body.should match @user.name + session[:ttl].should be_nil + end + + it 'should end a logged-in session whose ttl has expired' do + session[:ttl] = Time.now - 4.hours + get :frontpage + response.should redirect_to signin_path + session[:user_id].should be_nil + end + + end + end diff --git a/spec/controllers/public_body_change_requests_controller_spec.rb b/spec/controllers/public_body_change_requests_controller_spec.rb index 8fe7befeb..4053b2f40 100644 --- a/spec/controllers/public_body_change_requests_controller_spec.rb +++ b/spec/controllers/public_body_change_requests_controller_spec.rb @@ -28,6 +28,7 @@ describe PublicBodyChangeRequestsController, "creating a change request" do it "should send an email to the site contact address" do post :create, {:public_body_change_request => @change_request_params} + change_request_id = assigns[:change_request].id deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] @@ -37,8 +38,8 @@ describe PublicBodyChangeRequestsController, "creating a change request" do mail.body.should include('new_body@example.com') mail.body.should include('New Body') mail.body.should include("Please") - mail.body.should include('http://test.host/admin/body/new?change_request_id=') - mail.body.should include('http://test.host/admin/change_request/edit/') + mail.body.should include("http://test.host/admin/bodies/new?change_request_id=#{change_request_id}") + mail.body.should include("http://test.host/admin/change_requests/#{change_request_id}/edit") end it 'should show a notice' do @@ -83,6 +84,7 @@ describe PublicBodyChangeRequestsController, "creating a change request" do it 'should send an email to the site contact address' do post :create, {:public_body_change_request => @change_request_params} + change_request_id = assigns[:change_request].id deliveries = ActionMailer::Base.deliveries deliveries.size.should == 1 mail = deliveries[0] @@ -92,8 +94,8 @@ describe PublicBodyChangeRequestsController, "creating a change request" do mail.body.should include('new_body@example.com') mail.body.should include(@public_body.name) mail.body.should include("Please") - mail.body.should include("http://test.host/admin/body/edit/#{@public_body.id}?change_request_id=") - mail.body.should include('http://test.host/admin/change_request/edit/') + mail.body.should include("http://test.host/admin/bodies/#{@public_body.id}/edit?change_request_id=#{change_request_id}") + mail.body.should include("http://test.host/admin/change_requests/#{change_request_id}/edit") end it 'should show a notice' do diff --git a/spec/controllers/public_body_controller_spec.rb b/spec/controllers/public_body_controller_spec.rb index 840b4bb28..130631ef6 100644 --- a/spec/controllers/public_body_controller_spec.rb +++ b/spec/controllers/public_body_controller_spec.rb @@ -70,6 +70,18 @@ describe PublicBodyController, "when showing a body" do get :show, :url_name => "dFh", :view => 'all' response.should redirect_to(:controller => 'public_body', :action => 'show', :url_name => "dfh") end + + it 'keeps the search_params flash' do + # Make two get requests to simulate the flash getting swept after the + # first response. + search_params = { 'query' => 'Quango' } + get :show, { :url_name => 'dfh', :view => 'all' }, + nil, + { :search_params => search_params } + get :show, :url_name => 'dfh', :view => 'all' + expect(flash[:search_params]).to eq(search_params) + end + end describe PublicBodyController, "when listing bodies" do @@ -479,4 +491,15 @@ describe PublicBodyController, "when doing type ahead searches" do response.should render_template('public_body/_search_ahead') assigns[:xapian_requests].should be_nil end + + it 'remembers the search params' do + search_params = { + 'query' => 'Quango', + 'page' => '1', + 'bodies' => '1' + } + get :search_typeahead, search_params + expect(flash[:search_params]).to eq(search_params) + end + end diff --git a/spec/controllers/request_controller_spec.rb b/spec/controllers/request_controller_spec.rb index 26e46a966..02237b29d 100644 --- a/spec/controllers/request_controller_spec.rb +++ b/spec/controllers/request_controller_spec.rb @@ -956,6 +956,20 @@ describe RequestController, "when searching for an authority" do }.should_not raise_error(StandardError) end end + + it "remembers the search params" do + session[:user_id] = @user.id + search_params = { + 'query' => 'Quango', + 'page' => '1', + 'bodies' => '1' + } + + get :select_authority, search_params + + expect(flash[:search_params]).to eq(search_params) + end + end describe RequestController, "when creating a new request" do @@ -1073,6 +1087,16 @@ describe RequestController, "when creating a new request" do response.redirect_url.should =~ /request\/why_is_your_quango_called_gerald\/new$/ end + it "sets the request_sent flash to true if successful" do + session[:user_id] = @user.id + post :new, :info_request => { :public_body_id => @body.id, + :title => "Why is your quango called Geraldine?", :tag_string => "" }, + :outgoing_message => { :body => "This is a silly letter. It is too short to be interesting." }, + :submitted_new_request => 1, :preview => 0 + + expect(flash[:request_sent]).to be_true + end + it "should give an error if the same request is submitted twice" do session[:user_id] = @user.id @@ -2392,6 +2416,23 @@ describe RequestController, "when doing type ahead searches" do get :search_typeahead, :q => "dog -chicken" assigns[:xapian_requests].results.size.should == 1 end + + it 'can filter search results by public body' do + get :search_typeahead, :q => 'boring', :requested_from => 'dfh' + expect(assigns[:query]).to eq('requested_from:dfh boring') + end + + it 'defaults to 25 results per page' do + get :search_typeahead, :q => 'boring' + expect(assigns[:per_page]).to eq(25) + end + + it 'can limit the number of searches returned' do + get :search_typeahead, :q => 'boring', :per_page => '1' + expect(assigns[:per_page]).to eq(1) + expect(assigns[:xapian_requests].results.size).to eq(1) + end + end describe RequestController, "when showing similar requests" do @@ -2442,7 +2483,7 @@ describe RequestController, "when caching fragments" do :info_request_id => 132, :id => 44, :get_attachments_for_display => nil, - :html_mask_stuff! => nil, + :apply_masks! => nil, :user_can_view? => true, :all_can_view? => true) attachment = FactoryGirl.build(:body_text, :filename => long_name) @@ -2537,10 +2578,9 @@ describe RequestController, "#new_batch" do assigns[:existing_batch].should_not be_nil end - it 'should display a success notice' do + it 'sets the batch_sent flash to true' do make_request - notice_text = "<p>Your Freedom of Information requests will be <strong>sent</strong> shortly!" - flash[:notice].should match notice_text + expect(flash[:batch_sent]).to be_true end end @@ -2655,7 +2695,7 @@ describe RequestController, "#select_authorities" do end - context 'when asked for JSON', :focus => true do + context 'when asked for JSON' do it 'should be successful' do get :select_authorities, {:public_body_query => "Quan", :format => 'json'}, {:user_id => @user.id} diff --git a/spec/controllers/services_controller_spec.rb b/spec/controllers/services_controller_spec.rb index 14731f090..621dbaaac 100644 --- a/spec/controllers/services_controller_spec.rb +++ b/spec/controllers/services_controller_spec.rb @@ -12,6 +12,14 @@ describe ServicesController, "when returning a message for people in other count @old_locale = FastGettext.locale() end + it 'keeps the flash' do + # Make two get requests to simulate the flash getting swept after the + # first response. + get :other_country_message, nil, nil, :some_flash_key => 'abc' + get :other_country_message + expect(flash[:some_flash_key]).to eq('abc') + end + it "should show no alaveteli message when in the deployed country" do config = MySociety::Config.load_default() config['ISO_COUNTRY_CODE'] = "DE" @@ -60,21 +68,25 @@ describe ServicesController, "when returning a message for people in other count response.should be_success response.body.should == 'Hello! We have an <a href="/help/alaveteli?country_name=Deutschland">important message</a> for visitors outside Deutschland' end + it "should default to no message if the country_from_ip domain doesn't exist" do AlaveteliConfiguration.stub!(:gaze_url).and_return('http://12123sdf14qsd.com') get :other_country_message response.should be_success response.body.should == '' end + it "should default to no message if the country_from_ip service doesn't exist" do AlaveteliConfiguration.stub!(:gaze_url).and_return('http://www.google.com') get :other_country_message response.should be_success response.body.should == '' end - it "should default to no message if the country_from_ip service returns an error" do + + it "should default to no message and log the error with url if the country_from_ip service returns an error" do FakeWeb.register_uri(:get, %r|500.com|, :body => "Error", :status => ["500", "Error"]) AlaveteliConfiguration.stub!(:gaze_url).and_return('http://500.com') + Rails.logger.should_receive(:warn).with /500\.com.*500 Error/ get :other_country_message response.should be_success response.body.should == '' diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb index 413d395c5..443856cf3 100644 --- a/spec/controllers/user_controller_spec.rb +++ b/spec/controllers/user_controller_spec.rb @@ -1,6 +1,63 @@ # coding: utf-8 require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') +describe UserController do + + describe :set_profile_photo do + + context 'user is banned' do + + before(:each) do + @user = FactoryGirl.create(:user, :ban_text => 'Causing trouble') + session[:user_id] = @user.id + @uploadedfile = fixture_file_upload("/files/parrot.png") + + post :set_profile_photo, :id => @user.id, + :file => @uploadedfile, + :submitted_draft_profile_photo => 1, + :automatically_crop => 1 + end + + it 'redirects to the profile page' do + expect(response).to redirect_to(set_profile_photo_path) + end + + it 'renders an error message' do + msg = 'Banned users cannot edit their profile' + expect(flash[:error]).to eq(msg) + end + + end + + end + + describe :set_profile_about_me do + + context 'user is banned' do + + before(:each) do + @user = FactoryGirl.create(:user, :ban_text => 'Causing trouble') + session[:user_id] = @user.id + + post :set_profile_about_me, :submitted_about_me => '1', + :about_me => 'Bad stuff' + end + + it 'redirects to the profile page' do + expect(response).to redirect_to(set_profile_about_me_path) + end + + it 'renders an error message' do + msg = 'Banned users cannot edit their profile' + expect(flash[:error]).to eq(msg) + end + + end + + end + +end + # TODO: Use route_for or params_from to check /c/ links better # http://rspec.rubyforge.org/rspec-rails/1.1.12/classes/Spec/Rails/Example/ControllerExampleGroup.html describe UserController, "when redirecting a show request to a canonical url" do diff --git a/spec/factories/holidays.rb b/spec/factories/holidays.rb new file mode 100644 index 000000000..531130c8a --- /dev/null +++ b/spec/factories/holidays.rb @@ -0,0 +1,8 @@ +FactoryGirl.define do + + factory :holiday do + day Date.new(2010, 1, 1) + description "New Year's Day" + end + +end diff --git a/spec/factories/incoming_messages.rb b/spec/factories/incoming_messages.rb index ec0afdcd0..b29fe8ce9 100644 --- a/spec/factories/incoming_messages.rb +++ b/spec/factories/incoming_messages.rb @@ -10,6 +10,9 @@ FactoryGirl.define do FactoryGirl.create(:body_text, :incoming_message => incoming_message, :url_part_number => 1) + + incoming_message.raw_email.incoming_message = incoming_message + incoming_message.raw_email.data = "somedata" end factory :plain_incoming_message do diff --git a/spec/factories/info_request_events.rb b/spec/factories/info_request_events.rb new file mode 100644 index 000000000..cdd303ad6 --- /dev/null +++ b/spec/factories/info_request_events.rb @@ -0,0 +1,12 @@ +FactoryGirl.define do + + factory :info_request_event do + info_request + event_type 'response' + params_yaml '' + factory :sent_event do + event_type 'sent' + end + end + +end diff --git a/spec/fixtures/files/fake-authority-add-tags.rb b/spec/fixtures/files/fake-authority-add-tags.csv index a5612d87f..a5612d87f 100644 --- a/spec/fixtures/files/fake-authority-add-tags.rb +++ b/spec/fixtures/files/fake-authority-add-tags.csv diff --git a/spec/fixtures/files/ical-holidays.ics b/spec/fixtures/files/ical-holidays.ics new file mode 100644 index 000000000..6ccf31202 --- /dev/null +++ b/spec/fixtures/files/ical-holidays.ics @@ -0,0 +1,22 @@ +BEGIN:VCALENDAR +VERSION:2.0 +METHOD:PUBLISH +PRODID:-//uk.gov/GOVUK calendars//EN +CALSCALE:GREGORIAN +BEGIN:VEVENT +DTEND;VALUE=DATE:20140102 +DTSTART;VALUE=DATE:20140101 +SUMMARY:New Year's Day +UID:ca6af7456b0088abad9a69f9f620f5ac-17@gov.uk +SEQUENCE:0 +DTSTAMP:20140916T090346Z +END:VEVENT +BEGIN:VEVENT +DTEND;VALUE=DATE:20150102 +DTSTART;VALUE=DATE:20150101 +SUMMARY:New Year's Day +UID:ca6af7456b00a69f9f620f5ac-17@gov.uk +SEQUENCE:0 +DTSTAMP:20140916T090346Z +END:VEVENT +END:VCALENDAR diff --git a/spec/fixtures/files/multiple-locales-same-name.csv b/spec/fixtures/files/multiple-locales-same-name.csv new file mode 100644 index 000000000..43505f6a6 --- /dev/null +++ b/spec/fixtures/files/multiple-locales-same-name.csv @@ -0,0 +1,2 @@ +"#id","request_email","name","name.es","tag_string","home_page" +23842,"test@test.es","Test","Test",37,"http://www.test.es/" diff --git a/spec/helpers/public_body_helper_spec.rb b/spec/helpers/public_body_helper_spec.rb new file mode 100644 index 000000000..0bf55abb4 --- /dev/null +++ b/spec/helpers/public_body_helper_spec.rb @@ -0,0 +1,141 @@ +# encoding: UTF-8 +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe PublicBodyHelper do + include PublicBodyHelper + + describe :public_body_not_requestable_reasons do + + before do + @body = FactoryGirl.build(:public_body) + end + + it 'returns an empty array if there are no reasons' do + expect(public_body_not_requestable_reasons(@body)).to eq([]) + end + + it 'includes a reason if the law does not apply to the authority' do + @body.tag_string = 'not_apply' + msg = 'Freedom of Information law does not apply to this authority, so you cannot make a request to it.' + expect(public_body_not_requestable_reasons(@body)).to include(msg) + end + + it 'includes a reason if the body no longer exists' do + @body.tag_string = 'defunct' + msg = 'This authority no longer exists, so you cannot make a request to it.' + expect(public_body_not_requestable_reasons(@body)).to include(msg) + end + + it 'links to the request page if the body has no contact email' do + @body.request_email = '' + msg = %Q(<a href="/new/#{ @body.url_name }" + class="link_button_green">Make + a request to this authority</a>).squish + + expect(public_body_not_requestable_reasons(@body)).to include(msg) + end + + it 'returns the reasons in order of importance' do + @body.tag_string = 'defunct not_apply' + @body.request_email = '' + + reasons = public_body_not_requestable_reasons(@body) + + expect(reasons[0]).to match(/no longer exists/) + expect(reasons[1]).to match(/does not apply/) + expect(reasons[2]).to match(/Make a request/) + end + + end + + + describe :type_of_authority do + + it 'falls back to "A public authority"' do + public_body = FactoryGirl.build(:public_body) + expect(type_of_authority(public_body)).to eq('A public authority') + end + + it 'handles Unicode' do + category = FactoryGirl.create(:public_body_category, :category_tag => 'spec', + :description => 'ünicode category') + heading = FactoryGirl.create(:public_body_heading) + heading.add_category(category) + public_body = FactoryGirl.create(:public_body, :tag_string => 'spec') + + + expect(type_of_authority(public_body)).to eq('<a href="/body/list/spec">Ünicode category</a>') + end + + it 'constructs the correct string if there are tags which are not categories' do + heading = FactoryGirl.create(:public_body_heading) + 3.times do |i| + category = FactoryGirl.create(:public_body_category, :category_tag => "spec_#{i}", + :description => "spec category #{i}") + heading.add_category(category) + end + public_body = FactoryGirl.create(:public_body, :tag_string => 'spec_0 spec_2 unknown') + expected = '<a href="/body/list/spec_0">Spec category 0</a> and <a href="/body/list/spec_2">spec category 2</a>' + expect(type_of_authority(public_body)).to eq(expected) + end + + + context 'when associated with one category' do + + it 'returns the description wrapped in an anchor tag' do + category = FactoryGirl.create(:public_body_category, :category_tag => 'spec', + :description => 'spec category') + heading = FactoryGirl.create(:public_body_heading) + heading.add_category(category) + public_body = FactoryGirl.create(:public_body, :tag_string => 'spec') + + anchor = %Q(<a href="/body/list/spec">Spec category</a>) + expect(type_of_authority(public_body)).to eq(anchor) + end + end + + context 'when associated with several categories' do + + it 'joins the category descriptions and capitalizes the first letter' do + heading = FactoryGirl.create(:public_body_heading) + 3.times do |i| + category = FactoryGirl.create(:public_body_category, :category_tag => "spec_#{i}", + :description => "spec category #{i}") + heading.add_category(category) + end + public_body = FactoryGirl.create(:public_body, :tag_string => 'spec_0 spec_1 spec_2') + + description = [ + %Q(<a href="/body/list/spec_0">Spec category 0</a>), + ', ', + %Q(<a href="/body/list/spec_1">spec category 1</a>), + ' and ', + %Q(<a href="/body/list/spec_2">spec category 2</a>) + ].join('') + + expect(type_of_authority(public_body)).to eq(description) + end + + end + + context 'when in a non-default locale' do + + it 'creates the anchor href in the correct locale' do + # Activate the routing filter, normally turned off for helper tests + RoutingFilter.active = true + category = FactoryGirl.create(:public_body_category, :category_tag => 'spec', + :description => 'spec category') + heading = FactoryGirl.create(:public_body_heading) + heading.add_category(category) + public_body = FactoryGirl.create(:public_body, :tag_string => 'spec') + + anchor = %Q(<a href="/es/body/list/spec">Spec category</a>) + I18n.with_locale(:es) { expect(type_of_authority(public_body) +).to eq(anchor) } + end + + end + + end + +end diff --git a/spec/integration/admin_public_body_category_edit_spec.rb b/spec/integration/admin_public_body_category_edit_spec.rb new file mode 100644 index 000000000..043524189 --- /dev/null +++ b/spec/integration/admin_public_body_category_edit_spec.rb @@ -0,0 +1,59 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') +require File.expand_path(File.dirname(__FILE__) + '/alaveteli_dsl') + +describe 'Editing a Public Body Category' do + before do + AlaveteliConfiguration.stub!(:skip_admin_auth).and_return(false) + + confirm(:admin_user) + @admin = login(:admin_user) + @category = FactoryGirl.create(:public_body_category) + end + + it 'can edit the default locale' do + @admin.visit edit_admin_category_path(@category) + @admin.fill_in 'public_body_category_title__en', :with => 'New Category EN' + @admin.click_button 'Save' + + @category.reload + expect(@category.title).to eq('New Category EN') + end + + it 'can add a translation for a single locale' do + expect(@category.find_translation_by_locale('fr')).to be_nil + + @admin.visit edit_admin_category_path(@category) + @admin.fill_in 'public_body_category_translations_attributes_fr_title__fr', :with => 'New Category FR' + @admin.fill_in 'public_body_category_translations_attributes_fr_description__fr', :with => 'FR Description' + @admin.click_button 'Save' + + @category.reload + I18n.with_locale(:fr) do + expect(@category.title).to eq('New Category FR') + end + end + + it 'can add a translation for multiple locales' do + # Add FR translation + @admin.visit edit_admin_category_path(@category) + @admin.fill_in 'public_body_category_translations_attributes_fr_title__fr', :with => 'New Category FR' + @admin.fill_in 'public_body_category_translations_attributes_fr_description__fr', :with => 'FR Description' + @admin.click_button 'Save' + + # Add ES translation + @admin.visit edit_admin_category_path(@category) + @admin.fill_in 'public_body_category_translations_attributes_es_title__es', :with => 'New Category ES' + @admin.fill_in 'public_body_category_translations_attributes_es_description__es', :with => 'ES Description' + @admin.click_button 'Save' + + @category.reload + I18n.with_locale(:fr) do + expect(@category.title).to eq('New Category FR') + end + + I18n.with_locale(:es) do + expect(@category.title).to eq('New Category ES') + end + end + +end diff --git a/spec/integration/admin_public_body_edit_spec.rb b/spec/integration/admin_public_body_edit_spec.rb index 613793dd4..aeec3e65a 100644 --- a/spec/integration/admin_public_body_edit_spec.rb +++ b/spec/integration/admin_public_body_edit_spec.rb @@ -18,7 +18,7 @@ describe 'Editing a Public Body' do end it 'can edit the default locale' do - @admin.visit admin_body_edit_path(@body) + @admin.visit edit_admin_body_path(@body) @admin.fill_in 'public_body_name__en', :with => 'New Quango EN' @admin.click_button 'Save' @@ -29,7 +29,7 @@ describe 'Editing a Public Body' do it 'can add a translation for a single locale' do expect(@body.find_translation_by_locale('fr')).to be_nil - @admin.visit admin_body_edit_path(@body) + @admin.visit edit_admin_body_path(@body) @admin.fill_in 'public_body_translations_attributes_fr_name__fr', :with => 'New Quango FR' @admin.click_button 'Save' @@ -40,19 +40,19 @@ describe 'Editing a Public Body' do end it 'can add a translation for multiple locales', :focus => true do - @admin.visit admin_body_edit_path(@body) + @admin.visit edit_admin_body_path(@body) @admin.fill_in 'public_body_name__en', :with => 'New Quango EN' @admin.click_button 'Save' # Add FR translation expect(@body.find_translation_by_locale('fr')).to be_nil - @admin.visit admin_body_edit_path(@body) + @admin.visit edit_admin_body_path(@body) @admin.fill_in 'public_body_translations_attributes_fr_name__fr', :with => 'New Quango FR' @admin.click_button 'Save' # Add ES translation expect(@body.find_translation_by_locale('es')).to be_nil - @admin.visit admin_body_edit_path(@body) + @admin.visit edit_admin_body_path(@body) @admin.fill_in 'public_body_translations_attributes_es_name__es', :with => 'New Quango ES' @admin.click_button 'Save' diff --git a/spec/integration/admin_public_body_heading_edit_spec.rb b/spec/integration/admin_public_body_heading_edit_spec.rb new file mode 100644 index 000000000..6c7a5a74b --- /dev/null +++ b/spec/integration/admin_public_body_heading_edit_spec.rb @@ -0,0 +1,58 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') +require File.expand_path(File.dirname(__FILE__) + '/alaveteli_dsl') + +describe 'Editing a Public Body Heading' do + before do + AlaveteliConfiguration.stub!(:skip_admin_auth).and_return(false) + + confirm(:admin_user) + @admin = login(:admin_user) + @heading = FactoryGirl.create(:public_body_heading) + end + + it 'can edit the default locale' do + @admin.visit edit_admin_heading_path(@heading) + @admin.fill_in 'public_body_heading_name__en', :with => 'New Heading EN' + @admin.click_button 'Save' + + @heading.reload + expect(@heading.name).to eq('New Heading EN') + end + + it 'can add a translation for a single locale' do + expect(@heading.find_translation_by_locale('fr')).to be_nil + + @admin.visit edit_admin_heading_path(@heading) + @admin.fill_in 'public_body_heading_translations_attributes_fr_name__fr', :with => 'New Heading FR' + @admin.click_button 'Save' + + @heading.reload + I18n.with_locale(:fr) do + expect(@heading.name).to eq('New Heading FR') + end + end + + it 'can add a translation for multiple locales' do + # Add FR translation + expect(@heading.find_translation_by_locale('fr')).to be_nil + @admin.visit edit_admin_heading_path(@heading) + @admin.fill_in 'public_body_heading_translations_attributes_fr_name__fr', :with => 'New Heading FR' + @admin.click_button 'Save' + + # Add ES translation + expect(@heading.find_translation_by_locale('es')).to be_nil + @admin.visit edit_admin_heading_path(@heading) + @admin.fill_in 'public_body_heading_translations_attributes_es_name__es', :with => 'New Heading ES' + @admin.click_button 'Save' + + @heading.reload + I18n.with_locale(:fr) do + expect(@heading.name).to eq('New Heading FR') + end + + I18n.with_locale(:es) do + expect(@heading.name).to eq('New Heading ES') + end + end + +end diff --git a/spec/integration/admin_spec.rb b/spec/integration/admin_spec.rb index 8e6351d2c..bdd6e9d8c 100644 --- a/spec/integration/admin_spec.rb +++ b/spec/integration/admin_spec.rb @@ -5,29 +5,25 @@ describe "When administering the site" do before do AlaveteliConfiguration.stub!(:skip_admin_auth).and_return(false) + confirm(:admin_user) + @admin = login(:admin_user) end it "allows an admin to log in as another user" do - # First log in as Joe Admin - confirm(:admin_user) - admin = login(:admin_user) - - # Now fetch the "log in as" link to log in as Bob - admin.get_via_redirect "/en/admin/user/login_as/#{users(:bob_smith_user).id}" - admin.response.should be_success - admin.session[:user_id].should == users(:bob_smith_user).id + # post to the "log in as" url to log in as Bob + @admin.post_via_redirect "/en/admin/users/#{users(:bob_smith_user).id}/login_as" + @admin.response.should be_success + @admin.session[:user_id].should == users(:bob_smith_user).id end it 'does not allow a non-admin user to login as another user' do robin = login(:robin_user) - robin.get_via_redirect "/en/admin/user/login_as/#{users(:bob_smith_user).id}" + robin.post_via_redirect "/en/admin/users/#{users(:bob_smith_user).id}/login_as" robin.response.should be_success robin.session[:user_id].should_not == users(:bob_smith_user).id end it "allows redelivery of an incoming message to a closed request" do - confirm(:admin_user) - admin = login(:admin_user) ir = info_requests(:fancy_dog_request) close_request(ir) InfoRequest.holding_pen_request.incoming_messages.length.should == 0 @@ -36,10 +32,9 @@ describe "When administering the site" do InfoRequest.holding_pen_request.incoming_messages.length.should == 1 new_im = InfoRequest.holding_pen_request.incoming_messages[0] ir.incoming_messages.length.should == 1 - post_params = {'redeliver_incoming_message_id' => new_im.id, - 'url_title' => ir.url_title} - admin.post '/en/admin/incoming/redeliver', post_params - admin.response.location.should == 'http://www.example.com/en/admin/request/show/101' + post_params = { 'url_title' => ir.url_title } + @admin.post "/en/admin/incoming_messages/#{new_im.id}/redeliver", post_params + @admin.response.location.should == 'http://www.example.com/en/admin/requests/101' ir = InfoRequest.find_by_url_title(ir.url_title) ir.incoming_messages.length.should == 2 @@ -47,8 +42,6 @@ describe "When administering the site" do end it "allows redelivery of an incoming message to more than one request" do - confirm(:admin_user) - admin = login(:admin_user) ir1 = info_requests(:fancy_dog_request) close_request(ir1) @@ -60,15 +53,41 @@ describe "When administering the site" do InfoRequest.holding_pen_request.incoming_messages.length.should == 1 new_im = InfoRequest.holding_pen_request.incoming_messages[0] - post_params = {'redeliver_incoming_message_id' => new_im.id, - 'url_title' => "#{ir1.url_title},#{ir2.url_title}"} - admin.post '/en/admin/incoming/redeliver', post_params + post_params = { 'url_title' => "#{ir1.url_title},#{ir2.url_title}" } + @admin.post "/en/admin/incoming_messages/#{new_im.id}/redeliver", post_params ir1.reload ir1.incoming_messages.length.should == 2 ir2.reload ir2.incoming_messages.length.should == 2 - admin.response.location.should == 'http://www.example.com/en/admin/request/show/106' + @admin.response.location.should == 'http://www.example.com/en/admin/requests/106' InfoRequest.holding_pen_request.incoming_messages.length.should == 0 end + describe 'when administering the holding pen' do + + it "shows a rejection reason for an incoming message from an invalid address" do + ir = FactoryGirl.create(:info_request, :allow_new_responses_from => 'authority_only', + :handle_rejected_responses => 'holding_pen') + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "frob@nowhere.com") + raw_email = InfoRequest.holding_pen_request.get_last_public_response.raw_email + @admin.get "/en/admin/raw_emails/#{raw_email.id}" + @admin.response.should contain "Only the authority can reply to this request" + end + + it "guesses a misdirected request" do + ir = FactoryGirl.create(:info_request, :allow_new_responses_from => 'authority_only', + :handle_rejected_responses => 'holding_pen') + mail_to = "request-#{ir.id}-asdfg@example.com" + receive_incoming_mail('incoming-request-plain.email', mail_to) + interesting_email = InfoRequest.holding_pen_request.get_last_public_response.raw_email + # now we add another message to the queue, which we're not interested in + receive_incoming_mail('incoming-request-plain.email', ir.incoming_email, "") + InfoRequest.holding_pen_request.incoming_messages.length.should == 2 + @admin.get "/en/admin/raw_emails/#{interesting_email.id}" + @admin.response.should contain "Could not identify the request" + @admin.response.should contain ir.title + end + + + end end diff --git a/spec/integration/alaveteli_dsl.rb b/spec/integration/alaveteli_dsl.rb index 1d56abbdf..370628d98 100644 --- a/spec/integration/alaveteli_dsl.rb +++ b/spec/integration/alaveteli_dsl.rb @@ -21,7 +21,7 @@ module AlaveteliDsl response.should redirect_to(:controller => 'user', :action => 'signin', :token => post_redirect.token) follow_redirect! response.should render_template("user/sign") - response.body.should match(/To send your FOI request, please sign in or make a new account./) + response.body.should match(/To send your FOI request, create an account or sign in/) end end @@ -33,15 +33,16 @@ def login(user) sess.reset! sess.extend(AlaveteliDsl) - if user.is_a? User - u = user - else - u = users(user) - end + u = user.is_a?(User) ? user : users(user) + sess.visit signin_path - sess.fill_in "Your e-mail:", :with => u.email - sess.fill_in "Password:", :with => "jonespassword" - sess.click_button "Sign in" + + sess.within '#signin_form' do + sess.fill_in "Your e-mail:", :with => u.email + sess.fill_in "Password:", :with => "jonespassword" + sess.click_button "Sign in" + end + assert sess.session[:user_id] == u.id end end diff --git a/spec/integration/download_request_spec.rb b/spec/integration/download_request_spec.rb index 638198cde..48b42b11d 100644 --- a/spec/integration/download_request_spec.rb +++ b/spec/integration/download_request_spec.rb @@ -56,7 +56,7 @@ describe 'when making a zipfile available' do admin = login(FactoryGirl.create(:admin_user)) post_data = {:incoming_message => {:prominence => 'requester_only', :prominence_reason => 'boring'}} - admin.post_via_redirect "/en/admin/incoming/update/#{info_request.incoming_messages.first.id}", post_data + admin.put_via_redirect "/en/admin/incoming_messages/#{info_request.incoming_messages.first.id}", post_data admin.response.should be_success # Admin retains the requester only things @@ -104,7 +104,7 @@ describe 'when making a zipfile available' do post_data = {:outgoing_message => {:prominence => 'requester_only', :prominence_reason => 'boring', :body => 'Some information please'}} - admin.post_via_redirect "/en/admin/outgoing/update/#{info_request.outgoing_messages.first.id}", post_data + admin.put_via_redirect "/en/admin/outgoing_messages/#{info_request.outgoing_messages.first.id}", post_data admin.response.should be_success # Admin retains the requester only things @@ -237,7 +237,7 @@ describe 'when making a zipfile available' do admin = login(FactoryGirl.create(:admin_user)) post_data = {:incoming_message => {:prominence => 'requester_only', :prominence_reason => 'boring'}} - admin.post_via_redirect "/en/admin/incoming/update/#{info_request.incoming_messages.first.id}", post_data + admin.put_via_redirect "/en/admin/incoming_messages/#{info_request.incoming_messages.first.id}", post_data admin.response.should be_success # Admin retains the requester only things @@ -285,7 +285,7 @@ describe 'when making a zipfile available' do post_data = {:outgoing_message => {:prominence => 'requester_only', :prominence_reason => 'boring', :body => 'Some information please'}} - admin.post_via_redirect "/en/admin/outgoing/update/#{info_request.outgoing_messages.first.id}", post_data + admin.put_via_redirect "/en/admin/outgoing_messages/#{info_request.outgoing_messages.first.id}", post_data admin.response.should be_success # Admin retains the requester only things diff --git a/spec/integration/errors_spec.rb b/spec/integration/errors_spec.rb index 4fa12fb21..39f1279ce 100644 --- a/spec/integration/errors_spec.rb +++ b/spec/integration/errors_spec.rb @@ -59,7 +59,6 @@ describe "When errors occur" do response.should render_template('general/exception_caught') response.code.should == '404' response.body.should match("Sorry, we couldn't find that page") - response.body.should match(%Q(invalid value for Integer)) end # it 'should handle non utf-8 parameters' do @@ -76,7 +75,6 @@ describe "When errors occur" do InfoRequest.stub!(:find_by_url_title!).and_raise("An example error") get("/request/example") response.should render_template('general/exception_caught') - response.body.should match('An example error') response.code.should == "500" end @@ -111,7 +109,6 @@ describe "When errors occur" do get("/es/request/example") response.should render_template('general/exception_caught') response.body.should match('Lo sentimos, hubo un problema procesando esta página') - response.body.should match('An example error') end it "should render a 403 with text body for attempts at directory listing for attachments" do @@ -136,7 +133,7 @@ describe "When errors occur" do it 'should show a full trace for general errors' do InfoRequest.stub!(:find).and_raise("An example error") - get("/admin/request/show/333") + get("/admin/requests/333") response.body.should have_selector('div[id=traces]') response.body.should match('An example error') end diff --git a/spec/integration/view_request_spec.rb b/spec/integration/view_request_spec.rb index eecb984f5..4d04c97d7 100644 --- a/spec/integration/view_request_spec.rb +++ b/spec/integration/view_request_spec.rb @@ -33,7 +33,7 @@ describe "When viewing requests" do # Admin makes the incoming message requester only post_data = {:incoming_message => {:prominence => 'hidden', :prominence_reason => 'boring'}} - admin.post_via_redirect "/admin/incoming/update/#{info_request.incoming_messages.first.id}", post_data + admin.put_via_redirect "/admin/incoming_messages/#{info_request.incoming_messages.first.id}", post_data admin.response.should be_success cache_directories_exist?(info_request).should be_false diff --git a/spec/lib/alaveteli_text_masker_spec.rb b/spec/lib/alaveteli_text_masker_spec.rb new file mode 100644 index 000000000..1a4782a83 --- /dev/null +++ b/spec/lib/alaveteli_text_masker_spec.rb @@ -0,0 +1,146 @@ +# -*- coding: utf-8 -*- +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe AlaveteliTextMasker do + include AlaveteliTextMasker + + describe :apply_masks! do + + describe 'when applying censor rules' do + + before do + @cheese_censor_rule = FactoryGirl.build(:censor_rule, :text => 'Stilton', + :replacement => 'Jarlsberg') + @colour_censor_rule = FactoryGirl.build(:censor_rule, :text => 'blue', + :replacement => 'yellow') + @regex_censor_rule = FactoryGirl.build(:censor_rule, :text => 'm[a-z][a-z][a-z]e', + :replacement => 'cat', + :regexp => true) + @censor_rules = [@cheese_censor_rule, @colour_censor_rule, @regex_censor_rule] + end + + it "should do nothing to a JPEG" do + data = "There was a mouse called Stilton, he wished that he was blue." + apply_masks!(data, "image/jpeg", :censor_rules => @censor_rules) + data.should == "There was a mouse called Stilton, he wished that he was blue." + end + + it "should replace censor text in Word documents" do + data = "There was a mouse called Stilton, he wished that he was blue." + apply_masks!(data, "application/vnd.ms-word", :censor_rules => @censor_rules) + data.should == "There was a xxxxx called xxxxxxx, he wished that he was xxxx." + end + + it 'should handle multibyte characters correctly' do + data = 'á mouse' + @regex_censor_rule.text = 'á' + apply_masks!(data, "application/octet-stream", :censor_rules => @censor_rules).should == 'x mouse' + end + + it "should apply censor rules to HTML files" do + data = "There was a mouse called Stilton, he wished that he was blue." + apply_masks!(data, 'text/html', :censor_rules => @censor_rules) + data.should == "There was a cat called Jarlsberg, he wished that he was yellow." + end + + end + + it "should replace ASCII email addresses in Word documents" do + data = "His email was foo@bar.com" + expected = "His email was xxx@xxx.xxx" + apply_masks!(data, "application/vnd.ms-word") + data.should == expected + end + + + it "should replace UCS-2 addresses in Word documents" do + data = "His email was f\000o\000o\000@\000b\000a\000r\000.\000c\000o\000m\000, indeed" + apply_masks!(data, "application/vnd.ms-word") + data.should == "His email was x\000x\000x\000@\000x\000x\000x\000.\000x\000x\000x\000, indeed" + end + + def pdf_replacement_test(use_ghostscript_compression) + config = MySociety::Config.load_default() + previous = config['USE_GHOSTSCRIPT_COMPRESSION'] + config['USE_GHOSTSCRIPT_COMPRESSION'] = use_ghostscript_compression + orig_pdf = load_file_fixture('tfl.pdf') + pdf = orig_pdf.dup + + orig_text = MailHandler.get_attachment_text_one_file('application/pdf', pdf) + orig_text.should match(/foi@tfl.gov.uk/) + + apply_masks!(pdf, "application/pdf") + + masked_text = MailHandler.get_attachment_text_one_file('application/pdf', pdf) + masked_text.should_not match(/foi@tfl.gov.uk/) + masked_text.should match(/xxx@xxx.xxx.xx/) + config['USE_GHOSTSCRIPT_COMPRESSION'] = previous + end + + it "should replace everything in PDF files using pdftk" do + pdf_replacement_test(false) + end + + it "should replace everything in PDF files using ghostscript" do + pdf_replacement_test(true) + end + + it "should not produce zero length output if pdftk silently fails" do + orig_pdf = load_file_fixture('psni.pdf') + pdf = orig_pdf.dup + apply_masks!(pdf, "application/pdf") + pdf.should_not == "" + end + + it "should apply hard-coded privacy rules to HTML files" do + data = "http://test.host/c/cheese" + apply_masks!(data, 'text/html') + data.should == "[Alaveteli login link]" + end + + it 'should replace a simple email address' do + expected = "the address is [email address]" + apply_masks!("the address is test@example.com", 'text/html', {}).should == expected + end + + it 'should replace a mobile phone number prefixed with "Mobile"' do + expected = "the mobile is [mobile number]" + apply_masks!("the mobile is Mobile 55555 555555", 'text/html', {}).should == expected + end + + it 'should replace a mobile phone number prefixed with "Mob Tel"' do + expected = "the mobile is [mobile number]" + apply_masks!("the mobile is Mob Tel: 55555 555 555", 'text/html', {}).should == expected + end + + it 'should replace a mobile phone number prefixed with "Mob/Fax:"' do + expected = "the mobile is [mobile number]" + apply_masks!("the mobile is Mob/Fax: 55555 555555", 'text/html', {}).should == expected + end + + it "should replace an Alaveteli login link" do + expected = "the login link is [Alaveteli login link]" + apply_masks!("the login link is http://test.host/c/ekfmsdfkm", 'text/html', {}).should == expected + end + + it "should replace a https Alaveteli login link" do + expected = "the login link is [Alaveteli login link]" + apply_masks!("the login link is https://test.host/c/ekfmsdfkm", 'text/html', {}).should == expected + end + + it "should apply censor rules to text" do + censor_rule = FactoryGirl.build(:censor_rule, :text => 'mouse', :replacement => 'cat') + expected = "here is a cat" + apply_masks!("here is a mouse", 'text/html', {:censor_rules => [ censor_rule ]}).should == expected + end + + it 'should apply extra masks to text' do + mask = {:to_replace => 'mouse', :replacement => 'cat'} + expected = "here is a cat" + apply_masks!("here is a mouse", 'text/html', {:masks => [ mask ]}).should == expected + end + + end + +end + diff --git a/spec/mailers/outgoing_mailer_spec.rb b/spec/mailers/outgoing_mailer_spec.rb index a11d56dd3..3df5018fe 100644 --- a/spec/mailers/outgoing_mailer_spec.rb +++ b/spec/mailers/outgoing_mailer_spec.rb @@ -75,14 +75,14 @@ describe OutgoingMailer, "when working out follow up subjects" do ir = info_requests(:fancy_dog_request) im = ir.incoming_messages[0] - ir.email_subject_request.should == "Freedom of Information request - Why do you have & such a fancy dog?" + ir.email_subject_request(:html => false).should == "Freedom of Information request - Why do you have & such a fancy dog?" end it "should use 'Re:' and inital request subject for followups which aren't replies to particular messages" do ir = info_requests(:fancy_dog_request) om = outgoing_messages(:useless_outgoing_message) - OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" + OutgoingMailer.subject_for_followup(ir, om, :html => false).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" end it "should prefix with Re: the subject of the message being replied to" do @@ -91,7 +91,7 @@ describe OutgoingMailer, "when working out follow up subjects" do om = outgoing_messages(:useless_outgoing_message) om.incoming_message_followup = im - OutgoingMailer.subject_for_followup(ir, om).should == "Re: Geraldine FOI Code AZXB421" + OutgoingMailer.subject_for_followup(ir, om, :html => false).should == "Re: Geraldine FOI Code AZXB421" end it "should not add Re: prefix if there already is such a prefix" do @@ -101,7 +101,7 @@ describe OutgoingMailer, "when working out follow up subjects" do om.incoming_message_followup = im im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Re: Geraldine FOI Code AZXB421") - OutgoingMailer.subject_for_followup(ir, om).should == "Re: Geraldine FOI Code AZXB421" + OutgoingMailer.subject_for_followup(ir, om, :html => false).should == "Re: Geraldine FOI Code AZXB421" end it "should not add Re: prefix if there already is a lower case re: prefix" do @@ -113,7 +113,7 @@ describe OutgoingMailer, "when working out follow up subjects" do im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: re: Geraldine FOI Code AZXB421") im.parse_raw_email! true - OutgoingMailer.subject_for_followup(ir, om).should == "re: Geraldine FOI Code AZXB421" + OutgoingMailer.subject_for_followup(ir, om, :html => false).should == "re: Geraldine FOI Code AZXB421" end it "should use 'Re:' and initial request subject when replying to failed delivery notifications" do @@ -126,7 +126,7 @@ describe OutgoingMailer, "when working out follow up subjects" do im.raw_email.data = im.raw_email.data.sub("Subject: Geraldine FOI Code AZXB421", "Subject: Delivery Failed") im.parse_raw_email! true - OutgoingMailer.subject_for_followup(ir, om).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" + OutgoingMailer.subject_for_followup(ir, om, :html => false).should == "Re: Freedom of Information request - Why do you have & such a fancy dog?" end end diff --git a/spec/mailers/request_mailer_spec.rb b/spec/mailers/request_mailer_spec.rb index 8ba2a7bec..9e98dbc00 100644 --- a/spec/mailers/request_mailer_spec.rb +++ b/spec/mailers/request_mailer_spec.rb @@ -427,8 +427,7 @@ describe RequestMailer, 'requires_admin' do it 'body should contain the full admin URL' do mail = RequestMailer.requires_admin(@info_request).deliver - - mail.body.should include('http://test.host/en/admin/request/show/123') + mail.body.should include('http://test.host/en/admin/requests/123') end it "body should contain the message from the user" do diff --git a/spec/models/about_me_validator_spec.rb b/spec/models/about_me_validator_spec.rb new file mode 100644 index 000000000..5610cead8 --- /dev/null +++ b/spec/models/about_me_validator_spec.rb @@ -0,0 +1,53 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe AboutMeValidator do + + describe :new do + + it 'sets each supported attribute on the instance' do + params = { :about_me => 'My description' } + validator = AboutMeValidator.new(params) + expect(validator.about_me).to eq('My description') + end + + end + + describe :valid? do + + it 'is valid if about_me is =< 500' do + params = { :about_me => 'a'*500 } + validator = AboutMeValidator.new(params) + expect(validator).to be_valid + end + + it 'is valid if about_me is blank' do + params = { :about_me => '' } + validator = AboutMeValidator.new(params) + expect(validator).to be_valid + end + + it 'is valid if about_me is nil' do + params = { :about_me => nil } + validator = AboutMeValidator.new(params) + expect(validator).to be_valid + end + + it 'is invalid if about_me is > 500' do + params = { :about_me => 'a'*501 } + validator = AboutMeValidator.new(params) + expect(validator).to have(1).error_on(:about_me) + end + + end + + describe :about_me do + + it 'has an attribute accessor' do + params = { :about_me => 'My description' } + validator = AboutMeValidator.new(params) + expect(validator.about_me).to eq('My description') + end + + end + +end diff --git a/spec/models/holiday_import_spec.rb b/spec/models/holiday_import_spec.rb new file mode 100644 index 000000000..21061f63f --- /dev/null +++ b/spec/models/holiday_import_spec.rb @@ -0,0 +1,157 @@ +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') + +describe HolidayImport do + + it 'validates the presence of a feed if the source is a feed' do + holiday_import = HolidayImport.new(:source => 'feed') + holiday_import.valid?.should be_false + holiday_import.errors[:ical_feed_url].should == ["can't be blank"] + end + + it 'does not validate the presence of a feed if the source is suggestions' do + holiday_import = HolidayImport.new(:source => 'suggestions') + holiday_import.valid?.should be_true + end + + it 'validates that the source is either "feed" or "suggestions"' do + holiday_import = HolidayImport.new(:source => 'something') + holiday_import.valid?.should be_false + holiday_import.errors[:source].should == ["is not included in the list"] + end + + it 'validates that all holidays create from attributes are valid' do + holiday_import = HolidayImport.new(:source => 'suggestions', + :holidays_attributes => {"0" => {:description => '', + "day(1i)"=>"", + "day(2i)"=>"", + "day(3i)"=>""}}) + holiday_import.valid?.should be_false + holiday_import.errors[:base].should == ["These holidays could not be imported"] + end + + it 'validates that all holidays to import are valid' do + holiday_import = HolidayImport.new + holiday_import.holidays = [ Holiday.new ] + holiday_import.valid?.should be_false + holiday_import.errors[:base].should == ['These holidays could not be imported'] + end + + it 'defaults to importing holidays for the current year' do + holiday_import = HolidayImport.new + holiday_import.start_year.should == Time.now.year + holiday_import.end_year.should == Time.now.year + end + + it 'allows the start and end year to be set' do + holiday_import = HolidayImport.new(:start_year => 2011, :end_year => 2012) + holiday_import.start_year.should == 2011 + holiday_import.end_year.should == 2012 + end + + it 'sets the start and end dates to the beginning and end of the year' do + holiday_import = HolidayImport.new(:start_year => 2011, :end_year => 2012) + holiday_import.start_date.should == Date.new(2011, 1, 1) + holiday_import.end_date.should == Date.new(2012, 12, 31) + end + + it 'sets a default source of suggestions' do + holiday_import = HolidayImport.new + holiday_import.source.should == 'suggestions' + end + + it 'allows the source to be set' do + holiday_import = HolidayImport.new(:source => 'feed') + holiday_import.source.should == 'feed' + end + + it 'allows an iCal feed URL to be set' do + holiday_import = HolidayImport.new(:ical_feed_url => 'http://www.example.com') + holiday_import.ical_feed_url.should == 'http://www.example.com' + end + + it 'sets a default populated flag to false' do + holiday_import = HolidayImport.new + holiday_import.populated.should == false + end + + it 'returns a readable description of the period for multiple years' do + HolidayImport.new(:start_year => 2011, :end_year => 2012).period.should == '2011-2012' + end + + it 'returns a readable description of the period for a single year' do + HolidayImport.new(:start_year => 2011, :end_year => 2011).period.should == '2011' + end + + it 'returns the country name for which suggestions are generated' do + HolidayImport.new.suggestions_country_name.should == 'Germany' + end + + describe 'when populating a set of holidays to import from suggestions' do + + before do + holidays = [ { :date => Date.new(2014, 1, 1), :name => "New Year's Day", :regions => [:gb] } ] + Holidays.stub!(:between).and_return(holidays) + @holiday_import = HolidayImport.new(:source => 'suggestions') + @holiday_import.populate + end + + it 'should populate holidays from the suggestions' do + @holiday_import.holidays.size.should == 1 + holiday = @holiday_import.holidays.first + holiday.description.should == "New Year's Day" + holiday.day.should == Date.new(2014, 1, 1) + end + + it 'should return a flag that it has been populated' do + @holiday_import.populated.should == true + end + + end + + describe 'when populating a set of holidays to import from a feed' do + + before do + @holiday_import = HolidayImport.new(:source => 'feed', + :ical_feed_url => 'http://www.example.com', + :start_year => 2014, + :end_year => 2014) + end + + it 'should populate holidays from the feed that are between the dates' do + @holiday_import.stub!(:open).and_return(load_file_fixture('ical-holidays.ics')) + @holiday_import.populate + @holiday_import.holidays.size.should == 1 + holiday = @holiday_import.holidays.first + holiday.description.should == "New Year's Day" + holiday.day.should == Date.new(2014, 1, 1) + end + + it 'should add an error if the calendar cannot be parsed' do + @holiday_import.stub!(:open).and_return('some invalid data') + @holiday_import.populate + expected = ["Sorry, there's a problem with the format of that feed."] + @holiday_import.errors[:ical_feed_url].should == expected + end + + it 'should add an error if the calendar cannot be found' do + @holiday_import.stub!(:open).and_raise Errno::ENOENT.new('No such file or directory') + @holiday_import.populate + expected = ["Sorry we couldn't find that feed."] + @holiday_import.errors[:ical_feed_url].should == expected + end + + end + + describe 'when saving' do + + it 'saves all holidays' do + holiday = Holiday.new + holiday_import = HolidayImport.new + holiday_import.holidays = [ holiday ] + holiday.should_receive(:save) + holiday_import.save + end + + end + +end diff --git a/spec/models/holiday_spec.rb b/spec/models/holiday_spec.rb index 89849abb7..2f8eeabd9 100644 --- a/spec/models/holiday_spec.rb +++ b/spec/models/holiday_spec.rb @@ -9,87 +9,98 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') -describe Holiday, " when calculating due date" do +describe Holiday do - def due_date(ymd) - return Holiday.due_date_from_working_days(Date.strptime(ymd), 20).strftime("%F") - end + describe :new do - context "in working days" do - it "handles no holidays" do - due_date('2008-10-01').should == '2008-10-29' + it 'should require a day' do + holiday = Holiday.new + holiday.valid?.should be_false + holiday.errors[:day].should == ["can't be blank"] end + end - it "handles non leap years" do - due_date('2007-02-01').should == '2007-03-01' - end + describe " when calculating due date" do - it "handles leap years" do - due_date('2008-02-01').should == '2008-02-29' + def due_date(ymd) + return Holiday.due_date_from_working_days(Date.strptime(ymd), 20).strftime("%F") end - it "handles Thursday start" do - due_date('2009-03-12').should == '2009-04-14' - end + context "in working days" do + it "handles no holidays" do + due_date('2008-10-01').should == '2008-10-29' + end - it "handles Friday start" do - due_date('2009-03-13').should == '2009-04-15' - end + it "handles non leap years" do + due_date('2007-02-01').should == '2007-03-01' + end - # Delivery at the weekend ends up the same due day as if it had arrived on - # the Friday before. This is because the next working day (Monday) counts - # as day 1. - # See http://www.whatdotheyknow.com/help/officers#days - it "handles Saturday start" do - due_date('2009-03-14').should == '2009-04-15' - end - it "handles Sunday start" do - due_date('2009-03-15').should == '2009-04-15' - end + it "handles leap years" do + due_date('2008-02-01').should == '2008-02-29' + end - it "handles Monday start" do - due_date('2009-03-16').should == '2009-04-16' - end + it "handles Thursday start" do + due_date('2009-03-12').should == '2009-04-14' + end - it "handles Time objects" do - Holiday.due_date_from_working_days(Time.utc(2009, 03, 16, 12, 0, 0), 20).strftime('%F').should == '2009-04-16' - end - end + it "handles Friday start" do + due_date('2009-03-13').should == '2009-04-15' + end - context "in calendar days" do - it "handles no holidays" do - Holiday.due_date_from_calendar_days(Date.new(2008, 10, 1), 20).should == Date.new(2008, 10, 21) - end + # Delivery at the weekend ends up the same due day as if it had arrived on + # the Friday before. This is because the next working day (Monday) counts + # as day 1. + # See http://www.whatdotheyknow.com/help/officers#days + it "handles Saturday start" do + due_date('2009-03-14').should == '2009-04-15' + end + it "handles Sunday start" do + due_date('2009-03-15').should == '2009-04-15' + end - it "handles the due date falling on a Friday" do - Holiday.due_date_from_calendar_days(Date.new(2008, 10, 4), 20).should == Date.new(2008, 10, 24) - end + it "handles Monday start" do + due_date('2009-03-16').should == '2009-04-16' + end - # If the due date would fall on a Saturday it should in fact fall on the next day that isn't a weekend - # or a holiday - it "handles the due date falling on a Saturday" do - Holiday.due_date_from_calendar_days(Date.new(2008, 10, 5), 20).should == Date.new(2008, 10, 27) + it "handles Time objects" do + Holiday.due_date_from_working_days(Time.utc(2009, 03, 16, 12, 0, 0), 20).strftime('%F').should == '2009-04-16' + end end - it "handles the due date falling on a Sunday" do - Holiday.due_date_from_calendar_days(Date.new(2008, 10, 6), 20).should == Date.new(2008, 10, 27) - end + context "in calendar days" do + it "handles no holidays" do + Holiday.due_date_from_calendar_days(Date.new(2008, 10, 1), 20).should == Date.new(2008, 10, 21) + end - it "handles the due date falling on a Monday" do - Holiday.due_date_from_calendar_days(Date.new(2008, 10, 7), 20).should == Date.new(2008, 10, 27) - end + it "handles the due date falling on a Friday" do + Holiday.due_date_from_calendar_days(Date.new(2008, 10, 4), 20).should == Date.new(2008, 10, 24) + end - it "handles the due date falling on a day before a Holiday" do - Holiday.due_date_from_calendar_days(Date.new(2008, 12, 4), 20).should == Date.new(2008, 12, 24) - end + # If the due date would fall on a Saturday it should in fact fall on the next day that isn't a weekend + # or a holiday + it "handles the due date falling on a Saturday" do + Holiday.due_date_from_calendar_days(Date.new(2008, 10, 5), 20).should == Date.new(2008, 10, 27) + end - it "handles the due date falling on a Holiday" do - Holiday.due_date_from_calendar_days(Date.new(2008, 12, 5), 20).should == Date.new(2008, 12, 29) - end + it "handles the due date falling on a Sunday" do + Holiday.due_date_from_calendar_days(Date.new(2008, 10, 6), 20).should == Date.new(2008, 10, 27) + end + + it "handles the due date falling on a Monday" do + Holiday.due_date_from_calendar_days(Date.new(2008, 10, 7), 20).should == Date.new(2008, 10, 27) + end + + it "handles the due date falling on a day before a Holiday" do + Holiday.due_date_from_calendar_days(Date.new(2008, 12, 4), 20).should == Date.new(2008, 12, 24) + end - it "handles Time objects" do - Holiday.due_date_from_calendar_days(Time.utc(2009, 03, 17, 12, 0, 0), 20).should == Date.new(2009, 4, 6) + it "handles the due date falling on a Holiday" do + Holiday.due_date_from_calendar_days(Date.new(2008, 12, 5), 20).should == Date.new(2008, 12, 29) + end + + it "handles Time objects" do + Holiday.due_date_from_calendar_days(Time.utc(2009, 03, 17, 12, 0, 0), 20).should == Date.new(2009, 4, 6) + end end end end - diff --git a/spec/models/incoming_message_spec.rb b/spec/models/incoming_message_spec.rb index 3b6887f76..f6e524de3 100644 --- a/spec/models/incoming_message_spec.rb +++ b/spec/models/incoming_message_spec.rb @@ -423,127 +423,50 @@ describe IncomingMessage, " checking validity to reply to with real emails" do end -describe IncomingMessage, " when censoring data" do - - before(:each) do - @test_data = "There was a mouse called Stilton, he wished that he was blue." - - @im = incoming_messages(:useless_incoming_message) - - @censor_rule_1 = CensorRule.new() - @censor_rule_1.text = "Stilton" - @censor_rule_1.replacement = "Jarlsberg" - @censor_rule_1.last_edit_editor = "unknown" - @censor_rule_1.last_edit_comment = "none" - @im.info_request.censor_rules << @censor_rule_1 - - @censor_rule_2 = CensorRule.new() - @censor_rule_2.text = "blue" - @censor_rule_2.replacement = "yellow" - @censor_rule_2.last_edit_editor = "unknown" - @censor_rule_2.last_edit_comment = "none" - @im.info_request.censor_rules << @censor_rule_2 - - @regex_censor_rule = CensorRule.new() - @regex_censor_rule.text = 'm[a-z][a-z][a-z]e' - @regex_censor_rule.regexp = true - @regex_censor_rule.replacement = 'cat' - @regex_censor_rule.last_edit_editor = 'unknown' - @regex_censor_rule.last_edit_comment = 'none' - @im.info_request.censor_rules << @regex_censor_rule - load_raw_emails_data - end - - it "should do nothing to a JPEG" do - data = @test_data.dup - @im.binary_mask_stuff!(data, "image/jpeg") - data.should == @test_data - end - - it "should replace censor text in Word documents" do - data = @test_data.dup - @im.binary_mask_stuff!(data, "application/vnd.ms-word") - data.should == "There was a xxxxx called xxxxxxx, he wished that he was xxxx." - end - - it "should replace ASCII email addresses in Word documents" do - orig_data = "His email was foo@bar.com" - data = orig_data.dup - @im.binary_mask_stuff!(data, "application/vnd.ms-word") - data.should == "His email was xxx@xxx.xxx" - end - - it "should replace UCS-2 addresses in Word documents" do - orig_data = "His email was f\000o\000o\000@\000b\000a\000r\000.\000c\000o\000m\000, indeed" - data = orig_data.dup - @im.binary_mask_stuff!(data, "application/vnd.ms-word") - data.should == "His email was x\000x\000x\000@\000x\000x\000x\000.\000x\000x\000x\000, indeed" - end - - it 'should handle multibyte characters correctly' do - orig_data = 'á' - data = orig_data.dup - @regex_censor_rule = CensorRule.new() - @regex_censor_rule.text = 'á' - @regex_censor_rule.regexp = true - @regex_censor_rule.replacement = 'cat' - @regex_censor_rule.last_edit_editor = 'unknown' - @regex_censor_rule.last_edit_comment = 'none' - @im.info_request.censor_rules << @regex_censor_rule - lambda{ @im.binary_mask_stuff!(data, "text/plain") }.should_not raise_error - end - def pdf_replacement_test(use_ghostscript_compression) - config = MySociety::Config.load_default() - previous = config['USE_GHOSTSCRIPT_COMPRESSION'] - config['USE_GHOSTSCRIPT_COMPRESSION'] = use_ghostscript_compression - orig_pdf = load_file_fixture('tfl.pdf') - pdf = orig_pdf.dup - - orig_text = MailHandler.get_attachment_text_one_file('application/pdf', pdf) - orig_text.should match(/foi@tfl.gov.uk/) - - @im.binary_mask_stuff!(pdf, "application/pdf") - - masked_text = MailHandler.get_attachment_text_one_file('application/pdf', pdf) - masked_text.should_not match(/foi@tfl.gov.uk/) - masked_text.should match(/xxx@xxx.xxx.xx/) - config['USE_GHOSTSCRIPT_COMPRESSION'] = previous - end - - it "should replace everything in PDF files using pdftk" do - pdf_replacement_test(false) - end - - it "should replace everything in PDF files using ghostscript" do - pdf_replacement_test(true) - end - - it "should not produce zero length output if pdftk silently fails" do - orig_pdf = load_file_fixture('psni.pdf') - pdf = orig_pdf.dup - @im.binary_mask_stuff!(pdf, "application/pdf") - pdf.should_not == "" - end - - it "should apply censor rules to HTML files" do - data = @test_data.dup - @im.html_mask_stuff!(data) - data.should == "There was a cat called Jarlsberg, he wished that he was yellow." - end - - it "should apply hard-coded privacy rules to HTML files" do - data = "http://#{AlaveteliConfiguration::domain}/c/cheese" - @im.html_mask_stuff!(data) - data.should == "[WDTK login link]" - end +describe IncomingMessage, " when censoring data" do - it "should apply censor rules to From: addresses" do - @im.stub!(:mail_from).and_return("Stilton Mouse") - @im.stub!(:last_parsed).and_return(Time.now) - safe_mail_from = @im.safe_mail_from - safe_mail_from.should == "Jarlsberg Mouse" - end + before(:each) do + @test_data = "There was a mouse called Stilton, he wished that he was blue." + + @im = incoming_messages(:useless_incoming_message) + + @censor_rule_1 = CensorRule.new() + @censor_rule_1.text = "Stilton" + @censor_rule_1.replacement = "Jarlsberg" + @censor_rule_1.last_edit_editor = "unknown" + @censor_rule_1.last_edit_comment = "none" + @im.info_request.censor_rules << @censor_rule_1 + + @censor_rule_2 = CensorRule.new() + @censor_rule_2.text = "blue" + @censor_rule_2.replacement = "yellow" + @censor_rule_2.last_edit_editor = "unknown" + @censor_rule_2.last_edit_comment = "none" + @im.info_request.censor_rules << @censor_rule_2 + + @regex_censor_rule = CensorRule.new() + @regex_censor_rule.text = 'm[a-z][a-z][a-z]e' + @regex_censor_rule.regexp = true + @regex_censor_rule.replacement = 'cat' + @regex_censor_rule.last_edit_editor = 'unknown' + @regex_censor_rule.last_edit_comment = 'none' + @im.info_request.censor_rules << @regex_censor_rule + load_raw_emails_data + end + + it "should replace censor text" do + data = "There was a mouse called Stilton, he wished that he was blue." + @im.apply_masks!(data, "application/vnd.ms-word") + data.should == "There was a xxxxx called xxxxxxx, he wished that he was xxxx." + end + + it "should apply censor rules to From: addresses" do + @im.stub!(:mail_from).and_return("Stilton Mouse") + @im.stub!(:last_parsed).and_return(Time.now) + safe_mail_from = @im.safe_mail_from + safe_mail_from.should == "Jarlsberg Mouse" + end end @@ -565,15 +488,16 @@ describe IncomingMessage, " when censoring whole users" do it "should apply censor rules to HTML files" do data = @test_data.dup - @im.html_mask_stuff!(data) + @im.apply_masks!(data, 'text/html') data.should == "There was a mouse called Gorgonzola, he wished that he was blue." end it "should replace censor text to Word documents" do data = @test_data.dup - @im.binary_mask_stuff!(data, "application/vnd.ms-word") + @im.apply_masks!(data, "application/vnd.ms-word") data.should == "There was a mouse called xxxxxxx, he wished that he was blue." end + end @@ -770,3 +694,16 @@ describe IncomingMessage, "when extracting attachments" do end end + +describe IncomingMessage, 'when getting the body of a message for html display' do + + it 'should replace any masked email addresses with a link to the help page' do + incoming_message = IncomingMessage.new + body_text = 'there was an [email address] here' + incoming_message.stub!(:get_main_body_text_folded).and_return(body_text) + incoming_message.stub!(:get_main_body_text_unfolded).and_return(body_text) + expected = 'there was an [<a href="/help/officers#mobiles">email address</a>] here' + incoming_message.get_body_for_html_display.should == expected + end + +end diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb index 9ad616ea5..70947584b 100644 --- a/spec/models/info_request_spec.rb +++ b/spec/models/info_request_spec.rb @@ -824,7 +824,7 @@ describe InfoRequest do im = mock_model(IncomingMessage, :subject => nil, :valid_to_reply_to? => true) - subject = ir.email_subject_followup im + subject = ir.email_subject_followup(:incoming_message => im, :html => false) subject.should match(/^Re: Freedom of Information request.*fancy dog/) end diff --git a/spec/models/public_body_category_link_spec.rb b/spec/models/public_body_category_link_spec.rb index 8d91f02d5..fd5608480 100644 --- a/spec/models/public_body_category_link_spec.rb +++ b/spec/models/public_body_category_link_spec.rb @@ -1,10 +1,11 @@ # == Schema Information # -# Table name: public_body_category_link +# Table name: public_body_category_links # -# public_body_category_id :integer not null -# public_body_heading_id :integer not null -# category_display_order :integer +# public_body_category_id :integer not null +# public_body_heading_id :integer not null +# category_display_order :integer +# id :integer not null, primary key # require 'spec_helper' diff --git a/spec/models/public_body_category_spec.rb b/spec/models/public_body_category_spec.rb index c185a3169..297bd096a 100644 --- a/spec/models/public_body_category_spec.rb +++ b/spec/models/public_body_category_spec.rb @@ -2,46 +2,13 @@ # # Table name: public_body_categories # -# id :integer not null, primary key -# locale :string -# title :text not null -# category_tag :text not null -# description :text not null -# display_order :integer +# id :integer not null, primary key +# category_tag :text not null # require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe PublicBodyCategory do - describe 'when loading the data' do - it 'should use the display_order field to preserve the original data order' do - PublicBodyCategory.add(:en, [ - "Local and regional", - [ "local_council", "Local councils", "a local council" ], - "Miscellaneous", - [ "other", "Miscellaneous", "miscellaneous" ], - [ "aardvark", "Aardvark", "daft test"],]) - - headings = PublicBodyHeading.all - cat_group1 = headings[0].public_body_categories - cat_group1.count.should eq 1 - cat_group1[0].title.should eq "Local councils" - - cat_group2 = headings[1].public_body_categories - cat_group2.count.should eq 2 - cat_group2[0].title.should eq "Miscellaneous" - cat_group2[0].public_body_category_links.where( - :public_body_heading_id => headings[1].id). - first. - category_display_order.should eq 0 - - cat_group2[1].title.should eq "Aardvark" - cat_group2[1].public_body_category_links.where( - :public_body_heading_id => headings[1].id). - first. - category_display_order.should eq 1 - end - end context 'when validating' do @@ -67,5 +34,145 @@ describe PublicBodyCategory do category.should_not be_valid category.errors[:description].should == ["Description can't be blank"] end + + it 'validates the translations' do + category = FactoryGirl.build(:public_body_category) + translation = category.translations.build + expect(category).to_not be_valid + end + + it 'uses the base model validation for the default locale' do + category = PublicBodyCategory.new + translation = category.translations.build(:locale => 'en', + :description => 'No title') + category.valid? + translation.valid? + + expect(category).to have(1).error_on(:title) + expect(translation).to have(0).errors_on(:title) + end + + end + + describe :save do + + it 'saves translations' do + category = FactoryGirl.build(:public_body_category) + category.translations_attributes = { :es => { :locale => 'es', + :title => 'El Category', + :description => 'Spanish description' } } + + category.save + expect(PublicBodyCategory.find(category.id).translations.size).to eq(2) + end + end + + describe :translations_attributes= do + + context 'translation_attrs is a Hash' do + + it 'does not persist translations' do + category = FactoryGirl.create(:public_body_category) + category.translations_attributes = { :es => { :locale => 'es', + :title => 'El Category', + :description => 'Spanish description' } } + + expect(PublicBodyCategory.find(category.id).translations.size).to eq(1) + end + + it 'creates a new translation' do + category = FactoryGirl.create(:public_body_category) + category.translations_attributes = { :es => { :locale => 'es', + :title => 'El Category', + :description => 'Spanish description' } } + category.save + category.reload + expect(category.title(:es)).to eq('El Category') + end + + it 'updates an existing translation' do + category = FactoryGirl.create(:public_body_category) + category.translations_attributes = { 'es' => { :locale => 'es', + :title => 'Name', + :description => 'Desc' } } + category.save + + category.translations_attributes = { 'es' => { :id => category.translation_for(:es).id, + :locale => 'es', + :title => 'Renamed', + :description => 'Desc' } } + category.save + expect(category.title(:es)).to eq('Renamed') + end + + it 'updates an existing translation and creates a new translation' do + category = FactoryGirl.create(:public_body_category) + category.translations.create(:locale => 'es', + :title => 'Los Category', + :description => 'ES Description') + + expect(category.translations.size).to eq(2) + + category.translations_attributes = { + 'es' => { :id => category.translation_for(:es).id, + :locale => 'es', + :title => 'Renamed' }, + 'fr' => { :locale => 'fr', + :title => 'Le Category' } + } + + expect(category.translations.size).to eq(3) + I18n.with_locale(:es) { expect(category.title).to eq('Renamed') } + I18n.with_locale(:fr) { expect(category.title).to eq('Le Category') } + end + + it 'skips empty translations' do + category = FactoryGirl.create(:public_body_category) + category.translations.create(:locale => 'es', + :title => 'Los Category', + :description => 'ES Description') + + expect(category.translations.size).to eq(2) + + category.translations_attributes = { + 'es' => { :id => category.translation_for(:es).id, + :locale => 'es', + :title => 'Renamed' }, + 'fr' => { :locale => 'fr' } + } + + expect(category.translations.size).to eq(2) + end + + end + end + +end + +describe PublicBodyCategory::Translation do + + it 'requires a locale' do + translation = PublicBodyCategory::Translation.new + translation.valid? + expect(translation.errors[:locale]).to eq(["can't be blank"]) + end + + it 'is valid if no required attributes are assigned' do + translation = PublicBodyCategory::Translation.new(:locale => I18n.default_locale) + expect(translation).to be_valid + end + + it 'requires a title if another required attribute is assigned' do + translation = PublicBodyCategory::Translation.new(:description => 'spec') + translation.valid? + expect(translation.errors[:title]).to eq(["Title can't be blank"]) + end + + it 'requires a description if another required attribute is assigned' do + translation = PublicBodyCategory::Translation.new(:title => 'spec') + translation.valid? + expect(translation.errors[:description]).to eq(["Description can't be blank"]) + end + end diff --git a/spec/models/public_body_heading_spec.rb b/spec/models/public_body_heading_spec.rb index add2cac60..be3e7c7d2 100644 --- a/spec/models/public_body_heading_spec.rb +++ b/spec/models/public_body_heading_spec.rb @@ -2,9 +2,7 @@ # # Table name: public_body_headings # -# id :integer not null, primary key -# locale :string -# name :text not null +# id :integer not null, primary key # display_order :integer # @@ -12,26 +10,6 @@ require 'spec_helper' describe PublicBodyHeading do - context 'when loading the data' do - - before do - PublicBodyCategory.add(:en, [ - "Local and regional", - [ "local_council", "Local councils", "a local council" ], - "Miscellaneous", - [ "other", "Miscellaneous", "miscellaneous" ],]) - end - - it 'should use the display_order field to preserve the original data order' do - headings = PublicBodyHeading.all - headings[0].name.should eq 'Local and regional' - headings[0].display_order.should eq 0 - headings[1].name.should eq 'Miscellaneous' - headings[1].display_order.should eq 1 - end - - end - context 'when validating' do it 'should require a name' do @@ -52,6 +30,13 @@ describe PublicBodyHeading do heading.valid? heading.display_order.should == PublicBodyHeading.next_display_order end + + it 'validates the translations' do + heading = FactoryGirl.build(:public_body_heading) + translation = heading.translations.build + expect(heading).to_not be_valid + end + end context 'when setting a display order' do @@ -65,4 +50,105 @@ describe PublicBodyHeading do PublicBodyHeading.next_display_order.should == 1 end end + + describe :save do + + it 'saves translations' do + heading = FactoryGirl.build(:public_body_heading) + heading.translations_attributes = { :es => { :locale => 'es', + :name => 'El Heading' } } + + heading.save + expect(PublicBodyHeading.find(heading.id).translations.size).to eq(2) + end + + end + + describe :translations_attributes= do + + context 'translation_attrs is a Hash' do + + it 'does not persist translations' do + heading = FactoryGirl.create(:public_body_heading) + heading.translations_attributes = { :es => { :locale => 'es', + :name => 'El Heading' } } + + expect(PublicBodyHeading.find(heading.id).translations.size).to eq(1) + end + + it 'creates a new translation' do + heading = FactoryGirl.create(:public_body_heading) + heading.translations_attributes = { :es => { :locale => 'es', + :name => 'El Heading' } } + heading.save + heading.reload + expect(heading.name(:es)).to eq('El Heading') + end + + it 'updates an existing translation' do + heading = FactoryGirl.create(:public_body_heading) + heading.translations_attributes = { 'es' => { :locale => 'es', + :name => 'Name' } } + heading.save + + heading.translations_attributes = { 'es' => { :id => heading.translation_for(:es).id, + :locale => 'es', + :name => 'Renamed' } } + heading.save + expect(heading.name(:es)).to eq('Renamed') + end + + it 'updates an existing translation and creates a new translation' do + heading = FactoryGirl.create(:public_body_heading) + heading.translations.create(:locale => 'es', + :name => 'Los Heading') + + expect(heading.translations.size).to eq(2) + + heading.translations_attributes = { + 'es' => { :id => heading.translation_for(:es).id, + :locale => 'es', + :name => 'Renamed' }, + 'fr' => { :locale => 'fr', + :name => 'Le Heading' } + } + + expect(heading.translations.size).to eq(3) + I18n.with_locale(:es) { expect(heading.name).to eq('Renamed') } + I18n.with_locale(:fr) { expect(heading.name).to eq('Le Heading') } + end + + it 'skips empty translations' do + heading = FactoryGirl.create(:public_body_heading) + heading.translations.create(:locale => 'es', + :name => 'Los Heading') + + expect(heading.translations.size).to eq(2) + + heading.translations_attributes = { + 'es' => { :id => heading.translation_for(:es).id, + :locale => 'es', + :name => 'Renamed' }, + 'fr' => { :locale => 'fr' } + } + + expect(heading.translations.size).to eq(2) + end + end + end +end + +describe PublicBodyHeading::Translation do + + it 'requires a locale' do + translation = PublicBodyHeading::Translation.new + translation.valid? + expect(translation.errors[:locale]).to eq(["can't be blank"]) + end + + it 'is valid if all required attributes are assigned' do + translation = PublicBodyHeading::Translation.new(:locale => I18n.default_locale) + expect(translation).to be_valid + end + end diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb index f12582f21..7b55efda1 100644 --- a/spec/models/public_body_spec.rb +++ b/spec/models/public_body_spec.rb @@ -30,106 +30,81 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe PublicBody do - describe :translations_attributes= do - - context 'translation_attrs is a Hash' do - - it 'takes the correct code path for a Hash' do - attrs = {} - attrs.should_receive(:each_value) - PublicBody.new().translations_attributes = attrs - end - - it 'updates an existing translation' do - body = public_bodies(:geraldine_public_body) - translation = body.translation_for(:es) - params = { 'es' => { :locale => 'es', - :name => 'Renamed' } } - - body.translations_attributes = params - I18n.with_locale(:es) { expect(body.name).to eq('Renamed') } - end - - it 'updates an existing translation and creates a new translation' do - body = public_bodies(:geraldine_public_body) - translation = body.translation_for(:es) - - expect(body.translations.size).to eq(2) - - body.translations_attributes = { - 'es' => { :locale => 'es', - :name => 'Renamed' }, - 'fr' => { :locale => 'fr', - :name => 'Le Geraldine Quango' } - } - - expect(body.translations.size).to eq(3) - I18n.with_locale(:es) { expect(body.name).to eq('Renamed') } - I18n.with_locale(:fr) { expect(body.name).to eq('Le Geraldine Quango') } - end - - it 'skips empty translations' do - body = public_bodies(:geraldine_public_body) - translation = body.translation_for(:es) - - expect(body.translations.size).to eq(2) - - body.translations_attributes = { - 'es' => { :locale => 'es', - :name => 'Renamed' }, - 'fr' => { :locale => 'fr' } - } - - expect(body.translations.size).to eq(2) - end - - end - - context 'translation_attrs is an Array' do - - it 'takes the correct code path for an Array' do - attrs = [] - attrs.should_receive(:each) - PublicBody.new().translations_attributes = attrs - end - - it 'creates a new translation' do - body = public_bodies(:geraldine_public_body) - body.translation_for(:es).destroy - body.reload - - expect(body.translations.size).to eq(1) - - body.translations_attributes = [ { - :locale => 'es', - :name => 'Renamed' - } - ] - - expect(body.translations.size).to eq(2) - I18n.with_locale(:es) { expect(body.name).to eq('Renamed') } - end - - it 'skips empty translations' do - body = public_bodies(:geraldine_public_body) - body.translation_for(:es).destroy - body.reload - - expect(body.translations.size).to eq(1) - - body.translations_attributes = [ - { :locale => 'empty' } - ] - - expect(body.translations.size).to eq(1) - end - - end - - end - + describe :translations_attributes= do + + context 'translation_attrs is a Hash' do + + it 'does not persist translations' do + body = FactoryGirl.create(:public_body) + body.translations_attributes = { :es => { :locale => 'es', + :name => 'El Body' } } + + expect(PublicBody.find(body.id).translations.size).to eq(1) + end + + it 'creates a new translation' do + body = FactoryGirl.create(:public_body) + body.translations_attributes = { :es => { :locale => 'es', + :name => 'El Body' } } + body.save + body.reload + expect(body.name(:es)).to eq('El Body') + end + + it 'updates an existing translation' do + body = FactoryGirl.create(:public_body) + body.translations_attributes = { 'es' => { :locale => 'es', + :name => 'El Body' } } + body.save + + body.translations_attributes = { 'es' => { :id => body.translation_for(:es).id, + :locale => 'es', + :name => 'Renamed' } } + body.save + expect(body.name(:es)).to eq('Renamed') + end + + it 'updates an existing translation and creates a new translation' do + body = FactoryGirl.create(:public_body) + body.translations.create(:locale => 'es', + :name => 'El Body') + + expect(body.translations.size).to eq(2) + + body.translations_attributes = { + 'es' => { :id => body.translation_for(:es).id, + :locale => 'es', + :name => 'Renamed' }, + 'fr' => { :locale => 'fr', + :name => 'Le Body' } + } + + expect(body.translations.size).to eq(3) + I18n.with_locale(:es) { expect(body.name).to eq('Renamed') } + I18n.with_locale(:fr) { expect(body.name).to eq('Le Body') } + end + + it 'skips empty translations' do + body = FactoryGirl.create(:public_body) + body.translations.create(:locale => 'es', + :name => 'El Body') + + expect(body.translations.size).to eq(2) + + body.translations_attributes = { + 'es' => { :id => body.translation_for(:es).id, + :locale => 'es', + :name => 'Renamed' }, + 'fr' => { :locale => 'fr' } + } + + expect(body.translations.size).to eq(2) + end + end + end end + describe PublicBody, " using tags" do before do @public_body = PublicBody.new(:name => 'Aardvark Monitoring Service', @@ -548,7 +523,7 @@ describe PublicBody, " when loading CSV files" do PublicBody.find_by_name('Fake Authority of Northern Ireland').tag_array_for_search.should == ['aTag', 'fake'] # Import again to check the 'add' tag functionality works - new_tags_file = load_file_fixture('fake-authority-add-tags.rb') + new_tags_file = load_file_fixture('fake-authority-add-tags.csv') errors, notes = PublicBody.import_csv(new_tags_file, '', 'add', false, 'someadmin') # false means real run # Check tags were added successfully @@ -567,15 +542,284 @@ describe PublicBody, " when loading CSV files" do PublicBody.find_by_name('Fake Authority of Northern Ireland').tag_array_for_search.should == ['aTag', 'fake'] # Import again to check the 'replace' tag functionality works - new_tags_file = load_file_fixture('fake-authority-add-tags.rb') + new_tags_file = load_file_fixture('fake-authority-add-tags.csv') errors, notes = PublicBody.import_csv(new_tags_file, 'fake', 'replace', false, 'someadmin') # false means real run # Check tags were added successfully - PublicBody.find_by_name('North West Fake Authority').tag_array_for_search.should == ['aTag'] - PublicBody.find_by_name('Scottish Fake Authority').tag_array_for_search.should == ['aTag'] + PublicBody.find_by_name('North West Fake Authority').tag_array_for_search.should == ['aTag', 'fake'] + PublicBody.find_by_name('Scottish Fake Authority').tag_array_for_search.should == ['aTag', 'fake'] PublicBody.find_by_name('Fake Authority of Northern Ireland').tag_array_for_search.should == ['aTag', 'fake'] end + + context 'when the import tag is set' do + + context 'with a new body' do + + it 'appends the import tag when no tag_string is specified' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + ,q@localhost,Quango,,http://example.org + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, 'imported', 'add', false, 'someadmin') + + expected = %W(imported) + expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) + end + + it 'appends the import tag when a tag_string is specified' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + ,q@localhost,Quango,first_tag second_tag,http://example.org + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, 'imported', 'add', false, 'someadmin') + + expected = %W(first_tag imported second_tag) + expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) + end + + it 'replaces with the import tag when no tag_string is specified' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + ,q@localhost,Quango,,http://example.org + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, 'imported', 'replace', false, 'someadmin') + + expected = %W(imported) + expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) + end + + it 'replaces with the import tag and tag_string when a tag_string is specified' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + ,q@localhost,Quango,first_tag second_tag,http://example.org + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, 'imported', 'replace', false, 'someadmin') + + expected = %W(first_tag imported second_tag) + expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) + end + + end + + context 'an existing body without tags' do + + before do + @body = FactoryGirl.create(:public_body, :name => 'Existing Body') + end + + it 'will not import if there is an existing body without the tag' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }",,#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + errors, notes = PublicBody.import_csv(csv, 'imported', 'add', false, 'someadmin') + + expected = %W(imported) + errors.should include("error: line 2: Name Name is already taken for authority 'Existing Body'") + end + + end + + context 'an existing body with tags' do + + before do + @body = FactoryGirl.create(:public_body, :tag_string => 'imported first_tag second_tag') + end + + it 'created with tags, different tags in csv, add import tag' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }","first_tag new_tag",#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, 'imported', 'add', false, 'someadmin') + expected = %W(first_tag imported new_tag second_tag) + expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) + end + + it 'created with tags, different tags in csv, replace import tag' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }","first_tag new_tag",#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, 'imported', 'replace', false, 'someadmin') + + expected = %W(first_tag imported new_tag) + expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) + end + + end + + end + + context 'when the import tag is not set' do + + context 'with a new body' do + + it 'it is empty if no tag_string is set' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + ,q@localhost,Quango,,http://example.org + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'add', false, 'someadmin') + + expected = [] + expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) + end + + it 'uses the specified tag_string' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + ,q@localhost,Quango,first_tag,http://example.org + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'add', false, 'someadmin') + + expected = %W(first_tag) + expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) + end + + it 'replaces with empty if no tag_string is set' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + ,q@localhost,Quango,,http://example.org + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') + + expected = [] + expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) + end + + it 'replaces with the specified tag_string' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + ,q@localhost,Quango,first_tag,http://example.org + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') + + expected = %W(first_tag) + expect(PublicBody.find_by_name('Quango').tag_array_for_search).to eq(expected) + end + + end + + context 'with an existing body without tags' do + + before do + @body = FactoryGirl.create(:public_body) + end + + it 'appends when no tag_string is specified' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }",,#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'add', false, 'someadmin') + + expected = [] + expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) + end + + it 'appends when a tag_string is specified' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }",new_tag,#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'add', false, 'someadmin') + + expected = %W(new_tag) + expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) + end + + it 'replaces when no tag_string is specified' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }",,#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') + + expected = [] + expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) + end + + it 'replaces when a tag_string is specified' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }",new_tag,#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') + + expected = %W(new_tag) + expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) + end + + end + + describe 'with an existing body with tags' do + + before do + @body = FactoryGirl.create(:public_body, :tag_string => 'first_tag second_tag') + end + + it 'created with tags, different tags in csv, add tags' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }","first_tag new_tag",#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'add', false, 'someadmin') + + expected = %W(first_tag new_tag second_tag) + expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) + end + + it 'created with tags, different tags in csv, replace' do + csv = <<-CSV.strip_heredoc + #id,request_email,name,tag_string,home_page + #{ @body.id },#{ @body.request_email },"#{ @body.name }","first_tag new_tag",#{ @body.home_page } + CSV + + # csv, tag, tag_behaviour, dry_run, editor + PublicBody.import_csv(csv, '', 'replace', false, 'someadmin') + + expected = %W(first_tag new_tag) + expect(PublicBody.find(@body.id).tag_array_for_search).to eq(expected) + end + + end + + end + it "should create bodies with names in multiple locales" do original_count = PublicBody.count @@ -700,6 +944,22 @@ CSV PublicBody.csv_import_fields = old_csv_import_fields end + it "should import translations for fields whose values are the same as the default locale's" do + original_count = PublicBody.count + + csv_contents = load_file_fixture("multiple-locales-same-name.csv") + + errors, notes = PublicBody.import_csv(csv_contents, '', 'replace', true, 'someadmin', ['en', 'es']) # true means dry run + errors.should == [] + notes.size.should == 3 + notes[0..1].should == [ + "line 2: creating new authority 'Test' (locale: en):\n\t{\"name\":\"Test\",\"request_email\":\"test@test.es\",\"home_page\":\"http://www.test.es/\",\"tag_string\":\"37\"}", + "line 2: creating new authority 'Test' (locale: es):\n\t{\"name\":\"Test\"}", + ] + notes[2].should =~ /Notes: Some bodies are in database, but not in CSV file:\n( .+\n)*You may want to delete them manually.\n/ + + PublicBody.count.should == original_count + end end describe PublicBody do @@ -762,6 +1022,53 @@ describe PublicBody do end + describe :has_request_email? do + + before do + @body = PublicBody.new(:request_email => 'test@example.com') + end + + it 'should return false if request_email is nil' do + @body.request_email = nil + @body.has_request_email?.should == false + end + + it 'should return false if the request email is "blank"' do + @body.request_email = 'blank' + @body.has_request_email?.should == false + end + + it 'should return false if the request email is an empty string' do + @body.request_email = '' + @body.has_request_email?.should == false + end + + it 'should return true if the request email is an email address' do + @body.has_request_email?.should == true + end + end + + describe :special_not_requestable_reason do + + before do + @body = PublicBody.new + end + + it 'should return true if the body is defunct' do + @body.stub!(:defunct?).and_return(true) + @body.special_not_requestable_reason?.should == true + end + + it 'should return true if FOI does not apply' do + @body.stub!(:not_apply?).and_return(true) + @body.special_not_requestable_reason?.should == true + end + + it 'should return false if the body is not defunct and FOI applies' do + @body.special_not_requestable_reason?.should == false + end + end + end describe PublicBody, " when override all public body request emails set" do @@ -854,3 +1161,95 @@ describe PublicBody, 'when asked for popular bodies' do end end + +describe PublicBody do + + describe :is_requestable? do + + before do + @body = PublicBody.new(:request_email => 'test@example.com') + end + + it 'should return false if the body is defunct' do + @body.stub!(:defunct?).and_return true + @body.is_requestable?.should == false + end + + it 'should return false if FOI does not apply' do + @body.stub!(:not_apply?).and_return true + @body.is_requestable?.should == false + end + + it 'should return false there is no request_email' do + @body.stub!(:has_request_email?).and_return false + @body.is_requestable?.should == false + end + + it 'should return true if the request email is an email address' do + @body.is_requestable?.should == true + end + + end + + describe :is_followupable? do + + before do + @body = PublicBody.new(:request_email => 'test@example.com') + end + + it 'should return false there is no request_email' do + @body.stub!(:has_request_email?).and_return false + @body.is_followupable?.should == false + end + + it 'should return true if the request email is an email address' do + @body.is_followupable?.should == true + end + + end + + describe :not_requestable_reason do + + before do + @body = PublicBody.new(:request_email => 'test@example.com') + end + + it 'should return "defunct" if the body is defunct' do + @body.stub!(:defunct?).and_return true + @body.not_requestable_reason.should == 'defunct' + end + + it 'should return "not_apply" if FOI does not apply' do + @body.stub!(:not_apply?).and_return true + @body.not_requestable_reason.should == 'not_apply' + end + + + it 'should return "bad_contact" there is no request_email' do + @body.stub!(:has_request_email?).and_return false + @body.not_requestable_reason.should == 'bad_contact' + end + + it 'should raise an error if the body is not defunct, FOI applies and has an email address' do + expected_error = "not_requestable_reason called with type that has no reason" + lambda{ @body.not_requestable_reason }.should raise_error(expected_error) + end + + end + +end + +describe PublicBody::Translation do + + it 'requires a locale' do + translation = PublicBody::Translation.new + translation.valid? + expect(translation.errors[:locale]).to eq(["can't be blank"]) + end + + it 'is valid if all required attributes are assigned' do + translation = PublicBody::Translation.new(:locale => I18n.default_locale) + expect(translation).to be_valid + end + +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 7dcd3ab8a..2245a024f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -369,3 +369,21 @@ describe User, "when calculating if a user has exceeded the request limit" do end + +describe User do + + describe :banned? do + + it 'is banned if the user has ban_text' do + user = FactoryGirl.build(:user, :ban_text => 'banned') + expect(user).to be_banned + end + + it 'is not banned if the user has no ban_text' do + user = FactoryGirl.build(:user, :ban_text => '') + expect(user).to_not be_banned + end + + end + +end diff --git a/spec/script/handle-mail-replies_spec.rb b/spec/script/handle-mail-replies_spec.rb index 90a8de27c..62d5c1dab 100644 --- a/spec/script/handle-mail-replies_spec.rb +++ b/spec/script/handle-mail-replies_spec.rb @@ -3,9 +3,9 @@ require "external_command" def mail_reply_test(email_filename) Dir.chdir Rails.root do - xc = ExternalCommand.new("script/handle-mail-replies", "--test") - xc.run(load_file_fixture(email_filename)) - + xc = ExternalCommand.new("script/handle-mail-replies", "--test", + :stdin_string => load_file_fixture(email_filename)) + xc.run xc.err.should == "" return xc end @@ -13,8 +13,9 @@ end describe "When filtering" do it "should not fail when not in test mode" do - xc = ExternalCommand.new("script/handle-mail-replies") - xc.run(load_file_fixture("track-response-exim-bounce.email")) + xc = ExternalCommand.new("script/handle-mail-replies", + { :stdin_string => load_file_fixture("track-response-exim-bounce.email") }) + xc.run xc.err.should == "" end diff --git a/spec/script/mailin_spec.rb b/spec/script/mailin_spec.rb index 46ad39f7f..0ff094c2b 100644 --- a/spec/script/mailin_spec.rb +++ b/spec/script/mailin_spec.rb @@ -3,12 +3,12 @@ require "external_command" def mailin_test(email_filename) Dir.chdir Rails.root do - xc = ExternalCommand.new("script/mailin") + mail = load_file_fixture(email_filename) ir = info_requests(:other_request) mail.gsub!('EMAIL_TO', ir.incoming_email) mail.gsub!('EMAIL_FROM', 'responder@localhost') - xc.run(mail) + xc = ExternalCommand.new("script/mailin", :stdin_string => mail).run xc.err.should == "" return xc end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 74a4891c2..93bcfa1ba 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,6 +18,7 @@ SimpleCov.start('rails') do add_filter 'lib/has_tag_string' add_filter 'lib/acts_as_xapian' add_filter 'lib/themes' + add_filter '.bundle' end Spork.prefork do diff --git a/spec/views/public_body/show.html.erb_spec.rb b/spec/views/public_body/show.html.erb_spec.rb index 0559fc8ef..6ebc39caa 100644 --- a/spec/views/public_body/show.html.erb_spec.rb +++ b/spec/views/public_body/show.html.erb_spec.rb @@ -2,12 +2,12 @@ require File.expand_path(File.join('..', '..', '..', 'spec_helper'), __FILE__) describe "public_body/show" do before do - @pb = mock_model(PublicBody, - :name => 'Test Quango', + @pb = mock_model(PublicBody, + :name => 'Test Quango', :short_name => 'tq', - :url_name => 'testquango', + :url_name => 'testquango', :notes => '', - :type_of_authority => 'A public body', + :tags => [], :eir_only? => nil, :info_requests => [1, 2, 3, 4], # out of sync with Xapian :publication_scheme => '', @@ -15,6 +15,7 @@ describe "public_body/show" do :calculated_home_page => '') @pb.stub!(:override_request_email).and_return(nil) @pb.stub!(:is_requestable?).and_return(true) + @pb.stub!(:special_not_requestable_reason?).and_return(false) @pb.stub!(:has_notes?).and_return(false) @pb.stub!(:has_tag?).and_return(false) @xap = mock(ActsAsXapian::Search, :matches_estimated => 2) @@ -43,7 +44,7 @@ describe "public_body/show" do it "should tell total number of requests" do render - response.should match "4 Freedom of Information requests" + response.should match "4 requests" end it "should cope with no results" do @@ -58,44 +59,12 @@ describe "public_body/show" do response.should match "The search index is currently offline" end - it "should link to Charity Commission site if we have numbers to do so" do - @pb.stub!(:has_tag?).and_return(true) - @pb.stub!(:get_tag_values).and_return(['98765', '12345']) - - render - response.should have_selector("div#header_right") do - have_selector "a", :href => /charity-commission.gov.uk.*RegisteredCharityNumber=98765$/ - end - response.should have_selector("div#header_right") do - have_selector "a", :href => /www.charity-commission.gov.uk.*RegisteredCharityNumber=12345$/ - end - end - - it "should link to Scottish Charity Regulator site if we have an SC number" do - @pb.stub!(:has_tag?).and_return(true) - @pb.stub!(:get_tag_values).and_return(['SC1234']) - - render - response.should have_selector("div#header_right") do - have_selector "a", :href => /www.oscr.org.uk.*id=SC1234$/ - end - end - - - it "should not link to Charity Commission site if we don't have number" do - render - response.should have_selector("div#header_right") do - have_selector "a", :href => /charity-commission.gov.uk/ - end - end - - end -def mock_event - return mock_model(InfoRequestEvent, - :info_request => mock_model(InfoRequest, - :title => 'Title', +def mock_event + return mock_model(InfoRequestEvent, + :info_request => mock_model(InfoRequest, + :title => 'Title', :url_title => 'title', :display_status => 'waiting_response', :calculate_status => 'waiting_response', |