ChatGPT解决这个技术问题 Extra ChatGPT

Rspec 3 how to test flash messages

I want to test controller's action and flash messages presence with rspec.

action:

def create
  user = Users::User.find_by_email(params[:email])
  if user
    user.send_reset_password_instructions
    flash[:success] = "Reset password instructions have been sent to #{user.email}."
  else
    flash[:alert] = "Can't find user with this email: #{params[:email]}"
  end

  redirect_to root_path
end

spec:

describe "#create" do
  it "sends reset password instructions if user exists" do
    post :create, email: "email@example.com"      
    expect(response).to redirect_to(root_path)
    expect(flash[:success]).to be_present
  end
...

But I've got an error:

Failure/Error: expect(flash[:success]).to be_present
   expected `nil.present?` to return true, got false

r
rabusmar

You are testing for the presence of flash[:success], but in your controller you are using flash[:notice]


Oh, sorry, I just slipped here. Same error with flash[:notice]
In that case, the problem is probably with your controller code and/or test data. Try to change the expect(flash[:notice]) to expect(flash[:alert]), and if the test passes then probably it's just that the test email doesn't exists.
M
Meg Gutshall

The best way to test flash messages is provided by the shoulda gem.

Here are three examples:

expect(controller).to set_flash
expect(controller).to set_flash[:success]
expect(controller).to set_flash.now[:alert].to(/are not valid/)

M
Mugur 'Bud' Chirica

If you are more interested in the content of the flash messages you can use this:

expect(flash[:success]).to match(/Reset password instructions have been sent to .*/)

or

expect(flash[:alert]).to match(/Can't find user with this email: .*/)

I would advise against checking for a specific message unless that message is critical and/or it does not change often.


k
killerkiara

With: gem 'shoulda-matchers', '~> 3.1'

The .now should be called directly on the set_flash.

Using set_flash with the now qualifier and specifying now after other qualifiers is no longer allowed.

You'll want to use now immediately after set_flash. For instance:

# Valid
should set_flash.now[:foo]
should set_flash.now[:foo].to('bar')

# Invalid
should set_flash[:foo].now
should set_flash[:foo].to('bar').now

A
Artur INTECH

The another approach is to leave out the fact that a controller has flash messages and write integration test instead. This way you increase the chances that you will not need to alter the test once you decide to show that message using JavaScript or by some another way.

See also https://stackoverflow.com/a/13897912/2987689