Caution: rem in @media query definitions ignore your font-size

Note

Using rem only ever makes sense when the root font size is dynamic, i.e. you leave control to the user. Either by a) respecting their user agent defaults, or by b) offering multiple root font sizes in your application.

By defining @media queries in rem, they will accommodate to the root font size of your page. At a larger root font, breakpoints will be at larger widths, scaling with the font. However, there is a catch in case b) mentioned in the note above.

Relative length units in media queries are based on the initial value,...

Problems with git submodules in Gitlab CI

If you are using git submodules in Gitlab CI, you might run into a "The project you were looking for could not be found or you don't have permission to view it."

Gitlab added a feature that new projects are no longer allowed to be cloned inside CI runs of other repositories by default. To fix this

  • Go into the project used as a submodule
  • Go to "Settings" -> "CI/CD" (if you don't see this section, enable it in "Settings" -> "General" -> "Visibility, project features, permissions")
  • Go to "Token Access"
  • Either disable "Limit access to ...

Rails: Testing file downloads with request specs

tl;dr

Prefer request specs over end-to-end tests (Capybara) to joyfully test file downloads!

Why?

Testing file downloads via Capybara is not easy and results in slow and fragile tests. We tried different approaches and the best one is just okay.

Tests for file downloads via Capybara ...

  • ... are slow,
  • ... are fragile (breaks CI, breaks if Selenium driver changes, ...),
  • ... need workarounds for your specia...

Geordi 10.0.0 released

10.0.0 2024-03-07

Compatible changes

  • console command: You can now globally disable the IRB multiline feature by setting irb_flags: --nomultiline in ~/.config/geordi/global.yml. All configured irb_flags are automatically passed on to the console IRB.
  • console command: Ctrl + C now properly exits a local Rails console
  • rspec and cucumber commands: Run specs even if the automatic chromedriver update fails
  • Improve detection of IRB version
  • Add new hints to 'Did you know'

Breaking changes

  • dump command: Drop...

Grid by Example: a website about CSS Grid

Rachel Andrew has built a website about CSS Grid.

  • Video tutorials
  • More than 30 layout examples for feature demonstration
  • Layout patterns for copy-paste use
  • All grouped by topic: "Placing items onto the grid", "Sizing of tracks and items" etc. with video, linked articles, examples each

Chaining Capybara matchers in RSpec

You can chain multiple Capybara matchers on the page or any element:

expect(page)
  .to have_content('Example Course')
  .and have_css('.course.active')
  .and have_button('Start')

When you chain multiple matchers using and, [Capybara will retry the entire chain](https://github.com/teamcapybara/capybara/blob/c0cbf4024c1abd48b0c22c2930e7b05af58ab284/lib/capybara/rspec/matc...

Virtual scrolling: A solution for scrolling wide content on desktops

I recently built a screen with a very high and wide table in the center. This posed some challenges:

  • Giving the table a horizontal scroll bar is very unergonomic, since the scrollbar might be far off screen.
  • Making the whole page scrollable looks bad, since I don't want the rest of the UI to scroll.
  • Giving the table its own vertical scrollbar and a limited height would have solved it, but felt weird, since the table was 90% of the page.

What I ended up doing is reusing the horizontal page scrollbar (which is naturally fixed at t...

You should be using the Web Animations API

The Web Animations API has great browser support, and you should be using it to animate DOM elements from JavaScript, or to control or wait for CSS animations.

Here is a quick overview of a few useful features:

Animating elements from JavaScript

Use the Element#animate() function to perform animations on an element.

Its API probably a bit different from how your...

Heads up: You should always use "current_window.resize_to" to resize the browser window in tests

I recently noticed a new kind of flaky tests on the slow free tier GitHub Action runners: Integration tests were running on smaller screen sizes than specified in the device metrics. The root cause was the use of Selenium's page.driver.resize_window_to methods, which by design does not block until the resizing process has settled:

We discussed this issue again recent...

Use <input type="number"> for numeric form fields

Any form fields where users enter numbers should be an <input type="number">.

Numeric inputs have several benefits over <input type="text">:

  • On mobile or tablet devices, number fields show a special virtual keyboard that shows mostly digit buttons.
  • Decimal values will be formatted using the user's language settings.
    For example, German users will see 1,23 for <input type="number" value="1.23">.
  • Values in the JavaScript API or when submitting forms to the server will always use a point as decimal separator (i.e. "1.23" eve...

CI Template for GitHub Actions

Usually our code lives on GitLab, therefore our documentation for CI testing is extensive in this environment. If you are tied to GitHub e.g. because your customer uses it, you may use the following GitHub Actions template for the CI integration. It includes jobs for rspec (parallelized using knapsack, unit + feature specs), rubocop, eslint, coverage and license_finder.

Note that GitHub does not allow the use of YAML anchors and aliases. You can instead use [compos...

Where to keep project files that should not go to Git

Sometimes you have a file that is related to a project, while not actually being part of it. You'd like to keep them around, but others won't need them – e.g. some notes, a log, or a database dump.

Sure, you have a project directory – but all of it is tracked by Git. A project's tmp/ directory is usually not tracked, but by definition it is not a good place to keep things.

An excluded directory for related files

I suggest you keep your related files in a related-files/ directory within your project(s).

To keep this directory u...

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.

How to configure Selenium WebDriver to not automatically close alerts or other browser dialogs

tl;dr

We recommend configuring Selenium's unhandled prompt behavior to { default: 'ignore' }.

When running tests in a real browser, we use Selenium. Each browser is controlled by a specific driver, e.g. Selenium::WebDriver::Chrome for Chrome.

There is one quirk to all drivers (at least those following the W3C webdriver spec) that can be impractical:
When any user prompt (like an alert) is encountered when trying to perform an action, they will [dismiss the dialog by defaul...

Creating a self-signed certificate for local HTTPS development

Your development server is usually running on an insecure HTTP connection which is perfectly fine for development.

If you need your local dev server to be accessible via HTTPS for some reason, you need both a certificate and its key. For a local hostname, you need to create those yourself.
This card explains how to do that and how to make your browser trust the certificate so it does not show warnings for your own certificate.

Easy: self-signed certificate

To just create a certificate for localhost, you can use the following command....

RubyMine: Real-time Collaborating in the IDE

RubyMine has a collaboration feature called "Code With Me". Using it, you can invite someone into your local editor to work together. This is nicer to the eyes and much more powerful than sharing code through some video chat.

How to

Getting started is really simple:

  1. Click the "add person" icon in the top-right editor corner (or hit Ctrl + Shift + Y) and select "Start Session".
  2. Choose permissions:
    • "Read-only" lets others only watch you.
    • "Edit files" is needed for pairing. Note that this allows remote partners to, well, ...

open-next-failure: An alias to speed up test debugging

Getting an entire test suite green can be a tedious task which involves frequent switches between the CLI that is running tests back to the IDE where its cause can be fixed.

The following bash aliases helped me speed up that process:

alias show-next-failure="bundle exec rspec --next-failure"
alias open-next-failure="show-next-failure || show-next-failure --format json  | jq -r '.examples[0]' | jq '\"--line \" + (.line_number|tostring) + \" \" + .file_path' | xargs echo | xargs rubymine"

There is a lot going on above but the gist...

Migrating from Elasticsearch to Opensearch: searchkick instructions (without downtime!)

General

A general overview about why and how we migrate can be found under Migrating from Elasticsearch to Opensearch

This card deals with specifics concerning the use of searchkick.

Step 1: Make Opensearch available for Searchkick

In your Gemfile

# Search
gem 'searchkick'                   # needs to be > 5, to use Opensearch 2
gem 'elasticsearch'
gem 'opensearch-ruby'

in config/initializers/searchkick.rb (or wherever you have configured your Searchkick settings) add:

SEARCHKICK_CLIENT_T...

RailsStateMachine 2.2.0 released

  • Added: State machine can now use the :prefix-option to avoid name collision if you define multiple state machines on the same model, and use state names more than once
    • Previously state_machine-definitions like this:
        class Form
        
          state_machine :first_wizard_stage do
            state :completed
          end
      
          state_machine :second_wizard_stage do
            state :completed
          end
          
        end
      
      would produce the following warning:
        rails_state_machine-2.1....
      

How to: Upgrade CarrierWave to 3.x

While upgrading CarrierWave from version 0.11.x to 3.x, we encountered some very nasty fails. Below are the basic changes you need to perform and some behavior you may eventually run into when upgrading your application. This aims to save you some time understanding what happens under the hood to possibly discover problems faster as digging deeply into CarrierWave code is very fun...

Whitelists and blacklists

The following focuses on extension allowlisting, but it is the exact same thing for content type allowlisting with the `content_ty...

Heads Up: Selenium 4 uses a binary to determine the chromedriver

I recently stumbled over a problem that my feature tests broke in CI because of a mismatching chromedriver version.

In this specific project we have a fixed Chromium version in a Debian 12 environment instead of Chrome. The tests however used a recent chrome version instead.

$ chromedriver --version
ChromeDriver 117.0.5938.149 (e3344ddefa12e60436fa28c81cf207c1afb4d0a9-refs/branch-heads/5938@{#1539})
$ chromium --version
Chromium 117.0.5938.149 built on Debian 12.1, running on Debian 12.1

> WARN Selenium [:selenium_manager] The chromed...

RSpec: Leverage the power of Capybara Finders and Matchers for view specs

View specs are a powerful tool to test several rendering paths by their cases instead of using a more costing feature spec. This is especially useful because they become quite convenient when used with Capybara::Node::Finders and Capybara::RSpecMatchers. This allows to wirte view unit specs as you can isolate specific part...

Spreewald, Cucumber: Selector for the nth Element

The recommended additional setup of the spreewald gem, a useful set of cucumber steps, includes adding a file for defining custom selectors which can be used as prose within steps:

When I follow "Edit" within the controls section

Where the controls section can be any arbitrary defined css selector within selectors.rb


Often it can be useful to select the nth element of a specific selector. Luckily, this can ...

RSpec: Efficiently rerunning failed examples during development

Note

Don't use reruns as a mean to work around flaky tests. You should always try to fix those instead of rerunning them regularly.

Setup

Configure RSpec to persist the result of your test runs to a file. This is necessary to be able to rerun examples.
Add this to your spec/spec_helper.rb :

  config.example_status_persistence_file_path = 'spec/examples.txt'

Rerun all failed examples using --only-failures

bundle exec rspec --only-failures (or `...