I use HTTP status code symbols in code in a controller such as:
render json: {
auth_token: user.authentication_token,
user: user
},
status: :created
or
render json: {
errors: ["Missing parameter."]
},
success: false,
status: :unprocessable_entity
In the code of my request spec I also would like to use the symbols:
post user_session_path, email: @user.email, password: @user.password
expect(last_response.status).to eq(201)
...
expect(last_response.status).to eq(422)
However each test where I use the symbols instead of integers fails:
Failure/Error: expect(last_response.status).to eq(:created)
expected: :created
got: 201
(compared using ==)
Here is the latest list of HTTP status code symbols in Rack.
The response
object responds to several of the symbol types as messages. So you can simply do:
expect(response).to be_success
expect(response).to be_error
expect(response).to be_missing
expect(response).to be_redirect
For the other types, such as :created
, you can create a simple custom matcher for this which wraps assert_response
:
RSpec::Matchers.define :have_status do |type, message = nil|
match do |_response|
assert_response type, message
end
end
expect(response).to have_status(:created)
expect(response).to have_status(404)
This should work fine for controller specs which have the proper state setup. It will not work for feature specs. I haven't tried with request specs, so your milage may vary there.
The reason this works is it leverages the fact that RSpec controller specs have similar state setup behind the scenes. So when assert_response
accesses @response
it is available.
This matcher can probably be improved by simply copying the code used by assert_response
into the matcher:
RSpec::Matchers.define :have_status do |type, message = nil|
match do |response|
if Symbol === type
if [:success, :missing, :redirect, :error].include?(type)
response.send("#{type}?")
else
code = Rack::Utils::SYMBOL_TO_STATUS_CODE[type]
response.response_code == code
end
else
response.response_code == type
end
end
failure_message do |response|
message or
"Expected response to be a <#{type}>, but was <#{response.response_code}>"
end
end
This is now available out of the box with RSpec Rails 3: https://www.relishapp.com/rspec/rspec-rails/v/3-0/docs/matchers/have-http-status-matcher