HTTPie nice command line HTTP client
HTTPie consists of a single http command designed for painless debugging and interaction with HTTP servers, RESTful APIs, and web services
It easy to use and has very nice defaults and coloured output which makes it good for local testing.
Usage examples with curl equivalent:
# curl post
curl --data "foo=23&bar=42" https://example.org/blub
# httpie post
http https://example.org/blub foo=23 bar=42
# curl localhost
curl localhost:3000/users
# httpie localhost
http :3000/users
PostgreSQL: WITH Queries (Common Table Expressions)
PostgreSQL's Common Table Expressions (CTEs) can be used to extract sub-queries from bulky SQL statements into a temporary table to be referenced instead.
This is most useful to avoid ugly joins or sub-selects. CTEs can be used for SELECT
, INSERT
, UPDATE
or DELETE
.
Example (from the PostgreSQL docs):
WITH regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
), top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (SE...
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...
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-helper
is not in the Gemfile - developers with different chrome versions will have problems using the same
chromedriver-helper
version
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...
Cucumber: Identifying slow steps that drag down your test speed
In most projects I know, Cucumber test suite speed is not an issue. Of course, running 350 features takes its time, but still each test for itself is reasonably fast. There is nothing you can do to fundamentally speed up such a test (of course, you should be using parallel_tests).
However, in projects that go beyond clicking around in a web GUI and checking results, there might be various measures to speed things up. Katapult tests for example could be sped up more than 4 times by re...
Turning off VCR when stubbing with Webmock
Sometimes when working with VCR you still want to use webmock. Since VCR hooks into webmock and fails when an unknown request is happening, you have to turn it off in order to use webmock like you are used to. Here is how to do this in rspec.
RSpec.configure do |config|
config.around do | example |
if example.metadata[:turn_off_vcr]
VCR.turn_off!
example.run
VCR.turn_on!
else
example.run
end
end
end
Rails + Sidekiq::Web: Configuration for wildcard session cookies
When you're using Sidekiq::Web
to monitor the Sidekiq status AND have your session cookie configured to a wildcard domain like .example.com
, you need to take an additional step to keep your cookies valid.
Issue
Sidekiq::Web
is mounted into your Rails application and will use the Rails session cookie for protection from CSRF attacs. While it somehow figures out the cookie name, it does NOT respect cookie configuration like a custo...
Webservice to test and inspect requests
Requestb.in is a webservice that gives you a temporary URL you can use to test request. The page will automatically record and display the latest web request made to it.
How to install packages from newer Ubuntu releases
We're usually running Ubuntu LTS versions. Sometimes newer hardware requires packages from more recent Ubuntu releases that only come with 6 months of support. If there is really no other way, it's possible to install packages from later Ubuntu releases
Caution: Pay really close attention to what you're doing. Depending on the package, this process may require upgrading a lot of dependencies, possibly breaking the system! You really should not do this unless you've carefully calculated the impact on your system
Preparation
First,...
JavaScript: Testing the type of a value
Checking if a JavaScript value is of a given type can be very confusing:
- There are two operators
typeof
andinstanceof
which work very differently. - JavaScript has some primitive types, like string literals, that are not objects (as opposed to Ruby, where every value is an object).
- Some values are sometimes a primitive value (e.g.
"foo"
) and sometimes an object (new String("foo")
) and each form requires different checks - There are three different types for
null
(null
,undefined
andNaN
) and each has different rules for...
RSpec: Run a single spec (Example or ExampleGroup)
RSpec allows you to mark a single Example/ExampleGroup so that only this will be run. This is very useful when using a test runner like guard.
Add the following config to spec/spec_helper.rb
:
RSpec.configure do |config|
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run_including :focus => true
config.run_all_when_everything_filtere...
Capybara: Accessing the parent of an element
If you already selected an element and want to get its parent, you can call find(:xpath, '..')
on it.
To get the grand-parent element, call find(:xpath, '../..')
.
Example
Find a link which contains a twitter icon and check that it links to the correct page:
<a href="http://twitter.com/">
<i class="icon is-twitter"></i>
</a>
link = page.find("a .icon.is-twitter").find(:xpath, '..')
expect(link[:href]).to eq("http://twitter.com/")
About XPath
There is a good overview on XPath syntax on [w3schools](htt...
RSpec: Running examples by name (or running a single shared example)
When an Rspec example fails, I usually investigate by running that example again using rspec <file:line>
. However, this does not work with shared examples, since Rspec doesn't know in which context the shared example should be run.
But there is a different way: You can run the shared example using the -e
, --example
option. It takes a string value and runs all scenarios containing that substring in their full description.
This allows you to run a single uniquely named example, all examples with
similar names, all the examples in a u...
Spreewald: Content-Disposition not set when testing a download's filename
Precondition
- You are not using javascript tests
- The file is served from a public folder (not via controller)
Problem description
If you deliver files from a public folder it might be that the Content-Disposition
header is not set. That's why the following spreewald step might raise an error:
Then I should get a download with filename "..."
expected: /filename="some.pdf"$/
got: nil (using =~) (RSpec::Expectations::ExpectationNotMetError)
Solution
One solution...
Fixing flaky E2E tests
An end-to-end test (E2E test) is a script that remote-controls a web browser with tools like Selenium WebDriver. This card shows basic techniques for fixing a flaky E2E test suite that sometimes passes and sometimes fails.
Although many examples in this card use Ruby, Cucumber and Selenium, the techniques are applicable to all languages and testing tools.
Why tests are flaky
Your tests probably look like this:
When I click on A
And I click on B
And I click on C
Then I should see effects of C
A test like this works fine...
Async control flow in JavaScript: Promises, Microtasks, async/await
Slides for Henning's talk on Sep 21st 2017.
Understanding sync vs. async control flow
Talking to synchronous (or "blocking") API
print('script start')
html = get('/foo')
print(html)
print('script end')
Script outputs 'script start'
, (long delay), '<html>...</html>'
, 'script end'
.
Talking to asynchronous (or "evented") API
print('script start')
get('foo', done: function(html) {
print(html)
})
print('script end')
Script outputs 'script start'
, 'script end'
, (long ...
Rails: namespacing models with table_name_prefix instead of table_name
When you want to group rails models of a logical context, namespaces are your friend. However, if you have a lot of classes in the same namespace it might be tedious to specify the table name for each class seperately:
class Accounting::Invoice < ApplicationRecord
self.table_name = 'accounting_invoices'
...
end
class Accounting::Payment < ApplicationRecord
self.table_name = 'accounting_payments'
...
end
A replacement for the self.table_name
-assignment is the table_name_prefix
in the module definition:
modu...
RSpec: How to define classes for specs
RSpec allows defining methods inside describe
/context
blocks which will only exist inside them.
However, classes (or any constants, for that matter) will not be affected by this. If you define them in your specs, they will exist globally. This is because of how RSpec works (short story: instance_eval
).
Negative example:
describe Notifier do
class TestRecord < ApplicationRecord # DO NOT do this!
# ...
end
let(:record) { TestRecord.new }
it { ... }
end
# TestRecord will exist here, outside of the spec!
D...
How to change the class in FactoryBot traits
FactoryBot allows a :class
option to its factory
definitions, to set the class to construct. However, this option is not supported for trait
s.
Most often, you can just define a nested factory instead of a trait, and use the :class
option there.
factory :message do
factory :reply, class: Message::Reply do
# ...
end
end
If you need/want to use traits instead (for example, it might make more sense semantically), you can not use a :class
on a trait
.
In that case, use initialize_with
to define the record's constr...
How to avoid ActiveRecord::EnvironmentMismatchError on "rails db:drop"
After loading a staging dump into development, you might get an ActiveRecord::EnvironmentMismatchError
when trying to replace the database (like rails db:drop
, rails db:schema:load
).
$ rails db:drop
rails aborted!
ActiveRecord::EnvironmentMismatchError: You are attempting to modify a database that was last run in `staging` environment.
You are running in `development` environment. If you are sure you want to continue, first set the environment using:
bin/rails db:environment:set RAILS_ENV=development
Starting with R...
Dealing with I18n::InvalidPluralizationData errors
When localizing model attributes via I18n you may run into errors like this:
I18n::InvalidPluralizationData: translation data { ... } can not be used with :count => 1. key 'one' is missing.
They seem to appear out of the blue and the error message is more confusing than helpful.
TL;DR A model (e.g. Post
) is lacking an attribute (e.g. thread
) translation.
Fix it by adding a translation for that model's attribute (attributes.post.thread
). The error message reveals the (wrongly) located I18n data (from `attributes.thread...
How to pair a Bose Quiet Comfort 35 with your Ubuntu computer
You need to disable "Bluetooth low energy", then follow these core steps:
- Make sure the headphones are in pairing mode.
- Pair with System Settings > Bluetooth. On 16.04 I had to choose "proceed without pairing" and enter the PIN "0000"
- Select & test the headphones in System Settings > Sound. Choose High Fidelity Playback (A2DP Sink).
I also had to install a package with sudo apt-get install pulseaudio-module-bluetooth
and load it with pactl load-module module-bluetooth-discover
. Put the latter command into ~/.bashrc
or you'll...
Ruby: A small summary of what return, break and next means for blocks
Summary
- Use
return
to return from a method.return
accepts a value that will be the return value of the method call. - Use
break
to quit from a block and from the method that yielded to the block.break
accepts a value that supplies the result of the expression it is “breaking” out of. - Use
next
to skip the rest of the current iteration.next
accepts an argument that will be the result of that block iteration.
The following method will serve as an example in the details below:
def example
puts yield
puts ...
Custom Ruby method Enumerable#count_by (use for quick statistics)
I frequently find myself needing a combination of group_by
, count
and sort
for quick statistics. Here's a method on Enumerable
that combines the three:
module Enumerable
def count_by(&block)
group_by(&block)
.transform_values(&:count)
.sort_by(&:last)
.to_h
end
end
Just paste that snippet into a Rails console and use #count_by
now!
Usage examples
- Number of email addresses by domain:
> User.all.count_by { |user| user.email.sub /^.*@/, '' }
=> { "sina.cn"=>2, ..., "hotmail.com"=>128...