Standalone Cucumber Test Suite

Sometimes you inherit a non Rails or non Rack based web app such as PHP, Perl, Java / JEE, etc. I like using cucumber for functional testing so I put together this project structure to use as a starting point for testing non Ruby web based applications.

Getting your e-mails back after upgrading Thunderbird to version 3

If you previously used version 2.x of Thunderbird and upgraded to 3.x (for example through an Ubuntu release upgrade) you might notice that Thunderbird will not show any of your old e-mails or settings.

This results from a different directory being used for storing profiles and configuration.

You can replace the blank profile with your old one like this:
cd ~
mv .thunderbird .thunderbird-invalid
cp -R .mozilla-thunderbird .thunderbird

Upon its next start, Thunderbird brings up the migration wizard introducing you to a few vers...

Match strings in a given order with Cucumber and Capybara

Sometimes the order in which strings appear on a page matters to you.

Spreewald gives you steps like these:

Then I should see in this order:
  | Alpha Group |
  | Augsburg    |
  | Berlin      |
  | Beta Group  |

Or, if you prefer multiline strings:

Then I should see in this order:
  """
  Alpha Group
  Augsburg
  Berlin
  Beta Group
  """

The step ignores all HTML tags and only tests on plain text.

Machinist: Refer to another named blueprint inside a blueprint

Note: We are talking about Machinist 1 here, Machinist 2 may have solved this or might require a different approach.


Machinist allows named blueprints (e.g. User.blueprint(:admin)) that inherit from the master blueprint (User.blueprint).

If you also want to inherit from another blueprint (e.g. if "vip" should load "premium" and the master blueprint) you can do this:
User.blueprint(:vip) do
# Fields for the vip blueprint go her...

Using the full power of have_css

Capybara's has_css? matcher has a couple of options you might find useful.

Check that a selector appears a given number of times

Use the :count option like this:

Then /^I should see (\d+) users?$/ do |count|
  page.should have_css('ul#users li', :count => count.to_i)
end

Check that a selector has a given text content

Use the :text option like this:

Then /^I should see a user with name "([^\"]*)"$/ do |nam...

An obscure kernel feature to get more info about dying processes

This post will describe how I stumbled upon a code path in the Linux kernel which allows external programs to be launched when a core dump is about to happen. I provide a link to a short and ugly Ruby script which captures a faulting process, runs gdb to get a backtrace (and other information), captures the core dump, and then generates a notification email.

Cucumber step to match table rows with Capybara

These steps are now part of Spreewald.

This note describes a Cucumber step that lets you write this:

Then I should see a table with the following rows:
  | Bruce Wayne       | Employee    | 1972 |
  | Harleen Quinzel   | HR          | 1982 |
  | Alfred Pennyworth | Engineering | 1943 |

If there are additional columns or rows in the table that are not explicitely expected, the step won't complain. It does however expect the rows to be ordered as stat...

Reload the page in your Cucumber features

Both these approaches will keep your GET parameters -- and will only work for GET requests.

  • Capybara:

    When /^I reload the page$/ do
      visit [ current_path, page.driver.request.env['QUERY_STRING'] ].reject(&:blank?).join('?')
    end
    
  • Webrat:

    When /^I reload the page$/ do
      visit url_for(request.params)
    end
    

For a step that distinguishes between drivers (Selenium, Rack::Test, Culerity), check [n4k3d.com](http://n4k3d.com/blog/2011/02/02/reloading-the-page-in-cucumber-with-capybara-and-seleniu...

Replace substrings in Cucumber step argument transforms

Cucumber step argument transforms can be a powerful way to make your steps more flexible.

Note however that if your transform only matches a substring (no ^ and $ markers at the beginning and end), you are still expected to return a replacement for the whole string that was piped through the transform. If you don't do that, you will truncate that string and possibly make the calling step match where it should not.

Let's say you want a transform that replaces subs...

RSpec's context method is broken

RSpec's context (which is basically an alias for describe) takes over your whole application. No object may have its own context method, or you will always receive errors like

"No description supplied for example group declared on ~/project/app/..."

The easiest workarounds:

  • do not name any method context
  • use describe instead of context in your specs, and put this into your spec_helper.rb:\
    Spec::DSL::Main.class_eval do
    if method_defined? :context
    undef :context
    end
    end

Recent RSpec features you might not know about

With its you can switch the subject of an example to a method value of the current subject:

describe Array do
  its(:length) { should == 0 }
end

stub_chain is the tie to go along with should_receive_chain's tux:

object.stub_chain(:first, :second, :third).and_return(:this)

You can restore the original implementation of stubbed methods with unstub:

object.stub(:foo => 'bar')
# ...
object.unstub(:foo)

In recent RSpecs ...

Check that a text field is empty with Cucumber

This will not work (it always passes):

Then the "Title" field should contain ""

The value is turned into a regular expression, and an empty regular expression matches any string!

Do this instead for Capybara:

Then the "Title" field should contain "^$"

And do this step for Webrat:

Then /^the "([^"]*)" field should( not)? be empty$/ do |field, negate|
  expectation = negate ? :should_not : :should
  field_labeled(field).value.send(expectation, be_blank)
