Geordi 1.2 released
Changes:
-
Remove some old binaries (commands still exist in
geordi
) and mark others as deprecated -
Rewrite deploy command to support most deploy scenarios:
- master to production
- feature branch to staging
- master to staging or production to production (plain deploy)
- Improve Cucumber command (fixes #18):
- Fix pass-through of unknown options to Cucumber
- Add --rerun=N option to rerun failed Cucumber tests up to N times. Reboots the test environment between runs, thus will pick up fixes you made durin...
Gemspecs must not list the same gem as both runtime and development dependency
When you're developing a gem, never list the same dependency as both runtime and development dependency in your .gemspec
.
So don't do this:
spec.add_dependency 'activesupport'
spec.add_development_dependency 'activesupport', '~> 2.3'
If you do this, your gemspec will not validate and modern versions of Bundler will silently ignore it. This leads to errors like:
Could not find your-gem-0.1.2 in any of the sources
What to do instead
If you want to freeze a different version of a dependency for your t...
SSHKit 1.9.0 failure for Capistrano deploy
SSHKit 1.9.0 might fail with the following error, when trying to deploy a Rail application. Upgrading the gem to version 1.21.0 fixed the issue.
Traceback (most recent call last):
17: from /home/user/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/sshkit-1.9.0/lib/sshkit/runners/parallel.rb:12:in `block (2 levels) in execute'
16: from /home/user/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/sshkit-1.9.0/lib/sshkit/backends/abstract.rb:29:in `run'
15: from /home/user/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/sshkit-1.9....
Migrating to Spreewald
This describes how to migrate an existing cucumber test suite to Spreewald.
-
Add the gem
-
Include spreewald into your cucumber environment by putting
require 'spreewald/web_steps'
require 'spreewald/email_steps'
# ...
or just
require 'spreewald/all_steps'
into yoursupport/env.rb
. -
Look through your step definitions for everything that might be included in Spreewald. Candidates are
web_steps
,shared_steps
,table_steps
, `em...
Resolving Element cannot be scrolled into view (Selenium::WebDriver::Error::MoveTargetOutOfBoundsError) on Mavericks
After I upgraded to Mac OS X Mavericks, I regularly got this error message when running Cucumber features with Selenium:
Element cannot be scrolled into view:[object XrayWrapper [object HTMLInputElement]] (Selenium::WebDriver::Error::MoveTargetOutOfBoundsError)
I had the Terminal window running the test on my secondary screen, whereas the Selenium-webdriven Firefox always started on my primary one. Now if I had focused the secondary screen when running the tests, Selenium could not start Firefox and switch to it (probably because t...
makandra/capybara-lockstep
capybara-lockstep can help you with flaky end-to-end tests:
This Ruby gem synchronizes Capybara commands with client-side JavaScript and AJAX requests. This greatly improves the stability of a full-stack integration test suite, even if that suite has timing issues.
Silence specific deprecation warnings in Rails 3+
Sometimes you're getting an ActiveSupport deprecation warning that you cannot or don't want to fix. In these cases, it might be okay to silence some specific warnings. Add this to your initializers, or require it in your tests:
silenced = [
/Not considered a useful test/,
/use: should(_not)? have_sent_email/,
] # list of warnings you want to silence
silenced_expr = Regexp.new(silenced.join('|'))
ActiveSupport::Deprecation.behavior = lambda do |msg, stack|
unless msg =~ silenced_expr
ActiveSupport::Deprecation::DEFAULT_BEHAVI...
How to silence thin boot messages
Each time thin
boots, it prints a boot message :
Thin web server (v1.6.3 codename Protein Powder)
Maximum connections set to 1024
Listening on localhost:36309, CTRL+C to stop
If you are running parallel tests with thin
, this will clutter you output. Disable thin
logging with these lines:
# e.g. in features/support/thin.rb
require 'thin'
Thin::Logging.silent = true
Note that this disables all logging in tests. Instead, you also might set a different logger with `Thin::Loggi...
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...
Compare two jQuery objects for equality
Every time you call $(...)
jQuery will create a new object. Because of this, comparing two jQuery collections with ==
will never return true, even when they are wrapping the same native DOM elements:
$('body') == $('body') // false
In order to test if two jQuery objects refer to the same native DOM elements, use is
:
var $a = $('body');
var $b = $('body');
$a.is($b); // true
Jasmine equality matcher for jQuery
See [here](/makandra/34925-jasmine-testing-complex-types-for-e...
PostgreSQL's OVERLAPS operator is not fully inclusive
PostgreSQL supports the SQL OVERLAPS
operator. You can use it to test if two date ranges overlap:
=> SELECT ('2001-02-16'::date, '2001-12-21'::date) OVERLAPS
('2001-12-20'::date, '2002-10-30'::date);
overlaps
--------
true
An important caveat is that the date ranges are defined as start <= time < end
. As such the later date is not included in the range:
=> SELECT ('2001-02-16'::date, '2001-12-21'::date) OVERLAPS
('2001-12-21'::date, '2002-10-30'::date);
overlaps
--------
false
Also compar...
Testing terminal output with RSpec
When testing Ruby code that prints something to the terminal, you can test that output.
Since RSpec 3.0 there is a very convenient way to do that.
Anything that writes to stdout (like puts
or print
) can be captured like this:
expect { something }.to output("hello\n").to_stdout
Testing stderr works in a similar fashion:
expect { something }.to output("something went wrogn\n").to_stderr
Hint: Use heredoc to test multi-line output.
expect { something }.to output(<<-MESSAGE.strip_heredoc).to_stdout...
Selenium: Network throttling via Chromedriver
You can throttle the network in your headless chrome via Selenium. This might be useful for debugging issues with flaky integration tests or slow page simulations.
page.driver.browser.network_conditions = {offline: false, latency: 5, download_throughput: 2 * 1024, upload_throughput: 2 * 1024}
The settings will match to the following UI component in Chrome:
Were the values for the default profiles might match the values from this post:
**S...
Rails: Parsing a time in a desired timezone
Sometimes you want to have a time in a given timezone independent from you Rails timezone settings / system timezone. I usually have this use case in tests.
Example
Time.parse('2020-08-09 00:00')
will return different results e.g. 2020-08-09 00:00:00 +0200
depending on the Rails timezone settings / system timezone. But in this example we always want to have the given time in UTC because that's what the API returns.
it 'returns a valid API response', vcr: true do
expect(client.get('/users/1')).to have_attributes(
name: 'So...
Usage of RSpec's raise_error
Never use raise_error
without specifying the Error you expect.
expect { do_a_lot_of_complicated_stuff }.to raise_error
will be green if you make any error in programming. E.g. a simple typo would make the test above green. The block will catch the Spec::
exception and the test will be happy.
Be sure to always have custom errors in your models and raise them in a manner that lets you know what went wrong.
expect { execute_payment! }.to raise_error(PayPal...
How to communicate between processes in Ruby with sockets
In Ruby you can communicate between processes with sockets. This might be helpful in tests that validate parallel executions or custom finalization logic after the garbage collector. Here is an example how such an communication will look like:
require 'socket'
BUFFER_SIZE = 1024
# DGRAM has the advantage that it stops reading the pipe if the next messages starts. In case the message size is larger than the
# BUFFER_SIZE, you need to handle if you are reading another part of the current message or if you already reading the
# next mess...
Katapult 0.3.0 released
Katapult 0.3.0 brings Rails 5 and Ruby 2.5 support with a new design, plus a ton of smaller features, fixes and improvements.
Features
- Generating a Rails 5.1.4 app on Ruby 2.5.0
- Dropped asset pipeline in favor of Webpacker
- The generated application now has a sleek, simple design based on Bootstrap
- Employing Unpoly
- New application model DSL shortcut
crud
for "create a model and a web UI with crud actions" - The generated application model is now a transformable e...
Undefined method log for Selenium::WebDriver::Remote::W3C::Bridge
In case your integration tests crash with a message like below, try to upgrade Capybara to a newer version (3.35.3 was good enough). You might encounter this issue when you enabled the w3c option in Selenium.
undefined method `log' for #<Selenium::WebDriver::Remote::W3C::Bridge:0x000055995647ded0>
Your affected code might look similar to this call below and will work after the upgrade again.
Setup your terminal to not scroll when there is new output
When you are scrolling up to investigate a test failure it is super annoying when the terminal scrolls back down whenever the running test outputs another line. Luckily you can disable this behavior:
- Gnome terminal: *Edit -> Profile preferences -> Scrolling", uncheck Scroll on output
- Terminator: Right click on terminal screen, Preferences -> Profile -> (for each profile) -> Scrolling, uncheck Scroll on output
Rails 3/4: How to add routes for specs only
If you want to have routes that are only available in tests (e.g. for testing obscure redirects), you can use the with_routing
helper -- but that one destroys existing routes which may break a specs that require them to work.
To keep both "regular" and test routes, do this:
class MyApplicationController < ActionController::Base
def show
render text: 'Welcome to my application'
end
end
test_routes = Proc.new do
get '/my_application' => 'my_application#show'
end
Rails.application.routes.ev...
GitHub Actions: Manually running a workflow
To start a workflow manually it must have a trigger called workflow_dispatch
:
---
name: Tests
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
branches:
- master
In the Actions tab of your repo you can now select a workflow and press "Run Workflow".
How to check if a file is a human readable text file
Ruby's File class has a handy method binary?
which checks whether a file is a binary file. This method might be telling the truth most of the time. But sometimes it doesn't, and that's what causes pain. The method is defined as follows:
# Returns whether or not +file+ is a binary file. Note that this is
# not guaranteed to be 100% accurate. It performs a "best guess" based
# on a simple test of the first +File.blksize+ characters.
#
# Example:
#
# File.binary?('somefile.exe') # => true
# File.binary?('somefile.txt') # => fal...
The Bark Blog » Testing Rails Model Plugins
Unfortunately, by default plugin tests are pretty bland. They use the plain unit test suite supplied by Ruby, and not any of the extended Rails test framework. This will leave our plugin’s test classes with no access to fixtures, database.yml configuration, or any of those nice class auto-loading features.
Testing for XSS in Markdown Fields
If you render markdown from user input, an attacker might be able to use this to inject javascript code into the source code of your page.
The linked github page is a collection of common markdown XSS payloads which is handy for writing tests.
Producing arbitrary links:
[Basic](javascript:alert('Basic'))
[Local Storage](javascript:alert(JSON.stringify(localStorage)))
[CaseInsensitive](JaVaScRiPt:alert('CaseInsensitive'))
[URL](javascript://www.google.com%0Aalert('URL'))
[In Quotes]('javascript:alert("InQuotes")')