How to test if an element has scrollbars with JavaScript (Cucumber step inside)

The basic idea is pretty simple: an element's height is accessible via the offsetHeight property, its drawn height via scrollHeight -- if they are not the same, the browser shows scrollbars.

var hasScrollbars = element.scrollHeight != element.offsetHeight;

So, in order to say something like...

Then the element "#dialog_content" should not have scrollbars

... you can use this step (only for Selenium scenarios):

Then /^the element "([^\"]+)" should( not)? have scrollbars$/ do |selector, no_scrollbars|
  scroll_heig...

How to find out the currently focused DOM element with JavaScript

This works in all relevant browsers:

document.activeElement

You can use this in your Selenium steps, for example, to assert that a form field is or is not focused.

Performance analysis of MySQL's FULLTEXT indexes and LIKE queries for full text search

When searching for text in a MySQL table, you have two choices:

  • The LIKE operator
  • FULLTEXT indexes (which currently only work on MyISAM tables, but will one day work on InnoDB tables. The workaround right now is to extract your search text to a separate MyISAM table, so your main table can remain InnoDB.)

I always wondered how those two methods would scale as the number of records incr...

Custom error pages in Rails

Basic error pages

To add a few basic styles to the default error pages in Rails, just edit the default templates in public, e.g. public/404.html.

A limitation to these default templates is that they're just static files. You cannot use Haml, Rails helpers or your application layout here. If you need Rails to render your error pages, you need the approach below.

Advanced error pages

  1. Register your own app as the applicatio...

Cronjobs: "Craken" is dead, long live "Whenever"

Our old solution for cronjobs, the "craken" plugin, is no longer maintained and does not work on Rails 3.2+.

We will instead use the whenever gem.

"Whenever" works just like "craken", by putting your rake tasks into the server's cron table. Everything seems to work just like we need it.

Installation for new projects

  1. Add "whenever" to your Gemfile:

     group :deploy do
       gem 'whenever', require: false
     end
    
  2. Add it to your config/deploy.rb:
    ...

CSS that lets your alarm bells ring

Harry Roberts, a youngster from the UK, wrote a comprehensive article telling you how to smell CSS rot early.

Examples:

  • Undoing styles
  • Magic numbers
  • Qualified selectors
  • Dangerous selectors
  • Reactive !important

… and more.

How to change the hostname in Cucumber features

Capybara uses www.example.com as the default hostname when making requests.
If your application does something specific on certain hostnames and you want to test this in a feature, you need to tell Capybara to assume a different host.

Given /^our host is "([^\"]+)"$/ do |host|
  page.config.stub app_host: "http://#{host}"
  
  # In older Capybaras (< 2.15) you needed to do this instead:
  Capybara.stub app_host: "http://#{host}"
end

You can now say:

When I go to the start page
Then I should not see "Home ...

SearchableTrait is now a gem: Dusen

For two years we've been using SearchableTrait which gives models the ability to process Googlesque queries like this:

Contact.search('a mix of words "and phrases" and qualified:fields')

This trait used to be a huge blob of code without tests and documentation, so I made a gem out of it. Check out https://github.com/makandra/dusen for code, tests, and a huge README.

You should use the Dusen gem and delete SearchableTrait in all future projects.

Note that the syntax to define query proc...

How to solve Selenium focus issues

Selenium cannot reliably control a browser when its window is not in focus, or when you accidentally interact with the browser frame. This will result in flickering tests, which are "randomly" red and green. In fact, this behavior is not random at all and completely depends on whether or not the browser window had focus at the time.

This card will give you a better understanding of Selenium focus issues, and what you can do to get your test suite stable again.

Preventing accidental interaction with the Selenium window
--------------------...

How to fix: Unable to read files from a VirtualBox shared host folder

When you want to copy/move from a shared folder (on Windows guests, for example) and it fails with absurd error messages (lots of text or an error about the target being read-only), you are probably running on Guest Additions that no longer match your VirtualBox version.

Fix: install the latest VirtualBox Guest Additions in your guest machine.

Note that you need to make sure you are using the correct ISO.

How to fix: VirtualBox Guest Additions setup is out of date

When you are trying to install/update VirtualBox Guest Additions on your guest machine but the setup is for a different/older version (for example 4.0.4 tools for a 4.1.x VirtualBox installation), try this:

sudo apt-get install virtualbox-guest-additions-iso

For some reason, this is no dependency to VirtualBox itself -- and if you have an old ISO lying around, VirtualBox will just pick that one, regardless of its version.

Oh joy.

Zeus promises to make rails development faster

I am talking about development speed. When your application starts growing and you start adding gems, it starts to take really long to start up, be it the server, console or just running a single spec.

Zeus is smart, you don’t have to put it in your Gemfile or run it with Bundler, all you need to do is create a JSON config file via zeus init and then start the server zeus start.

