It's time to make your specs even more awesome! SmartRspec adds useful macros and matchers into the RSpec's test suite, so you can quickly define specs for your Rails app and get focused on making things turn into green.
Compatible with:
- Ruby 1.9+
- ActiveRecord (model macros)
Add this line to your application's Gemfile:
gem 'smart_rspec'
Execute:
$ bundle
Require the gem at the top of your spec/rails_helper.rb
(or equivalent):
require 'smart_rspec'
Then include the SmartRspec module:
RSpec.configure do |config|
config.include SmartRspec
end
You will just need to define a valid subject
to start using SmartRspec's macros in your spec file.
It builds specs for model attributes and test its type, enumerated values and defaults:
RSpec.describe User, type: :model do
subject { FactoryGirl.build(:user) }
has_attributes :email, type: :String
has_attributes :is_admin, type: :Boolean
has_attributes :score, type: :Integer, default: 0
has_attributes :locale, type: :String, enum: %i(en pt), default: 'en'
end
It builds specs and test model associations like belongs_to
, has_one
and has_many
.
RSpec.describe User, type: :model do
subject { FactoryGirl.build(:user) }
belongs_to :business
has_one :project
has_many :tasks
end
It builds specs and forces model validations to fail, meaning that you will only turn specs into green when you specify the corresponding validation in the model. In order to get a nice semantics it's recommended to use the fails_validation_of
macro within a "when invalid" context, like:
RSpec.describe User, type: :model do
subject { FactoryGirl.build(:user) }
context 'when invalid' do
fails_validation_of :email, presence: true, email: true
fails_validation_of :name, length: { maximum: 80 }, uniqueness: true
fails_validation_of :username, length: { minimum: 10 }, exclusion: { in: %w(foo bar) }
# Other validations...
end
end
The fails_validation_of
implements specs for the following validations:
presence
email
length
exclusion
inclusion
uniqueness
format
In two cases it will require a valid mock to be passed so SmartRspec can use it to force the validation to fail properly.
For uniqueness with scope:
other_user = FactoryGirl.build(:other_valid_user)
fails_validation_of :username, uniqueness: { scope: :name, mock: other_user }
For format:
fails_validation_of :foo, format: { with: /foo/, mock: 'bar' }
SmartRspec gathers a collection of custom useful matchers:
it { expect(true).to be_boolean }
it { expect('true').not_to be_boolean }
it { expect('tiagopog@gmail.com').to be_email }
it { expect('tiagopog@gmail').not_to be_email }
it { expect('http://adtangerine.com').to be_url }
it { expect('adtangerine.com').not_to be_url }
it { expect('http://adtangerine.com/foobar.png').to be_image_url }
it { expect('http://adtangerine.com/foobar.jpg').not_to be_image_url(:gif) }
it { expect('http://adtangerine.com/foo/bar').not_to be_image_url }
it { expect(Foo.fetch_api).to be_a_list_of(Foo)) }
it { expect([1, 2, 3, 4]).to be_ascending }
it { expect([1, 4, 2, 3]).not_to be_ascending }
it { expect([4, 3, 2, 1]).to be_descending }
it { expect([1, 2, 3, 4]).not_to be_descending }
it { expect([1]).to have(1).item }
it { expect(%w(foo bar)).to have(2).items }
it { expect(%w(foo bar)).not_to have(1).item }
it { expect(%w(foo bar foobar)).to have_at_least(3).items }
it { expect(%w(foo bar foobar)).to have_at_most(3).items }
subject { User.new(email: nil, name: Faker::Name.name) }
it 'has an invalid email' do
subject.valid?
is_expected.to have_error_on(:email)
end
Comparing to array:
it { expect(%w(foo bar foobar)).to include_items(%w(foo bar foobar)) }
Comparing to multiple arguments:
it 'includes all items' do
item1, item2 = 'foo', 'bar'
expect(%w(foo bar)).to include_items(item1, item2))
end
- Some of the "have" matchers (precisely
have
,have_at_least
andhave_at_most
) were taken from therspec-collection_matchers
gem. - Some of the macros/matchers were inspired in RSpec helpers that I worked along with two friends (Douglas André and Giovanni Bonetti) at the Beauty Date project.
- Create macros for model scopes;
- Create macros for controllers;
- Add more matchers;
- Take groups of matchers into modules;
- Turn the whole into "A" in Code Climate.
- Fork it;
- Create your feature branch (
git checkout -b my-new-feature
); - Create your specs and make sure they are passing;
- Document your feature in the README.md;
- Commit your changes (
git commit -am 'Add some feature'
); - Push to the branch (
git push origin my-new-feature
); - Create new Pull Request.