Rspec: around(:all) and around(:each) hook execution order
Background
-
before(:all)
runs the block once before all of the examples. -
before(:each)
runs the block once before each of your specs.
Summary
-
around(:suite)
does not exist. -
around(:all)
runs afterbefore(:all)
and beforeafter(:all)
. -
around(:each)
runs beforebefore(:each)
and afterafter(:each)
.
As this is not 100% obvious (and not yet documented) it is written down in this card. In RSpec 3 :each
has the alias :example
and :all
the alias :context
.
Example
RSpec.configure do |config|
...
Vagrant: create entry for box in .ssh/config
If you want to ssh into your vagrant box without switching into the project directory and typing vagrant ssh
, you can also create an entry directly in ~/.ssh/config
. This will allow you to use ssh <my-box>
from anywhere. Simply paste the information provided by vagrant ssh-config
to your ~/.ssh/config
-File: vagrant ssh-config >> ~/.ssh/config
Example:
$ vagrant ssh-config
Host foobar-dev
HostName 127.0.0.1
User vagrant
Port 2200
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
Id...
How to mount a legacy database to migrate data
There are many approaches out there how you can import data from a legacy application to a new application. Here is an approach which opens two database connections and uses active record for the legacy system, too:
1. Add you database information to you config/database.yml
.
data_migration:
database: your_application_data_migration
2. Create a separate application record for the data migration, e.g. in app/data_migration/migration_record.rb
. You will need to create an app/data_migration.rb
class first.
class DataMig...
Understanding Scope in Ruby
Scope is all about where something is visible. It’s all about what (variables, constants, methods) is available to you at a given moment. If you understand scope well enough, you should be able to point at any line of your Ruby program and tell which variables are available in that context, and more importantly, which ones are not.
The article gives detailed explanation on the variable scope in ruby with examples that are easy to understand. Every ruby developer should at least know the first part of the article by heart. The second half ...
JavaScript: Polyfill native Promise API with jQuery Deferreds
You should prefer native promises to jQuery's Deferreds. Native promises are much faster than their jQuery equivalent.
Native promises are supported on all browsers except IE <=11, Android <= 4.4 and iOS <= 7.
If you need Promise
support for these old browsers y...
JavaScript: How to query the state of a Promise
Native promises have no methods to inspect their state.
You can use the promiseState
function below to check whether a promise is fulfilled, rejected or still pending:
promiseState(promise, function(state) {
// `state` now either "pending", "fulfilled" or "rejected"
});
Note that the callback passed to promiseState
will be called asynchronously in the next [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/...
How to use a local gem in your Gemfile
You can use local copies of gems in your Gemfile
like this:
gem 'spreewald', path: '~/gems/spreewald'
As soon as you have bundled your project with the local copy of the gem, all code changes in the copy will be available on your project. So you can for example set a debugger or add console output in the gem and use it from your project.
If you checked out the gem with your versioning tool, you can easily reset your changes afterwards or make a pull request for the gem if you improved it.
Don't commit a Gemfile with local path...
IRB: last return value
In the ruby shell (IRB) and rails console the return value of the previous command is saved in _
(underscore). This might come in handy if you forgot to save the value to a variable and further want to use it.
Example:
irb(main):001:0> 1 + 2
=> 3
irb(main):002:0> _
=> 3
irb(main):003:0> a = _
=> 3
RSpec's hash_including matcher does not support nesting
You can not use the hash_including
argument matcher with a nested hash:
describe 'user' do
let(:user) { {id: 1, name: 'Foo', thread: {id: 1, title: 'Bar'} }
it do
expect(user).to match(
hash_including(
id: 1, thread: {id: 1}
)
)
end
end
The example will fail and returns a not very helpful error message:
expected {:id => 1, :name => "Foo", :thread => {:id => 1, :title => "Bar"}} to...
Selenium cannot obtain stable Firefox connection
When using geordi for integration tests you might get the following error when trying to run geordi cucumber
:
unable to obtain stable firefox connection in 60 seconds (127.0.0.1:7055) (Selenium::WebDriver::Error::WebDriverError)
This means, that the vnc window the tests is talking to has no proper firefox version running. To figure out the issue this might help you:
- Check if the
.firefox-version
(e.g.24.0
) is the same as~/bin/firefoxes/24.0/firefox
says in the browser - Maybe [rest...
Ubuntu: Share internet connections with other computers
You can configure a Ubuntu system as a gateway in order to share it's internet connection (maybe via WLAN or tethering) with other computers on the network.
On the gateway
- Enable ip traffic forwarding:
-
Open
/etc/sysctl.conf
-
Uncomment the line
net.ipv4.ip_forward=1
-
Reload using
sudo sysctl -p /etc/sysctl.conf
-
- Reconfigure ip_tables to allow NAT:
- Download the attached file
- Replace
online_device
with the name of the network device that provides the internet connection
...
Capistrano: Doing things on rollback
Capistrano has the concept of a "rollback" that comes in really handy in case of errors. When you notice that your recent deploy was faulty, run cap deploy:rollback
and you're back with the previous release. In case of an error during a deployment, Capistrano will rollback itself.
But, you may ask, how can it know how to revert all the custom stuff I'm doing during deployment? It can't. But you can tell it how to.
Capistrano 3
Deploy and rollback are nearly identi...
How to make Webpacker compile once for parallel tests, and only if necessary
Webpack is the future. We're using it in our latest Rails applications.
For tests, we want to compile assets like for production.
For parallel tests, we want to avoid 8 workers compiling the same files at the same time.
When assets did not change, we do not want to spend time compiling them.
Here is our solution for all that.
Its concept should work for all test suites.
Copy the following to config/initializers/webpacker_compile_once.rb
. It will patch Webpacker, but only for the test
environment:
# Avoid hardcoded asset host...
Cucumber: Test that an element is not overshadowed by another element
I needed to make sure that an element is visible and not overshadowed by an element that has a higher z-index
(like a modal overlay).
Here is the step I wanted:
Then the very important notice should not be overshadowed by another element
This is the step definition:
Then(/^(.*?) should not be overshadowed by another element$/) do |locator|
selector = selector_for(locator)
expect(page).to have_css(selector)
js = <<-JS
var selector = #{selector.to_json};
var elementFromSelector = document.querySelector(selector)...
Ruby: define a class with Struct.new
This card will show you a cool way to define a class using Struct.new.
A common usecase for Structs are temporary data structures which just hold state and don't provide behaviour. In many cases you could use a simple hash as a data structure instead. However, a Struct provides you with a nice constructor, attribute accessors and complains if you try to access undefined attributes. Structs are easy to compare (by attributes). A struct gives meaning to the data.
Disclaimer
Structs are great...
How to: Rails cache for individual rspec tests
Rails default config uses the ActiveSupport::Cache::NullStore
and disables controller caching for all environments except production:
config.action_controller.perform_caching = false
config.cache_store = :null_store
If you want to test caching you have at least two possibilities:
- Enable caching for every test (not covered by this card and straightforward)
- Enable caching for individual test
Enable caching for individual test (file cache)
1. Leave the defau...
Shoulda Matchers: how to test conditional validations
Shoulda Matchers don't provide canditional validations (validations with if:
option). Here is how to write tests for the condition:
Class:
class Employee < ActiveRecored::Base
validates :office, presence: true, if: manager?
def manager?
...
end
end
Test:
describe Employee do
describe '#office' do
context 'is a manager' do
before { allow(subject).to receive(:manager?).and_return(true) }
it { is_expected.to validate_presence_o...
MySQL 5.7.5 enables `ONLY_FULL_GROUP_BY` mode per default
When using GROUP BY
, MySQL now complains if the SELECT
includes columns which are not part of the GROUP BY
.
Reason:
There could be multiple values for those columns per group but only one value can be picked for the results.
The default behaviour of MySQL prior to version 5.7 will not complain and arbitrarily choose a value. But this leads to non-deterministic results. So MySQL now has enabled the only_full_group_by
setting by default to prevent this.
In Rails this could lead to some trouble, because scopes do not have sp...
Rails: How to write custom email interceptors
Nowadays it is fairly easy to intercept and modify mails globally before they are sent. All you have to do is register an interceptor class which responds to .delivering_email(message)
. This card will show you two common use cases.
Subject prefix:
Usually you want to prefix the subject line of emails with the current environment (except production) so you can differentiate between production mails and mails from other environments. Of course a...
Capistrano 2: How to deploy a single server
When you have a multi-server setup, you'll be adding a new server from time to time. Before doing a full deploy, you might want to test that server in an isolated deploy. There is a single way to do this: the HOSTFILTER
env variable.
Commenting out "server" lines in the Capistrano deploy config will raise a Capistrano::NoMatchingServersError
with <task> is only run for servers matching {:roles=> <role>}, but no servers matched
. Instead, specify the server-under-test like this:
HOSTFILTER=separate-sidekiq.makandra.de cap productio...
Working with or without time zones in Rails applications
Rails supports time zones, but there are several pitfalls. Most importantly because Time.now
and Time.current
are completely different things and code from gems might use one or the other.
Especially configuring an application that cares only about one time zone is a bit tricky.
The following was tested on Rails 5.1 but should apply to Rails 4.2 as well.
Using only local time
Your life will be easier if your application does not need to support time zones. Disable them like this:
config.time_zone = 'Berlin' # Your local ...
How to define height of a div as percentage of its variable width
This is useful if, for example, you want to use a background-image that has to scale with the width and the div should only have the height of the picture.
html:
<div class="outer">
<div class="inner">
</div>
</div>
css:
.outer {
width: 100%;
background-image: image-url('background.png');
background-size: cover;
}
.inner {
padding-top: 60%;
}
How does it work?
There are several CSS attributes that can handle values as percentage. But they use different other attributes as "reference value...
Git: rebase dependent feature branch after squash
This card will show you how to use git rebase --onto
without confusion.
Use case:
You've got two feature branches (one
and two
), where two
depends on one
. Now commits of branch one
have changed after you branched two
from it (i.e. after code review the commits of branch one
are squashed). Thus the commit history of branch one
has changed. Branch two
's history however didn't change.
Solution:
To make the branches share the same commit history again you will have to rebase and replay (attach) the a...
Webmock's hash_including doesn't parse query values to string
Webmocks hash_including
is similar to RSpec::Mocks::ArgumentMatchers#hash_including
. Be aware that hash_including
(webmock v3.0.1) doesn't parse integer values to String.
Without hash including you would say:
uri = URI('http://example.com/?foo=1&bar=2')
stub_request(:get, 'example.com').with(query: {foo: 1, bar: 2})
Net::HTTP.get(uri) # ===> Success
If you only want to check if foo
is present you can use hash_including
:
uri = URI('http://example.com/?foo=1&bar=2')
stub_request(:get, 'example.com').with(query: hash_i...