View

When defining methods in specs, you can super into previous definitions

When you def methods in RSpec tests, you can use super to call a method definition that was created in a surrounding describe/context block.

Example:

describe User do

  def build_user(attributes = {})
    User.new(attributes)
  end

  describe '#my_method' do
    it 'does something' do
      # ...
    end

    context 'when the user has an e-mail address' do
      def build_user(attributes = {})
        super({ email: 'user@example.com' }.merge(attributes))
      end

      it 'd...
Repeats

Capybara: Find an element that contains a string

There is no CSS selector for matching elements that contains a given string ¹. Luckily, Capybara offers the :text option to go along with your selector:

page.find('div', text: 'Expected content')

You can also pass a regular expression!

page.find('div', text: /Expected contents?/i)

Note that if your CSS selector is as generic as div, you might get a lot more results than you expect. E.g. a <div class="container"> that surrounds your entire layout will probably also contain that text (in a descendant) and Capybara wil…

Repeats

Cucumber features as documentation

Cucumber allows for prose in features and scenarios. Example:

Feature: Cancel account

  There are several ways to cancel a user account. Admins need to 
  do it in complex cases, but normally, users can do it themselves.
  
  Scenario: User cancels his own account
    
    Users should be able to cancel an account themselves, so the 
    admins do not need to do it.
    
    Given a user account for "willy@astor.de"
    When I sign in as "willy@astor.de"
    And I follow "Cancel account"
    Then I should see "Account canceled"

B…

Repeats

Find an ActiveRecord by any column (useful for Cucumber steps)

The attached patch lets you find a record by a string or number in any column:

User.find_by_anything('carla')
User.find_by_anything('email@domain.de')
User.find_by_anything(10023)

There's also a bang variant that raises ActiveRecord::NotFound if no record matches the given value:

User.find_by_anything!('carla')

Boolean and binary columns are excluded from the search because that would be crazy.

I recommend copying the attachment to features/support/find_by_anything.rb, since it is most useful in Cucumber step …

RubyMine: You can disable inspections you don't care about

When you find yourself constantly ignoring a RubyMine warning, you can simple disable that warning and de-clutter your editor. E.g. in my Cucumber scenarios RubyMine underlines 90% of all lines because it does not know about spreewald, making the file really hard to read.

You can disable any unwanted inspection by opening File / Settings / Editor / Inspections and searching for the warning text.

What you disable or keep is up to your personal preference. I personally disable at least the following…

Repeats

Grep through the DOM using the Capybara API

When your Cucumber feature needs to browse the page HTML, and you are not sure how to express your query as a clever CSS or XPath expression, there is another way: You can use all and find to grep through the DOM and then perform your search in plain Ruby.

Here is an example for this technique:

Then /^I should see an image with the filename...
Repeats

Debugging cucumber feature with javascript + firefox vnc

TL;DR Debugging problems with javascript errors in cucumber tests is sometimes easier in the browser. Run the test, stop at the problematic point (with Then pause from Spreewald 1.7+) and open VNC for Firefox.

Features:

Repeats

Geordi: How to rerun failed features

Cucumber will save a file tmp/parallel_cucumber_failures.log will the filenames and line number of the failed scenarios after a full test run.

Normally you can say cucumber -p rerun (rerun is a profile defined by default in config/cucumber.yml) to rerun all failed scenarios. Unfortunately this does not work with geordi yet.

Here is a list of possible workarounds:

```
geordi firefox bundle exec cucumber -p rerun
cat tmp/parallel_cucucmber_failures.log | xargs geordi cucumber
geordi cucumber `cat…

Repeats

How to fill in multiple lines in a textarea with cucumber

If you want to fill in textareas with multiple lines of text (containing line breaks) you can use Cucumber's docstrings:

And I fill in "Comment" with:

"""
This is a long comment.
With multiple lines.

And paragraphs.
"""

The step definition is part of the spreewald gem

Repeats

How to update a single gem conservatively

The problem

Calling bundle update GEMNAME will update a lot more gems than you think. E.g. when you do this:

bundle update cucumber-rails

… you might think this will only update cucumber-rails. But it actually updates cucumber-rails and all of its dependencies. This will explode in your face when one of these dependencies release a new version with breaking API changes. Which is all the time.

In the example above updating cucumber-rails will give you Capybara 2.0 (because capybara is a dependency of `cucumber-rail…

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…

VNC browser disappears while typing

We often use the Then console step from spreewald in combination with geordi vnc from geordi to debug tests within a real browser. Sometimes when you type in the browser it suddenly disappears. You will only see a grey screen then.

This will always happen if you press the d key. Press the d key again and the browser will appear again.

Repeats

Raising JavaScript errors in Cucumber scenarios and how to silence them for particular scenarios

Raising JavaScript errors in Cucumber

With selenium JavaScript errors do not cause any failture in your cucumber scenarios. To archive a failture we can use the the Ruby bindings to Selenium Webdriver expose the Webdriver logging API introduced in version 2.38 .

The following step can be used:

```
Then /^there should be no JavaScript errors$/ do
if alert_present?
# Chrome 54 and/or Chromedriver 2.24 introduced a breaking change on how
# accessing browser logs work.
#
# Apparently, while an alert/confirm is open, Chro…

Repeats

How to make changes to a Ruby gem (as a Rails developer)

At makandra, we've built a few gems over the years. Some of these are quite popular: spreewald (475k downloads), active_type (330k downloads), and geordi (210k downloads) for example (numbers from 2018).

Developing a Ruby gem is different from developing Rails applications, with the biggest difference: there is no Rails. This means:

  • no defined structure (neither for code nor directories)
  • no autoloading of classes, i.e. you need to require all files yourself
  • no [active_support](https://api.rubyonrails.org/classes/ActiveSupport.ht…

Cucumber steps to travel through time with Timecop

These steps are now part of Spreewald.


Here are some useful examples how to use the attached Cucumber Timecop steps:

When the date is 2011-05-06
When the time is 2011-05-06 17:30

There is also one really awesome step that lets you travel to the past or to the future:

When /^it is (\d+|a|some) (seconds?|minutes?|hours?|days?|months?|years?) (later|earlier)$/

As you can see, you describe the *time unit amo…

Repeats

Jasmine: Adding custom matchers

Definition

A matcher is a function that returns an object with a compare key. Usually it is registered with beforeEach:

beforeEach ->
  jasmine.addMatchers
  
    # Example matcher
    toBeAnything: ->
      compare: (actualValue, matcherArguments...) ->
         # Do some computations here ...
         
         # Return whether the actualValue matches the expectation
         pass: true

Usage

expect(actualValue).toBeAnything(matcherArguments...)

When a matcher is invoked, Jasmine will call its compare() fu…

Upgrading a Rails app to Cucumber 3

Upgrade gems

You need to update a lof gems. Make sure you don't have any version constraints in your Gemfile or your bundle update won't do anything!

Upgrade cucumber_priority:

bundle update cucumber_priority

Upgrade spreewald:

bundle update spreewald

Upgrade cucumber_factory:

bundle update cucumber_factory

Upgrade parallel_tests:

bundle update parallel_tests

Even on the latest version, parallel_tests will print some deprecation warnings due to using an older formatter A…

Firefox: Focus-sensitive Selenium tests do not work reliably in parallel test execution

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


Firefox will not trigger focus/blur events when its window is not focused. While this makes sense in standard usage, it breaks in parallel test execution.

Please do not rely on focus events in your tests. The linked card has an example of how to build passing tests that deal with focus/blur events.

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