How to not repeat yourself in Cucumber scenarios
It is good programming practice to Don't Repeat Yourself (or DRY). In Ruby on Rails we keep our code DRY by sharing behavior by using inheritance, modules, traits or partials.
When you reuse behavior you want to reuse tests as well. You are probably already reusing examples in unit tests. Unfortunately it is much harder to reuse code when writing integration tests with Cucumber, where you need to...
Geordi: Choose your firefox version for cuc
Geordi 0.16+ supports running selenium tests with project-specific firefox versions.
Just update the gem. It will still default to using the old 5.0.1 firefox. If you want another one, add a file .firefox-version
to your project, containing your preferred version.
geordi cucumber
will prompt (and guide) you to install the given version. You can delete any old installation sitting in /opt/firefox-for-selenium
if you have one.
Implementing social media "like" buttons: Everything you never wanted to know
So you client has asked you to implement a row of buttons to like the URL on Facebook, Twitter and Google+. Here are some things you should know about this.
0. Security considerations
Each "like" button is implemented by including a Javascript on your site. This means you are running fucking remote code on your page. You are giving Facebook, Twitter and Google+ full permission to e. g. copy user cookies. Check with your client if she is cool with that. Also note that if you're site is suggesting security by operating under HTTPS ...
Enable CSRF protection in Javascript tests
You might not know that Rails disables CSRF protection in tests. This means that if you accidentally forget to send the CSRF token for non-GET requests, your tests will be green even though your application is completely broken (a failed CSRF check usually logs out the user). Rails probably does this because CSRF protection sort of requires Javascript.
You want to enable CSRF protection in Cucumber scenarios that can speak Javascript. To do so, copy the a...
Cucumber: Detect if the current Capybara driver supports Javascript
Copy the attached file to features/support
. This gets you a convenience method:
Capybara.javascript_test?
Is true
for Selenium, capybara-webkit, Poltergeist and a custom driver called :chrome
(which we sometimes like to use for Selenium+Chrome).
Similar sounding but completely different card: Detect if a Javascript is running under Selenium WebDriver (with Rails)
Disable text-transforms in Selenium tests
Using text-transform: uppercase
- especially on form labels - can cause you serious headaches in Selenium tests. Sometimes the web driver will see the uppercase text, sometimes it won't, and umlauts will be a problem as well.
Simply disable it in tests, by
-
adding a body class for tests
%body{'data-environment' => Rails.env}
-
overriding the transforms
[data-environment="test"] * text-transform: none !important
Understanding AngularJS service types
Angular comes with different types of services. Each one with its own use cases.
All of these services are singletons. You probably want to use Factory all the time.
Provider
- is the parent of all other services (except
constant
) - can be configured using `app.config(function(Provider) { ...})
- a little complex
Factory
- simpler than Provider, but without configuration
- definition: `app.factory('name', someFunction)
-
someFunction
is called when thename
service is instantiated and should return an object
Se...
Compiling Javascript template functions with the asset pipeline
The asset pipeline (which is actually backed by sprockets) has a nice feature where templates ending in .jst
are compiled into Javascript template functions. These templates can be rendered by calling JST['path/to/template'](template: 'variables')
:
<!-- templates/hello.jst.ejs -->
<div>Hello, <span><%= name %></span>!</div>
// application.js
//= require templates/hello
$("#hello").html(JST["templates/hello"]({ name: "Sam" }));
Whatever is in the <% ... %>
is evaluated in Javascript...
Capybara: Trigger requests with custom request method
Preface: Normally, you would not need this in integrations tests (probably that's why it is so hard to achieve), because it is no actual "integration testing". If you use this step, know what you are doing.
Destroying a record with Capybara is not as easy as calling visit user_path(user, method: :delete)
, because RackTest's visit
can only perform GET requests.
With this step you can destroy a records using either Selenium or RackTest. Ex...
Consul 0.10.0 allows multiple power mappings for nested resources
Consul 0.10.0 now allows multiple power mappings for nested resources.
When using nested resources you probably want two power
checks and method mappings: One for the parent resource, another for the child resource.
Say you have the following routes:
resources :clients do
resources :notes
end
And the following power definitions:
class Power
...
power :clients do
Client.active if si...
RSpec: Where to put custom matchers and other support code
Custom matchers are a useful RSpec feature which you can use to DRY up repetitive expectations in your specs. Unfortunately the default directory structure generated by rspec-rails
has no obvious place to put custom matchers or other support code.
I recommend storing them like this:
spec/support/database_cleaner.rb
spec/support/devise.rb
spec/support/factory_bot.rb
spec/support/vcr.rb
spec/support/matchers/be_allowed_access.rb
s...
RSpec: Where to put shared example groups
Shared example groups are a useful RSpec feature. Unfortunately the default directory structure generated by rspec-rails
has no obvious place to put them.
I recommend storing them like this:
spec/models/shared_examples/foo.rb
spec/models/shared_examples/bar.rb
spec/models/shared_examples/baz.rb
spec/controllers/shared_examples/foo.rb
spec/controllers/shared_examples/bar.rb
spec/controllers/shared_examples/baz.rb
To ma...
Rails: Disable options of a select field
Simply give the select
helper an option :disabled
, passing either a single value or an array. You need to specify the option's value
, not its text.
= form.select :country, Address.countries_for_select, :include_blank => true, :disabled => ['disabled-value1', 'disabled-value-2']
Also see Cucumber: Check if a select field contains a disabled option on how to test this.
Cucumber: Check if a select field contains a disabled option
For Capybara, use this step:
Then /^"([^"]*)" should be a disabled option for "([^"]*)"(?: within "([^\"]*)")?$/ do |value, field, selector|
with_scope(selector) do
field_labeled(field).find(:xpath, ".//option[text() = '#{value}'][@disabled]").should be_present
end
end
Automated "git bisect" will make your day
So you're hunting down a regression (or just a bug) and want to use git bisect
to find out when it was introduced? Smart kid.
If you have a shell command ready to reveal if your current state is good or bad, you can have git do most of the work for you.
Using git bisect run <your command>
you can tell git that your command will reveal the issue; git on the other hand will use the return value of that call to decide if the state is good or bad.
...
MySQL: Careful when using database locks in transactions
We tend to use database transactions as a magic bullet to get rid of all our concurrency problems. When things get really bad, we might even throw in some locking mechanism, but then are usually done with it.
Unfortunately, transactions semantics in databases are actually very complicated, and chances are, your making some incorrect assumptions.
The MySQL innodb engine actually has [four different modes](ht...
Consul 0.9 lets you optimize records checks
Consul 0.9 comes with many new features to optimize powers that only check access to a given record. e.g. Power.current.post?(Post.last)
. See below for details.
Powers that only check a given object
Sometimes it is not convenient to define powers as a collection. Sometimes you only want to store a method that
checks whether a given object is accessible.
To do so, simply define a power that ends in a question mark:
class Power
...
power :upd...
ActionView::Template::Error (dump format error for symbol(0x6d))
I recently encountered the error above when I was running selenium tests.
Thanks to a post on stackoverflow I found out that clearing all files in tmp/cache in my project folder made the issue go away.
Switch to a recently opened tab with Cucumber
Similar to closing an opened browser window, spreewald now supports the I switch to the new browser tab
step.
Info
See the Spreewald README for more cool features.
You can use it to test links that were opened with a link_to(..., :target => '_blank')
link or other ways that create new tabs or windows.
Important
This only works with
Selenium
...
Riding Rails: Rails 4.0: Final version released!
Rails 4.0 is finally ready after a thorough process of betas and release candidates. It's an amazing new version packed with new goodies and farewells to old features past their expiration date.
Upgrading Rails 2 from 2.3.8 through 2.3.18 to Rails LTS
This card shows how to upgrade a Rails 2 application from Rails 2.3.8 through every single patch level up to 2.3.18, and then, hopefully, Rails LTS.
2.3.8 to 2.3.9
This release has many minor changes and fixes to prepare your application for Rails 3.
Step-by-step upgrade instructions:
- Upgrade
rails
gem - Change your
environment.rb
so it saysRAILS_GEM_VERSION = '2.3.9'
- Change your ...
Before you make a merge request: Checklist for common mistakes
Merge requests are often rejected for similar reasons.
To avoid this, before you send a merge request, please confirm that your code ...
- has been reviewed by yourself beforehand
- fulfills every requirement defined as an acceptance criterion
- does not have any log or debugging statements like
console.log(...)
,byebug
etc. - has green tests
- has tests...
marcandre/backports ยท GitHub
Essential backports that enable many of the nice features of Ruby 1.8.7 up to 2.0.0 for earlier versions.
How to clear cookies in Capybara tests (both Selenium and Rack::Test)
Capybara drivers will usually delete all cookies after each scenario. If you need to lose cookie data in the middle of a scenario, you can do this:
browser = Capybara.current_session.driver.browser
if browser.respond_to?(:clear_cookies)
# Rack::MockSession
browser.clear_cookies
elsif browser.respond_to?(:manage) and browser.manage.respond_to?(:delete_all_cookies)
# Selenium::WebDriver
browser.manage.delete_all_cookies
else
raise "Don't know how to clear cookies. Weird driver?"
end