Upgrading Capybara with deprecated Integer selectors

Capybara added a deprecation warning in version 3.35.3 (version from 2019) that shows up if your selector is not of type String or Symbol.

Example:

click_link(10) # bad
click_link("10") # good

You might encounter this error e.g. in a pagination step or similar where you want to click on numbers. To figure out where this deprecation warning comes from try to run the tests with a step output.

bundle exec parallel_cucumber --test-options "--format=pretty" feature

The deprecation message looks like following:

Locator In...

Geordi 6.0.0 released

6.0.0 2021-06-02

Compatible changes

  • geordi commit will continue even if one of the given projects is inaccessible. It will only fail if no stories could be found at all.

Breaking changes

Chromedriver: Disabling the w3c option might break your integration tests with Chrome 91

We recently noticed issues with Chrome 75+ when having the w3c option enabled within the Selenium webdriver. It looks like recent Selenium versions don't have any issues with the w3c interface anymore. And starting with Chrome 91 this fix might cause unexpected issues, so you should try to enabled this option again or just remove the following line from you configuration:

options.add_option('w3c', false)

Background: Setting the w3c option t...

Accessing JavaScript objects from Capybara/Selenium

When testing JavaScript functionality in Selenium (E2E), you may need to access a class or function inside of a evaluate_script block in one of your steps. Capybara may only access definitions that are attached to the browser (over the window object that acts as the base). That means that once you are exporting your definition(s) in Webpacker, these won't be available in your tests (and neither in the dev console). The following principles/concepts also apply to Sprockets.

Say we have a StreetMap class:

// street_map.js
class S...

Heads up: Byebug has problems with zeitwerk

I encountered a unlucky behavior of byebug 11.1.3 (the most recent version at time of writing) when using it with Rails 6 and it's new autoloading component, zeitwerk. There already is a issue for that, so I hope it will be fixed with a future release.

The following test succeeds:

  context 'factories' do
    let(:test_case) { FactoryBot.create(:test_case) }
    it 'are valid' do
      expect(test_case).to be_valid
    end
  end

But when I did the same in byebug the foll...

RSpec: Ensuring a method is called on an object that will be created in the future

rspec >= 3.1 brings a method and_wrap_original. It seems a bit complicated at first, but there are use cases where it helps to write precise tests. For example it allows to add expectations on objects that will only be created when your code is called.

If you have older rspec, you could use expect_any_instance_of, but with the drawback, that you can't be sure if it really was the correct instance which got the message.

Example

The example model uses different validators based on a flag:

class MyModel < ApplicationRecord

 ...

Ruby: Fixing strings with invalid encoding and converting to UTF-8

When dealing with external data sources, you may have to deal with improperly encoded strings.
While you should prefer deciding on a single encoding with the data-providing party, you can not always force that on external sources.
It gets worse when you receive data with encoding declaration that does not reliably fit the accompanying string bytes.

Here is a Ruby class that helps converting such strings to a proper encoding.
Note that it tries several approaches of changing the encoding. **This is not a silver bullet and may or may not work...

Disabling client caching with Cache-Control: no-store

Browsers usually cache website content in order to provide the user with faster responses. Examples are returning to a website using the "Back" button, or reopening a browser and restoring previous tabs.

However, there are applications where this kind of client caching produces annoying results: a time tracking tool may show a wrong clock-in state, or an SPA todo app may display an outdated list. In these cases, client caching should be disabled.

In order to prevent client caching, set a Cache-Control header of no-store. This tells _...

RubyMine: How to exclude single files

In RubyMine folders can be excluded from search, navigation etc. by marking it as excluded. You might sometimes wish to exclude single files, too. An example could be .byebug_history which is located in the project root directory.

Single files can be excluded by pattern in the Settings:

  1. In the Settings/Preferences dialog Ctrl+Alt+S, go to Project structure
  2. In the Exclude files field, type the masks that define the names of files and folders to be exclu...

Carrierwave: Using a nested directory structure for file system performance

When storing files for lots of records in the server's file system, Carrierwave's default store_dir approach may cause issues, because some directories will hold too many entries.

The default storage directory from the Carrierwave templates looks like so:

class ExampleUploader < CarrierWave::Uploader::Base
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
end

If you store files for 500k records, that store_dir's parent directory will have 500k sub-directories which will cause some...

Debugging your Webpack build time with Speed Measure Plugin

If your Webpack build is slow, you can use the Speed Measure Plugin for Webpack to figure out where time is being spent.
Note that at time of writing, Webpack 5 seems unsupported. It works on Webpack 4, though.

Wire it into your application as described in the library's documentation:

  1. Hook into your environment file, e.g. config/webpack/development.js and instead of exporting your Webpack config,...

When does Webpacker compile?

Webpack builds can take a long time, so we only want to compile when needed.

This card shows what will cause Webpacker (the Rails/Webpack integration) to compile your assets.

When you run a dev server

While development it is recommended to boot a webpack dev server using bin/webpack-dev-server.

The dev server compiles once when booted. When you access your page on localhost before the initial compilation, the page may load without assets.

The ...

Limiting GitLab CI runner to specific branches or events

Use rules to include or exclude jobs in pipelines.

Rules are evaluated in order until the first match. When a match is found, the job is either included or excluded from the pipeline, depending on the configuration. The job can also have certain attributes added to it.

