View
Repeats

How to tackle complex refactorings in big projects

Sometimes huge refactorings or refactoring of core concepts of your application are necessary for being able to meet new requirements or to keep your application maintainable on the long run. Here are some thoughts about how to approach such challenges.

Break it down

Try to break your refactoring down in different parts. Try to make tests green for each part of your refactoring as soon as possible and only move to the next big part if your tests are fixed. It's not a good idea to work for weeks or months and wait for ALL puzzle pieces to…

Repeats

Getter and setter functions for Javascript properties

Javascript objects can have getter and setter functions that are called when a property is read from or written to.

For example, if you'd like an object that has a virtual person.fullName attribute that dynamically composes person.firstName and person.lastName:

```
var person = {

firstName: 'Guybrush',

lastName: 'Threepwood',

get fullName() {
return this.firstName + " " + this.lastName;
},

set fullName(name) {
var parts = name.split(" ");
this.firstName = parts[0];
this.lastName = parts[1];
}

};
```…

Linked contentRepeats

Ruby: What extend and include do

All Rubyists should be familiar with the common definitions for include and extend. You include a module to add instance methods to a class and extend to add class methods. Unfortunately, this common definition isn’t entirely accurate. It fails to explain why we use instance.extend(Module) to add methods to an instance. Shouldn’t it be instance.include(Module)? To figure this out we’re going to start by discussing where methods are stored.

  • include: Adds methods from the provided Module to the object
  • extend: Calls include on the single…
Repeats

Capybara will not find links without an href attribute

Capybara will fail to find <a> tags that are missing an href attribute. This will probably happen to you every now and then on JavaScript-heavy applications.

An example would be an AngularJS application where the following HTML actually works. [1]

<a ng-click="hello()">Hello</a>

Capybara will fail to find that link, even though looking it up via the DOM shows it:

>> find_link("Hello")
Capybara::ElementNotFound: Unable to find link "Hello"

>> find("a").text
=> "Hello"

To make find_link and click_link work…

Repeats

Using ES6 without a transpiler

If your app does not need to support IE11, you can use most ES6 features without a build step. Just deliver your plain JavaScript without transpilation through Babel or TypeScript, and modern browsers will run them natively.

Features supported by all modern browsers include:

  • fat arrow functions (() => { expr })
  • let / const
  • class
  • async / await
  • Promises
  • Generators
  • Symbols
  • Rest arguments (...args)
  • Destructuring

You won't be able to use import and export, or use npm modules.

See this [ES6 compatibility mat…

Linked contentRepeats

Custom error messages in RSpec or Cucumber steps

Sometimes you have a test expectation but actually want a better error message in case of a failure. Here is how to do that.

Background

Consider this test:

User.last.should be_present

In case of an error, it will fail with a not-so-helpful error message:

expected present? to return true, got false (Spec::Expectations::ExpectationNotMetError)

Solution

That can be fixed easily. RSpec expectations allow you to pass an error message like this:

User.last.should be_present, 'Could not find a user!'

Now your test will…

Deprecated

How to overwrite and reset constants within Cucumber features

In order to save the original value of a constant, set the new value and restore the old value after a scenario was completed, you can use the following helper. It takes care of saving the old constant value, setting the new one without throwing warnings and resets the value with an After hook.

This module also enables you to introduce new global constants.
Since these newly defined constants do not have any value to be reset to,
they simply are deleted (remove_const) once the respective Cucumber step finishes.

You can copy the file at…

Upgrading Ruby from 1.8.7 to 2.3.5

Suggested Workflow

Set the ruby version in .ruby-version to 2.3.5, then perform these steps one by one, fixing errors as they occur:

1) Update gems as listed below, and bundle
2) Boot a Rails console - see below for a list of changes you will probably need
3) Run Specs with --backtrace option
4) Run Cucumber features (with Geordi's --debug option)
5) When all tests are green, look through your Gemfile and remove as many version constraints as possible.
6) Boot the application in different environements to spot further issues, e…

Repeats

Cucumber Factory: How to assign polymorphic associations

Cucumber factory supports polymorphic associations out of the box. Just keep in mind that you need to use named associations for this purpose.

class Person < ApplicationModel
  has_many :buildings, inverse_of: :owner
end

class Company < ApplicationModel
  has_many :buildings, inverse_of: :owner
end

class Building < ApplicationModel
  belongs_to :owner, optional: true, polymorphic: true
