Testing flash.now in Rails

TUE, 22 JAN 2008

I know this is an old problem, but I was still not satisfied with the current way of testing flash.now messages. If you love writing test cases, I’m sure that you will bump into the problem of testing flash.now message in your controller.

We usually use flash.now to display a message for an immediately rendered page, meaning not redirected:

flash.now[:notice] = 'You gotta be kidding me!'

The :notice key-value pair will be cleared once the action has been performed, and when you perform your test, flash.now[:notice] will return null.

# flahs.now[:notice] returns nil
assert_equal 'You gotta be kidding me!', flash.now[:notice]

# or in rspec
flash.now[:notice].should == 'You gotta be kidding me!'

So, what do we do now? The good news is Rails Wiki suggested two ways, which I’ll probably add the third way shortly after this:

First is to use assert_select:

assert_select "div.message", "You gotta be kidding me!"

The problem with assert_select, it needs to render your view, but often we just want to test the message without rendering the view, rendering view may throw errors especially if you are testing with mock objects.

The second way was suggested by Justin Gus, through his flashblack plugin, pretty nifty I thought, because it meets the objectives in which he stated:

  • The solution should only have effect in tests. It should not implicitly weave its way into production behavior.
  • I should be conscious when the behavior is in affect.
  • It should require very little effort on my part to enable the feature
  • It should be simple

Sample codes with flashback plugin:

flashback
get :index
assert_equal 'You gotta be kidding me!', flash.flashed[:notice]

But there’s one problem I was facing, I don’t like the call the extra flashback method.

So here is my attempt through a simple monkey patching of FlashNow and FlashHash class. The patch will store flash.now messages into flash[:now], which can be easily referred in your test codes, through flash.now_cache.

  1. Append this code snippet to your /test/test_helper.rb file or /spec/spec_helper.rb if you are using RSpec.
    module ActionController
      module Flash 
        class FlashNow
          def initialize(flash)
            @flash = flash
            @flash[:now_cache] = {}
          end
          
          def []=(k, v)
            @flash[k] = v
            @flash.discard(k)
            @flash[:now_cache][k] = v
            v
          end
        end
        
        class FlashHash
          def now_cache
            self[:now_cache] || {}
          end
        end
      end 
    end
    
  2. And now you can test flash.now mesages through:
    # Unit Test
    assert_equal 'You gotta be kidding me!', flash.now_cache[:notice]
    
    # RSpec
    flash.now_cache[:notice].should == 'You gotta be kidding me!'
    

Would welcome suggestion to improve this further. Thanks, and hope it will be helpful to you.

13 Comments . Comments Feed . Trackback URI
Thu, 7 Feb 08 09:17 am . Justin "Gus" Knowlden wrote:

Herryanto,

Thanks for the “nifty” vote. It’s the only vote I’ve received so far, so 100% of the people agree it’s a “nifty” solution.

I’m in complete agreement about calling the `flashback` method. I commented in my own blog entry (http://gusg.us/2008/1/18/flashback-to-flash-now) asking for improvements and alternatives as well.

I had a solution just like yours, but I also disliked the idea of modifying the `[]=` method; mostly for fear of it changing in the future and I not realizing it for a while.

Finally, though monkey-patching is definitely fun, I dislike doing it because it feels like the code is hiding. It’s not explicit.

Since there are at least two people in this world annoyed enough to fix it, maybe we ought to find a fix and send it to the core group!?

Mon, 18 Feb 08 09:09 pm . Collin VanDyck wrote:

Thank you for this! I am just getting my feet wet with rspec and I stumbled into this this morning. Very helpful.

Fri, 22 Feb 08 01:16 am . Chris Sepic wrote:

Herryanto, thanks for this…I found it very helpful.

Tue, 26 Feb 08 02:18 am . Dan Z wrote:

Excellent! This is exactly what I was looking for. Thanks!

Fri, 14 Mar 08 01:13 am . Federico wrote:

Iam trying to use the flashed method but I get the error “NoMethodError: undefined method `flashed’ for {}:ActionController::Flash::FlashHash”

What am i doing wrong?

Fri, 14 Mar 08 09:31 am . Herryanto Siatono wrote:

Federico, you shouldn’t be calling “flash.flashed[:key_name]” if you are using my method, you should only call “flashed” when you are using flashback plugin by Justin.

With my patch in your test_helper.rb or spec_helper.rb you should just call flash.now_cache[:key_name].

Fri, 28 Mar 08 10:04 am . Vinícius Teles wrote:

Herryanto, thanks a lot. This was very useful to me!

Fri, 28 Mar 08 11:53 am . » Use flash.now to render current view Advanced Rails: Rails Books and Blogs wrote:

[…] This blog tell the details,and this page tells how to test flash.now and more in the this bolg . […]

Thu, 3 Apr 08 10:27 pm . Ishrat wrote:

I put the code in my spec helper file and did exactly as instructed. But when I am running spec it is failing as it is getting nil object.
Can you help me please??

Wed, 9 Apr 08 06:49 pm . ishrat wrote:

I slightly changed the code and it worked for me. My change is as follows:

module ActionController
module Flash
class FlashNow
def initialize
@flash = {}
@now_cache = {}
@flash[@now_cache] = {}
end

def []=(k, v)
@now_cache = k
@flash[@now_cache]= v
v
end
end

class FlashHash
def now_cache
self || {}
end
end
end
end

Sat, 19 Apr 08 08:59 am . Xavier Shay wrote:

Here’s another way which is a bit cleaner and more succinct:

http://rhnh.net/2008/04/19/testing-flash-now-with-rspec

Sun, 18 May 08 08:37 pm . Living on the edge (of Rails) #20 - script/dbconsole and flash.now now test-able | redemption in a blog wrote:

[…] This is something that many of us Rails developers have probably come across when writing tests for flash messages being set with flash.now, myself included. Basically, you couldn’t test the contents of your flash.now because they were always being emptied before your test could get to them. […]

Fri, 22 Jan 10 04:48 pm . ATle wrote:

Herryanto, thanks very much. Your third way is very helpful to me!

Add Your Comment



(optional)