giant robots smashing into other giant robots

Written by thoughtbot

lolconomy

This week in open source

bourbon

So this bourbon gem…people seem to like it: there was a RailsCast about it and the principle author (Phil LaPier) will be speaking at Frontend United about it.

This week people cleaned up the obsolete CSS attributes: Thibaut (Thibaut) removed -moz-inline-block (d73ea46), Chad Mazzola removed both -ms-border-radius and -o-border-radius (10a5908), and Phil LaPier (plapier) removed -moz-box-orient (6331e26). Gabe Berke-Williams (gabebw) fixed support for Rails 2 (eacd5ee and e9347e7) and, lesson learned, removed Gemfile.lock (671ad33).

factory_girl

Version 2.6.3 of factory_girl is out, all y’all. In this action-packed version we got a cucumber step named e.g. Given the following post exists (note the lack of : at the end), via cj (cj) (d4b8cac and 48afe24). Barun Singh (barunio) fixed a bug where the factory’s traits weren’t compiled in the very first time the factory was used (68ca50f), plus a factory can use all the traits on any ancestor (f14a8cf). Joshua Clayton (joshuaclayton) is now listed as an author (07d2834), so congrats to him and his hard work. As part of that hard work he discovered that the vintage syntax broke in MRI 1.9.2-p318, and then fixed it (a7acc3e).

This just in! Version 3.0.0.rc1 is now public! It breaks everything, again! Please try it and open issues with what breaks:

gem 'factory_girl', '3.0.0.rc1'

bourne

Oh hey version 1.1.1 of bourne is out (650afb0)! Bourne is an extension to mocha that adds test spies so your tests can read like normal tests. Tristan Dunn (tristandunn) added support for mocha 0.10.5 (286d8f9) and fixed a long-standing error message that occurs when you forget to stub a method before spying on it (17dc7d2).

Gabe Berke-Williams (gabebw), who pushed the release, also did some maintainance: adding Travis CI notifications to the README (7d6eb37), removing Gemfile.lock (950a445), and some general code cleanups (4bbe610 and b0f1f99).

shoulda-matchers

The big deal in shoulda-matchers over the past week was when Fujimura Daisuke (fujimura) added the ability to specify the key for the flash message in the set_the_flash matcher (0e0339e, ef866e2, and fd4aa53):

it { should set_the_flash[:alert].to("Password doesn't match") }

Gabe Berke-Williams (gabebw) did his usual maintainance of converting the docs to use Markdown (85c37c4), cleaning up the ModelBuilder that’s used in the tests (31595b0), and showing off how often our build is broken in the README using Travis CI (eebb806), which he also did to shoulda proper (7d805d0).

cocaine

Also victim to the Travis CI treatment was cocaine, via Gabe Berke-Williams (gabebw) again (ac47b6f and 490c406).

paperclip

The paperclip project is gearing up for a groundbreaking (maybe app-breaking?) release, but in the meantime Mike Boone (boone) fixed an infinitely-growing PATH environment variable (06d69af) while Mike Burns (mike-burns)—also known as: me—totally broke backward compatibility by changing the default :path and :url configuration setting (26f4d40). These new settings avoid overwriting files on different models and also scales to more than 1024 instances of the same model.

capybara-webkit

In capybara-webkit news, Joe Ferris (jferris) controversially allowed the user to interact with invisible elements (02f2a8a), and caught the fact that Capybara.timeout is deprecated (4d954b7).

lolconomy

This week in open source

kumade

It was a refactoring week on kumade, the Heroku deployer. Gabe Berke-Williams and Josh Clayton refactored the Packager class, splitting it out into handlers for Jammit, Less, and no-op packagers (d854184). Then Gabe Berke-Williams (gabebw) went off on his own to introduce a CommandLine class, wrapping Cocaine with some Thor (0c3840d and 72424c0). Meanwhile Joshua Clayton (joshuaclayton) changed should_not have_received to should have_received.never (6652197).

suspenders

