Using ngrok for exposing your development server to the internet

Sometimes you need to access a dev server running on localhost from another machine that is not part of the same network. Maybe you want to use your phone to test a web page, but are only in a guest WiFi. In the past, we often used some port forwarding or other techniques to expose the service to the internet.

Enter ngrok, a command line tool that gives you an on-the-fly internet...

RSpec: Inferring spec type from file location

RSpec Rails can automatically mix in different behaviors to your tests based on their type tag, for example enabling you to call get and
post in specs with the tag type: :request.

Alternatively you can skip these tags by setting the config config.infer_spec_type_from_file_location! in the spec_helper.rb. This will automatically choose the right type context based on the file location of the test.

For instan...

RSpec: Define negated matcher

You can use RSpec::Matchers.define_negated_matcher to define a negated version of an existing matcher.

This is particularly useful in composed matcher expressions or to create more expressive and meaningful matchers.

Examples

RSpec::Matchers.define_negated_matcher :not_change, :change

describe 'A negated matcher' do
  it 'can be used to chain negated changes' do
    expect { subject.maybe_change(object) }
      .to not_change(object, :attr_1)
      .and not_change(contract, :attr_2)
  end
end
RSpec::...

Caching in Rails < 6.1 may down parts of your application when using public cache control

Proxy caching is a good feature to serve your publicly visible application content faster and reduce load on your servers. It is e.g. available in nginx, but also affects proxies delivered by ISPs.

