One-liner syntax in RSpec's should-based and expect-based syntaxes

RSpec supports a one-liner syntax for setting an expectation on the subject:

describe Array do
  describe "when first created" do
    it { should be_empty }
  end
end

The example description "it should be empty" will be defined automatically.

With RSpec 3's expect-based syntax you use it_is_expected instead:

describe Array do
  describe "when first created" do
    it { is_expected.to be_empty }
  end
end

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

RSpec 3 argument constraints use weak equality

If you expect method calls in RSpec 3, be aware that the argument matchers use very liberal equality rules (more like === instead of ==).

For example:

expect(subject).to receive(:foo).with(MyClass)

subject.foo(MyClass)      # satisfies the expectation
subject.foo(MyClass.new)  # also satisfies the expectation

expect(subject).to receive(:bar).with(/regex/)

subject.bar(/regex/)      # satisfies the expectation
subject.bar('regex')      # also satisfies the expectation

This is usually not an issue, except when your method ...

IIFEs in Coffeescript

In JavaScript we often use Immediately Invoked Function Expessions (or IIFEs) to prevent local variables from bleeding into an outside scope:

(function() {
  var foo = "value"; // foo is scoped to this IIFE
})();

In Coffeescript an IIFE looks like this:

(->
  foo = "value" # foo is scoped to this IIFE
)()

There is also a shorthand syntax with do:

do ->
  foo = "value" # foo is scoped to this IIFE

You can also use do with arguments t...

RSpec: be_true does not actually check if a value is true

Don't use be_true to check if a value is true. It actually checks if it anything other than nil or false. That's why it has been renamed to be_truthy in recent RSpec versions.

The same thing holds for be_false, which actually checks if a value is not "truthy".

If you want to check for true or false in RSpec 2, write this instead:

value.should == true
value.should == false

If you want to check for true or false in RSpec 3+, write this instead:

e...

NoMethodError: undefined method `cache' for Gem:Module

I got this error when running Rails 2.3 tests for Rails LTS. More stacktrace:

NoMethodError: undefined method `cache' for Gem:Module
    /vagrant/rails-2-3-lts-repository/railties/lib/rails_generator/lookup.rb:212:in `each'
    /vagrant/rails-2-3-lts-repository/railties/lib/rails_generator/lookup.rb:146:in `to_a'
    /vagrant/rails-2-3-lts-repository/railties/lib/rails_generator/lookup.rb:146:in `cache'
    /opt/vagrant_ruby/lib/ruby/1.8/fileutils.rb:243:in `inject'
    /vagrant/rails-2-3-lts-repository/railties/l...

Geordi 1.3 released