Our app making gem, suspenders, saw some updates from Matt Jankowski (mjankowski): Rails 3.1 (10ac09a, 97881fc, 354321d, c8f8c85, and db08366), bourbon (d490b36), flutie (e0bab83), the Hoptoad → Airbrake name change (6def3d7), and tying together the asset pipeline (a4ce3e7 and c760a33).

paul_revere

We have a one-off announcement plugin for Rails, named paul_revere. Nick Quaranto (qrush) released version 0.2.1 (3574b40 and dfbf940).

shoulda-matchers

Our collection of RSpec matchers, shoulda-matchers, is not passing on my laptop. Prem Sichanugrist (sikachu) built out the continuous integration tests more to attempt to clarify the issue (3d94390, 4450c86, 1a3aeec, 6785f59, f1f5e6d).

bourbon

The SCSS gem, bourbon, saw actual words being used by Matt Jankowski (mjankowski) in the documentation (b8afdea), plus Phil LaPier (plapier) updated the docs with resources for investigating browser compatibility (35539c9). He also added this sweet variable, $all-text-inputs, representing all HTML5 textual inputs like color, date, phone, password, URL, and so on (d1def76 and fb299e6). To wrap it all up he released version 0.1.8 (f3046bd).

paperclip

Lots of bug fixes in paperclip, the Rails image uploader plugin gem, this week. Cody Caughlan (ruckus) added S3 support for an HTTP proxy (4661cef). Denis Yagofarov (denyago) preserved the path set for the Cocaine gem (3a35ba9). Aditya Sanghi (asanghi) gave us a warning when two models save files to the same place on the filesystem (8d43e19). Daniel Evans (danielevans) removes the temporary file after it has been uploaded and processed (748332e). Edison (edison) added a feature where you can set the file system path based on a method in the model (996ca87 and 1738f3c).

Prem Sichanugrist (sikachu) then attacked some outstanding bugs: escape the URL (23cb822), handle a space leak where an array was growing by one for each request (d18d814), make the Interpolations.hash class method confirm to the expected signature for hash methods (e526c86), and preserve the filename for S3 attachments when we know the filename (522a53e).

Prem then did some refactoring, splitting the storage tests into individual unit tests (0ca98d1, d204c7d, 31d74d6), stubbing Cocaine (0a77f64), removing some noisy debugging (fd891e0), and cleaning up whitespace (825e1f1 and b2cac53). After all of this he released version 2.4.2 (9edeb01).

factory_girl

Features and refactorings were the name of the game for factory_girl, the fixture replacement for Rails. Joe Ferris and Josh Clayton fixed traits so now you can override attributes of them. They did this by refactoring attributes, introducing an intermediate Declaration object that knows how to compile down to a full factory (a154e64 and f8638b). Joe Ferris (jferris) made callbacks into first-class objects with validations (0f87ca3, ede051f, and 4d30663). Thomas Walpole (twalpole) fixed an inconsistency, ensuring that parent callbacks are called before child callbacks (27c4b21).

Oh man check this: Joel Meador (janxious) updated the ChangeLog (306e51b and 88cf88)! Joshua Clayton (joshuaclayton) went along with this, too (9c95a2) before releasing version 2.1.2 (58e75bc and c1360e).

capybara-webkit

The capybara-webkit test driver, which Joe presented about at Boston Ruby, continues to improve. Gabe Berke-Williams (gabebw) gave us a documentation edit (f493b22), while Matthew Mongeau (halogenandtoast) striped and normalized spaces for consistency with Selenium (6d92f35) and also added support for unknown content types (ff0a6e7, 9257fe3, and 353fe86)

dancroak

JavaScript integration testing example: installing and using Mixpanel

We’ve been on a quest for years to make sure our integration tests cover the JavaScript components of the app. Here’s an example: installing Mixpanel in Copycopter to track visits, user sign ups, user activity during the free trial, and subscriptions.

Gemfile:

gem 'capybara-webkit'

features/support/env.rb:

Capybara.javascript_driver = :webkit

features/mixpanel.feature:

Background:
  Given the following plan exists:
    | id | name       | price | trial |
    | 16 | Supersonic | 5     | false |
    | 5  | Trial      | 0     | true  |
  And the following limits exist:
    | plan             | name     | value |
    | name: Supersonic | users    | 13    |
    | name: Supersonic | projects | 14    |

