Test whether a form field exists with Cucumber and Capybara

The step definition below lets you say:

 Then I should see a field "Password"
 But I should not see a field "Role"

Here is the step definition:

Then /^I should( not)? see a field "([^"]*)"$/ do |negate, name|
  expectation = negate ? :should_not : :should
  begin
    field = find_field(name)
  rescue Capybara::ElementNotFound
    # In Capybara 0.4+ #find_field raises an error instead of returning nil
  end
  field.send(expectation, be_present)
end

Note that you might have to adapt the step defi...

HTML5 Please: Use the new and shiny responsibly

Look up HTML5 features, know if they are ready for use, and if so find out you should use them – with polyfills, fallbacks or as they are.

gammons/fake_arel - GitHub

Gem to get Rails 3's new ActiveRecord query interface (where, order) and the new scope syntax (chaining scope definitions) in Rails 2.

You also get #to_sql for scopes.

marcandre/backports - GitHub

Gem to get Ruby 1.9 features in Ruby 1.8.

How to revert features for deployment, merge back, and how to stay sane

Removing features and merging those changes back can be painful. Here is how it worked for me.\
tl;dr: Before merging back: reinstate reverted features in a temporary branch, then merge that branch.

Scenario

Consider your team has been working on several features in a branch, made many changes over time and thus several commits for each feature.\
Now your client wants you to deploy while there are still stories that were rejected previously and can't be deployed.
...

How to organize and execute cucumber features (e.g. in subdirectories)

In cucumber you are able to run features in whatever directory you like. This also includes executing features in subdirectories. There are only some things you have to take care of.

By default, cucumber loads all *.rb files it can find (recursively) within the directory you passed as argument to cucumber.

$ cucumber # defaults to directory "features"
$ cucumber features
$ cucumber my/custom/features/dir

So, if you would like to organize features in subdirectories, you won't have *any problems when running the whole test...

Fix: Cucumber won't start though cucumber.yml is correct

This is for you if you get this error:

cucumber.yml was found, but could not be parsed. Please refer to cucumber's documentation on correct profile usage.

Actually, it's likely that your cucumber.yml is just fine but not your rerun.txt.\
This sometimes happens when running multiple Cucumber workers with parallel_tests that write into rerun.txt simultaneously -- ending up with a messy, invalid file.

Just remove it and you ar...

Detect mobile or touch devices on both server and client

Although it's tempting flirt with detecting mobile/touch devices with CSS media queries or Javascript feature detection alone, this approach will be painful when heavily customizing a feature beyond just tweaking the looks. Eventually you will want want the same detection logic to be available on both server and client side.

This card shows how to get a Ruby method touch_device? for your Rails views and a method TouchDevice.isPresent() for your Javascripts.

Note that we are detecting touch devices by grepping the user agent, and the ke...

How to click hidden submit buttons with Selenium

In your Cucumber features you can't really click hidden elements when using Selenium (it does work for a plain Webrat scenario, though).

Unfortunately you need to hack around it, like this:

When /^I press the hidden "([^\"]+)" submit button$/ do |label|
  page.evaluate_script <<-JS
    $('input[type=submit][value="#{label}"]').show().click();
  JS
end

If your button is nested into a container that is hidden this will not do the trick. You need a more complex method to also show surrounding containers:

When /^I pre...

How to fix the Apple Mail search problem in MacOS X 10.7 Lion

After my update from MacOS X 10.6 Snow Leopard to 10.7 Lion the search function in Apple Mail stopped working.
There were no or too little search results, when I typed something in the search field.
It looked like my mailboxes couldn't be indexed by spotlight anymore.

And here is the simple solution:

  1. Mark your mailbox in the list of mailboxes on the left in your apple mail window by clicking on its name once.
  2. From the menu select "Mailbox" => "Rebuild".
  3. After the rebuild you should get the right search results again.
  4. Proceed wi...

Re-enable submit buttons disabled by the :disable_with option

Submit buttons in Rails come with a useful option :disable_with which will disable the button when clicked and change its label to something like "Please wait...".

An annoying side effect of that feature is that when you use the back button to return to the form, the submit button will be greyed out and disabled.

A solution is to re-enable the submit button before leaving the page. This works in Rails 3:

$(window).unload(function() {
  $.rails.enableFormElements($($.rails.formSubmitSelector));
});

davetron5000/methadone - GitHub

Framework to write command-line apps in Ruby. Comes with a nice way of processing parameter options, some utility classes and Cucumber steps for testing your CLI app.

