I'm just starting with rails and testing, and not sure what's good way to dry code like this.
require 'rails_helper'
describe EventsController, type: :controller do
let(:admin) { create(:user_admin) }
let(:mod) { create(:user_moderator) }
let(:user) { create(:user) }
let(:link) { create(:link) }
let(:event) { create(:event) }
describe 'GET #new' do
it 'allows admin user to perform action' do
sign_in admin
get :new, link: link.id
expect(flash[:alert]).to_not match(/^You are not authorized to perform this action./)
end
it 'allows mod user to perform action' do
sign_in mod
get :new, link: link.id
expect(flash[:alert]).to_not match(/^You are not authorized to perform this action./)
end
it 'does not allow regular user to perform action' do
sign_in user
get :new, link: link.id
expect(flash[:alert]).to match(/^You are not authorized to perform this action./)
end
it 'does not allow guest to perform action' do
get :new, link: link.id
expect(flash[:alert]).to match(/^You are not authorized to perform this action./)
end
end
describe 'POST #create' do
it 'allows admin user to perform action' do
sign_in admin
post :create, event: attributes_for_event(event, link)
expect(flash[:alert]).to_not match(/^You are not authorized to perform this action./)
end
it 'allows mod user to perform action' do
sign_in mod
post :create, event: attributes_for_event(event, link)
expect(flash[:alert]).to_not match(/^You are not authorized to perform this action./)
end
it 'does not allow regular user to perform action' do
sign_in user
post :create, event: attributes_for_event(event, link)
expect(flash[:alert]).to match(/^You are not authorized to perform this action./)
end
it 'does not allow guest to perform action' do
post :create, event: attributes_for_event(event, link)
expect(flash[:alert]).to match(/^You are not authorized to perform this action./)
end
end
end
-
\$\begingroup\$ Please state only the code's purpose in the title. \$\endgroup\$Jamal– Jamal2015年03月24日 13:09:58 +00:00Commented Mar 24, 2015 at 13:09
3 Answers 3
You could DRY the specs in the following way:
- perform the authentication of the user in a
before
block - when testing a controller the
subject
could be the request itself - use
context
blocks for better structure - use functions for making the assertions when it comes to
flash
messages
So, keeping these in mind, you could write your specs like this:
require 'rails_helper'
describe EventsController, type: :controller do
let(:link) { create(:link) }
let(:event) { create(:event) }
let(:admin) { create(:user_admin) }
let(:moderator) { create(:user_moderator) }
let(:user) { create(:user) }
AUTHORIZATION_ERROR = /^You are not authorized to perform this action/
describe 'GET #new' do
subject { get :new, link: link.id }
before(:each) do
sign_in(authorized_resource) if authorized_resource.present?
end
context 'for user with admin role' do
let(:authorized_resource) { admin }
it 'does not display an alert' do
subject
expect(flash[:alert]).to_not match(AUTHORIZATION_ERROR)
end
end
context 'for user with moderator role' do
let(:authorized_resource) { moderator }
it 'does not display an alert' do
subject
expect(flash[:alert]).to_not match(AUTHORIZATION_ERROR)
end
end
context 'for user with no role' do
let(:authorized_resource) { user }
it 'displays an alert' do
subject
expect(flash[:alert]).to match(AUTHORIZATION_ERROR)
end
end
context 'for guest user' do
it 'displays an alert' do
subject
expect(flash[:alert]).to match(AUTHORIZATION_ERROR)
end
end
end
end
It might make sense to check for response codes as well (e.g. 401 Unauthorized
, 403 Forbidden
, etc) since a flash message on its own does say much about what's going on with the controller.
I don't think this spec needs DRY-ing. You've reduced things down to realistic usage scenarios, which is exactly what you want to do. The steps in each spec are not 100% the same, so there really isn't any code repetition.
While it may feel like you've got repeated code, your tests are explicit and easy to follow. I wouldn't change anything.
I would just factor out the flash error into a constant. Also, I believe the trailing period in your regex should be escaped, as you don't want to match any character.
require 'rails_helper'
FLASH_ERROR = /^You are not authorized to perform this action\./
describe EventsController, type: :controller do
let(:admin) { create(:user_admin) }
let(:mod) { create(:user_moderator) }
let(:user) { create(:user) }
let(:link) { create(:link) }
let(:event) { create(:event) }
describe 'GET #new' do
it 'allows admin user to perform action' do
sign_in admin
get :new, link: link.id
expect(flash[:alert]).to_not match FLASH_ERROR
end
it 'allows mod user to perform action' do
sign_in mod
get :new, link: link.id
expect(flash[:alert]).to_not match FLASH_ERROR
end
it 'does not allow regular user to perform action' do
sign_in user
get :new, link: link.id
expect(flash[:alert]).to match FLASH_ERROR
end
it 'does not allow guest to perform action' do
get :new, link: link.id
expect(flash[:alert]).to match FLASH_ERROR
end
end
describe 'POST #create' do
it 'allows admin user to perform action' do
sign_in admin
post :create, event: attributes_for_event(event, link)
expect(flash[:alert]).to_not match FLASH_ERROR
end
it 'allows mod user to perform action' do
sign_in mod
post :create, event: attributes_for_event(event, link)
expect(flash[:alert]).to_not match FLASH_ERROR
end
it 'does not allow regular user to perform action' do
sign_in user
post :create, event: attributes_for_event(event, link)
expect(flash[:alert]).to match FLASH_ERROR
end
it 'does not allow guest to perform action' do
post :create, event: attributes_for_event(event, link)
expect(flash[:alert]).to match FLASH_ERROR
end
end
end