Stabilize integrations tests with flakyness introduced by Turbo / Stimulus / Hotwire

If you run a Rails app that is using Turbo, you might observe that your integration tests are unstable depending on the load of your machine. We have a card "Fixing flaky E2E tests" that explains various reasons for that in detail.

Turbo currently ships with three modules:

  • Turbo Drive accelerates links and form submissions by negating the need for full page reloads.
  • Turbo Frames decompose pages into independent contexts, which scope navigation and can be lazily loaded.
  • T...

Disable SimpleCov if you only run a fraction of your tests

Coverage reports are rarely useful if you run only small parts of your test suite.

Just do not load SimpleCov in this case, and you will see less noise in your test output:

if RSpec.configuration.files_to_run.count > 5
  require "simplecov"
  SimpleCov.start 'rails'
end

See also

Javascript: How to match text by Unicode properties

The linked MDN article is quite informative of a neat feature supported by all major browsers: Unicode character class escape.

You can use it to write regular expressions that work on the full UTF-8 space, not just Latin/ASCII. For example, a password policy matcher might include regular expressions like [A-z] or [0-9], but those do not match e.g. German umlauts or [Eastern Arabic Numerals](https:/...

RSpec: Marking sections in long examples

RSpec examples can get quite long, especially in feature specs. This makes them hard to read & understand. Also, when executing them, it may take seconds to see any progress.

To improve this, I have successfully been using a little "step" helper in my tests. It marks semantic sections, structuring an example while improving documentation. When the test runs, each step prints its message (or a dot, depending on your formatter).

# spec/support/step_helper.rb
module StepHelper

  # Use this helper to label groups of related actions in l...

How to silence Puma for your feature tests

When RSpecs runs the first feature spec, you may see log output like this:

Capybara starting Puma...
* Version 6.5.0, codename: Sky's Version
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:39949

You can disable this behavior by tweaking Capybara's Puma server in your spec/support/capybara.rb:

Capybara.server = :puma, { Silent: true }

Note

You don't need to configure this if you're using system tests with modern versions of Rails. They do [exactly the same](https://github.com/rails/rails/blob/ma...

Updated: How to allow testing beforeunload confirmation dialogs with modern ChromeDrivers

ChromeDriver 135 started following the W3C spec more closely, which broke testing beforeunload confirmations again. To get working confirmations in a testing browser again, unhandled_prompt_behavior needs to be set to the hash { default: :ignore }.

Selenium doesn't currently support setting this option to a hash, so a monkey patch is needed.

Managing chrome versions for selenium

Currently we often use geordi to run cucumber and rspec tests. Geordi takes care of installing a matching chromedriver for the installed google-chrome binary. The google-chrome binary is managed by apt.

Another approach is to use the Selenium Manager for installing and using the correct browser versions for you. Here is the setup you need for your integration tests:

Capybara.register_driver :chrome do |app|
  options = Sele...

Rails: Handling actions that need to happen after all transactions

In Rails 7.2. the feature ActiveRecord.after_all_transactions_commit was added, for code that may run either inside or outside a transaction (we have a special card for nested transactions in general) and needs to perform work after the state changes have been properly persisted. e.g. sending an email.

Example

def publish_article(article)
  article.update(published: true)

  ActiveRecord.after_all_transactions_commit do
    PublishNotification...

Testing for Performance: How to Ensure Your Web Vitals Stay Green

Frontend performance and user experience are orthogonal to feature development. If care is not taken, adding features usually degrades frontend performance over time.

Many years, frontend user experience has been hard to quantify. However, Google has developed some metrics to capture user experience on the web: the Web Vitals. The Core Web Vitals are about "perceived loading speed" (Largest Contentful Paint), reactivity (Interaction to Next Paint) and visual stability (Content Layout Shift).

I have recent...

Better performance insights with gem `rails_performance`

Even if you don't make any beginner mistakes like N+1 queries or missing DB indices, some requests can have bad performance. Without good performance metrics, you probably won't notice this until it's too late.

We investigated multiple gems and found that rails_performance (https://github.com/igorkasyanchuk/rails_performance) provides a lot of valuable information with very little setup cost. It only needs Redis which we use in the majority of our applications anyw...

Selenium: Fix Chrome's "Unsafe Password" Warning

tl;dr

Set profile.password_manager_leak_detection to false in your Selenium Chrome options to disable password leak detection and suppress the warning.

Problem

When running Selenium tests with recent versions of Chrome and Chromedriver (e.g., version 136+), entering “unsafe” (weak or reused) passwords in forms triggers a browser warning:

"This password has appeared in a data breach…"

This alert can break automated test runs, especially in CI/CD pipelines.

Solution

You can **disable Chrome’s password leak ...

Output of ParallelTests::Cucumber::FailuresLogger was fixed in 4.9.1

Our projects with parallel_tests and cucumber used to have a patched failure logger as the one from parallel_tests was missing spaces which resulted in the output not being a valid rerun argument. With version 4.9.1 output of ParallelTests::Cucumber::FailuresLogger was fixed.

You can remove the patch (e.g. features/support/cucumber_failures_logger.rb) and switch the logger in config/cucumber.yml back to ParallelTests::Cucumber::FailuresLogger.

Thanks to Dominik for [the fix](https://github.com/grosser/parallel_tests/commit/...

Selecting the nth element matching a selector

The :nth-child pseudo class is commonly used for targeting elements based on their position within a parent container, for example the third element in a list or every even-numbered item. However, :nth-child can do more.

In modern CSS specifications (Level 4), there’s an additional feature that lets you use :nth-child in combination with a list of css selectors. This way, you can ta...

Git Rebase: How to squash/fixup/edit/... commits without actually rebasing (keeping the base)

Purpose:
Interactively rebase your current branch onto main, keeping the original base commit (i.e. not rebasing onto main directly).

Use Case:
Useful when you've branched off a long-lived feature branch and want to clean up your commits without changing the original base. Afterwards you will be able to rebase one clean commit interactively onto main without going through each commit individually using git rebase -i main.

What it does:

  • Opens an interactive rebase UI to choose squash/edit/fixup for each co...

How to set Chrome's time zone in Selenium tests

For Selenium tests, your browser starts in your local timezone, or whatever your system's environment specifies.
This is usually good enough. To test any timezone-dependent behavior in Chrome, you can change the time zone using the Chrome DevTools Protocol.

Example

Chrome accepts any IANA time zone name, like "Europe/Berlin" or "Asia/Tokyo".
Here is the relevant command for Capybara:

page.driver.browser.execute_cdp('Emulation.setTimezoneOverride', timezoneId: 'Asia/Tokyo')
``...

Rails: Keeping structure.sql stable between developers

Why Rails has multiple schema formats

When you run migrations, Rails will write your current database schema into db/schema.rb. This file allows to reset the database schema without running migrations, by running rails db:schema:load.

The schema.rb DSL can serialize most common schema properties like tables, columns or indexes. It cannot serialize more advanced database features, like views, procedures, triggers or custom ditionaries. In these cases you must switch to a SQL based schema format:

# in application.rb
config.a...

A "text-wrap: balance" fallback approach

Here is a workaround for when you want to use text-wrap: balance but must also render nicely for browsers that don't support it (mostly Safari <17.5).

Step 1: Put some <br>s into your HTML

First, place explicit line breaks that should work for most cases.
This depends on your use case and is affected by e.g. container widths or user content.

<div class="my-element">
  <p>
    Average score
    <br>
 ...

How to automatically optimize SVG files with esbuild

SVG files often contain redundant information, like editor metadata or hidden elements. When esbuild handles your static assets, you can easily optimize SVG files using svgo as a plugin. Here is how to do it.

Adding svgo as an esbuild plugin

  1. Add the svgo package to your project's package.json
  2. Adjust your esbuild.config.js like so:
const esbuild = require('esbuild')
const svgo = require('svgo')

const options = {
  // ...
  loader: {
    // ...
    '.svg': 'copy', // this may be different...

Rails: Using PostgreSQL full-text search without a gem

PostgreSQL can cosplay as a full-text search engine. It doesn't have the features or fidelity of ElasticSearch or Algolia, but it's good enough if you just need to search and rank large volumes of text.

This card will teach you how to index, search and rank your Rails models in a PostgreSQL full-text index. We will do this without using any gems aside from ActiveRecord. While there are gems like pg_search or pg_fulltext, manual integration requires very...

Using Low-Level Prompts for High-Accuracy AI Coding

The key to unlocking the full potential of LLMs in coding lies in crafting precise prompts. The main challenge is learning how to structure prompts effectively to guide the model toward accurate results. Further evidence supporting this is the fact that Aider already writes ~70% of its own code (as of 02/2025). However, when starting out, your results may fall short of efficiently generating large portions of your code with the...

How to disable telemetry for various open source tools and libraries

Hint

If you are using our opscomplete.com hosting we can set all environment variables mentioned below for your deployment on request.

If you're lucky DO_NOT_TRACK=1 opts you out of CLI telemetry - it's not widely adopted. When you're using any of the libraries below, I'd rather opt out explicitly:

Yarn

https://yarnpkg.com/advanced/telemetry (Since: Version 2.2)

Disable for a project:

#...

Ignore Selenium driver deprecations

If you update Selenium regularly, you'll run into deprecation warnings similar to:

WARN Selenium [:clear_local_storage] [DEPRECATION] clear_local_storage is deprecated and will be removed in a future release

You can ignore this deprecation warning and clean your logs with logfilters:

Selenium::WebDriver.logger.ignore(:clear_local_storage)

Just specify the tag (:clear_local_storage) you want to ignore.

How the Date Header Affects Cookie Expiration and Caching

tl;dr

When a cookie includes an Expires attribute or an HTTP response includes caching headers like Expires or Cache-Control, their validity depends on the server's Date header if present. Otherwise, the browser uses its local time. This can lead to issues in tests with mocked time or inconsistent cache behavior.

Cookie Expires depends on the Date header or browser time

When a cookie includes an Expires attribute, the browser evaluates the expiration date relative to a reference time:

  1. If the HTTP response ...

Text fragments in the browser URI fragment

Text fragments allow linking directly to a specific portion of text in a web document, without requiring the author to annotate it with an ID, using particular syntax in the URL fragment. Supporting browsers are free to choose how to draw attention to the linked text, e.g. with a color highlight and/or scrolling to the content on the page. This is useful because it allows web content authors to deep-link to other content they don't control, without relying on the presence of IDs to make that possible. Building on top of that, it could be u...