After that, you’re ready to go, all you need to do is prefix every command with zeus. That means rails server becomes zeus server, `rails console...

A jQuery plugin for producing bar charts from tables.

As the title says: this jQuery plugin creates bar charts from HTML tables. It comes in some different flavors.

Check the examples page: http://alphagov.github.com/magna-charta/.

Capybara 2.0 has been released

The gem author Jonas Nicklas highlights in a Google Groups post that the release

  • is not backwards compatible to 1.x versions of Capybara
  • does not support Ruby 1.8.x anymore
  • removes confusion with Rails' built in integration tests (you put capybara rspec integration tests into the spec/feature/... folder) and the :type metadata has been changed from :request to :feature
  • throws exceptions when trying to interact with an element whose identifier is...

How to set the default monospace font on Xfce (Xubuntu)

While you can set your own font in your terminal or other tools, it will not change the default "Monospace" font that some applications use.

To change that, edit ~/.fonts.conf and add settings for the "monospace" family. Here is how it looks on my machine now:

<fontconfig>
  <match target="pattern">
    <test qual="any" name="family">
      <string>monospace</string>
    </test>
    <edit name="family" mode="assign">
      <string>DejaVu Sans Mono</string>
    </edit>
  </match>
</fontconfig>
...

Rails: When to use :inverse_of in has_many, has_one or belongs_to associations

When you have two models in a has_many, has_one or belongs_to association, the :inverse_of option in Rails tells ActiveRecord that they're two sides of the same association.

Example with a has_many / belongs_to association:

class Forum < ActiveRecord::Base
  has_many :posts, inverse_of: :forum
end

class Post < ActiveRecord::Base
  belongs_to :forum, inverse_of: :posts
end

Knowing the other side of the same association Rails can optimize object loading so forum and forum.posts[0].forum will reference the same o...

Taming icon fonts for use in Rails views

Icon fonts like Font Awesome are infinitely scalable, look great on high-DPI displays and will give your app a modern look.

However, icon fonts can be very awkward to use compared to raster icons. Elements are given icons by giving them a special class like icon-plus or icon-home:

<span class="icon-plus">Create</span>

The icon font's stylesheet will then recognize this class and insert the icon as the element's :before style.

In practic...

Internet Explorer will download CSS files twice, if referenced via scheme-less URLs

You can use scheme-less URLs (or protocol-relative URLs) to have browsers use the current protocol (HTTP or HTTPS) when loading content referenced with such an URL.

A protocol relative URL doesn’t contain a protocol. For example, http://stevesouders.com/images/book-84x110.jpg becomes //stevesouders.com/images/book-84x110.jpg

Browsers substitute the protocol of the page itself for the resource’s missing protocol. Problem solved!

But:

Internet Explorer 7 & 8 will download st...

Cucumber: Wait for any requests to finish before moving on to the next scenario

Background

Generally, Selenium tests use the browser to interact with the page. If it's unavailable, a timeout error is thrown.

Now, consider a scenario like this:

@javascript
Scenario: Receive an e-mail after clicking the fancy link
  When I follow "fancy link"
  Then I should have an e-mail with the subject "Hello"

When the last step in the scenario passes, you are done. Right? Wrong.

Why it's not enough

What if clicking our "fancy link" above sends the e-mail that we expect, but it also does stuff on the server...

Waiting for page loads and AJAX requests to finish with Capybara

If you're using the Capybara webdriver, steps sometimes fail because the browser hasn't finished loading the next page yet, or it still has a pending AJAX request. You'll often see workarounds like

When I wait for the page to load
Then ...

Workarounds like this do not work reliably, will result in flickering tests and should be avoided. There is no known reliable way to detect if the browser has finished loading the page.

Solution

Instead you should wait until you can observe the result of a page load. E.g. if y...

Regex pattern to validate email addresses

Our most recent pattern is

EMAIL = /\A[a-z0-9\+\-_\.]+@[a-z\d\-.]+\.[a-z]+\z/i

Notes

  • Don't replace [a-z0-9\+\-_\.] with \w ! Otherwise the pattern would allow ßs and many other invalid characters.
  • The email address standard allows more patterns of emails than those which work in practice (e.g. a@a is valid). In result our pattern is more strictly.
  • Caution: john..doe@example.com and john.doe@example..com are accepted as well.

Advice: Reduce scopes with joins to simple IN-queries

In theory you can take any scope and extend it with additional joins or conditions. We call this chaining scopes.

In practice chaining becomes problematic when scope chains grow more complex. In particular having JOINs in your scope will reduce the scope's ability to be chained with additional JOINs without crashes or side effects. This is because ActiveRecord doesn't really "understand" your scope chain, it only mashes together strings that mostly happen to look like a MySQL query in the end.

**I don't generally advice against u...

Cucumber pitfall: "Around" does not apply to your "Background" steps

Around will not happen until after a feature's Background has been processed. Use Before and After to avoid that.

Details

Consider this Cucumber feature file:

Feature: Something that needs to be tested

  Background:
    Given a user
      And I sign in        
    
  Scenario: Sign out
    When I sign out
    Then I should see "Signed out"
  
  Scenario: Something else
    # ...

Now, assume you have these step definitions:

Around do
  puts "** Around: before yield"

...

Manually requiring your application's models will lead to trouble

In a nutshell:

If you require your Rails models manually, pay attention to the path you use. Unless you have to, don't do it at all.

Background

Consider these classes:

# app/models/user.rb

class User < ActiveRecord::Base
  validate :magic

  def magic
    errors.add_to_base('failed') if bad_things?
  end
end

^
# app/models/foo.rb

require 'user'

class Foo
  # something happens here
end

Now, when your environment is booted, Rails will automatically load your models, like User...