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 (e.g. 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...

HTML: Auto fill-in OTP received in text message (SMS)

Browsers can auto fill-in one time codes if advised. Use it like this:

<input autocomplete="one-time-code">

Demo: https://twitter.com/sulco/status/1320700982943223808

Browser support is pretty good since mid-2022 (Chrome 93+, no Firefox).

Updated: How to upgrade Rails: Workflow advice

Added a link to the Rails upgrade awarenes list

Upgrade Rails: Awareness list

Disclaimer

This card is a collection of guides and things to have in mind when upgrading to a specific version. It is not meant to be complete, so please feel free to contribute!

General workflows

Upgrade to Rails 7

Upgrade to Rails 6

  • [...

Don't use log level :debug in your production environments

Catch phrase

You don't want sensitive user data in your logs.

Background

Rails per default filters sensitive data like passwords and tokens and writes [FILTERED] to the logs. The code which is responsible for enabling that usually lives in filter_parameter_logging.rb (Rails.application.config.filter_parameters). Here is an example of a filtered log entry:

Unfiltered:
`User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."token" = $1 LIMIT $2 [["token", "secret-token"], ["LIMIT", 1]]`

After the filter is appl...

Advanced plotting in Ruby with Gnuplot

Besides Plotting graphs in Ruby with Gruff, which comes handy for many uses cases, you sometimes might need configuration for more advanced plots, e.g. for academic concerns. Then using Gnuplot, the first academic open source plotting software, might be a good option.

There are several wrappers for Ruby available and I mainly looked at one of the two most frequently used ones, which are [ruby_gnuplot](https://github.com/rdp/ruby_gnuplot...

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.


...

What Ruby’s ||= (Double Pipe / Or Equals) Really Does

It is a common misunderstanding that all [op]=-operators work the same way, but actually they don't.

||= and &&=

Those are special cases, because the assignment will only happen if the first variable passes the check (false or nil for || and true for &&).

a ||= b   # => a || (a = b)
a &&= b   # => a && (a = b)

But still, if reading a has any side effects, they will take place regardless of to what a resolves.

Other [op]=

Assignment will always take place, no matter the value of a.

Geordi: How to rerun failed features

Cucumber will save a file tmp/parallel_cucumber_failures.log will the filenames and line number of the failed scenarios after a full test run.

Normally you can say cucumber -p rerun (rerun is a profile defined by default in config/cucumber.yml) to rerun all failed scenarios. Unfortunately this does not work with geordi yet.

Here is a list of possible workarounds, that depends on you personal taste:

With geordi

geordi cucumber @tmp/parallel_cucumber_failures.log

or

# Use th...

Selenium: How to debug the communication with the Webdriver API

Selenium allows you to log all requests to the Webdriver API. Therefore add the following line to e.g. features/support/selenium.rb:

Selenium::WebDriver.logger.level = :debug

If you want to see the output of the driver itself, here is an example on how to enable Chromedriver logging.

Example output

When you run a command like bundle exec cucumber --format=pretty features/some.feature you will see the API communication before the step is printed (here you see the log for the step And I press "Save").

...

Git restore vs. reset for reverting previous revisions

The git doc states on the difference of these two commands:

  • git-restore[1] is about restoring files in the working tree from either the index or another commit. This command does not update your branch. The command can also be used to restore files in the index from another commit.
  • git-reset[1] is about updating your branch, moving the tip in order to add or remove commits from the branch. This operation changes the commit history.

git reset can also be used to restore th...

redirect_to and redirect

There are multiple ways to redirect URLs to a different URL in Rails, and they differ in small but important nuances.

Imagine you want to redirect the following url https://www.example.com/old_location?foo=bar to https://www.example.com/new_location?foo=bar.

Variant A

You can use ActionController::Redirecting#redirect_to in a controller action

class SomeController < ActionController::Base
  def old_location
    redirect_to(new_location_url(params.permit(:foo))) 
  end
end

This will:

  • It will redirect with a 302 st...

Do not pass all params into url_for

Rails' url_for is useful for generating routes from a Hash, but can lead to an open redirect vulnerability.

The problem

Imagine your application contains code that checks if the current request's path is what it would generate internally.
If different, it would redirect users to the generated/expected path.

expected_path = url_for(params.to_unsafe_h)

if expected_path != request.original_fullpath
  redirect_to expected_path
e...

Do not use "permit!" for params

Rails' Strong Parameters enable you to allow only specific values from request params to e.g. avoid mass assignment.

Usually, you say something like params.permit(:email, :password) and any extra parameters would be ignored, e.g. when calling to_h.
This is excellent and you should definitely use it.

What is permit! and why is it dangerous?

However, there is also params.permit! whic...

Running external commands with Open3

There are various ways to run external commands from within Ruby, but the most powerful ones are Open3.capture3 and Open3.popen3. Since those can do almost everything you would possibly need in a clean way, I prefer to simply always use them.

Behind the scenes, Open3 actually just uses Ruby's spawn command, but gives you a much better API.

Open3.capture3

Basic usage is

require 'open3'

stdout_str, error_str, status = Open3.capture3('/some/binary', 'with', 'some', 'args')
if status.success?...

Git: How to rebase your feature branch from one branch to another

In a nutshell: Use git rebase --onto target-branch source-commit

  • target-branch means "branch you want to be based on"
  • source-commit means "commit before your first feature commit"

Let's say my-feature-branch is based on master and we want it to be based on production. Consider this history:

%%{init: { 'gitGraph': {'showCommitLabel': true, 'mainBranchName': 'production'}} }%%

gitGraph
  commit id: "1"
  commit id: "2"
  branch master
  commit id: "3"
  commit id: "4"
  branch my-feature...

Touch devices don't have mouseover events

It might sound trivial, but there is no such thing as a "hover" or "mouseover" state on touch devices. If your application is supposed to work on iPads, smartphones, etc., don't hide information behind a tooltip, and don't make controls appear when hovering over another element.

Generally, things that happen/appear when you hover an element should do the same when you click the element.

Updated: Capybara: Running tests with headless Chrome

  • Added: Remote debugging instructions with a docker image

Updated: Balance your texts today with text-wrap: balance

Added caveat: usage not suggested in combination with word-break: break-word.

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')

Web Components Accessibility FAQ

In the linked page, Manuel Matuzović offers an FAQ regarding web components, and their accessibility in particular.

At time of writing this card, the post is still work in progress and will expand over time.

I can also recommend his blog in general.

Postgres in Alpine docker container: sorting order might differ

In CI test runs I noticed that string sorting order changed after switching from a debian-based PostgreSQL docker image to one that is based on Alpine Linux.

Debian image sorting: bar Bar foo Foo
Alpine image sorting: Bar Foo bar foo

Explanation

Alpine Linux is a very slim linux distribution that results in small docker image sizes (roughly 100MB instead of 150MB), so it's a popular choice. However, it does not have all comman locales installed and does not use all locales that a user installs by default.
Postgres orders string co...