rules replaces only/except and they can’t be used together in the same job. If you configure one job to use both keywords, the linter returns a key may not be used with rules error.

GitLab 12.3 introduced rules. You can use them in your .gitlab-ci.yml in your proj...

Clean code: Avoiding short versions in command options

This card is a general reminder to avoid the short version of a command option in shared code. It's much easier to understand a command and search for an option when it's written out.

You can still use the short version of the options in your own terminal or in code snippets that are more useful when they are very compact. For the latter case you often see a description of the command options one line below e.g. in posts on stackoverflow.

Example good (in code):

/usr/bin/gpg --output password.txt --decrypt password.txt.gpg

...

How to generate and test a htpasswd password hash

Generate a password

htpasswd -Bn firstname.lastname

This will ask you for a password and use bcrypt (-B, more secure) and print the output to stdout (-n).

Check if password matches the hash

You'll first have to write the password hash to a file:

echo firstname.lastname:$2y$05$4JXxd2GM/J2...9c3KJmFS > htpass_test

Check, if it is correct:

htpasswd -v htpass_test firstname.lastname

You probably should not use the -b switch to read the password from the command line as the password will then be visible...

How to push to Git without running CI on GitLab CI, GitHub Actions, or Travis CI

If a project ist configured to spawn CI runners for tests or deployment when pushing to the Repo, a habit of pushing WIP commits regularly may conflict with that.
Here are two solutions that allow you to keep pushing whenever you feel like it.

Special commit message

To skip a CI run, simply add [ci skip] or [skip ci] to your commit message. Example:

git commit -m "wip authentication [ci skip]"

Git push options (GitLab)

In addition to that, GitLab CI supports Git push options. Instead of changing your commit message, ...

Delivering Carrierwave attachments to authorized users only

Preparation

To attach files to your records, you will need a new database column representing the filename of the file. To do this, add a new migration (rails g migration <name>) with the following content:

class AddAttachmentToNotes < ActiveRecord::Migration[6.0]
  def change
    add_column :notes, :attachment, :string
  end
end

Don't forget to rename the class and change the column details to fit your purpose. Run it.

1) Deliver attachments through Rails

The first way is to store your Carrierwave attachments not ...

What does 100% mean in CSS?

The attached article examines what the percent unit (%) is relative to in CSS

The article does a great job of visualizing the dependencies. The TLDR is:

Own property % of
height parent height
width parent width
top parent height
left parent width
margin-top parent width
margin-left parent width
padding-top parent width
padding-left parent width

Ruby: How to convert hex color codes to rgb or rgba

When you have a hex color code, you can easily convert it into its RGB values using plain Ruby.

>> "#ff8000".match(/^#(..)(..)(..)$/).captures.map(&:hex)
=> [255, 128, 0]

You can use that to implement a simple "hex to CSS rgba value with given opacity" method:

def hex_color_to_rgba(hex, opacity)
  rgb = hex.match(/^#(..)(..)(..)$/).captures.map(&:hex)
  "rgba(#{rgb.join(", ")}, #{opacity})"
end
>> hex_color_to_rgba("#ff8000", 0.5)
=> "rgba(255, 128, 0, 0.5)"

If you need to support RGBA hex color codes,...

Online tool to convert tables between different formats

https://tableconvert.com/ is an online tool to convert tables between different formats (e.g. json, markdown, csv).
It also has a button to transpose a table ("rotate" it by 90 degree).

Image

The tool can be handy if you have tests with large markdown tables for testing contents of a flat json structure or csv.

Please note that you should not use it with sensitive data (like all online tools in general).

Capybara: Preventing headless Chrome from freezing your test suite

We prefer to run our end-to-end tests with headless Chrome. While it's a very stable solution overall, we sometimes see the headless Chrome process freeze (or the Capybara driver losing connection, we're not sure).

The effect is that your test suite suddenly stops progressing without an error. You will eventually see an error after a long timeout but until then it will seem that your suite is frozen. If you're also using [capybara-screenshot](https:/...

Capybara: Preventing server errors from failing your test

When your Rails application server raises error, Capybara will fail your test when it clears the session after the last step. The effect is a test that passes all steps, but fails anyway.

Capybara's behavior will help you to detect and fix errors in your application code. However, sometimes your application will explode with an error outside your control. Two examples:

  • A JavaScript library references a source map in its build, but forgets to package the source map
  • CarrierWave cleans up an upload or cache file after the record was delet...

E-mail deliverability

When your application is open for public sign up and sends out transactional e-mails to a large number of users, e-mail deliverability becomes an issue.

E-mail providers work hard to eliminate spam and have put in place relatively tight checks what kinds of emails they will accept, and from whom. To that end we use tools like mail-tester.com to make our mails as acceptable as possible. Unfortunately, there will always be providers that reject our e-mails for some reason or other, sometimes outside of our control.

For exa...

Capybara: Pretending to interact with the document

Browsers blocks abusable JavaScript API calls until the user has interacted with the document. Examples would be opening new tab or start playing video or audio.

E.g. if you attempt to call video.play() in a test, the call will reject with a message like this:

NotAllowedError: play() failed because the user didn't interact with the document first. https://goo.gl/xX8pDD

Workaround

To pretend document interaction in a test you can create an element, click on it, and remove the element again. This unblocks the entire JavaSc...