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

Geordi 1.0 released

Geordi 1.0 features a command line application geordi, that holds most of Geordi's previous commands.

New features

  • command help and usage examples right within geordi (geordi help and geordi help <command>)

  • quick command access: type just the first few letters of a command, e.g. geordi rs or geordi dev[server]

  • command dependencies, e.g. geordi rspec invokes geordi bundle-install (which bundles only if needed)

  • no cluttered /usr/bin, but all commands in one handy tool

  • template for easily adding new...

Always store your Paperclip attachments in a separate folder per environment

tl;dr: Always have your attachment path start with :rails_root/storage/#{Rails.env}#{ENV['RAILS_TEST_NUMBER']}/.


The directory where you save your Paperclip attachments should not look like this:

storage/photos/1/...
storage/photos/2/...
storage/photos/3/...
storage/attachments/1/...
storage/attachments/2/...

The problem with this is that multiple environments (at least development and test) will share the same directory structure. This will cause you pain eventually. Files will get overwritten and...

Using Spring and parallel_tests in your Rails application

You want Spring for super-fast binstubs like bin/rails or bin/rspec which avoid Rails boot time.
You want parallel_tests to speed up full test runs of large test suites.

Unfortunately, you do not want parallel_tests to use your Spring binstubs as those parallelized tests will share data and/or loose some information. There are some issues about this on GitHub and there is a suggested [workaround](https:...

How to solve Selenium focus issues

Selenium cannot reliably control a browser when its window is not in focus, or when you accidentally interact with the browser frame. This will result in flickering tests, which are "randomly" red and green. In fact, this behavior is not random at all and completely depends on whether or not the browser window had focus at the time.

This card will give you a better understanding of Selenium focus issues, and what you can do to get your test suite stable again.

Preventing accidental interaction with the Selenium window
--------------------...

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.

Firefox ESR Release Calendar

The linked table shows the support lifecycle for Firefox Extended Support Releases (ESR) which we sometimes need to support for enterprise customers.

The ESR cadence works something like this:

  • Firefox ESR freezes the then-current Firefox version for a year.
  • During this year Mozilla backports security patches to the current ESR, but does not add features.
  • Two subsequent ESR releases overlap for three months. This way enterprises have a quarter to test the new version and migrate their clients.

RSpec: ". not_to include" behaves like ".to exclude"

RSpec is smart when using the include-matcher in combination with .not_to. One could assume that

.not_to include(3, 4, 5)

evaluates to:

NOT( .to include(3, 4, 5) )

However, it behaves like:

.to (NOT include(3) && NOT include(4) && NOT include(5) )

Warning

Using .not_to in combination with the include-matcher doesn't logically negate the final truth value. It instead negates the individual include-expectations for each argument.

Proof

describe 'RSpec' do
  it "doesn't use logical nega...

Ruby 1.9 or Ruby 2.0 do not allow using shortcut blocks for private methods

Consider this class:

class Foo

  private
  
  def test
    puts "Hello"
  end
  
end

While you can say create a block to call that method (using ampersand and colon) on Ruby 1.8, ...

1.8.7 > Foo.new.tap(&:test)
Hello
=> #<Foo:0x1e253c8> 

... you cannot do that on Ruby 1.9 or 2.0:

1.9.3 > Foo.new.tap(&:test)
NoMethodError: private method `test' called for #<Foo:0x00000001e8c258>

^
2.0.0 > Foo.new.tap(&:test)
NoMethodError: private method `test' called for #<Foo:0x000000027bc738...

Upgrade guide for moving a Rails app from Webpack 3 to Webpack 4

Webpacker is Rails' way of integrating Webpack, and version 4 has been released just a few days ago, allowing us to use Webpack 4.

I successfully upgraded an existing real-world Webpack 3 application. Below are notes on everything that I encountered.
Note that we prefer not using the Rails asset pipeline at all and serving all assets through Webpack for the sake of consistency.

Preparations

  • Remove version locks in Gemfile for webpacker
  • Remove version locks in package.json for webpack and webpack-dev-server
  • Install by ca...

How to fix gsub on SafeBuffer objects

If you have an html_safe string, you won't be able to call gsub with a block and match reference variables like $1. They will be nil inside the block where you define replacements (as you already know).

This issue applies to both Rails 2 (with rails_xss) as well as Rails 3 applications.

Here is a fix to SafeBuffer#gsub. Note that it will only fix the $1 behavior, not give you a safe string in the end (see below).

Example

def test(input)...

Migration from the Asset Pipeline to Webpacker

This is a short overview of things that are required to upgrade a project from the Asset Pipeline to Webpacker. Expect this upgrade to take a few days even the diff is quite small afterwards.

Preparations

1. Find all libraries that are bundled with the asset pipeline. You can check the application.js and the application.css for require and import statements. The source of a library is most often a gem or a vendor directory.
2. Find an working example for each library in the application and write it down.
3. Find out the ver...

Upgrading Ruby from 1.8.7 to 2.3.5

Suggested Workflow

Set the ruby version in .ruby-version to 2.3.5, then perform these steps one by one, fixing errors as they occur:

  1. Update gems as listed below, and bundle
  2. Boot a Rails console - see below for a list of changes you will probably need
  3. Run Specs with --backtrace option
  4. Run Cucumber features (with Geordi's --debug option)
  5. When all tests are green, look through your Gemfile and remove as many version constraints as possible.
  6. Boot the application in different environements to spot further issues, e...

parallel_tests: Disable parallel run for tagged scenarios

Note: This technique is confusing and slows down your test suite.


Copy the attached code to features/support. This gets you a new Cucumber tag @no_parallel which ensures that the tagged scenario does not run in parallel with other scenarios that are tagged with @no_parallel. Other scenarios not tagged will @no_parallel can still run in parallel with the tagged test. Please read the previous sentence again.

This can help when multiple test processes that access a single resource that is hard to shar...

Running Rails 2 apps with modern MariaDB SQL server

You might have some trouble running a Rails LTS 2 app with MySQL 5.7.

If you don't want to hack Mysql 5.6 into your modern Ubuntu or use the MySQL sandbox, you might want to try MariaDB 10.x.

MariaDB 10.x should work with both old and new Rails applications.

[Switch to MariaDB](https://makandracards.com/makandra/468343-how-...

Jasmine: Mocking API requests in an Angular service spec

Situation: You want to write a spec for a function inside an Angular service. This function at some point makes an API request and acts upon response. Notably, your Angular app employs uiRouter, although it is not used nor actually required for this test.

Working test setup

# Capitalized expressions are intended to be replaced with YOUR values

describe 'SERVICE', ->

  beforeEach ->
    module 'MODULE'

    module ($urlRouterProvider) ->
      # Prevent uiRouter's initialization, i.e. do not sync the current URL
      # with its r...

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

Geordi 1.5.1 released

  • Improve geordi cucumber: Only attempt @solo run when the specified files contain the @solo tag, skip @solo run if any filename is passed with a line number (e.g. features/example.feature:3)
  • Improve geordi deploy: Find stages by their prefix (e.g. s -> staging, m -> makandra), bundle if needed, check the selected stage exists
  • Improve geordi server: Takes port as argument (e.g. geordi ser 3001), option --public (-P) starts the server with -b 0.0.0.0 to make it accessible from other machines in the local network, e.g. ...

Implementing social media "like" buttons: Everything you never wanted to know

So you client has asked you to implement a row of buttons to like the URL on Facebook, Twitter and Google+. Here are some things you should know about this.

0. Security considerations

Each "like" button is implemented by including a Javascript on your site. This means you are running fucking remote code on your page. You are giving Facebook, Twitter and Google+ full permission to e. g. copy user cookies. Check with your client if she is cool with that. Also note that if you're site is suggesting security by operating under HTTPS ...

Delete all MySQL records while keeping the database schema

You will occasionally need to clean out your database while keeping the schema intact, e.g. when someone inserted data in a migration or when you had to kill -9 a frozen test process.

Old Capybara versions already have the Database Cleaner gem as dependency. Otherwise add database_cleaner to your *Gemfile`. This lets you say this from the Rails console:

DatabaseCleaner.strategy = :truncation
DatabaseCleaner.cl...

Hide your Selenium browser window with a VNC server

This is now part of geordi. Please don't follow the instructions below, if you use geordi.

Inspired by the recent headless Selenium note, I found yet another solution for the problem to hide your selenium tests away.

This has the advantages
^

  • not to require a gem (so you do not force this on others)
  • to allow you to take a look at the running webdriver if necessary

Simply make a script th...

Run Chrome in a specific resolution or user agent with Selenium

When you want to test how an web-application reacts in a specific resolution, you can set up a specific Selenium driver for some tests:

 Before('@chrome320x480') do
     Capybara.current_driver = :chrome320x480
 end

 After('@chrome320x480') do
    Capybara.use_default_driver 
 end

You can use either chromium or chrome beta (as of 2012.05 the Version "19.0.1084.41 beta" works), or any other member of the family. It only needs to supports the "--window-size" command-line switch. [See this list](http://peter.sh...

Testing setTimeout and setInterval with Jasmine

Jasmine has a jasmine.clock() helper that you can use to travel through time and trigger setTimeout and setInterval callbacks:

beforeEach(function() {
  timerCallback = jasmine.createSpy("timerCallback");
  jasmine.clock().install();
});

afterEach(function() {
  jasmine.clock().uninstall();
});

it("causes a timeout to be called", function() {
  setTimeout(function() {
    timerCallback();
  }, 100);

  expect(timerCallba...

Speed up RSpec by deferring garbage collection

Update: This trick probably isn't very useful anymore in Ruby 2.x. The Ruby GC has improved a lot over the years.


Joe Van Dyk discovered that running the Ruby garbage collector only every X seconds can speed up your tests. I found that deferring garbage collection would speed up my RSpec examples by about 15%, but it probably depends on the nature of your tests. I also tried applying it to Cucumber f...