سؤال

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?

هل كانت مفيدة؟

المحلول 2

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

نصائح أخرى

Another approach with RSpec 3+ would be to test for an exception:

it 'responds with a 404 if the page is not found' do
  expect { get(:show, id: 'bad_id') }.to raise_error(ActionController::RoutingError)
end

The problem here is that you are confusing Capybara feature tests and RSpec controller tests. visit is a method provided by Capybara and get / response are provided by RSpec controller tests - you can't use them together.

To test this as a single RSpec controller test you can do:

it "returns a not found response" do
  get :show, { id: 'not_existing_page_321' }
  expect(response.status).to eq(404)
  expect(response.text).to match(/Page page_not_found doesn't exist/)
end

(N.b. The get line is different from what you posted - I haven't included the controller param as if you put this in spec/controllers/pages_controller_spec.rb where it belongs you don't need that)

Or as a single Capybara feature test:

it "renders a not found response" do
  visit page_path('page_not_found')
  expect(page.status_code).to eq(404)
  within '.alert-error' do
    expect(page).to have_content("Page page_not_found doesn't exist")
  end
end
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top