How to test render status: 404 with Rails4 and RSpec when using rescue_from

http-response-codes, rspec, ruby-on-rails

Solution

Although I'm not very happy with this solution, at least this is a work around:

I splited the test into two separate specs. One for testing the response code 404 (with GET instead of visit) and a second to test the alert. The second test is necessary because `get` doesn't render the view - even if `render_views` is defined on top of the spec-file.

  it 'response with 404 if page not found' do
    get :show, { controller: 'pages', id: 'not_existing_page_321' }
    expect(response.status).to eq(404)
  end

  it 'renders an error-message if page not found and shows index' do
    visit page_path('page_not_found')
    within '.alert-error' do
      page.should have_content("Page page_not_found doesn't exist")
    end
  end

Problem

I have a Rails4 application with a 'PagesController'. The show-method throws a customized Exception 'PageNotFoundError' when a Page is not found. On top of the controller I defined `rescue_from PageNotFoundError, with: :render_not_found` `render not found` is a private method of `PagesController` and looks like: ``` def render_not_found flash[:alert]=t(:page_does_not_exists, title: params[:id]) @pages = Page.all render :index, status: :not_found #404 end ``` The rails-log in development-mode shows: ``` Started GET "/pages/readmef" for 127.0.0.1 at 2013-08-02 23:11:35 +0200 Processing by PagesController#show as HTML Parameters: {"id"=>"readmef"} .. Completed 404 Not Found in 14ms (Views: 12.0ms) ``` So, it seams my :status => :not_found works, so far. When I do `curl -v http://0.0.0.0:3000/pages/readmef` curl logs ``` curl -v http://localhost:3000/pages/readmef * About to connect() to localhost port 3000 (#0) * Trying 127.0.0.1... * connected * Connected to localhost (127.0.0.1) port 3000 (#0) > GET /pages/readmef HTTP/1.1 > User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8x zlib/1.2.5 > Host: localhost:3000 > Accept: */* > < HTTP/1.1 404 Not Found < X-Frame-Options: SAMEORIGIN ``` But the following test with RSpec fails: ``` it 'renders an error if page not found' do visit page_path('not_existing_page_321') expect(response.status).to eq(404) within( '.alert-error' ) do page.should have_content('Page not_existing_page_321 doesn\'t exist') end end 1) PagesController renders an error if page not found Failure/Error: expect(response.status).to eq(404) expected: 404 got: 200 ``` Everything looks fine and even the test.log says 404 ``` $ tail -f log/test.log Started GET "/pages/not_existing_page_321" for 127.0.0.1 at 2013-08-03 09:48:13 +0200 Processing by PagesController#show as HTML Parameters: {"id"=>"not_existing_page_321"} Rendered pages/_page.haml (0.8ms) Rendered layouts/_navigation.haml (0.6ms) Rendered layouts/_messages.haml (0.2ms) Rendered layouts/_locales.haml (0.3ms) Rendered layouts/_footer.haml (0.6ms) Completed 404 Not Found in 6ms (Views: 4.5ms) ``` I tried different Servers, WebRICK, Thin, unicorn. Everything works as expected in development and production mode. Even the test.log is correct but the test fails. Can anybody tell me why the test says 200 instead of 404?

Original source