Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tiagopog/smart_rspec

Suite of macros and matchers to get your RSpec on steroids.
https://github.com/tiagopog/smart_rspec

Last synced: about 2 months ago
JSON representation

Suite of macros and matchers to get your RSpec on steroids.

Awesome Lists containing this project

README

        

# SmartRspec

[![Build Status](https://travis-ci.org/tiagopog/smart_rspec.svg)](https://travis-ci.org/tiagopog/smart_rspec)
[![Code Climate](https://codeclimate.com/github/tiagopog/smart_rspec/badges/gpa.svg)](https://codeclimate.com/github/tiagopog/smart_rspec)
[![Dependency Status](https://gemnasium.com/tiagopog/smart_rspec.svg)](https://gemnasium.com/tiagopog/smart_rspec)
[![Gem Version](https://badge.fury.io/rb/smart_rspec.svg)](http://badge.fury.io/rb/smart_rspec)

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.

## Installation

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):

``` ruby
require 'smart_rspec'
```

Then include the SmartRspec module:

``` ruby
RSpec.configure do |config|
config.include SmartRspec
end
```

## Usage

* [Macros](#macros)
* [has_attributes](#has_attributes)
* [belongs_to, has_one, has_many](#belongs_to-has_one-has_many)
* [fails_validation_of](#fails_validation_of)
* [Matchers](#matchers)
* ["Be" matchers](#be-matchers)
* [be_boolean](#be_boolean)
* [be_email](#be_email)
* [be_url](#be_url)
* [be_image_url](#be_image_url)
* [be_a_list_of](#be_a_list_of)
* [be_ascending](#be_ascending)
* [be_descending](#be_descending)
* ["Have" matchers](#have-matchers)
* [have](#have)
* [have_at_least](#have_at_least)
* [have_at_most](#have_at_most)
* [have_error_on](#have_error_on)
* [Other matchers](#other-matchers)
* [include_items](#include_items)

### Macros

You will just need to define a valid `subject` to start using SmartRspec's macros in your spec file.

#### has_attributes

It builds specs for model attributes and test its type, enumerated values and defaults:
``` ruby
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
```

#### belongs_to, has_one, has_many

It builds specs and test model associations like `belongs_to`, `has_one` and `has_many`.
``` ruby
RSpec.describe User, type: :model do
subject { FactoryGirl.build(:user) }

belongs_to :business
has_one :project
has_many :tasks
end
```

#### fails_validation_of

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:

``` ruby
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:
``` ruby
other_user = FactoryGirl.build(:other_valid_user)
fails_validation_of :username, uniqueness: { scope: :name, mock: other_user }
```

For format:
``` ruby
fails_validation_of :foo, format: { with: /foo/, mock: 'bar' }
```

### Matchers

SmartRspec gathers a collection of custom useful matchers:

#### Be matchers

##### be_boolean
``` ruby
it { expect(true).to be_boolean }
it { expect('true').not_to be_boolean }
```

##### be_email
``` ruby
it { expect('[email protected]').to be_email }
it { expect('tiagopog@gmail').not_to be_email }
```

##### be_url
``` ruby
it { expect('http://adtangerine.com').to be_url }
it { expect('adtangerine.com').not_to be_url }
```

##### be_image_url
``` ruby
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 }
```

##### be_a_list_of
``` ruby
it { expect(Foo.fetch_api).to be_a_list_of(Foo)) }
```

##### be_ascending

``` ruby
it { expect([1, 2, 3, 4]).to be_ascending }
it { expect([1, 4, 2, 3]).not_to be_ascending }
```

##### be_descending
``` ruby
it { expect([4, 3, 2, 1]).to be_descending }
it { expect([1, 2, 3, 4]).not_to be_descending }
```

#### Have matchers

##### have(x).items
``` ruby
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 }
```

##### have_at_least
``` ruby
it { expect(%w(foo bar foobar)).to have_at_least(3).items }
```

##### have_at_most
``` ruby
it { expect(%w(foo bar foobar)).to have_at_most(3).items }
```

##### have_error_on
``` ruby
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
```

#### Other matchers

##### include_items

Comparing to array:

``` ruby
it { expect(%w(foo bar foobar)).to include_items(%w(foo bar foobar)) }
```

Comparing to multiple arguments:

``` ruby
it 'includes all items' do
item1, item2 = 'foo', 'bar'
expect(%w(foo bar)).to include_items(item1, item2))
end
```

# Credits

1. Some of the "have" matchers (precisely `have`, `have_at_least` and `have_at_most`) were taken from the `rspec-collection_matchers` gem.
2. Some of the macros/matchers were inspired in RSpec helpers that I worked along with two friends ([Douglas André](https://github.com/douglasandre) and [Giovanni Bonetti](https://github.com/giovannibonetti)) at the
[Beauty Date](https://beautydate.com.br) project.

# TODO

- 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.

## Contributing

1. Fork it;
2. Create your feature branch (`git checkout -b my-new-feature`);
3. Create your specs and make sure they are passing;
4. Document your feature in the README.md;
4. Commit your changes (`git commit -am 'Add some feature'`);
5. Push to the branch (`git push origin my-new-feature`);
6. Create new Pull Request.