Testing flash.now with RSpec
flash.now has always been a pain to test. The the traditional rails approach is to use assert_select and find it in your views. This clearly doesn’t work if you want to test your controller in isolation.
Other folks have found work arounds to the problem, including mocking out the flash or monkey patching it.
These solutions feel a bit like using a sledgehammer to me. If you’re going to monkey patch/mock something, you want it to be as discreet as possible so to minimize the chance of the implementation changing underneath you and also to reduce the affect on other areas of your application. Also, why duplicate perfectly good code that is provided elsewhere?
The real problem with testing flash.now is that it gets cleaned up (via #sweep) at the end of the action before you get to test anything. So let’s solve that problem and that problem only: disable sweeping of flash.now:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# spec/spec_helper.rb module DisableFlashSweeping def sweep end end # A spec describe BogusController, "handling GET to #index" do it "sets flash.now[:message]" do @controller.instance_eval { flash.extend(DisableFlashSweeping) } get :index flash.now[:message].should_not be_nil end end |
instance_eval is used to access the flash, since it’s a protected method, and we extend with the minimum possible code to do what we want – blanking out the sweep method. This should not cause problems because sweeping is only relevant across multiple requests, which we shouldn’t be doing in our controller specs.
May 16, 2008 at 11:57 PM
Thanks! Direct, and to the point. You can also do this without a special module by just stubbing out sweep directly:
describe BogusController, "handling GET to #index" do it "sets flash.now[:message]" do @controller.instance_eval{flash.stub!(:sweep)} get :index flash.now[:message].should_not be_nil end endMay 22, 2008 at 3:25 AM
If you want this for all your controller spec's this seems to be a neat enough approach.
Spec::Runner.configure do |config| ... config.before(:each, :behaviour_type => :controller) do @controller.instance_eval { flash.stub!(:sweep) } end ... endJuly 10, 2008 at 2:02 AM
I'll have to second (or third?) Alf's one liner. It worked for me, though I'm thinking it needs a wrapper. I'm not quite ready to vouch for Darragh's catch all setup. Not sure if I need it.
February 16, 2010 at 6:38 AM
Darragh,
Thank you! that was helpful
April 26, 2010 at 2:17 PM
Yes, this was very handy. Stubbing the sweep method is a lot cleaner than adding plugins and whatnot as suggested elsewhere.
Thanks all for showing which bit to neuter!
April 26, 2010 at 2:20 PM
Actually there is another option, as per http://rubyflare.com/2009/07/12/testing-flash-now-with-rspec/
Simply assert on response.flash instead of flash.
It works for my test case, at least.