end

Works

```
Given there is a person with the name "Nice person"
And there is a buildin…

Cucumber: How to find unused step definitions

Cucumber has an output format that prints step definitions only. You can use this to find unused ones:

  1. Temporarily add require_relative 'env' to the top of the first file in features/support. --dry-run makes Cucumber skip loading env.rb.
  2. Open a really wide terminal window.
  3. bundle exec cucumber --dry-run --format stepdefs | grep -B1 'NOT MATCHED' --no-group-separator | grep features/step_definitions

This will print all unused step definitions from your project – however, the result will include false positives. Step…

How to upgrade Rails: Workflow advice

When upgrading Rails versions – especially major versions – you will run into a lot of unique issues, depending on the exact version, and depending on your app.

However, it is still possible to give some generic advice on how you want to tackle the update in principle.

How many update steps?

Besides the Rails upgrade itself, you might also want to

  • upgrade your other gems
  • upgrade your Ruby versions

First decide in how many steps you want to run the upgrade. I suggest

  • To do a separate step for each major rails versions. So, if…

How to access before/after pseudo element styles with JavaScript

Accessing pseudo elements via JavaScript or jQuery is often painful/impossible. However, accessing their styles is fairly simple.

Using getComputedStyle

First, find the element in question.

let element = document.querySelector('.my-element') // or $('.my-element').get(0) when using jQuery

Next, use JavaScript's getComputedStyle. It takes an optional 2nd argument to filter for pseudo elements.

```javascript
let style = window.getComputedStyle(element, '::before')
let color = style.getPropertyValue('background-color…

Repeats

Understanding database cleaning strategies in tests

TLDR: In tests you need to clean out the database before each example. Use :transaction where possible. Use :deletion for Selenium features or when you have a lot of MyISAM tables.

Understanding database cleaning

You want to clean out your test database after each test, so the next test can start from a blank database. To do so you have three options:

  • Wrap each test in a transaction which is rolled back when you're done (through DatabaseCleaner.strategy = :transaction or `config.use_transactional_fi…
Linked contentRepeats

cucumber_factory 1.14 lets you set array fields, has_many associations, numbers without quotes

Setting array columns

When using PostgreSQL array columns, you can set an array attribute to a value with square brackets:

Given there is a movie with the tags ["comedy", "drama" and "action"]

Setting has_many associations

You can set has_many associations by referring to multiple named records in square brackets:

```
Given there is a movie with the title "Sunshine"
And there is a movie with the title "Limitles…

Linked contentRepeats

Ruby's percent notation can do more than strings

Percent Notation

We already know that that we can create strings using the percent notation:

%{<foo="bar's ton">} is perfectly fine Ruby.

Modifier

But there is more. The curly brackets ({}) are interchangable with most unicode characters (e.g. square brackets[]).
Furthermore, you can add a "modifier" to the percent notation to control the return type of th…

Linked contentRepeats

Bash: Build and execute command lines on the fly with "xargs"

xargs is a powerful bash tool that can take input from $STDIN and pass it to a given command. I.e. you can do the following:

$> cat tmp/parallel_cucumber_failures.log
features/authentication.feature:33
features/backend/pages.feature:5
features/backend/pages.feature:60

$> cat tmp/parallel_cucumber_failures.log | xargs geordi cucumber
# Running features
> Only: features/authentication.feature:33 features/backend/pages.feature:5 features/backend/pages.feature:60
...

How to: Run geordi in a single proccess with parallel test setup

Geordi uses parallel_tests if available for running the test suite. To debug an application it is very unhandy to have multiple processes as your terminal I/O will not work as expected once a breakpoint is hit.

Even parallel_tests support an option to enable a single process run, it is not possible to pass this option through geordi. But you can set the number of processes via ENV variable manually:

```
PARALLEL_TEST_PROCESSORS=1 bundle exec geordi cucu…

Repeats

When defining methods in specs, you can super into previous definitions

When you def methods in RSpec tests, you can use super to call a method definition that was created in a surrounding describe/context block.

Example:

describe User do

  def build_user(attributes = {})
    User.new(attributes)
  end

  describe '#my_method' do
    it 'does something' do
      # ...
    end

    context 'when the user has an e-mail address' do
      def build_user(attributes = {})
        super({ email: 'user@example.com' }.merge(attributes))
      end

      it 'd...
This website uses cookies to improve usability and analyze traffic.
Accept or learn more