Changes:

  • Geordi is now (partially) tested with Cucumber. Yay!
  • geordi cucumber supports a new @solo tag. Scenarios tagged with @solo will be excluded from parallel runs, and run sequentially in a second run
  • Support for Capistrano 2 AND 3 (will deploy without :migrations on Capistrano 3)
  • Now requires a .firefox-version file to set up a test firefox. By default now uses the system Firefox/a test Chrome/whatever and doesn't print warnings any more.
  • geordi deploy --no-migrations (aliased -M): Deploy with `cap ...

ActiveRecord meets database views with scenic

Using Scenic, you can bring the power of SQL views to your Rails application without having to switch your schema format to SQL. Scenic provides a convention for versioning views that keeps your migration history consistent and reversible and avoids having to duplicate SQL strings across migrations. As an added bonus, you define the structure of your view in a SQL file, meaning you get full SQL syntax highlighting in the editor of your choice and can easily test your SQL in the database console during development.

[https://robots.thoughtb...

Showing a custom maintenance page while deploying

Note

The maintenance mode is enabled on all application server as soon as the file /public/system/maintenance.html is present.

Installation

Add this line to your application's Gemfile:

 gem 'capistrano', '~> 3.0'
 gem 'capistrano-maintenance', '~> 1.0'

Add this line to you application's Capfile:

require 'capistrano/maintenance'

Enable task

Present a maintenance page to visitors. Disables your application's web interface by writing a #{maintenance_basename}.html file to each web server. The servers m...

bash: print columns / a table

Ever wondered how you can create a simple table output in bash? You can use the tool column for creating a simple table output.

Column gives you the possibility to indent text accurate to the same level. Pipe output to column -t (maybe configure the delimeter with -s) and see the magic happening.

detailed example

I needed to separate a list of databases and their corresponding size with a pipe symbol: |
Here is a example list.txt:

DB	Size_in_MB
foobar	11011.2
barfoo	4582.9
donkey	4220.8
shoryuken	555.9
hadouken	220.0
k...

yujinakayama/transpec: The RSpec syntax converter

A comprehensive script to convert test suites from RSpec 2 to RSpec 3. This converts more than should/expect syntax.

How to render an html_safe string escaped

Once Rails knows a given string is html_safe, it will never escape it. However, there may be times when you still need to escape it. Examples are some safe HTML that you pipe through JSON, or the display of an otherwise safe embed snippet.

There is no semantically nice way to do this, as even raw and h do not escape html_safe strings (the former just marks its argument as html_safe). You need to turn your string into an unsafe string to get the escaping love from Rails:

embed = javascript_tag('var foo = 1337;') # This is an h...

Geordi 1.2 released

Changes:

  • Remove some old binaries (commands still exist in geordi) and mark others as deprecated
  • Rewrite deploy command to support most deploy scenarios:
    • master to production
    • feature branch to staging
    • master to staging or production to production (plain deploy)
  • Improve Cucumber command (fixes #18):
    • Fix pass-through of unknown options to Cucumber
    • Add --rerun=N option to rerun failed Cucumber tests up to N times. Reboots the test environment between runs, thus will pick up fixes you made durin...

How to open a new tab with Selenium

Until recently, you could open a new tab via window.open when using execute_script in Selenium tests. It no longer works in Chrome (will show a "popup blocked" notification).

This is because browsers usually block window.open unless the user interacted with an element for security reasons. I am not sure why it did work via Selenium before.

Here is an approach that will insert a link into the page, and have Selenium click it:

path = "/your/path/here"
id = "helper_#{SecureRandom.hex(8)}"
execute_script <<-JAVASCRIPT
  ...

Using regular expressions in JavaScript

Regular expressions in Javascript are represented by a RegExp object. There also is a regex literal as in many other languages: /regex/. However, they are used slightly differently.

Regex literal

  • Usage: /foo+/
  • Shorthand for creating a regular expression object

RegExp() object

  • Usage: RegExp("foo+") or new RegExp("foo+")
  • No surrounding slashes required (they're the literal markers)
  • Since the argument is a string, backslashes need to be escaped as well: RegExp("\\d+")

Gotchas

  • Regex objects [never eq...

RSpec & Devise: How to sign in users in request specs

You know that Devise offers RSpec test helpers for controller specs. However, in request specs, they will not work.

Here is a solution for request specs, adapted from the Devise wiki. We will simply use Warden's test helpers -- you probably already load them for your Cucumber tests.

First, we define sign_in and sign_out methods. These will behave just like ...

Defining and calling lambdas or procs (Ruby)

Ruby has the class Proc which encapsulates a "block of code". There are 2 "flavors" of Procs:

  • Those with "block semantics", called blocks or confusingly sometimes also procs
  • Those with "method semantics", called lambdas

lambdas

They behave like Ruby method definitions:

  • They are strict about their arguments.
  • return means "exit the lambda"

How to define a lambda

  1. With the lambda keyword

    test = lambda do |arg|
      puts arg
    end
    
  2. With the lambda literal -> (since Ruby 1.9.1)
    ...

Stop writing "require 'spec_helper'" in every spec

Simply add this to your .rspec instead:

--require spec_helper

If you are on rspec >= 3 and use a rails_helper.rb require this instead of the spec_helper:

--require rails_helper

If you are using parallel_tests and this is not working for you, .rspec might be ignored. Try using a .rspec_parallel file.

Case Study: Analyzing Web Font Performance

Table of contents of the linked article:

What are Web Fonts?

  • Advantages of Web Fonts
  • Disadvantages of Web Fonts
    • Fallback Fonts
    • CSS3 @font Declaration Example
    • Fallback Font Example
    • Render Blocking and Critical Rendering Path
    • FOIT

Optimizing Web Font Delivery Further

  • Prioritize Based On Browser Support
  • Choose Only Styles You Need
  • Character Sets
  • Host Fonts Locally or Prefetch
  • Store in LocalStorage with Base64 Encoding
  • Another Method

Web Font Pe...

Test your application's e-mail spam scoring with mail-tester.com

You can use mail-tester.com to check your application's e-mails for issues that might cause e-mails to be classified as spam.

They provide a one-time e-mail addresses that you can use to sign up etc. You can then check for scoring results of SpamAssassin and other potential issues.
You don't need to hit 10/10. Something around 9/10 is perfectly fine.

Note:

  • For password-protected staging sites you will get an error for links that can not be resolved. This is fine, simply check production once available.
  • ...

Lazy-loading images

Note

This card does not reflect the current state of lazy loading technologies. The native lazy attribute could be used, which is supported by all major browsers since 2022.

Since images are magnitudes larger in file size than text (HTML, CSS, Javascript) is, loading the images of a large web page takes a significant amount of the total load time. When your internet connection is good, this is usually not an issue. However, users with limited bandwidth (i.e. on mobile) need to mine their data budget...

How to run a small web server (one-liner)

Sometimes you just want to have a small web server that serves files to test something.

Serve the current directory

On Ruby 1.9.2+ you can do the following ("." for current directory). You might need to gem install webrick on modern Rubies.

ruby -run -ehttpd . -p8000

Python 2.x offers a similar way.

python -m SimpleHTTPServer 8000 .

This is the same way with Python 3.x

python -m http.server

In both cases your web server is single-threaded and will block when large files are being downloaded from you.

WEBrick ...

Gemspecs must not list the same gem as both runtime and development dependency

When you're developing a gem, never list the same dependency as both runtime and development dependency in your .gemspec.

So don't do this:

spec.add_dependency 'activesupport'
spec.add_development_dependency 'activesupport', '~> 2.3'

If you do this, your gemspec will not validate and modern versions of Bundler will silently ignore it. This leads to errors like:

Could not find your-gem-0.1.2 in any of the sources

What to do instead

If you want to freeze a different version of a dependency for your t...

Reverse-proxying web applications with nginx

While you can use Apache as a reverse proxy, it tries to be too smart. Try nginx instead, it's much simpler to set up.

After struggling with Apache for quite a while, since I simply could not make it pass through the Digest Authentication of my target host (that I proxied to), I switched to nginx. Here is what I did.

  1. Have nginx

    sudo apt-get install nginx
    
  2. Define your nginx config, e.g. at /etc/nginx/conf.d/reverse-proxy.conf:

    server {
      listen 127.0.0.1;
      
      location /...