Testing w/ Analytical Gem and RSpec

Back | rails, ruby, testing | 1/30/2012 |

We use the Analytical gem to include various thirdparty Javascripts in our Rails application. Our test environment was configured with dummy values in config/analytical.yml.

  1. production:
  2.   google:
  3.     key: <%= ENV['GOOGLE_UA'] %>
  4.   kiss_metrics:
  5.     js_url_key: <%= ENV['KISS_METRICS_URL_KEY'] %>
  6.  
  7. test:
  8.   google:
  9.     key: 'UA-12345'
  10.   kiss_metrics:
  11.     js_url_key: 12345
  12.  
  13. development:

We wrote a few simple tests to make sure the analytical code is being included properly. For example, we can check whether Google Analytics is included on the splash page.

  1. context "google analytics" do
  2.   it "should appear on the splash page" do
  3.     visit "/"
  4.     within :css, "script[type='text/javascript']:contains('.google-analytics.com/')" do
  5.       page.should have_content("UA-12345")
  6.     end
  7.   end
  8. end

Or, more complicated, test whether a user ID is sent to Kissmetrics.

  1. context "kiss-metrics analytics" do
  2.   it "should appear on the splash page" do
  3.     visit "/"
  4.     within :css, "script[type='text/javascript']:contains('kissmetrics.com/')" do
  5.       page.should have_content("12345")
  6.     end
  7.   end
  8.   context "logged-in user" do
  9.     before(:each) do
  10.       login_as @user
  11.       visit "/"
  12.     end
  13.     it "should appear on the search page" do
  14.       within :css, "script[type='text/javascript']:contains('kissmetrics.com/')" do
  15.         page.should have_content("12345")
  16.       end
  17.     end
  18.     it "should include user id" do
  19.       within :css, "script[type='text/javascript']:contains(\"identify\")" do
  20.         page.should have_content("[\"identify\", \"#{@user.id}\"]);")
  21.       end
  22.     end
  23.   end
  24. end

The drawback of this approach is that the Analytical code is included with every other test that doesn’t need it. With every Capybara test that runs in a browser, this hits DNS, then makes an HTTP request to Google and Kissmetrics. We cannot stub that with VCR or another gem because we’re using a real browser. But we can selectively enable Analytics without a configuration file by emptying the :test block in config/analytical.yml by configuring it before any test that needs it.

  1. before :each do
  2.     @analytical_options = ApplicationController.analytical_options.dup
  3.     ApplicationController.analytical_options = @analytical_options.merge({
  4.         :modules => [ :google, :kiss_metrics ],
  5.         :google => { :key => "UA-12345" },
  6.         :kiss_metrics => { :js_url_key => 12345 }
  7.     })
  8. end
  9. after :each do
  10.     ApplicationController.analytical_options = @analytical_options
  11. end

It helps to be open-source. Looking at the internals of Analytical, its options are processed inside each controller on load, then merged with request options on every request before anything is rendered. The code above updates the configuration between those two steps. Note that since we’re modifying a static we have to make sure to cleanup after ourselves.