At 38 minutes in the “unit testing” video, you mentioned we could write a test that ensures a user cannot mark another user’s task as complete. I put together the following scenario, but think it needs some work.
scenario 'not mark other users tasks as complete' do
other_user_todo = create(:todo, description: 'Buy some eggs', owner_email: 'not_me@example.com')
sign_in_as 'me@example.com'
#Posting code from here: http://stackoverflow.com/a/5616072/614775
page.driver.post("/todos/#{other_user_todo.id}/completion")
expect(page.driver.status_code).to eq 404
end
Moreover, when I run the test it doesn’t pass. I get the following failure:
ActiveRecord::RecordNotFound:
Couldn't find Todo with id=1 [WHERE "todos"."owner_email" = 'me@example.com']
How would you handle this type of testing, and more generally security testing so users can’t mess with other users stuff? I am thinking in this scenario a controller test might be the way to go, but would be interested in your ideas.
Thanks,
Aaron
@aaronrenner a controller spec is what you want here - while there are ways to simulate posts from the driver (which you did with page.driver.post
), a controller spec is definitely more suited for that type of test. We don’t cover controller specs in the online workshop so I’d dig through the RSpec docs for a couple examples of how to test it this way. You’re definitely on the right path though!
@joshclayton Thanks for the reply. For future reference here’s the controller spec I put together.
require 'spec_helper'
describe CompletionsController do
describe "POST 'create'" do
it "prevents completion of a todo that doesn't belong to the current user" do
sign_in_as "me@example.com"
other_user_todo = create :todo, owner_email: "not-me@example.com"
expect {
post :create, todo_id: other_user_todo.id
}.to raise_error(ActiveRecord::RecordNotFound)
end
end
def sign_in_as(user)
controller.sign_in_as(user)
end
end
Let me know if you would refactor it or take a different approach.
@aaronrenner is it possible to assert it returns a status code 404 or a 401 (to denote the user is not authorized to do anything to that certain todo)? Only other thing that I’d probably do is structure the spec like this:
describe CompletionsController, 'POST "create"' do
it '...' do
end
def sign_in_as(user)
end
end
This way, it’s one fewer level of nesting and easier to parse visually. Looks good though - and it’s a lot more obvious what’s happening here!