RSpec::DeclarativeRequests
A standardized structure for request specs in Rails.
require 'rails_helper'
RSpec.describe 'GET /widgets/:id' do
let(:id) { FactoryBot.create(:widget).id }
it { is_expected.to have_http_status(:ok) }
end
# fancier
RSpec.describe 'GET /widgets/:widget#id' do
let(:widget) { FactoryBot.create(:widget) }
it "responds with the widget" do
is_expected.to have_attributes(
status: 200,
content_type: 'application/json',
body: be_json( # `be_json` sold separately (from `saharspec` or `rspec-composable_json_matchers`)
widget: {
id: 7,
name: 'Kevin',
}
)
)
end
endSetup
Add to your Gemfile (probably in the :test group):
# Gemfile
group :test do
gem 'rspec-declarative_requests'
endInclude it in your RSpec config:
# spec/rails_helper.rb
RSpec.configure do |config|
# enabled for ALL request specs
config.include RSpec::DeclarativeRequests, type: :request
# OR: enable only for request specs tagged as :declarative
config.include RSpec::DeclarativeRequests, type: :request, declarative: true
endOr include it straight into the spec:
# spec/requests/whatever_spec.rb
require 'rails_helper'
RSpec.describe 'Whatever' do
include RSpec::DeclarativeRequests
describe 'GET /whatevers' do
# ...
end
endUsing subject
This gem sets the RSpec subject to the response, after making the request.
This allows you do use is_expected or expect(subject) to check the response.
describe 'GET /thing' do
it { is_expected.to be_ok }
# OR
it "responds with 200 OK" do
expect(subject).to be_ok
end
endUsing params
There is a let for request params that starts as an empty Hash. You can
either override it:
let(:params) do
{ my_param: 123 }
endOr you can modify it in a before block:
before do
params[:my_param] = 123
endUsing before blocks, you can do nested contexts:
context 'with a user' do
before { params[:user] = { id: 123 } }
context 'who is cool' do
before { params[:user][:is_cool] = true }
# ...
end
context 'who is not cool' do
before { params[:user][:is_cool] = false }
# ...
end
endUsing headers
There is a let for request headers that starts as an empty Hash. This works
exactly the same as params described above.
context 'requesting JSON' do
before { headers['Accepts'] = 'application/json' }
# ...
endPath Interpolation
The path in the request description behaves kind of like a Rails route.
Named segments that start with a : will be replaced by the value of the let
(or method) with the same name.
describe 'POST /things/:thing_id' do
let(:thing_id) { 4444 }
# ...
endIt's common to want to use an attribute of an object that you already have a
let for. To do that, use the # character.
describe 'POST /things/:thing#id' do
let(:thing) { FactoryBot.create(:thing) }
# ...
endAttributes can be chained together.
describe 'POST /things/:user#things#first#id' do
let(:user) { FactoryBot.create(:user, :with_things) }
# ...
endHashs can also be interpolated by their keys, which can be either strings or
symbols.
describe 'POST /things/:user#things#first#id' do
let(:user) do
{
things: [
{ id: 1 },
{ id: 2 },
]
}
end
#...
endLicense
This gem is available as open source under the terms of the MIT License.