@javascript
Scenario: Track visitor learning about Copycopter
  When I go to the homepage
  Then mixpanel should track the "visited-home" event
  When I follow "Take a tour"
  Then mixpanel should track the "clicked-tour" event
  When I follow "Next, view plans and pricing"
  Then mixpanel should track the "clicked-next-to-plans-and-pricing" event

@javascript
Scenario: Track visitor signing up for free trial
  When I go to the homepage
  And I follow "Plans and Pricing"
  Then mixpanel should track the "clicked-plans-and-pricing" event
  When I follow "Choose free trial"
  Then mixpanel should track the "viewed-plan" event with the properties:
    | plan_id | 5 |

We use the @javascript tag, which will use Capybara Webkit to drive the browser in these tests.

We explicitly set the id’s of the ActiveRecord objects so we can check that Mixpanel receives the right plan id’s using their properties feature.

features/step_definitions/mixpanel_steps.rb:

Then %r{^mixpanel should track the "(.*)" event$} do |event_name|
  mpq = JSON.parse(evaluate_script(%{JSON.stringify(mpq);}))
  mpq.should include(["track", event_name])
end

Then %r{^mixpanel should track the "(.*)" event with the properties:$} do |event_name, table|
  mpq        = JSON.parse(evaluate_script(%{JSON.stringify(mpq);}))
  properties = table.transpose.hashes.first
  mpq.should include(["track", event_name, properties])
end

This is a little funky. We’re using JSON.stringify via json2.js and then Ruby’s JSON.parse to convert Mixpanel’s mpq Javascript object into its Ruby equivalent in order to invoke expectations on it.

Therefore, we need to include json2.js in our app:

curl https://github.com/douglascrockford/JSON-js/raw/master/json2.js > public/javascripts/json2.js

app/views/shared/_javascript.html.erb:

<% if Rails.env.test? %>
  <%= javascript_include_tag "json2" %>
<% end %>

That smells like a hack, but whatever…

Also in that partial, the actual setup for Mixpanel:

<script type="text/javascript">
  var mpq = [];
  &lt;% if Rails.env.staging? || Rails.env.production? -%&gt;
    mpq.push(["init", "&lt;%= MIXPANEL_TOKEN %&gt;"]);
    (function() {
      var mp = document.createElement("script"); mp.type = "text/javascript"; mp.async = true;
      mp.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + "//api.mixpanel.com/site_media/js/api/mixpanel.js";
      var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(mp, s);
    })();
  &lt;% end -%&gt;
</script>

That mpq object looks familiar. We’re testing against it in our integration suite. It’s just a JavaScript Array.

We only include the rest of the Mixpanel setup in staging and production. It stuffs mixpanel.js into the DOM asynchronously.

We interpolate our Mixpanel account’s token based on the environment so we can run acceptance on our user story on staging.

config/environments/staging.rb:

MIXPANEL_TOKEN = "our-staging-token".freeze

config/environments/production.rb:

MIXPANEL_TOKEN = "our-production-token".freeze

To get the rest of the integration test passing, we follow the Mixpanel API normally.

views/homes/show.html.erb:

$(function () {
  mpq.push(["track", "visited-home"]);
  $("#tour-cloud").click(function () {
    mpq.push(["track", "clicked-tour"]);
  });
  $("#plans-cloud").click(function () {
    mpq.push(["track", "clicked-plans-and-pricing"]);
  });
  $("#next-to-plans").click(function () {
    mpq.push(["track", "clicked-next-to-plans-and-pricing"]);
  });
});

views/accounts/new.html.erb:

$(function () {
  mpq.push(["track", "viewed-plan", { plan_id: "&lt;%= @plan.id %&gt;" }]);
});

This use case is relatively common. Include some external service’s JavaScript and use their Javascript API in order to get good analytics on the app.

To make it happen smoothly, there’s a lot of interpolation and Ruby mixing with HTML and JavaScript. Things could go wrong and it feels good to have integration coverage for it.

Written by .