View

Writing Code Comments

Code comments allow for adding human readable text right next to the code: notes for other developers, and for your future self.

As always, with great power comes great responsibility. Code comments can go wrong in many ways: they may become outdated, silently move away from the code they're referring to, restate the obvious, or just clutter files.

Good Comments

Here are some simple rules to keep your comments helpful:

Avoid stating what some code does – prefer the Why
Some say, perfect code would not need a single comment. That'…

Capybara: How to find a hidden field by its label

To find an input with the type hidden, you need to specify the type hidden:

find_field('Some label', type: :hidden)

Otherwise you will see an exception :

find_field('Some label')
# => Capybara::ElementNotFound: Unable to find field "Some label" that is not disabled`.

Note: Usually you don't need to check the input of hidden fields in an integration test. But e.g. waiting for a datepicker library to write the expected value to this field before continuing the test, which prevents flaky tests, is a valid use case.

Linked contentAuto-destruct in 18 days

Updated: How to make a cucumber test work with multiple browser sessions

  • Simplified step
  • Added section "Effect on other step definitions"

How to make a cucumber test work with multiple browser sessions

Imagine you want to write a cucumber test for a user-to-user chat. To do this, you need the test to work with several browser sessions, logged in as separate users, at the same time.

Luckily, Capybara makes this relatively easy:

Scenario:

```
Scenario: Alice and Bob can chat
Given Alice, Bob, and a chat session
When I am signed in as "Alice"
And I go to the chat
And I am signed in as "Bob" [session: bob]
And I go to the chat [session: bob]
And I send the message "Hello, this is Alice!"
Then I should see "Hello, this …

Handling duplicate links with Capybara and Cucumber

Sometimes, you might have duplicate links on a page. Trying to click those links will by default cause Capybara to raise an Ambiguous match error.

If you do not care about which of those links are clicked, you can disable this errors by adding the following meta step:

When(/^(.*) \[allow ambiguous\]$/)do |step_text|
  prior_match_strategy = Capybara.match
  Capybara.match = :first
  step(step_text)
ensure
  Capybara.exact = prior_match_strategy
end

Use it with

When I follow "a duplicate link" [allow ambiguous]
Linked contentRepeats

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. They're saved into $APPLICATION_ROOT/tmp/capybara

The attached files contain config for cucumber integration and a Then show me a screenshot step.

Including assets for prettier presentation

Make sure to add this to config/environments/test.rb

```
# Do not generate digests fo…

Linked contentAuto-destruct in 9 days

CucumberFactory 2.0 released

We just released version 2.0 of CucumberFactory. The major version was increased because of the breaking change below.

2.0.0 - 2020-02-10

Breaking changes

  • CucumberFactory now raises an ArgumentError if some parts of a matched step were not used. For example, while this step was accepted in recent versions, it will now complain with the message Unable to parse attributes " and the ".:

    Given there is a user with the attribute "foo" and the
    

Compatible changes

Capybara 'fill_in': Ambiguous match for different input names

When you have two inputs, where one contains the name of the other (eg. Name and Name with special treatment), Capybara's fill_in method will fail with the following message:

Ambiguous match, found 2 elements matching visible field "Name" that is not disabled (Capybara::Ambiguous)

You can force Capybara to match exactly what you are typing (which makes your tests better anyways) with match: :prefer_exact:

name = 'Name'
value = 'Bettertest Cucumberbatch'
fill_in(field, with: value, match: :prefer_exact)

Furthermore…

Repeats

Rspec: around(:all) and around(:each) hook execution order

Summary

  • around(:suite) does not exist.
  • around(:all) runs after before(:all) and before after(:all).
  • around(:each) runs before before(:each) and after after(:each).

As this is not 100% obvious (and not yet documented) it is written down in this card. In RSpec 3 :each has the alias :example and :all the alias :context.

Example

