Rspec 3 how to test flash messages

Ruby on-RailsRubyRspec

Ruby on-Rails Problem Overview


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 protected]"      
    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

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

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

Solution 2 - Ruby on-Rails

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/)

Solution 3 - Ruby on-Rails

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.

Solution 4 - Ruby on-Rails

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

Solution 5 - Ruby on-Rails

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMike AndrianovView Question on Stackoverflow
Solution 1 - Ruby on-RailsrabusmarView Answer on Stackoverflow
Solution 2 - Ruby on-RailsRobin DaughertyView Answer on Stackoverflow
Solution 3 - Ruby on-RailsMugur 'Bud' ChiricaView Answer on Stackoverflow
Solution 4 - Ruby on-RailskillerkiaraView Answer on Stackoverflow
Solution 5 - Ruby on-RailsArturView Answer on Stackoverflow