RSpec-Rails Extensions
Some prettifications for RSpec Rails.
Installation
sudo gem install rspec-rails-ext
Then, within your spec/spec_helper.rb
require 'rspec_rails_extensions'
ActiveRecord::RecordInvalid
If you try to call ActiveRecord::RecordInvalid.new(@my_object) where @my_object is a mock then your exception will not be raised; instead you get a cryptic error. This is because RecordInvalid expects to be able to call certain methods on your ActiveRecord model, which your mock isn’t set up for. So instead, prepare your mock, like so:
@thingy = mock_model Thingy, :field => 'value'
prepare_for_errors_on @thingy
raise ActiveRecord::RecordInvalid.new(@thingy)
There’s also a short-cut method:
@thingy = invalid_model Thingy, :field => 'value'
raise ActiveRecord::RecordInvalid.new(@thingy)
Matchers
Some helpful matchers for testing HTTP statuses beyond the default be_success (200 OK)
# looks for a 201 Created (useful for API CREATE calls)
response.should be_successfully_created
# expects a Location field with the given URL (useful for API CREATE calls)
response.should point_to(url)
# looks for a 422 response (invalid object)
response.should be_unprocessable
# looks for a 404
response.should be_not_found
# looks for a 401
response.should
# looks for a 500
response.should be_an_error
Also a helper for testing which layout was used
# Makes sure it used the "bare" layout
response.should use_layout("bare")
Specifying your controllers
One of the issues with writing standard controller specifications, using RSpec’s inbuilt mock objects is that the “flow” of your specs feels wrong.
it "should display a page for a given thingy" do
@thingy = mock_model Thingy, :name => 'Wotsit'
Thingy.should_receive(:find).with('1').and_return(@thingy)
get :show, :id => '1'
response.should be_success
response.should render_template('thingies/show')
end
In other words you are setting expectations before you are doing the work - technically correct but it reads wrongly.
These extra helpers let you write specifications in a more english-like manner.
it "should display a page for a given thingy" do
@thingy = mock_model Thingy
on_getting :show, :id => '1' do
Thingy.should_receive(:find).with('1').and_return(@thingy)
end
response.should be_success
response.should render_template('thingies/show')
end
Isn’t that lovely?
ComparableArray
Ever wanted to check an array contains the right elements, but not cared about the order they were returned? Enter ComparableArray!
ComparableArray.new([:foo, :bar]).should =~ [:bar, :foo]
And there’s even a shorthand for it
(~[:foo, :bar]).should =~ [:bar, :foo]
It’s not required by default, you need to explicity require it.
require "rspec_rails_extensions/comparable_array"