Simple tricks to clean up your Capybara tests

I'd like to share with you a few simple tricks we use all the time at Elabs to clean up our Capybara tests.

Often we want to find a specific area of the page, and perform some action in that area. With the imminent release of Capybara 2.0, you will probably find yourselves doing this even more, since you will sometimes have to be more specific about which element you want to interact with, since Capybara will raise an error when more than one element can be found.

You are probably familiar with the within method in Capybara, so say you want to click a link in the main menu, you might do it like this:

within "header nav" do
  click_link "Archive"

But in Capybara, all methods like click_link and fill_in and so on can be chained, so you could have written the above more succinctly as:

find("header nav").click_link("Archive")

That's better. However, the central idea behind Capybara is that you should test your application the way a regular user would use it; your user knows what the main menu is, but they don't really know anything about that CSS selector.

I once wrote a blog post called "You're cuking it wrong", about best practices when using Cucumber, it ended with the following general rule:

A step description should never contain regexen, CSS or XPath selectors, any kind of code or data structure. It should be easily understood just by reading the description.

While it doesn't make sense to be as strict about this ideal in plain Capybara tests, there is still a point to be made about avoiding low level detail even in these tests.

With that in mind, let's revisit that example. What if we could simply write:


That's much more obvious. We clearly communicate the intent, and we don't include any irrelevant details in the test. The implementation is super simple:

module MenuSteps
  def main_menu
    find("header nav")

Now you might ask, what if I want to perform a lot of actions in a particular area of the page, this doesn't look so nice:

login_form.fill_in "Email", :with => ""
login_form.fill_in "Password", :with => "capybara"
login_form.click_button "Login"

Thankfully, the within method can actually take as an argument an actual element, not just a selector. So we can write this instead:

within login_form do
  fill_in "Email", :with => ""
  fill_in "Password", :with => "capybara"
  click_button "Login"

Concise and clear.


Of course, since main_menu and login_form are just methods, we could create similar methods which take arguments. Imagine we wanted to delete a particular comment on our blog. We could write this:

find(".comment", :text => "Worst article ever!").click_on("Remove")

Hopefully you can see where this is going:

comment("Worst article ever").click_on("Remove")

And the implementation:

module CommentSteps
  def comment(text)
    find(".comment", :text => text)

Much better!


This is a bit specific to RSpec, but if you're using a different test framework, you can adapt this to your needs.

In another test for our blog, we are creating comments, and we want to assert that the comment appears as intended.

page.should have_selector(".comment", :text => "Best article ever!")

Remember our guideline/rule. That selector has to go! It would be fantastic if we could simply write:

page.should have_comment("Best article ever!")

But now we have a problem. We could create an RSpec matcher, but that would actually be a bit cumbersome. It could look like this:

module CommentSteps
  extend RSpec::Matchers::DSL

  matcher :have_comment do |text|
    match_for_should { |node| node.has_selector?(".comment", :text => text) }
    match_for_should_not { |node| node.has_no_selector?(".comment", :text => text) }

It's important that you add both match_for_should and match_for_should_not, otherwise Capybara's waiting behaviour doesn't work properly.

This also doesn't give us particularly great error messages. We will get some variation on "expected true to be false", which isn't particular helpful.

There is a much easier way, which works well for simple cases like these:

module CommentSteps
  def have_comment(text)
    have_selector(".comment", :text => text)

Same functionality, but easier to understand, shorter, and it even gives us better errors. We are making use of the fact that have_selector just returns an RSpec matcher.

Ensure on

One thing we face often in our tests is that we need to be on a particular page to do something. This is especially important if we have abstracted something into a helper. Consider this:

module SessionSteps
  def login
    visit login_path
    fill_in "Email", :with => ""
    fill_in "Password", :with => "capybara"
    click_button "Login"

But what if we already are on the login page when we call login, we'll visit the page again, which wastes valuable execution time. Let's make sure we don't do that:

module SessionSteps
  def login
    visit login_path unless current_path == login_path
    fill_in "Email", :with => ""
    fill_in "Password", :with => "capybara"
    click_button "Login"

We immediately spot that this pattern would be sensible to abstract. We have this in almost all of our projects, and we call it ensure_on:

module CommonSteps
  def ensure_on(path)
    visit(path) unless current_path == path

Usage should be fairly obvious:

module SessionSteps
  def login
    ensure_on login_path
    fill_in "Email", :with => ""
    fill_in "Password", :with => "capybara"
    click_button "Login"

And for our final trick…

Suppose that on our blog, comments are moderated, and when someone posts a comment, we want to check that it appears in the moderation queue:

fill_in("Comment", :with => "Hi there")
visit moderation_queue_path
find(".moderation-queue").should have_comment("Hi there")

Of course we should create a moderation_queue method, like we did in the first example. But then we still need to remember that we need to actually visit that page before we fetch the element. Let's abstract that away:

module ModerationQueueSteps
  def moderation_queue
    ensure_on moderation_queue_path

Now we can write:

fill_in("Comment", :with => "Hi there")
moderation_queue.should have_comment("Hi there")

That reveals our intent much clearer. We have practically created a small little DSL for our tests, just by creating a couple of really simple helper methods.

So that's it, some really simple tricks which allow you to write cleaner, more understandable tests with Capybara.


Give a shit about copy

I follow the blog “Great not Big” by Carl Erickson at Atomic Object. Yesterday he wrote about their value mantra “Give a shit”. I think it’s a brilliant way to express that you care about what you do. He ends the blogpost with the question if others would rather use “care deeply” or “give a shit” in public and why.