Unfortunately, there is a little problem in Rails < 6.1 when delivering responses for different MIME-types. Say you have an arbitrary route in your Rails application that is able to respond with regular HTML and JSON. By sending the specific MIME type in the Accept header, you tell the application to either return HTML (text/html) or JSON (`t...

ImageMagick: Converting SVG to raster image formats like PNG or JPEG

Conversion

ImageMagick can convert SVGs to raster image formats.

Example for PNG:

convert input.svg output.png

If the SVG has a size of 24x24 (viewBox="0 0 24 24"), the resulting PNG will also have a size of 24x24.

Resizing

An SVG's viewBox specifies the intended size, but vector image formats can be scaled freely.

Resize flag (poor results)

If you want your raster image to be larger, the naive approach would be to use the resize flag.

convert -resize 96x96 input.svg output.png

However, this resu...

The TCF 2.0 (Tranparency and Consent Framework) standard, and what you should know about it

The Interactive Advertising Bureau (IAB) is a European marketing association which has introduced a standard how advertising can be served to users in line with the General Data Protection Regulation (GDPR). This standard is called the TCF 2.0 (Transparency and Consent Framework). If you want to integrate any kind of advertising into a website, chances are the advertising network will require your website to implement that standard. This is a very brief overview of what this means:

The basic idea in the TCF 2.0 ...

Ad blockers: How to debug blocked elements

Some users might use Adblock Plus or similar browser plugins to reduce the number of ads displayed. If you run into an issue that your application or part of an application is blocked, this card will give you some guidance on how to debug it.


In general ad blocking is not an issue for most of our web apps. But if your application uses iframes or is embedded in another site it's more prone to it.

Blocked elements most of the time appear to the user as empty frames in the page. The indicator icon of the ad blocker also gives ...

ES6 imports are hoisted to the top

From Exploring ES6:

Module imports are hoisted (internally moved to the beginning of the current scope). Therefore, it doesn’t matter where you mention them in a module and the following code works without any problems:

foo();
import { foo } from 'my_module';

Footgun example

When you're not aware of import hoisting you may be surprised that your code runs in a different order than you see in the source file.

The example below is taken from the [...

Ensure passing Jasmine specs from your Ruby E2E tests

Jasmine is a great way to unit test your JavaScript components without writing an expensive end-to-end test for every small requirement.

After we integrated Jasmine into a Rails app we often add an E2E test that opens that Jasmine runner and expects all specs to pass. This way we see Jasmine failures in our regular test runs.

RSpec

In a [feature spec](https://relishapp.com/rspec/rspec-rails/docs/feature-spec...

Using feature flags to stabilize flaky E2E tests

A flaky test is a test that is often green, but sometimes red. It may only fail on some PCs, or only when the entire test suite is run.

There are many causes for flaky tests. This card focuses on a specific class of feature with heavy side effects, mostly on on the UI. Features like the following can amplify your flakiness issues by unexpectedly changing elements, causing excessive requests or other timing issues:

  • Lazy loading images
  • Autocomplete in search f...

Setup Sidekiq and Redis

If you want Sidekiq to be able to talk to Redis on staging and production servers, you need to add the following to your configuration:

# config/initializers/sidekiq.rb
require 'sidekiq'

Sidekiq.configure_client do |config|
  config.redis = { url: REDIS_URL }
end

Sidekiq.configure_server do |config|
  config.redis = { url: REDIS_URL }
end

The following step may be skipped for new Sidekiq 6+, since it isn't recommended anymore to use a global redis client.

# config/initializers/redis.rb
require 'redis'
require_relativ...

RSpec: how to prevent the Rails debug page if you want to actually test for 404s

Within development and test environments, Rails is usually configured to show a detailed debug page instead of 404s. However, there might be some cases where you expect a 404 and want to test for it.

An example would be request-specs that check authorization rules. (If you use a gem like consul for managing authorization rules, you should always check these rules via power-specs. However, request-specs can be used as a light-weight version of integration tests here.)

In this case, Rails will replace the 404 page that you want to test ...

RSpec: automatic creation of VCR cassettes

This RailsCast demonstrated a very convenient method to activate VCR for a spec by simply tagging it with :vcr.

For RSpec3 the code looks almost the same with a few minor changes. If you have the vcr and webmock gems installed, simply include:

# spec/support/vcr.rb
VCR.configure do |c|
  c.cassette_library_dir = Rails.root.join("spec", "vcr")
  c.hook_into :webmock
end

RSpec.configure do |c|
  c.around(:each, :vcr) do |example|
    name = example.metadata[:full_descripti...

RSpec: ". not_to include" behaves like ".to exclude"

RSpec is smart when using the include-matcher in combination with .not_to. One could assume that

.not_to include(3, 4, 5)

evaluates to:

NOT( .to include(3, 4, 5) )

However, it behaves like:

.to (NOT include(3) && NOT include(4) && NOT include(5) )

Warning

Using .not_to in combination with the include-matcher doesn't logically negate the final truth value. It instead negates the individual include-expectations for each argument.

Proof

describe 'RSpec' do
  it "doesn't use logical nega...

Git shortcut to rebase onto another branch

Inspired by recent "git shortcut" cards I figured it would be nice to have one of these for rebasing a few commits onto another branch. The usual notation is prone to of-by-one errors as you have to either specify the commit before the ones you want to move or count the number of commits.

You may add this rebase-onto function to your ~/.bashrc:

function rebase-onto {
  commit=$(git log --oneline | fzf --prompt 'Select the first commit y...

Event delegation (without jQuery)

Event delegation is a pattern where a container element has a single event listener that handles events for all descendants that match a CSS selector.

This pattern was popularized by jQuery that lets you do this:

$('.container').on('click', '.message', function(event) {
  console.log("A message element was clicked!")
})

This technique has some advantages:

  1. When you have many descendants, you save time by only registering a single listener.
  2. When the descendants are changed dynamic...

Capybara can find links and fields by their [aria-label]

Sometimes a link or input field has no visible label. E.g. a text field with a magnifying glass icon 🔎 and a "Search" button does not really need a visible label "Query".

For accessibility reasons it is good practice to give such a field an [aria-label] attribute:

<input type="search" aria-label="Search contacts">

This way, when a visually impaired user focuses the field, the screen reader will speak the label text ("Search contacts").

Info

Without an `[aria-...

Semantic HTML

Besides their default styling properties, HTML elements have a semantic meaning. For example, an h1 tag is usually styled with a larger font and bold, while it denotes "the single most important headline in its context".

While CSS enables us to style almost any HTML element like anything that is needed, choosing HTML elements corresponding to the meaning of their content has a few advantages:

  • HTML becomes a little clearer
  • Edge cases have already been considered and implemented:
    • Keyboard support (tabbing, arrow keys)
    • State...

Ruby: You can nest regular expressions

Ruby lets you re-use existing RegExp objects by interpolating it into new patterns:

locales_pattern = /de|en|fr|es/i

html_tag_pattern = /<html lang="#{locales_pattern}">/

Any modifiers like /i or /x will be preserved within the interpolated region, which is pretty cool. So in the example above only the interpolated locales are case-insensitive, while the pattern around it (/<html .../) remains case-sensitive.

RSpec matcher to compare two HTML fragments

The RSpec matcher tests if two HTML fragments are equivalent. Equivalency means:

  • Whitespace is ignored
  • Types of attribute quotes are irrelevant
  • Attribute order is irrelevant
  • Comments are ignored

You use it like this:

html = ...
expect(html).to match_html(<<~HTML)
  <p>
    Expected content
  </p>  
HTML

You may override options from CompareXML by passing keyword arguments after the HTML string:

html = ...
expect(html).to match_html(<<~HTML, ignore_text_nodes: true)
 ...

Rails: Removing the cucumber-rails warning when setting cache_classes to false without Spring enabled

We are using Spring in our tests for sequential test execution but not for parallel test execution. And Rails requires you to set the config.cache_classes = false if you are using Spring in tests.

With our setup, this would raise the following error in cucumber-rails for parallel test executions due to some legacy database cleaner issue.

WARNING: You have set Rails' config.cache_classes to false
    (Spring needs cache_classes set to false). This is known to cause probl...

Working on the Linux command line: How to use bookmarks for directories

Bookmarks for directories will be most helpful if you are forced to work in deeply nested projects. Then it's really helpful!

This makes use of the CDPATH variable. Similar to the PATH variable, which holds the list of directories which are searched for executables, CDPATH contains the list of directories that are available for cd. Besides the current directory (.), you can add others to that.

The trick is to add a directory for bookmarks to CDPATH.

First, create the directory with: mkdir ~/.bookmarks.

Then add the followin...

Working on the Linux command line: How to efficiently navigate up

With cd .. you can navigate one directory up from the one you are at now. If you use that a lot, consider some handy aliases.

Add the following lines to your ~/.bashrc:

alias ..="cd .."
alias ...="cd ../.."
alias ....="cd ../../.."
alias .....="cd ../../../.."
alias ......="cd ../../../../.."

you can add even more aliases, but I usually loose track after too many levels and just jump to the directly directly, e.g. using its absolute path or its bookmark (see [this card](https://makandracards.com/makandra/504947-working-on-the-li...