RSpec: Run a single spec (Example or ExampleGroup)

RSpec allows you to mark a single Example/ExampleGroup so that only this will be run. This is very useful when using a test runner like guard.

Add the following config to spec/spec_helper.rb:

RSpec.configure do |config|
  # These two settings work together to allow you to limit a spec run
  # to individual examples or groups you care about by tagging them with
  # `:focus` metadata. When nothing is tagged with `:focus`, all examples
  # get run.
  config.filter_run_including :focus => true
  config.run_all_when_everything_filtere...

Capybara: Accessing the parent of an element

If you already selected an element and want to get its parent, you can call find(:xpath, '..') on it.

To get the grand-parent element, call find(:xpath, '../..').

Example

Find a link which contains a twitter icon and check that it links to the correct page:

<a href="http://twitter.com/">
  <i class="icon is-twitter"></i>
</a>
link = page.find("a .icon.is-twitter").find(:xpath, '..')
expect(link[:href]).to eq("http://twitter.com/")

About XPath

There is a good overview on XPath syntax on [w3schools](htt...

RSpec: Running examples by name (or running a single shared example)

When an Rspec example fails, I usually investigate by running that example again using rspec <file:line>. However, this does not work with shared examples, since Rspec doesn't know in which context the shared example should be run.

But there is a different way: You can run the shared example using the -e, --example option. It takes a string value and runs all scenarios containing that substring in their full description.

This allows you to run a single uniquely named example, all examples with
similar names, all the examples in a u...

Spreewald: Content-Disposition not set when testing a download's filename

Precondition

  • You are not using javascript tests
  • The file is served from a public folder (not via controller)

Problem description

If you deliver files from a public folder it might be that the Content-Disposition header is not set. That's why the following spreewald step might raise an error:

Then I should get a download with filename "..."
expected: /filename="some.pdf"$/
     got: nil (using =~) (RSpec::Expectations::ExpectationNotMetError)

Solution

One solution...

Fixing flaky E2E tests

An end-to-end test (E2E test) is a script that remote-controls a web browser with tools like Selenium WebDriver. This card shows basic techniques for fixing a flaky E2E test suite that sometimes passes and sometimes fails.

Although many examples in this card use Ruby, 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
And I click on B
And I click on C
Then I should see effects of C

A test like this works fine...

Async control flow in JavaScript: Promises, Microtasks, async/await

Slides for Henning's talk on Sep 21st 2017.


Understanding sync vs. async control flow

Talking to synchronous (or "blocking") API

print('script start')
html = get('/foo')
print(html)
print('script end')

Script outputs 'script start', (long delay), '<html>...</html>', 'script end'.

Talking to asynchronous (or "evented") API

print('script start')
get('foo', done: function(html) {
  print(html)
})
print('script end')

Script outputs 'script start', 'script end', (long ...

Rails: namespacing models with table_name_prefix instead of table_name

When you want to group rails models of a logical context, namespaces are your friend. However, if you have a lot of classes in the same namespace it might be tedious to specify the table name for each class seperately:

class Accounting::Invoice < ApplicationRecord
  self.table_name = 'accounting_invoices'
  ...
end

class Accounting::Payment < ApplicationRecord
  self.table_name = 'accounting_payments'
  ...
end

A replacement for the self.table_name-assignment is the table_name_prefix in the module definition:

modu...

RSpec: How to define classes for specs

RSpec allows defining methods inside describe/context blocks which will only exist inside them.
However, classes (or any constants, for that matter) will not be affected by this. If you define them in your specs, they will exist globally. This is because of how RSpec works (short story: instance_eval).

Negative example:

describe Notifier do
  class TestRecord < ApplicationRecord # DO NOT do this!
    # ...
  end
  
  let(:record) { TestRecord.new }
  
  it { ... }
end

# TestRecord will exist here, outside of the spec!

D...

How to change the class in FactoryBot traits

FactoryBot allows a :class option to its factory definitions, to set the class to construct. However, this option is not supported for traits.

Most often, you can just define a nested factory instead of a trait, and use the :class option there.

factory :message do
  factory :reply, class: Message::Reply do
    # ...
  end
end

If you need/want to use traits instead (for example, it might make more sense semantically), you can not use a :class on a trait.

In that case, use initialize_with to define the record's constr...

How to avoid ActiveRecord::EnvironmentMismatchError on "rails db:drop"

After loading a staging dump into development, you might get an ActiveRecord::EnvironmentMismatchError when trying to replace the database (like rails db:drop, rails db:schema:load).

$ rails db:drop
rails aborted!
ActiveRecord::EnvironmentMismatchError: You are attempting to modify a database that was last run in `staging` environment.
You are running in `development` environment. If you are sure you want to continue, first set the environment using:

        bin/rails db:environment:set RAILS_ENV=development

Starting with R...

Dealing with I18n::InvalidPluralizationData errors

When localizing model attributes via I18n you may run into errors like this:

I18n::InvalidPluralizationData: translation data { ... } can not be used with :count => 1. key 'one' is missing.

They seem to appear out of the blue and the error message is more confusing than helpful.

TL;DR A model (e.g. Post) is lacking an attribute (e.g. thread) translation.
Fix it by adding a translation for that model's attribute (attributes.post.thread). The error message reveals the (wrongly) located I18n data (from `attributes.thread...

How to pair a Bose Quiet Comfort 35 with your Ubuntu computer

You need to disable "Bluetooth low energy", then follow these core steps:

  1. Make sure the headphones are in pairing mode.
  2. Pair with System Settings > Bluetooth. On 16.04 I had to choose "proceed without pairing" and enter the PIN "0000"
  3. Select & test the headphones in System Settings > Sound. Choose High Fidelity Playback (A2DP Sink).

I also had to install a package with sudo apt-get install pulseaudio-module-bluetooth and load it with pactl load-module module-bluetooth-discover. Put the latter command into ~/.bashrc or you'll...

Ruby: A small summary of what return, break and next means for blocks

Summary

  • Use return to return from a method. return accepts a value that will be the return value of the method call.
  • Use break to quit from a block and from the method that yielded to the block. break accepts a value that supplies the result of the expression it is “breaking” out of.
  • Use next to skip the rest of the current iteration. next accepts an argument that will be the result of that block iteration.

The following method will serve as an example in the details below:

def example
  puts yield
  puts ...

Custom Ruby method Enumerable#count_by (use for quick statistics)

I frequently find myself needing a combination of group_by, count and sort for quick statistics. Here's a method on Enumerable that combines the three:

module Enumerable
  def count_by(&block)
    group_by(&block)
      .transform_values(&:count)
      .sort_by(&:last)
      .to_h
  end
end

Just paste that snippet into a Rails console and use #count_by now!

Usage examples

  • Number of email addresses by domain:
> User.all.count_by { |user| user.email.sub /^.*@/, '' }
=> { "sina.cn"=>2, ..., "hotmail.com"=>128...

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

Background

  • before(:all) runs the block once before all of the examples.
  • before(:each) runs the block once before each of your specs.

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|
  ...

Vagrant: create entry for box in .ssh/config

If you want to ssh into your vagrant box without switching into the project directory and typing vagrant ssh, you can also create an entry directly in ~/.ssh/config. This will allow you to use ssh <my-box> from anywhere. Simply paste the information provided by vagrant ssh-config to your ~/.ssh/config-File: vagrant ssh-config >> ~/.ssh/config

Example:

$ vagrant ssh-config
Host foobar-dev
  HostName 127.0.0.1
  User vagrant
  Port 2200
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  Id...

How to mount a legacy database to migrate data

There are many approaches out there how you can import data from a legacy application to a new application. Here is an approach which opens two database connections and uses active record for the legacy system, too:

1. Add you database information to you config/database.yml.

data_migration:
  database: your_application_data_migration

2. Create a separate application record for the data migration, e.g. in app/data_migration/migration_record.rb. You will need to create an app/data_migration.rb class first.

class DataMig...

Understanding Scope in Ruby

Scope is all about where something is visible. It’s all about what (variables, constants, methods) is available to you at a given moment. If you understand scope well enough, you should be able to point at any line of your Ruby program and tell which variables are available in that context, and more importantly, which ones are not.

The article gives detailed explanation on the variable scope in ruby with examples that are easy to understand. Every ruby developer should at least know the first part of the article by heart. The second half ...

JavaScript: Polyfill native Promise API with jQuery Deferreds

You should prefer native promises to jQuery's Deferreds. Native promises are much faster than their jQuery equivalent.

Native promises are supported on all browsers except IE <=11, Android <= 4.4 and iOS <= 7.

If you need Promise support for these old browsers y...

JavaScript: How to query the state of a Promise

Native promises have no methods to inspect their state.

You can use the promiseState function below to check whether a promise is fulfilled, rejected or still pending:

promiseState(promise, function(state) {
  // `state` now either "pending", "fulfilled" or "rejected"
});

Note that the callback passed to promiseState will be called asynchronously in the next [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/...

How to use a local gem in your Gemfile

You can use local copies of gems in your Gemfile like this:

gem 'spreewald', path: '~/gems/spreewald'

As soon as you have bundled your project with the local copy of the gem, all code changes in the copy will be available on your project. So you can for example set a debugger or add console output in the gem and use it from your project.
If you checked out the gem with your versioning tool, you can easily reset your changes afterwards or make a pull request for the gem if you improved it.

Don't commit a Gemfile with local path...

IRB: last return value

In the ruby shell (IRB) and rails console the return value of the previous command is saved in _ (underscore). This might come in handy if you forgot to save the value to a variable and further want to use it.

Example:

irb(main):001:0> 1 + 2
=> 3
irb(main):002:0> _
=> 3
irb(main):003:0> a = _
=> 3

RSpec's hash_including matcher does not support nesting

You can not use the hash_including argument matcher with a nested hash:

describe 'user' do
  let(:user) { {id: 1, name: 'Foo', thread: {id: 1, title: 'Bar'} }

  it do 
    expect(user).to match(
      hash_including(
        id: 1, thread: {id: 1}
      )
    )
  end
end  

The example will fail and returns a not very helpful error message:

expected {:id => 1, :name => "Foo", :thread => {:id => 1, :title => "Bar"}} to...

Selenium cannot obtain stable Firefox connection

When using geordi for integration tests you might get the following error when trying to run geordi cucumber:

unable to obtain stable firefox connection in 60 seconds (127.0.0.1:7055) (Selenium::WebDriver::Error::WebDriverError)

This means, that the vnc window the tests is talking to has no proper firefox version running. To figure out the issue this might help you:

  • Check if the .firefox-version (e.g. 24.0) is the same as ~/bin/firefoxes/24.0/firefox says in the browser
  • Maybe [rest...