Functional tests for flash messages after redirect
I'm not sure how to check flash messages with functional tests. My problem has something to do with redirect_to
because my test for flash[:error]
DOES pass. Here is what my create
action looks like:
def create
@user = User.new(params[:user])
if @user.save
redirect_to @user, flash: { success: "Welcome!" }
else
flash.now[:error] = "Signup failed:"
render 'new'
end
end
I have a passing test for flash[:error]
that 1) checks that flash[:error]
is the correct value, 2) checks the page for the flash div, and 3) gets a new page and checks that the flash message has been cleared. I tried to make an analogous test for flash[:success]
but it is failing when it tries to find the div on the page. Here is the failing test:
should "show flash[:success] message" do
post :create, user: { name: "valid user",
password: "userpw",
password_confirmation: "userpw",
email: "a@b.com" }
assert_redirected_to user_path(assigns(:user)), "user isn't being redirected to their page after registration"
assert_equal flash[:success], "Welcome!", "flash[:success] isn't being set properly"
assert_select "div.alert-success", flash[:success]
get :new
assert flash.empty?, "there shouldn't be any flash messages left after getting new page"
end
When I test this manually in a browser, it behaves as expected, but I'm not sure how to write the tests to reflect this. The first two assertions are passing (so the test recognizes that it is being redirected correctly, and that flash[:success]
is being set to "Welcome!"
). Based on that, I would think the assert_select
statement would be able to find the div, but if fails with this error message:
Expected at least 1 element matching "div.alert-success", found 0.
So I tried adding puts @response.body
right before the assert_select
statement, which printed this:
<html><body>You are being <a href="http://test.host/users/3">redirected</a>.</body></html>
This explains why it couldn't find the flash div, but I'm not sure how to "finish" the redirect so that it renders the correct view with the flash div. If I add a get
statement right before the assert_select
statement, the test passes, because now @response.body
has the flash div. However, this doesn't seem like an effective test because it doesn't reflect the behavior of my application - the user doesn't have to make a new request to see the flash message.
It also doesn't guarantee that the flash message shows up on the correct page. If I use the statement get :new
, the assertion still passes, which implies that the flash message would be present on the users#new
view. Even if I use
get :show, id: assigns(:user).id
to make sure the flash message shows up on the correct page, this still feels wrong because 1) now it is a success
response instead of a redirect
response, and 2) it still doesn't explain why I have to manually request ANY page to find the flash div - according to the docs, "The flash is a special part of the session which is cleared with each request. "
Anyway, is there a way to test that a flash message shows up correctly after a redirect?
I'm answering this question from the POV that what you're trying to test would be better tested elsewhere. If you're having a lot of trouble setting up the test, odds are there's a better way to test it :)
Testing that flash messages get cleared - flash messages are built into Rails, so it doesn't make a lot of sense to test something that the framework is handling for you.
Testing that elements show up on the page - view specs don't belong in controllers. Here is a description of the role of the controller:
A controller can thus be thought of as a middle man between models and views. It makes the model data available to the view so it can display that data to the user.
The controller is supposed to make data available to the view, not to specify how the data gets rendered. Imagine if you changed the name of your CSS class, then you'd have to also update your controller specs.
If you really want to test that flash messages show up, I would use an integration test.
上一篇: 如何在Servlet版本2.4的init()方法中获取ContextPath
下一篇: 在重定向后对闪存消息进行功能测试