Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to stub the :errors collection to act invalid when rspec tests a controller that uses respond_with

I refactored my OrgController to use respond_with and now the controller spec scaffold is failing with this message:

1) OrgsController POST create with invalid params re-renders the 'new' template
   Failure/Error: response.should render_template("new")
     expecting <"new"> but rendering with <"">

The spec looks like this:

it "re-renders the 'new' template" do
 Org.any_instance.stub(:save).and_return(false)
 post :create, {:org => {}}, valid_session
 response.should render_template("new")
end

I've read that I should stub the :errors hash to make it look like there is an error. What's the best way to do that?

like image 671
Chris Beck Avatar asked Jul 03 '12 07:07

Chris Beck


2 Answers

Using RSpec's new syntax which was introduced in v3, the stubbing would look like

allow_any_instance_of(Org).to receive(:save).and_return(false)
allow_any_instance_of(Org).to receive_message_chain(:errors, :full_messages)
  .and_return(["Error 1", "Error 2"])

The related controller code would look something like

if org.save
  head :ok
else
  render json: {
    message: "Validation failed",
    errors: org.errors.full_messages
  }, status: :unprocessable_entity # 422
end
like image 168
Dennis Avatar answered Oct 24 '22 20:10

Dennis


The message:

expecting <"new"> but rendering with <"">

suggests that it's a redirect not a render. Either your stubbing wasn't successful or your controller is but in the controller. You should be able to test if stubbing works with something like: Org.first.valid? or Org.new(valid_attibutes).valid?. For example stubbing will be broken if have mocha in your Gemfile, as in that case any_instance will be a mocha object, and rspec stub will not work on it. If stubbing works you can debug what happens in the controller with either logging or debugger.

For stubbing errors you can do something like this:

Org.any_instance.stub(:errors).and_return(ActiveModel::Errors.new(Org.new).tap {
  |e| e.add(:name,"cannot be nil")})

Or if controller uses only errors.full_messages then you can:

Org.any_instance.stub_chain("errors.full_messages").and_return(["error1","error2"])
like image 37
mfazekas Avatar answered Oct 24 '22 19:10

mfazekas