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' } with the monkey patch below.

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

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

How to work around selenium chrome missing clicks to elements which are just barely visible

Chromedriver (or selenium-webdriver?) will not reliably scroll elements into view before clicking them, and actually not click the element because of that.

We've seen this happen for elements which are just barely in the viewport (e.g. the upper 2px of a 40px button). Our assumption is that the element is considered visible (i.e. Capybara::Selenium::ChromeNode#visible? returns true for such elements) but the Selenium driver wants to actually click the center of the element which is outside of the viewport.

We don't know who exactly i...

Split your parallel tests by execution time and keep execution logs up to date

Both knapsack and parallel_tests have the option to split groups by historic execution time. The required logs for this might be outdated since you manually have to update and push them into your repository.

The following card includes an option how you can keep them consistently up to date with no extra effort locally and/or remotely.

How to always split by execution logs

Parallel Tests

The parallel_tests gem has the option flag `--group...

Lightning Talk: Coverage based Test Case Prioritization in Ruby on Rails

For my computer science bachelor's thesis I programmed and evaluated a CLI Test Case Prioritization (TCP) tool for makandra. It has been written as a Ruby Gem and was tested and evaluated against one Ruby on Rails project. This card will summarize and present the research results, the evaluation and the programmed CLI tool.

The code has been published for educational purposes on GitHub. The german bachelor's thesis has also been included for download at the end.


...

Chromedriver issue #4550 breaks the user agent for device emulation via device name

Newest versions of Chromedriver breaks the user agent for device emulation via device name. In previous versions the user agent of the emulated device was set. In the newest versions the user agent differs from the emulated device.

In Capybara an affected config looks like following:

Capybara.register_driver :mobi...

Capybara: How to find the focused element

Capybara allows you to filter elements that are focused.

page.find(:fillable_field, focused: true) # Filtering only fillable inputs for performance reasons
page.find(:xpath, '//*', focused: true) # Filter all fields

Legacy approach

In older version, it was possible to use the :focus pseudo-class. This seems not to work in newer versions anymore.

find(':focus')

How to transition the height of elements with unknown/auto height

If you want to collapse/expand elements with dynamic content (and thus unknown height), you can not transition between height: 0 and height: auto.

Doing it properly, with modern CSS features

In the past, you might have resorted to bulky JavaScript solutions or CSS hacks like transitioning between max-height: 0 and max-height: 9999px. All of them were awkward and/or have several edge cases.

With modern CSS, there is actually a way to do it properly:
Just use a display: grid container which transitions its grid row height betwe...

Use -webkit-line-clamp to natively truncate long (multi-line) texts with an ellipsis

Note: You won't need this for single lines of text. In this case it is better to just use the text-overflow property: Use CSS "text-overflow" to truncate long texts

You can use -webkit-line-clamp in your CSS/SASS to natively render an ellipsis (...) after a specific amount of lines for a multi-line text in your HTML.
Earlier, it was necessary to implement JavaScript solutions like Superclamp.js to enable this because the browser support has been rather limited...