```
RSpec.configure do |config|
config.before(:suite) { puts 'BEFORE :suite' }
config.after(:suite) { puts 'AFTER :suite' }
end

describe 'order of hook execution' do
around(:a…

Linked contentRepeats

Automated "git bisect" will make your day

So you're hunting down a regression (or just a bug) and want to use git bisect to find out when it was introduced? Smart kid.
If you have a shell command ready to reveal if your current state is good or bad, you can have git do most of the work for you.

Using git bisect run <your command> you can tell git that your command will reveal the issue; git on the other hand will use the return value of that call to decide if the state is good or bad. …

Repeats

Detect the current Rails environment from JavaScript or CSS

Detecting if a Javascript is running under Selenium WebDriver is super-painful. It's much easier to detect the current Rails environment instead.

You might be better of checking against the name of the current Rails environment. To do this, store the environment name in a data-environment of your <body>. E.g., in your application layout:

%body{'data-environment' => Rails.env}

Now you can say in a piece of Jav…

Repeats

Fixing flaky integration tests

This card shows basic techniques for fixing a flaky integration test suite that sometimes passes and sometimes fails. "Integration test" is a test script that remote-controls a web browser with tools like Selenium WebDriver.

Although the examples in this card use Cucumber and Selenium, the techniques are applicable to all languages and testing tools.

Why tests are flaky

Your tests probably look like this:

When I click on A
When I click on B
When I click on C
Then I should see effects of C

A test like this works fine most of t…

Repeats

Heads up: JavaScript does not like big numbers

In a JavaScript console, type this:

> 9112347935156469760
9112347935156470000

Ooops.

This occurs because JavaScript uses double precision floats to store numbers.

So according to IEEE floating point definition only numbers between -(2^53 - 1) (-9007199254740991) and 2^53 - 1 (9007199254740991) can safely be represented in JavaScript.

Note that ECMAScript 6 will probably also offer [Number.MAX_SAFE_INTEGER](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference…

Geordi 2.7.0 released

  • Fixed #68: The "cucumber" command now fails early when @solo features fail.
  • Added: The "setup" command now prints the db adapter when prompting db credentials.
  • Fixed #71: When used without staged changes, the "commit" command will print a warning and create an empty commit. Any arguments to the command are forwarded to Git.
  • Fixed: The "commit" command will not print the extra message any more.
  • Added: The "commit" command prints a (progre…

Linux, Arial and Helvetica: Different font rendering in Firefox and Chrome

When text renders differently in Firefox and Chrome, it may be caused by a font alias that both browsers handle differently.

Situation

A machine running Linux, and a website with the Bootstrap 3 default font-family: "Helvetica Neue", Helvetica, Arial, sans-serif.

Issue

Anti-aliasing and kerning of text looks bad in Firefox. Worse, it is rendered 1px lower than in Chrome (shifted down).

Reason

Firefox resolves "Helvetica" to an installed ["TeX Gyre Heros", which is its Ghostscript clone](https://www.fontsquirrel.com/fonts/…

Repeats

Capybara: you can use `evaluate_async_script` to execute asynchronous JavaScript

Capybara provides execute_script and evaluate_script to execute JavaScript code in a Selenium-controlled browser. This however is not a good solution for asynchronous JavaScript.

Enter evaluate_async_script, which allows you to execute some asynchronous code and wait until it finishes. There is a timeout of a couple of seconds, so it will not wait forever.

Use it like this:

```ruby
page.evaluate_async_script(«~JS)
let [done] = arguments
doSomethingAsynchronous().then(() => {
done() // call this to indicate we're done
})
J…

Email validation regex

There is a practical short list for valid/invalid example email addresses - Thanks to Florian L.! The definition for valid emails (RFC 5322) can be unhandy for some reasons, though.

Since Ruby 2.3, Ruby's URI lib has a built in email regex. Probably that's the best solution to work with:

```
URI::MailTo::EMAIL_REGEXP

=> /\A[a-zA-Z0-9.!#$%&'*+\/=?^_`{ }~-]+@[a-zA-Z0-…
Repeats

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…

This website uses cookies to improve usability and analyze traffic.
Accept or learn more