How to make changes to a Ruby gem (as a Rails developer)
At makandra, we've built a few gems over the years. Some of these are quite popular: spreewald (> 1M downloads), active_type (> 1M downloads), and geordi (> 200k downloads)
Developing a Ruby gem is different from developing Rails applications, with the biggest difference: there is no Rails. This means:
- no defined structure (neither for code nor directories)
- no autoloading of classes, i.e. you need to
requireall files yourself - no
active_supportniceties
Also, their scope...
How to fill in multiple lines in a textarea with cucumber
If you want to fill in textareas with multiple lines of text (containing line breaks / new lines) you can use Cucumber's docstrings:
And I fill in "Comment" with:
"""
This is a long comment.
With multiple lines.
And paragraphs.
"""
The step definition is part of the spreewald gem
Minimal JavaScript function to detect version of Internet Explorer or Edge
If possible your code should detect features, not browsers. But sometimes you just need to sniff the browser. And when you do, you're probably fighting a Microsoft product.
The following function returns a Number like 10, 11, 12, 13 for Internet Explorer or Edge (anything above 11 is Edge). It returns undefined for any other browser.
function ieVersion(uaString) {
uaString = uaString || navigator.userAgent;
var match = /\...
Designing HTML emails
The 90s are calling: they want their tables back. Unfortunately, you need them all for laying out your HTML emails.
Email client HTML rendering is way more scattered than browser HTML. While you might have a pretty good understanding of what features and patterns you can use to support all major browsers, I doubt anyone masters this craft for HTML email clients.
The only way to ensure your email looks good (acceptable, at least) in all mail clients, is to check it. Litmus is your go-to solution for this (see below). W...
RSpec: Expect one of multiple matchers to match
RSpec let's you chain a matcher with .or. The expectation will then pass if at least one matcher matches:
expect(color).to eq("red").or eq("green")
Real-world example
A real-world use case would be to test if the current page has a button with the label "Foo". There are many ways to render a button with CSS:
<input type="button" value="Foo">
<input type="submit" value="Foo">
<button>Foo</button>
We cannot express it with a single have_css() matcher, since we need the { text: 'Foo' } optio...
CSS: Using the current text color for other color properties
There is a kinda secret, yet well supported CSS feature called currentColor. It's like a special CSS variable that has been supported in almost all browsers for almost all time (see linked Caniuse).
Usage
The currentColor value can be used in CSS to indicate the current value of color should be used. A common use case is setting a border color:
a.ghost
color: white
border: 1px solid currentColor
&:hover
color: red // Border color will change as well
Note that in many cases, you can simply omit the color to ac...
Jasmine: Adding custom matchers
Definition
A matcher is a function that returns an object with a compare key. Usually it is registered with beforeEach:
beforeEach(() => {
jasmine.addMatchers({
// Example matcher
toBeAnything() {
return {
compare(actualValue, ...matcherArguments) {
// Do some computations here ...
// Return whether the actualValue matches the expectation
return {pass: true}
}
}
}
})
})
Usage
expect(actualValue).toBeAnything(...matcherArg...
Webpacker: Configuring browser compatibility
Webpacker uses Babel and Webpack to transpile modern JavaScript down to EcmaScript 5. Depending on what browser a project needs to support, the final Webpack output needs to be different. E.g. when we need to support IE11 we can rely on fewer JavaScript features. Hence our output will be more verbose than when we only need support modern browsers.
Rails 5.1+ projects often use Webpacker to preconfigure the Webpack pipeline for us. The default configuration works something like this:
- Webpack checks w...
RubyMine: You can disable inspections you don't care about
When you find yourself constantly ignoring a RubyMine warning, you can simple disable that warning and de-clutter your editor. E.g. in my Cucumber scenarios RubyMine underlines 90% of all lines because it does not know about spreewald, making the file really hard to read.
You can disable any unwanted inspection by opening File / Settings / Editor / Inspections and searching for the warning text.
What you disable or keep is up to your personal preference. I personally disable at least the following...
Geordi 1.9 released
New features:
geordi delete_dumps [directory]
Recursively search for files ending in *.dump and offer to delete those. When no argument is given, two default directories are searched for dump files: the current working directory and ~/dumps (for dumps created with geordi).
geordi drop_databases
Delete local MySQL/MariaDB and Postgres databases that are not whitelisted.
Authentication is handled via PAM for Postgres and MariaDB, via .my.cnf with fallback to mysql -p for MySQL. Different connection methods can be chosen via ...
Upgrading a Rails app to Cucumber 3
Upgrade gems
You need to update a lof gems. Make sure you don't have any version constraints in your Gemfile or your bundle update won't do anything!
Upgrade cucumber_priority:
bundle update cucumber_priority
Upgrade spreewald:
bundle update spreewald
Upgrade cucumber_factory:
bundle update cucumber_factory
Upgrade parallel_tests:
bundle update parallel_tests
Even on the latest version, parallel_tests will print some deprecation warnings due to using an older formatter A...
VNC browser disappears while typing
We often use the Then console step from spreewald in combination with geordi vnc from geordi to debug tests within a real browser. Sometimes when you type in the browser it suddenly disappears. You will only see a grey screen then.
This will always happen if you press the d key. Press the d key again and the browser will appear again.
Nested Spreewald patiently blocks are now patient
In Spreewald 1.10.4+, nested patiently blocks are now patient.
Here is an example:
patiently do
outer_code
patiently do
inner_code
end
end
On spreewald 1.11.2+ the inner block will wait for the full configured wait time (by default 5 seconds). The outer patiently block would now be out of time, but it will always be retried at least a second time. This behavior allows with_scope to be patient, and it must be patient, as explained below.
In versions 1.10.4 - 1.11.1, inner blocks would keep giving the ou...
How to: Solve gem loaded specs mutex
Use bundler > 1.15 to fix Gem::LOADED_SPECS_MUTEX (NameError).
Given the following project:
ruby -v
ruby 1.8.7
bundler -v
Bundler version 1.13.7
gem -v
1.8.30
rails -v
Rails 3.2.22.1
Running specs or features resulted in:
uninitialized constant Gem::LOADED_SPECS_MUTEX (NameError)
The previous settings described in Maximum version of Rubygems and Bundler for Ruby 1.8.7 and Rails 2.3 (even the rails version was rails 3.2 and not 2.3) seems not to work here, so I used (also described in the ca...
How to control Chromedriver using curl
Here is how to use Chromedriver without libraries like selenium-webdriver. This can be useful for debugging.
The following example visits a web page and reads the a headline's text contents.
-
Create a session. You will get a JSON response containing lots of information about your Chrome session, including a
sessionId. Use that to send any future commands to your chromedriver session.$ curl -XPOST http://localhost:9515/session -d '{"desiredCapabilities":{"browserName":"chrome"}}' {"sessionId":"your-session-id-here","sta...
Katapult 0.4.0 released
Features
- Generating a project README
- Finally: Support for modelling associations between models in your application model! Example:
# lib/katapult/application_model.rb
model 'Cart' do |cart|
cart.belongs_to 'User'
end
crud 'User' do |user|
user.attr :fullname
end
Cucumber: How to avoid VCR errors for unused requests in pending tests
When you have a pending Cucumber step (or feature) that also uses an existing VCR cassette, your pending test may fail at the very end with an error like this:
There are unused HTTP interactions left in the cassette:
- [get ...] => [200 ...]
- [get ...] => [200 ...] (VCR::Errors::UnusedHTTPInteractionError)
The error happens because your VCR is configured to complain about cassettes that contain extra requests which your test did not use. This is often a good configuration.
If you do not want to change your whole test suite...
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
crudfor "create a model and a web UI with crud actions" - The generated application model is now a transformable e...
Capybara: A step for finding images with filename and extension
This cucumber step is useful for testing an image (looking at the src of the image).
Then(/^I should see the image "([^"]*)"$/) do |filename_with_extension|
expect(page).to have_css("img[src*='#{filename_with_extension}']")
end
Then I should see the image "placeholder.png"
Outline: Read more about how to test a uploaded file here, e.g. file downloads.
Form letters with LibreOffice Writer
This is painful. Consider using Microsoft Office or switching careers. If you need to write < 20 letters consider doing it manually.
So you didn't listen and here it comes:
- Ignore the Mail Merge Wizard. It will crash or destroy your document.
- Export your addresses, recipient names, etc. as a
.odsspreadsheet (.xls,.xlsx,.ods). Use any columns that work for you, but be consistent. I like to use one column for the address, one column for the salutation line. - Import the spreadsheet as an address book source: *Tools => Add...
Error during Rails 5 upgrade: Environment data not found in the schema
This error is raised because your old database does not have a configured environment yet, which Rails 5 enforces.
If this error occurs while migrating your parallel test databases, make sure to update the parallel_tests gem first: current versions fix this. If you're still using Cucumber < v3, the latest version of parallel_tests will be 2.18.0.
HTML: Making browsers wrap long words
By default, browsers will not wrap text at syllable boundaries. Text is wrapped at word boundaries only.
This card explains some options to make browsers wrap inside a long word like "Donaudampfschifffahrt".
Option 1: hyphens CSS property (preferred)
Modern browsers can hyphenate natively. Use the hyphens CSS property:
hyphens: auto
There is also hyphens: none (disable hyphenations even at ­ entities) and hyphens: manual (hy...
xlsxtream: Streaming & Fast XLSX Spreadsheet Writer for Ruby
When writing XLSX files, there are gems like rubyXL or axlsx. While they do offer features like formatting or graphs, to represent spreadsheet cells, they have to keep several Ruby objects in memory. When writing huge files, both will become slow and consume lots of memory.
Enter Xlsxtream, a Ruby XLSX library with less features (e.g. no individual cell styles) but which does away with the memory issue by streaming ...
chromedriver-helper gem in Gemfile might break you selenium tests (of other projects)
Summary: Don't add chromedriver-helper to the Gemfile
- the executables might break your tests in projects where
chromedriver-helperis not in the Gemfile - developers with different chrome versions will have problems using the same
chromedriver-helperversion
Background
If you install the chromedriver-helper gem, but don't have it in you Gemfile, your selenium tests might fail with:
Selenium::WebDriver::Error::WebDriverError: unable to connect to chromedriver 127.0.0.1:9515
The reason is that chromedriver-helper ov...