Contents:
Add to Gemfile:
group :test do
gem 'rspec-rails', '~> 3.7.2'
end
Run bundle install
.
# spec/requests/users_spec.rb
require 'rails_helper'
RSpec.describe 'users', type: :request do
describe 'GET /users' do
it 'fetches list of users' do
get '/users'
# Or with params:
# get '/users', params: { active: true }
expect(response).to have_http_status(:ok)
end
end
end
You can define helper methods under spec/support/ to be used in various types of RSpecs e.g.:
# spec/support/request_helper.rb
module RequestHelper
def json_response
@json_response ||= JSON.parse(response.body, symbolize_names: true)
end
end
# spec/rails_helper.rb
require 'support/request_helper'
RSpec.configure do |config|
config.include RequestHelper, type: :request
end
# Gemfile
gem 'mongoid-rspec', github: 'mongoid/mongoid-rspec', ref: '68c95b133be1a1482fe882e39afd33262147d1f4'
Latest released version of mongoid-rspec
(4.0.0) does not support mongoid 7. Find out more here.
Run bundle install
.
# spec/rails_helper.rb
require 'mongoid-rspec'
Note: This has been tested on version 1.13.0 of mongoid-rspec
.
describe Preference do
# field
it { is_expected.to have_field(:ln).of_type(String) }
it { is_expected.to have_field(:ln).with_alias(:name).of_type(String) }
it { is_expected.to have_field(:ln).with_alias(:name).of_type(String).localized }
it { is_expected.to have_field(:ln).of_type(String).with_default_value_of('JD') }
# embed_many
it { is_expected.to embed_many(:bookings) }
it { is_expected.to embed_many(:bookings).with_polymorphism }
it { is_expected.to embed_many(:bookings).of_type(Reservation) }
it { is_expected.to embed_many(:bookings).stored_as(:bks) }
it { is_expected.to embed_many(:bookings).with_cascading_callbacks }
# embedded_in
it { is_expected.to be_embedded_in(:user) }
it { is_expected.to be_embedded_in(:preferable).with_polymorphism }
it { is_expected.to be_embedded_in(:user).of_type(Person) }
end
# Gemfile
gem 'webmock', '~> 3.4.2'
Run bundle install
.
# spec/rails_helper.rb
require 'webmock/rspec'
# spec/services/users_api_spec.rb
RSpec.describe UsersApi do
describe '#create' do
let(:api_request_body) do
{ user: {
first_name: 'Kevin',
last_name: 'Omar' } }.to_json
end
let(:api_request_headers) do
{ 'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Host' => 'localhost:3001',
'User-Agent' => 'Ruby'}
end
let(:api_response_body) do
{ customer_user: { id: 1, first_name: 'Kevin', last_name: 'Omar' } }.to_json
end
let!(:stub_api_request) do
stub_request(:post, 'http://www.example.com/api/v1/users').
with(body: api_request_body, headers: api_request_headers).
to_return(body: api_response_body)
# Or for error response, do:
# stub_request(...).to_return(status: 422)
end
before { do_action }
it { expect(stub_api_request).to have_been_requested }
end
end
FactoryGirl.define do
factory :reservation do
date { Date.today }
people 4
end
end
reservation = FactoryGirl.build(:reservation)
reservation.date # Thu, 12 Jan 2017
reservation.people # 4
Set unique values for an attribute.
FactoryGirl.define do
factory :reservation do
sequence(:title) { |n| "Foo-#{n}" }
sequence(:code, 101) { |n| "#{n}" }
end
end
reservation = FactoryGirl.build(:reservation)
reservation.title # "Foo-0"
reservation.code # "101"
other_reservation = FactoryGirl.build(:reservation)
other_reservation.title # "Foo-1"
other_reservation.code # "102"
Factory with a different name from the model.
FactoryGirl.define do
factory :booking, class: Reservation do
end
end
FactoryGirl.define do
factory :reservation do
association :shop
association :franchise, factory: :merchant
end
end
FactoryGirl.define do
factory :reservation do
after :build do |reservation|
reservation.customer = FactoryGirl.build(:customer)
end
after :create do |reservation|
3.times { reservation.tables << FactoryGirl.create(:table) }
end
end
end
FactoryGirl.define do
factory :reservation do
trait :vip do
is_vip true
end
trait :vvip do
vip
points 20
end
trait :with_tables do
after :build do |reservation|
3.times { reservation.tables << FactoryGirl.create(:table) }
end
end
end
end
reservation = FactoryGirl.build(:reservation, :vip)
reservation = FactoryGirl.build(:reservation, :vvip, :with_tables)
reservation = FactoryGirl.build(:reservation, :vvip, :with_tables, code: "101")
You can also define a factory using existing trait
s.
FactoryGirl.define do
factory :user do
trait :senior do
age 70
end
trait :special do
is_special true
end
factory :senior_special_user, traits: %i(senior special)
end
end
require_relative 'spec_helper'
require_relative '../spec_helper'
describe Reservation do
# let/let!
let(:shop){ build(:shop) }
let(:shop){ create(:shop) }
let!(:shop){ create(:shop) }
let(:reservation){ described_class.new }
let(:reservation){ build(:reservation, shop: shop) }
let(:reservation){ build(:reservation, :with_customer) }
let(:reservation){ build(:reservation, :with_customer, shop: shop) }
let(:reservation_attributes){ attributes_for(:reservation, shop: shop) }
let(:customer){ reservation.customer }
let(:customer) do
c = reservation.customer
c.name = 'JD'
c.save!
c
end
# methods
def foo
end
shared_examples_for 'foo bar' do
context 'when valid' do
let(:shop){ build(:shop) }
before { shop.save! }
it { is_expected.to eq shop }
end
end
it_behaves_like 'foo bar'
# collection
it { is_expected.to be_stored_in :reservations }
# describe/context
describe 'something' do
context 'when case' do
# Add test here
end
end
# Conditional rspecs
describe '#foo', if: reservation.respond_to?(:foo) do
end
# before/after
before { reservation.shop = shop }
# stub
before { allow( shop ).to receive(:reservations).and_return([reservation]) }
before { allow( shop ).to receive(:reservations).with(:online).and_return([reservation]) }
# subject
subject { shop }
subject { shop.reservations }
# respond_to
it { is_expected.to respond_to :shop }
it { is_expected.to respond_to :shop= }
# slugify
it { is_expected.to have_slug_for(:name) }
it { is_expected.to have_slug_for(:name).with_scope(:shop_id) }
# associations
it { is_expected.to belong_to(:shop) }
it { is_expected.to belong_to(:shop).of_type(Shop) }
it { is_expected.to belong_to(:shop).as_inverse_of(nil) }
it { is_expected.to have_many(:customers) }
it { is_expected.to have_many(:customers).of_type(Customer) }
it { is_expected.to have_and_belong_to_many(:customers) }
it { is_expected.to have_and_belong_to_many(:customers).of_type(Customer) }
# mass-assignment
it { is_expected.to allow_mass_assignment_of :start_date }
# index
it { is_expected.to have_index_for(shop_id: 1) }
it { is_expected.to have_index_for(shop_id: 1, menu_category_id: 1) }
it { is_expected.to have_index_for('partner_refs.partner_id' => 1, deleted_at: 1) }
# callbacks
it { is_expected.to callback(:normalize_date_ranges!).before(:validation) }
it { is_expected.to callback(:normalize_date_ranges!).after(:validation) }
# validations
it { is_expected.to validate_presence_of :shop_id }
it { is_expected.to validate_uniqueness_of(:name) }
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:shop_id) }
it { is_expected.to validate_uniqueness_of(:name).allow_blank?(true) }
it { is_expected.to validate_length_of(:currency).is(3) }
it { is_expected.to validate_length_of(:currency).within(3..5) }
it { is_expected.to validate_numericality_of(:service_fee_pct) }
it { is_expected.to validate_numericality_of(:service_fee_pct).to_allow(only_integer: true) }
it { is_expected.to validate_numericality_of(:service_fee_pct).greater_than_or_equal_to(0) }
it { is_expected.to validate_numericality_of(:service_fee_pct).less_than_or_equal_to(1) }
it { is_expected.to validate_inclusion_of(:min_advance_time).to_allow(0900) }
it { is_expected.to validate_format_of(:email).with_format(Devise.email_regexp) }
it { is_expected.to validate_format_of(:email).to_allow('[email protected]') }
it { is_expected.to validate_format_of(:email).not_to_allow('invalid-email') }
it { is_expected.to allow_value('[email protected]').for :email }
it { is_expected.to_not allow_value('[email protected]').for :email }
# methods
it { expect( Reservation ).to receive(:foo).with(arg1, arg2) }
it { described_class.any_instance.should receive(:foo) }
it { described_class.any_instance.should receive(:foo).with(:arg1, :arg2) }
it { described_class.any_instance.should receive(:foo).with(:arg1, :arg2).and_return(nil) }
it { expect{ subject.foo }.to raise_error }
# matchers to/to_not
it { is_expected.to be_a String }
it { is_expected.to be_nil }
it { is_expected.to_not be_nil }
it { is_expected.to be_empty }
it { is_expected.to be_truthy }
it { is_expected.to be_falsey }
it { is_expected.to be_valid }
it { is_expected.to be true }
it { is_expected.to be false }
it { is_expected.to eq shop }
it { is_expected.to include shop }
end
# app/models/user.rb
class User
include Mongoid::Document
include Mongoid::Timestamps
include Mongoid::Paranoia
end
# specs/models/user_spec.rb
describe User do
it { is_expected.to be_timestamped_document }
it { is_expected.to be_paranoid_document }
end
with Mongoid::Timestamps::Short
, do
it { is_expected.to be_timestamped_document.with(:short) }
# app/models/user.rb
class User
include Mongoid::Document
embeds_one :address_a
embeds_one :address_b, as: :addressable
embeds_one :address_c, class_name: 'PostalAddress'
embeds_one :address_d, store_as: :adrs
embeds_one :address_e, cascade_callbacks: true
end
# specs/models/user_spec.rb
describe User do
it { is_expected.to embed_one(:address_a) }
it { is_expected.to embed_one(:address_b).with_polymorphism }
it { is_expected.to embed_one(:address_c).of_type(PostalAddress) }
it { is_expected.to embed_one(:address_d).stored_as(:adrs) }
it { is_expected.to embed_one(:address_e).with_cascading_callbacks }
end
# specs/models/user_spec.rb
describe User do
it { is_expected.to accept_nested_attributes_for :bookings }
end
# app/models/user.rb
class User
include Mongoid::Document
include Mongoid::Paperclip
has_mongoid_attached_file :avatar
end
# specs/models/user_spec.rb
describe User do
it { is_expected.to respond_to :avatar }
it { is_expected.to respond_to :avatar= }
it { is_expected.to have_field(:avatar_file_name).of_type(String) }
it { is_expected.to have_field(:avatar_content_type).of_type(String) }
it { is_expected.to have_field(:avatar_file_size).of_type(Integer) }
it { is_expected.to have_field(:avatar_updated_at).of_type(DateTime) }
it { is_expected.to have_field(:avatar_fingerprint).of_type(String) }
end