Versatile Cucumber step regarding hovering above elements

Here's a pretty useful steps that hasn't made it into Spreewald yet.

It is best used with the auto-mapper for BEM classes in features/support/selectors.rb

When I hover above [selector] element

When /^I hover above (.*) element$/ do |selector|
  page.find(selector_for(selector)).hover
end

Example:

When I hover above the album's image element

→ triggers a hover event on .album--image

postgres: window functions

Good article about window functions. Also note how they use a postgres feature called common table expressions.

An auto-mapper for BEM classes in Cucumber selectors

When you are using the #selector_for helper in Cucumber steps, as e.g. Spreewald does, the following snippet will save you typing. It recognizes a prose BEM-style selector and maps it to the corresponding BEM class.

For a variation on this idea, see An auto-mapper for ARIA labels and BEM classes in Cucumber selectors.

Examples

"the main menu" -> '.main-menu'
"the item box's header" -> '.item-box--header'

Here are some examples of steps (using Spreewald, too):

T...

Fix error UDPSocket.open: wrong number of arguments (0 for 1)

I got the following error after updating the selenium-webdriver gem:

wrong number of arguments (0 for 1) (ArgumentError)
/home/pointoo-dev/.rvm/gems/ruby-1.8.7-p374/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/common/platform.rb:183:in `open'
/home/pointoo-dev/.rvm/gems/ruby-1.8.7-p374/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/common/platform.rb:183:in `ip'
/home/pointoo-dev/.rvm/gems/ruby-1.8.7-p374/gems/selenium-webdriver-2.35.1/lib/selenium/webdriver/common/platform.rb:196:in `interfaces'

It was caused...

Rails: Running specific migrations

When running migrations with rake db:migrate, there's the STEP and VERSION parameters that you can pass to nearly all commands.

# Migrate
rake db:migrate
rake db:migrate STEP=2
rake db:migrate VERSION=20080906120000

# Redo
rake db:migrate:redo
rake db:migrate:redo STEP=2
rake db:migrate:redo VERSION=20080906120000

# Rollback (starting from latest migration)
rake db:rollback
rake db:rollback STEP=2

# Run the `down` migration path of a certain migration file
rake db:migrate:down VERSION=20080906120000

Cucumber factory 1.10.0 released

I've pushed an update to Cucumber factory that simplifies working with FactoryGirl factories.

Say you define a factory with the class: option:

factory :admin, class: User
  email
  admin true
end

In the past, you had to write

Given there is a user (admin)

Now you can simply write

Given there is an admin

The class is inferred from the factory.

Geordi 1.0 released

Geordi 1.0 features a command line application geordi, that holds most of Geordi's previous commands.

New features

  • command help and usage examples right within geordi (geordi help and geordi help <command>)

  • quick command access: type just the first few letters of a command, e.g. geordi rs or geordi dev[server]

  • command dependencies, e.g. geordi rspec invokes geordi bundle-install (which bundles only if needed)

  • no cluttered /usr/bin, but all commands in one handy tool

  • template for easily adding new...

How to set up database_cleaner for Rails with Cucumber and RSpec

Add gem 'database_cleaner' to your Gemfile. Then:

Cucumber & Rails 3+

# features/support/database_cleaner.rb

DatabaseCleaner.clean_with(:deletion) # clean once, now
DatabaseCleaner.strategy = :transaction
Cucumber::Rails::Database.javascript_strategy = :deletion

Cucumber & Rails 2

The latest available cucumber-rails for Rails 2 automatically uses database_cleaner when cucumber/rails/active_record is required -- but only if transactional fixtures are off. To have database_cleaner work correctly:

  1. Add the ...

Refile: Ruby file uploads, take 3

Jonas Nicklas, the author of Carrierwave and Capybara, has released Refile, a gem for handling file uploads in Rails. It handles direct uploads (also direct uploads to Amazon S3) better than Carrierwave.

The story and reasoning behind some of the decisions in Refile, and how it's different from Carrierwave, by the author himself, is a good read before deciding which way you'll go.

Big Caveat: Refile only stores the original image and r...

Spreewald 1.2.0 released: new "select field should be sorted" step

Usage:

Then the "sorted" select should be sorted
But the "unsorted" select should not be sorted

How to circumvent Firefox's "Document expired" page in Selenium tests

When navigating back to a page that was received from a POST request, undesired side effects may happen. Therefore, modern browsers try to keep users from doing so, i.e. Firefox 24 displays an error page explaining what's wrong. If the user presses "Try Again", it shows an additional alert asking whether the user is certain.

Solution

If you need to circumvent this protection, e.g. to test that your application behaves correctly despite being misused, do this:

page.execute_script 'history.back()'
page.execute_script 'retryThis(this)...

Cucumber: More patience for Selenium features

When running Selenium features with parallel_tests, some browser-server interaction might take longer than usual and the impatient Capybara will not wait enough to see results.

Put the attached file into features/support/ to make Capybara more patient in scenarios tagged @javascript.

How to upgrade Cucumber on Rails 3+

  1. Run bundle update cucumber capybara cucumber-rails to update to the newest versions.

  2. Backup your features/support/path.rb to be able to add your own paths again after the cucumber installation script in step 4.

  3. Backup your features/support/env.rb file to be able to reintegrate parts like your blueprints setup:

    ENV["RAILS_ENV"] ||= "cucumber"
    require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')
    require 'spec/support/blueprints'
    
  4. Run `$ rails generate cucumber:install --capyba...

