Testing webpages globally (as in "around the globe")

These tools help you in checking websites globally:

DNS Checker
: This tool allows for global DNS propagation checking.

GeoScreenshot
: This tool takes screenshots of a given URL from various locations across the world.

Middleman configuration for Rails Developers

Middleman is a static page generator that brings many of the goodies that Rails developers are used to.

Out of the box, Middleman brings Haml, Sass, helpers etc. However, it can be configured to do even better. This card is a list of improvement hints for a Rails developer.

Gemfile

Remove tzinfo-data and wdm unless you're on Windows. Add these gems:

gem 'middleman-livereload'
gem 'middleman-sprockets' # Asset pipeline!

gem 'bootstrap-sass' # If you want to use Bootstrap

gem 'byebug'

gem 'capistrano'
gem 'capistrano-mid...

Beware: Nested Spreewald patiently blocks are not patient

Note: The behaviour of Spreewald's within step is as described below for version < 1.9.0; For Spreewald >= 1.9.0 it is as described in Solution 1.


When doing integration testing with cucumber and selenium you will often encounter problems with timing - For example if your test runs faster than your application, html elements may not yet be visible when the test looks for them. That's why Spreewald (a collection of cucumber steps) has a concept of doing things patiently, which means a given b...

RestClient / Net::HTTP: How to communicate with self-signed or misconfigured HTTPS endpoints

Occasionally, you have to talk to APIs via HTTPS that use a custom certificate or a misconfigured certificate chain (like missing an intermediate certificate).

Using RestClient will then raise RestClient::SSLCertificateNotVerified errors, or when using plain Net::HTTP:

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed

Here is how to fix that in your application.

Important: Do not disable certificate checks for production. The interwebs are full of people say...

VCR: Inspecting a request

Using VCR to record communication with remote APIs is a great way to stub requests in tests. However, you may still want to look at the request data like the payload your application sent.

Using WebMock, this is simple: Make your request (which will record/play a VCR cassette), then ask WebMock about it:

expect(WebMock).to have_requested(:post, 'http://example.com').with(body: 'yolo')

Easy peasy.

Related cards

Bug in Chrome 56+ prevents filling in fields with slashes using selenium-webdriver/Capybara

There seems to be a nasty bug in Chrome 56 when testing with Selenium and Capybara: Slashes are not written to input fields with fill_in. A workaround is to use javascript / jquery to change the contents of an input field.

Use the following code or add the attached file to your features/support/-directory to overwrite fill_in.

module ChromedriverWorkarounds

  def fill_in(locator, options = {})
    text = options[:with].to_s
    if Capybara.current_driver == :selenium && text.include?('/')
      # There is a nasty Bug in Chrome ...

Linux: Quickly create large files for testing

To create a 10 GB file:

fallocate -l 10G huge_file.dat

Capybara: Disable sound during Selenium tests

If the application under test makes sound, you probably want to disable this during integration testing.

You can use the args option to pass parameters to the browser. For Chrome:

Capybara.register_driver :selenium do |app|
  Capybara::Selenium::Driver.new(app, browser: :chrome, args: ["--mute-audio"])
end

I haven't found a corresponding command line option for Firefox.

Hat tip to kratob.

Ruby: Writing specs for (partially) memoized code

When you're writing specs for ActiveRecord models that use memoization, a simple #reload will not do:

it 'updates on changes' do
  subject.seat_counts = [5]
  subject.seat_total.should == 5
  # seat_total is either memoized itself, or using some
  # private memoized method
  
  subject.seat_counts = [5, 1]
  subject.seat_total.reload.should == 6 # => Still 5
end

You might be tempted to manually unmemoize any memoized internal method to get #seat_total to update, but that has two disadvant...

How Rails chooses error pages (404, 500, ...) for exceptions

When your controller action raises an unhandled exception, Rails will look at the exception's class and choose an appropriate HTTP status code and error page for the response.

For instance, an ActiveRecord::RecordNotFound will cause Rails to render a red "The page you were looking for doesn't exist" with a status code of "404" (not found).

The mapping from exception classes to error types is a hash in Rails.configuration.action_dispatch.rescue_responses. The...

Testing terminal output with RSpec

When testing Ruby code that prints something to the terminal, you can test that output.
Since RSpec 3.0 there is a very convenient way to do that.

Anything that writes to stdout (like puts or print) can be captured like this:

expect { something }.to output("hello\n").to_stdout

Testing stderr works in a similar fashion:

expect { something }.to output("something went wrogn\n").to_stderr

Hint: Use heredoc to test multi-line output.

expect { something }.to output(<<-MESSAGE.strip_heredoc).to_stdout...

Testing ActiveRecord callbacks with RSpec

Our preferred way of testing ActiveRecord is to simply create/update/destroy the record and then check if the expected behavior has happened.

We used to bend over backwards to avoid touching the database for this. For this we used a lot of stubbing and tricks like it_should_run_callbacks.

Today we would rather make a few database queries than have a fragile test full of stubs.

Example

Let's say your User model creates a first Project on cr...

Testing ActiveRecord validations with RSpec

Validations should be covered by a model's spec.

This card shows how to test an individual validation. This is preferrable to save an entire record and see whether it is invalid.

Recipe for testing any validation

In general any validation test for an attribute :attribute_being_tested looks like this:

  1. Make a model instance (named record below)
  2. Run validations by saying record.validate
  3. Check if record.errors[:attribute_being_tested] contains the expected validation error
  4. Put the attribute into a valid state
  5. Run...