end

Run a rake task in all environments

Use like this:

power-rake db:migrate VERSION=20100913132321

By default the environments development, test, cucumber and performance are considered. The script will not run rake on a production or staging environment.


This script is part of our geordi gem on github.

Using RSpec stubs and mocks in Cucumber

By default, Cucumber uses mocha. This note shows to use RSpec stubs and mocks instead.

Rspec 1 / Rails 2

Put the following into your env.rb:

require 'spec/stubs/cucumber'

Rspec 2 / Rails 3

Put the following into your env.rb:

require 'cucumber/rspec/doubles'

Note: Since Cucumber 4 it is important to require these lines in the env.rb and not any other file in support/* to register the hooks after any other After hook in support/*. Otherwise your doubles are removed, while other After steps requi...

Debug Ruby code

This is an awesome gadget in your toolbox, even if your test coverage is great.

  • gem install ruby-debug (Ruby 1.8) or gem install debugger (Ruby 1.9)
  • Start your server with script/server --debugger
  • Set a breakpoint by invoking debugger anywhere in your code
  • Open your application in the browser and run the code path that crosses the breakpoint
  • Once you reach the breakpoint, the page loading will seem to "hang".
  • Switch to the shell you started the server with. That shell will be running an irb session where you can step thr...

Bundler for Rails 2.3.x

Update RubyGems and Passenger

Bundler requires Rubygems >= 1.3.6. Run gem update --system if you have an older version.
It also is not compatible with older versions of passenger, so bring that up to date as well (2.2.15 works).

If you installed RubyGems through apt (which you should never do!), you may see a message giving you a hint to use apt to update.
Some people advise to install the 'rubygems-update-1.3.7' gem on Ubuntu systems if you used apt to install RubyGems.
I did that - and lost all...

Boolean attributes and pretty enumerations in Cucumber Factory 1.7

Boolean attributes can now be set by appending "which", "that" or "who" at the end:

Given there is a movie which is awesome
And there is a movie with the name "Sunshine" that is not a comedy
And there is a director who is popular

Instead of "and" you can now also use "but" and commas to join sentences:

Given there is a movie which is awesome, popular and successful but not science fiction
And there is a director with the income "500000" but with the account balance "-30000"

Update with `sudo gem install cucumber_facto...

Test e-mail dispatch in Cucumber

Spreewald has steps that let you test that e-mails have been sent, using arbitrary conditions in any combination.

The attached file is for legacy purposes only.

Regular Expressions - Cheat Sheet

You can write regular expressions some different ways, e.g. /regex/ and %r{regex}. For examples, look here.

Remember that it is always a good idea to match a regex visually first.

Characters

Literal Characters

[ ] \ ^ $ . | ? * + ( )

Character Classes

[ae]            matches a and e, e.g. gr[ae]y => grey or gray => but NOT graay or graey
[0-9]  ...

Multi-line step arguments in Cucumber

The following example is from the Cucumber wiki:

Given a blog post named "Random" with Markdown body
  """
  Some Title, Eh?
  ==============
  Here is the first paragraph of my blog post. Lorem ipsum dolor sit amet,
  consectetur adipiscing elit.
  """

That multi-line string will be given as the last block argument in your step definitions:

Given /^a blog post named "([^\"]*)" with Markdown body$/ do |title, markdown|
  Post.create!(:title =...

Change Paperclip secrets the hard way

So you screwed up and copied Paperclip secrets from one project to another. Here is a semi-automatic, painful way to migrate your existing attachment files to new locations.

You need to follow this step by step, do not just copy the whole thing into the console!

# 1. Get old paths by doing something like this on the console:
old_paths = ModelWithAttachment.all.collect { |m| [m.id, File.dirname(m.image.path(:original)).gsub(/original$/, '') ] if m.image.file? }.compact.uniq

# 2. Now change the Paperclip secret on the co...

Marry Capybara with SSL-enabled applications

Capybara does not play nice with sites that have some actions protected by SSL, some not. A popular way to implement this in Rails is using the ssl_requirement plugin by DHH, which redirects a requests from HTTP to HTTPS if the requested action requires SSL and vice versa.

Capybara follows the redirect, but seems to forget the changed protocol for the next request. The only hack-free workaround right now is to use URLs in lieu of paths everywhere (links, form actions).

For a hackful fi...

rspec_candy is now a gem

Our awesome collection of rspec helpers (formerly known as "spec_candy.rb") is now available as a gem. It works, it is tested and there will be updates.

Usage

Add rspec_candy to your Gemfile.

Add require 'rspec_candy/helpers' to your spec_helper.rb, after the rspec requires.

List of features

See on GitHub

Git: Merge a single commit from another branch

This is called "cherry-picking".

git cherry-pick commit-sha1

Note that since branches are nothing but commit pointers, cherry-picking the latest commit of a branch is as simple as

git cherry-pick my-feature-branch

Be aware that cherry-picking will make a copy of the picked commit, with its own hash. If you merge the branch later, the commit will appear in a history a second time (probably without a diff since there was nothing left to do).

Also see our advice for [cherry picking to production branches](https://makandraca...