I definitely say “Give a shit”. I work with copy and it’s hard. Many companies use the same phrases, and most of them sound hollow. When potential clients read the same things and promises over and over again it has no impact. I think the phrase “care deeply” will go unnoticed or leave the reader with the feeling of empty promises.

If you instead read “Give a shit” you will react. Some may be offended but I think most people will react positively and, most importantly, remember you. “Give a shit” will stick. It will leave the client with the feeling that you mean what you say, and that is good copy.

Copy shouldn’t be written to sound good or suck up to clients. It should reflect how we work, be straight forward and honest. No bullshit. At Elabs we work with an open and constant dialog with our clients, we discuss and advise. Our copy should reflect that, so our clients know what they can expect. Right now it doesn't, and we're working on changing that.

A phrase that I think unfortunately is used too often in our business, and therefore lost its appeal, is “handcrafted”. The initial thought about using the term handcrafted about development was good, even great. It emphasizes that developers care about their work, care about details and about building something with quality to be proud of. But when too many companies use the phrase it loses its meaning. It won’t stick. At Elabs we've used the word bespoke instead. The problem is that it’s actually the same word, just sounds fancier. And it’s not memorable.

So how do we convey the meaning of handcrafted without using the word? I don’t know. But if we want to stand out and make clients react and remember us we must give a shit about our copy.


A conference should be an experience filled with joy

Jonas Downey at 37signals wrote about their experiences at the XOXO conference in Portland last week. It sounds like it was a great conference, and the principles behind it echoes our ideas for Nordic Ruby. This passage from the blog post about XOXO sums up Nordic Ruby as well:

“Conference events shouldn’t be short and formal. Andy Baio and Andy McMillan could teach s course in throwing a good event. In short: allow your attendees plenty of room to breathe. Don’t pack in tons of simultaneous sessions in a generic hotel. Give people an experience. Give them free time. Give them good food and loads of coffee in a weird place.”
— Jonas Downey, Lessons in creativity and joy at XOXO

We share the XOXO organisers belief in having fun together. To create social time for the attendees. The conversations and new connections you make at a conference are important. So putting everyone in one place for a couple of days with a spacious schedule and parties in the evenings open up for socialising which, like Jonas writes in his blog post, is invaluable.

To read more about our thoughts on Nordic Ruby, check out CJ's blog post about Nordic Ruby 2012.


Nordic Ruby 2012

After running two successful Nordic Ruby conferences in Gothenburg (2010 and 2011), we knew we wanted to do something different this year. Since many of our attendees are from Stockholm, we decided to move the conference there.

We went for an "East meets West" theme representing both the move from the west coast of Sweden to the east coast, and bringing a Japanese programming language to western Europe. With that in mind, we found the perfect venue — Yasuragi Hasseludden — a Japanese style spa in the Stockholm archipelago.

The Yasuragi terrace

Having the conference at a spa also fit perfectly with what's always been our vision for Nordic Ruby; a great event that's brings people together, where everyone can have a shared experience, and leave recharged and inspired. Nordic Ruby has always been single track, with everyone having lunches and dinners together, to give that shared experience. We've also always had slightly different format than most other conferences, with short talks, each followed by a break at least as long. This ensures that everyone has plenty of time to meet and talk to other attendees and speakers, and gives everyone the chance to digest the avalanche of information that a conference can be.

Yasuragi proved the perfect venue to take these ideas to the next level. We included accommodation at the spa in the ticket price, which meant that people didn't disappear to different hotels at the end of the day, giving even more of a shared experience. The calm and relaxing atmosphere meant that people left the conference feeling energised, rather than drained as is the usual feeling after many other conferences. And of course, the Japanese style of the spa was a perfect homage to the origin of Ruby.

Corey Haines

We had some amazing speakers this year too, and we're very grateful to them for coming all the way to Sweden to share their knowledge and passion. We had fantastic experienced speakers such as Corey Haines and Steve Klabnik, but the speaker who blew everyone away was Katrina Owen. Katrina had never spoken at a conference before, but she presented her thoughts on the therapeutic aspects of refactoring in a masterful way. The audience was at the edge of their seats, spellbound by her pitch-perfect storytelling. She's since gone on to present at many other conferences, with equal aplomb.

Katrina Owen

What makes Nordic Ruby such a great experience for all of us though is the attendees. They embraced and added to the atmosphere of the conference, donning the yukata (traditional Japanese bathrobes) they were given, and taking full advantage of the environment. People reconnected with old friends, and made many new ones. In the end, that's what really matters. Our goal with Nordic Ruby has always been to facilitate this by providing a great opportunity and environment for it.

Some of the Elabs crew relaxing

We're busy planning next year's Nordic Ruby. As successful as this year's conference was, there are always things to improve. If you want to help out, we're always looking for sponsors. We couldn't make Nordic Ruby happen without the great support from our sponsors (Hashrocket, Engine Yard, Valtech, GitHub, and ProjectPuzzle this year). If you're interested in sponsoring next year, get in touch.

Nordic Ruby will be held June 6-9 next year. If you want to attend, you should follow @nordicruby on Twitter or track it on Lanyrd. We hope to see you there!

Working under the midnight sun

P.S. Check out more photos by our photographer Antony Sastre in our Flickr album.


Almost time for Nordic Ruby

Right now, all of us at Elabs are on our way to Stockholm for the 3rd annual Nordic Ruby – the conference that we organise every year.

Nordic Ruby is the highlight of the year for us. While organising it is a lot of work, we always leave refreshed and motivated. Listening to the presentations and meeting the attendees from all over the world is always inspiring. We can't wait for the conference to start tomorrow.

If you want to follow along, follow @elabs and @nordicruby on Twitter.