How to use HTTP status code symbols in RSpec?
Solution 1
On the one hand, response is built with methods like:
success?
redirect?
unprocessable?
full list do:
response.methods.grep(/\?/)
On the other hand, Rspec predicates transforms every foo?
method to a be_foo
matcher.
Not sure you can have the 201 this way unfortunately, but creating a custom matcher is quite easy.
Note Rails test only rely on a few statuses.
Solution 2
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
UPDATE: 2014-07-02
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
Solution 3
this works for me:
expect(response.response_code).to eq(Rack::Utils::SYMBOL_TO_STATUS_CODE[:not_found])
Solution 4
With rspec-rails (as of rspec 3) it's possible to use
expect(response).to have_http_status(:created)
Update 2018-06-11:
As of Rails 6, some of the matchers will be replaced (e. g. success
by successful
).
JJD
Android, Kotlin, Java, Git, Python, Ruby, Ruby on Rails, JavaScript, MacOS, Ubuntu #SOreadytohelp http://stackoverflow.com/10m
Updated on July 15, 2022Comments
-
JJD almost 2 years
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.
-
JJD over 10 yearsI tried
expect(last_response.status).to be_created
which fails with "undefined method `created?' for 201:Fixnum". -
apneadiving over 10 years
expect(last_response).to be_success
-
JJD over 10 yearsSame:
expect(last_response.status).to be_success
fails with "undefined method 'success?' for 201:Fixnum". I understood thatcreated?
is not part of the list and experimented with a custom matcher ... w/o success by now though. -
apneadiving over 10 yearsreread what I wrote:
expect(last_response)
notexpect(last_response.status)
-
JJD over 10 yearsI admin I did not read your comments so well but this time it fails with "undefined method `success?' for #<Rack::MockResponse:0x000000058c1180>"
-
apneadiving over 10 yearswhy do you have a
<Rack::MockResponse:0x000000058c1180>
it should be aActionController::TestResponse
. where do your specs live? -
JJD over 10 yearsThe request test I am executing is located in
spec/api/sessions_controller_spec.rb
. -
apneadiving over 10 yearsrequest spec? request specs should live in
spec/features
, controller spec should live inspec/controllers
, otherwise the wrong modules will be added (unless you include them manually) -
JJD over 10 yearsI might misunderstand but rspec-rails states that request specs belong either in
spec/requests
,spec/api
orspec/integration
. -
apneadiving over 10 yearsfrom your link:
Note that Capybara's DSL as shown is, by default, only available in specs in the spec/features directory
-
JJD over 10 yearsThanks. But when I move the test into
spec/features
it fails withundefined local variable or method 'app' for #<RSpec::Core::ExampleGroup::Neste..
. Thespec_helper.rb
containsconfig.include Rack::Test::Methods, type: :feature
meanwhile. See my updated question now includingpost user_session_path ...
. -
apneadiving over 10 yearsin a feature spec you should not bother about
response
, you should work onpage
.response
is for controllers spec. -
apneadiving over 10 yearsI dont what and how you did but when you do not follow the standard paths, it's normal you stumble upon many issues/
-
JJD over 10 yearsI guess I am on the wrong way. Can you point to the correct path please to test the response of my API endpoints?
-
apneadiving over 10 yearsThis shoul be controller specs, and you'd be able to use what I put in my answer
-
JJD over 10 yearsI am trying to follow your advise and tutorials like this but I still can't get it running. To avoid further drifting away from my original question here is a new post.
-
apneadiving over 10 yearsI've spent much time on your question without any counterpart, don't expect me to spend more elsewhere. sorry.
-
JJD over 10 yearsNo offense please. I am the last one who forgets to vote on people's help. Though, normally I wait until I the problem is solved in total before I vote or grant the answer flag.
-
Tinynumbers almost 9 yearsOnly in RSpec version 3 or later.
have_http_status
is not included in RSpec 2.