How to fix "unknown role" errors in Capistrano recipes

When you have a complex recipe setup with multistage deployment you may run into this error:

`role_list_from': unknown role `something' (ArgumentError)

Consider this task definition:

namespace :foo do
  task :bar, :roles => :something do
    # do crazy stuff
  end
end

Whenever we call foo.bar in our recipe, Capistrano will fail if you deploy to a stage where none of the servers has the role the error complains about, "something" in this case.

However, you can [hack around it](http://groups.google.com/group/ca...

Scenario outlines in Cucumber

Scenario outlines allow us to more concisely express repetitive examples through the use of a template with placeholders.

Bulk-change multiple table rows in a migration

Using rename_column, remove_column, etc. more than once in a migration makes that migration run slower than it should. Use change_table instead.

Consider this migration:

add_column :users, :name, :string
remove_column :users, :first_name
remove_column :users, :last_name
rename_column :users, :cool, :awesome

Migrating in this case means that all those commands are processed step by step, causing 4 SQL statements to change the table. In turn, your database needs to modify the table structure 4 times. When working on hu...

Ubuntu 11.10: Playing sound over front and back panel (or headphones and speakers) at once

I have a pair of headphones connected to my desktop's back panel and a headset connected to the front panel. I used to play sound over both outputs, but this suddenly stopped working this week.

Apparently, (perhaps through some update) "jack sensing" got turned on, which disables the back panel as soon as you connect something to your front panel audio jack.

To disable this feature, I used alsamixer (use the arrow keys to navigate right to "auto mute", and disable with the up key). For some reason the corresponding checkbox in the `gnome...

Error "execution expired (Timeout::Error)" when using Selenium and Webmock

If you get the above error when running tests in bulk (but not individually), it's actually the fault of Webmock.

Updating Webmock to version 1.7+ fixes this.

Be careful with "memoize"

ActiveSupport's memoize has a dangerous feature you might not know about.

Assume you have

class DeepThought
  extend ActiveSupport::Memoizable

  def life_universe_and_everything
     # some lengthy calculation returning 42
  end
  memoize :life_universe_and_everything
end

Then #life_universe_and_everything will of course cache the result after calculating it once. However, you can trigger a recalculation by calling #life_universe_and_everything(true).

If, however, your method looks like

de...

"Show me the page" fails to open a browser window

If you get an error like this:

Unable to launch /home/bruce/Projects/myproject/tmp/capybara/capybara-201110311210111407691101.html 

... update your launchy gem. It failed for us in version 0.4.x. We could fix the issue by upgrading to 2.0.5.

Cucumber.yml was found, but could not be parsed.

If you encounter the error message above when running cucumber, just execute...
rm rerun.txt
...in the Rails directory.

Or run...
tests
...from the geordi gem. This will do the work for you automatically.

Stub methods on any instance of a class in Rspec 1 and Rspec 2

RSpec 1 (Rails 2)

With the most recent spec_candy.rb helpers you can say:

User.stub_any_instance(:foo => :bar)
user = User.new
user.foo
# => :bar

RSpec 2 (Rails 3)

RSpec 2 comes with this feature built in:

User.any_instance.stub(:foo => :bar)
user = User.new
user.foo
# => :bar

RSpec 3
-------...

Stub a request's IP address in a Cucumber scenario

The solution in this card is based on a stack overflow post by Leventix.

If you need to make request come from a fixed IP address for the duration of a Cucumber scenario, the code below lets you write this:

Given my IP address is 188.174.117.205

Rails 3

Given /^my IP address is "(.*?)"$/ do |ip|
  ActionDispatch::Request.any_instance.stub(:remote_ip).and_return(ip)
end

Rails 2
-----...

Ruby 2.0 Implementation Work Begins: What is Ruby 2.0 and What’s New?

While 2.0 will include a number of syntax changes, new features and general improvements, mentioned below, it is anticipated to remain backward compatible with code written for 1.9.3 and Matz has stated that the changes are less significant than those made in the 1.8 to 1.9 jump.

Rails logs are not flushed automatically (in Rake tasks)

The Rails logger will store its content in a buffer and write it into the file system every 1000 lines. This will come back to bite you when using Rails.logger.info to write log output during Rake tasks or on a production console.

You often won't notice this because for the development and test environments auto_flushing is set to write after each line. On production environments the Rails logger writes only every 1000 lines -- and not upon shell or script ter...