Mike Andrianov
Mike Andrianov

Reputation: 3085

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

Upvotes: 93

Views: 64922

Answers (5)

Artur INTECH
Artur INTECH

Reputation: 7276

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

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

Upvotes: 2

Robin Daugherty
Robin Daugherty

Reputation: 7524

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

Upvotes: 54

Theo Chirica
Theo Chirica

Reputation: 4516

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.

Upvotes: 44

killerkiara
killerkiara

Reputation: 101

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

Upvotes: 5

rabusmar
rabusmar

Reputation: 4143

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

Upvotes: 78

Related Questions