Getter and setter functions for JavaScript properties

JavaScript objects can have getter and setter functions that are called when a property is read from or written to.

For example, if you'd like an object that has a virtual person.fullName attribute that dynamically composes person.firstName and person.lastName:

var person = {

  firstName: 'Guybrush',

  lastName: 'Threepwood',

  get fullName() {
    return this.firstName + " " + this.lastName;
  },
  
  set fullName(name) {
    var parts = name.split(" ");
    this.firstName = parts[0];
    this.lastName = parts[1];
  }

};
`...

Testing focus/blur events with Cucumber

This is a problem when using Selenium with Firefox. We recommend using ChromeDriver for your Selenium tests.


This setup allows to test focus/blur events in Cucumber tests (using Selenium). For background information, see How to solve Selenium focus issues.

Cucumber step definition:

# This step is needed because in Selenium tests, blur events are not triggered
# when the browser has no focus.
When /^I unfocus the "(.*?)" field to trigger ja...

Taking screenshots in Capybara

Capybara-screenshot can automatically save screenshots and the HTML for failed Capybara tests in Cucumber, RSpec or Minitest.

Requires Capybara-Webkit, Selenium or poltergeist for making screenshots. Screenshots are saved into $APPLICATION_ROOT/tmp/capybara.

Manually saving a page

Additionally you can trigger the same behavior manually from the test using Capybara::Session#save_and_open_page and [...

Reading an element's attributes with Capybara

capybara_element['attribute_name'] allows accessing an element's attributes in Capybara.

A few examples:

find('#my_element')['class']
# => "first-class second-class"

find('#my_input')['placeholder']
# => "My placeholder value"

find('a#example-link')['href']
# => "http://example.com"

find('#my_element')['missing_attribute']
# => nil

Cucumber: Removing uploaded files after test runs

Cucumber will clean up files you've uploaded in your Cucumber features automatically with the attached code. Put the file in features/support/.

Cucumber step to test whether a select field is sorted

This step will pass if the specified select is sorted.

Then /^the "(.*?)" select should be sorted$/ do |label, negate|
  select = find_field(label)
  options = select.all('option').reject { |o| o.value.nil? }

  options.collect(&:text).each_cons(2) do |a,b|
    (a.text.downcase <=> b.text.downcase).should <= 0
  end
end

In conjunction with this custom matcher, the each_cons block can be replaced with:

options.should be_naturally_sorted

Usage

Then the "Organizations" select should be sorted...

Asset Pipeline Basics

The Rails asset pipeline improves delivery of application assets (javascripts, stylesheets, images, fonts). Here are some basic facts about its inner workings.

No magic

Manifests are the handle on your assets:

app/assets/stylesheets/application.css # use via: stylesheet_link_tag 'application'

The asset pipeline only considers files you explicitly require within your manifest files. The most common directives used in manifests are require some/file and require_tree some/directory. Paths may be **relative to the current director...

vague puppet error messages with broken yaml files

If you get one of this errors:

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: (<unknown>): found character that cannot start any token while scanning for the next token at line 1297 column 3
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: undefined method `empty?' for nil:NilClass at /etc/puppet/environments/production/manifests/nodes.pp:1 on node example.makandra.de
Warning: ...

How to: Context-dependent word expansion in RubyMine

One of the many useful features of TextMate is autocompletion of words. If I were in TextMate right now, I could write "au[tab]", and it would complete it to "autocompletion". RubyMine can do this, too. When you write a word (e.g. a variable name), just hit ALT + / repeatedly and it will offer all completions for the letters you typed. This action is called Cyclic Expand Word in RubyMine / IntelliJ IDEA.

This feature keeps you from mistyping variable names, saves you keystrokes and speeds up development. ~10 keystrokes to the price ...

How to combine "change", "up", and "down" in a Rails migration

Rails migrations allow you to use a change method whose calls are automatically inverted for the down path. However, if you need to some path-specific logic (like SQL UPDATE statements) you can not define up and down methods at the same time.

If you were to define define all 3 of them, Rails would only run change and ignore up and down. However, Rails 4+ features a helper method called reversible:

class MyMigration < ActiveRecord::Migration

  def cha...

Upgrading a Rails 3.2 application to Ruby 2.1 is really easy

Upgrading from Ruby 1.8.7 to 2.1.2 took me an hour for a medium-sized application. It involved hardly any changes except

  • removing the occasional monkey patch where I had backported functionality from modern Rubies
  • Migrating from require to require_relative where I loaded RSpec factories in Cucumber's env.rb (the Rails application root is no longer in the load path by default)
  • replacing the old debugger with byebug
  • removing sytem_timer from Gemfile (see [this SO thread](http://stackoverflow.com/questions/7850216/how-to-inst...