Ruby: What extend and include do
All Rubyists should be familiar with the common definitions for include and extend. You include a module to add instance methods to a class and extend to add class methods. Unfortunately, this common definition isn’t entirely accurate. It fails to explain why we use instance.extend(Module) to add methods to an instance. Shouldn’t it be instance.include(Module)? To figure this out we’re going to start by discussing where methods are stored.
- include: Adds methods from the provided Module to the object
- extend: Calls include on the single...
parallel_tests: Disable parallel run for tagged scenarios
Note: This technique is confusing and slows down your test suite.
Copy the attached code to features/support. This gets you a new Cucumber tag @no_parallel which ensures that the tagged scenario does not run in parallel with other scenarios that are tagged with @no_parallel. Other scenarios not tagged will @no_parallel can still run in parallel with the tagged test. Please read the previous sentence again.
This can help when multiple test processes that access a single resource that is hard to shar...
YAML syntax compared with Ruby syntax
yaml4r is a juxtaposition of yaml documents and their Ruby couterpart. Thus, it does a great job as YAML-doc, e.g. when writing Rails locale files. Did you know that ...
-
<<is a merge key (similar to&in SASS) - there are variables, called aliases. Definition:
&alias Some content, usage:*alias.
Caveats
Specifying a key twice does not merge the sub keys, but override the first definition, e.g.
de:
car: # overridden
door: Tür
...
How to set the user agent in tests
The User-Agent HTTP header identifies the client and is sent by "regular" browsers, search engine crawlers, or other web client software.
Cucumber
In Rack::Test, you can set your user agent like this on Capybara:
Given /^my user agent is "(.+)"$/ do |agent|
page.driver.browser.header('User-Agent', agent)
# Or, for older Capybaras:
# page.driver.header('User-Agent', agent)
end
For Selenium tests with Firefox, it seems you can set the general.useragent.override profile setting to your preferred value. [See StackOver...
def vs. define_method
Ever wondered about the difference between def and define_method? Turns out there are three implicit contexts in Ruby. def and define_method differ in which one they use.
def
- Ruby keyword, starts a method definition
- Opens a new, isolated scope. Variables defined outside are not accessible inside and vice versa.
- Defines an instance method on the receiver (specified before the method name, e.g.
def object.foo); implicit receiver is the default definee
The default definee is not self and...
Test redirects to an external URL with Cucumber/Capybara
When a controller action redirects to an external URL (like http://somehost.com/some/path) you will find that this is hard to test with Cucumber and Capybara:
- A non-Javascript Rack::Test scenario will just ignore the host and try to open
/some/pathin your local application - A Selenium test will actually follow the redirect, which you probably don't want either
There are two workarounds for this. You can use either, or a combination of both.
- Write a controller spec
Controller specs can test if a resp...
How to disable cookies in cucumber tests
Unfortunately, Capybara does not offer a switch to disable cookies in your test browser. However, you can work around that by using a tiny Rack middleware -- it works for both Selenium and non-Selenium tests.
Wouldn't it be nice to say something like this?
Given cookies are disabled
When I try to sign in
Then I should see "Can't sign you in. Please enable cookies."
You can! Put the code below into some place like lib/rack/cookie_stripper.rb.
module Rack
class CookieStripper
ENABLED = false
...
Cucumber step to set cookies in your Capybara session
To set a cookie in your test browser for cucumber tests, you need to know which driver you are using. Use the step below according to your driver.
Rack::Test
Given /^I have a "([^\"]+)" cookie set to "([^\"]+)"$/ do |key, value|
headers = {}
Rack::Utils.set_cookie_header!(headers, key, value)
cookie_string = headers['Set-Cookie']
Capybara.current_session.driver.browser.set_cookie(cookie_string)
end
Note that Rack::Utils is only used to find out the correct cookie header string (you don't want to generate it yours...
Capybara 0.3.9 Bug: Chaining .find to scope doesn't work
The following code doesn't work like expected:
page.find(css_selector).find(other_css_selector)
The second .find will search the whole dom instead of a scope.
Rumor has it this is fixed in Capybara 0.4.1.
Selenium: How to close another tab (popup)
If you open a pop-up window [1] in your Selenium tests and you want to close it, you can do this:
# Find our target window
handle = page.driver.find_window("My window title")
# Close it
page.driver.browser.switch_to.window(handle)
page.driver.browser.close
# Have the Selenium driver point to another window
last_handle = page.driver.browser.window_handles.last
page.driver.browser.switch_to.window(last_handle)
Mind these:
-
find_windowreturns a window handle, which is something like `"{485fa8bd-fa99-...
Capturing signatures on a touch device
If you need to capture signatures on an IPad or similar device, you can use Thomas J Bradley's excellent Signature Pad plugin for jQuery.
To implement, just follow the steps on the Github page.
The form
If you have a model Signature with name: string, signature: text, you can use it with regular rails form like this:
- form_for @signature, :html => { :class => 'signature_form' } do |form|
%dl
%dt
= form...
Using CSS counters - CSS | MDN
Counters are an awesome CSS feature you didn't know about. It is supported in all browsers and IE8+.
CSS counters are an implementation of Automatic counters and numbering in CSS 2.1. The value of a counter is manipulated through the use of counter-reset and counter-increment and is displayed on a page using the counter() or counters() function of the content property.
lang/unicode_utils · GitHub
UnicodeUtils implements Unicode algorithms for case conversion, normalization, text segmentation and more in pure Ruby code.
If you don't need the ton of features that UnicodeUtils offers, try stringex.
Useful methods to process tables in Cucumber step definitions
When you accept a table in your Cucumber step definition, that table object will have the cryptic type Cucumber::Ast::Table. Don't immediately call table.raw to convert it into an array of arrays! Cucumber::Ast::Table has a lot of useful methods for tasks such as:
table.raw-
Turn the table into an array of arrays
table.hashes-
Convert the table to an array of hashes, where the keys are the table headers from the first row
`table.header...
Test that a form field is visible with Cucumber/Capybara
Spreewald now comes with a step that tests if a form field is visible:
Then the "Due date" field should be visible
But the "Author" field should not be visible
The step works by looking up the field for the given label, then checks if that field is hidden via CSS (or Javascript).
It is not currently tested if the label is visible or hidden. For this see: [Check that an element is visible or hidden via CSS with Cucumber/Capybara](https://makandracards.com/makandra/1049-check-that-an-elem...
Memcache: Your cache node may degenerate over time, check your settings
We recently had a problem on a Memcache cluster, where one of the servers showed a significantly worse cache hit rate and a lot more evictions.
It turned out that the only reason was that the server was running for a few months longer than the others. Some investigation showed this to be a known problem with Memcache: Once your cache gets full, it might be "hardwired" for your specific usage patterns. If those change (and you for example start to store larger values), memory is no longer allocated optimally, in extreme cases Memcache might ...
Behave.js
Behave.js is a lightweight library for adding IDE style behaviors to plain text areas, making it much more enjoyable to write code in. Features include:
- Custom Code/Behavior Fencing
- Hard and Soft Tabs
- Auto Open/Close Parenthesis, Brackets, Braces, Double and Single Quotes
- Auto delete a paired character
- Overwrite a paired character
- Multi-line Indentation/Unindentation
- Automatic Indentation
How to update a single gem conservatively
The problem
Calling bundle update GEMNAME will update a lot more gems than you think. E.g. when you do this:
bundle update cucumber-rails
... you might think this will only update cucumber-rails. But it actually updates cucumber-rails and all of its dependencies. This will explode in your face when one of these dependencies release a new version with breaking API changes. Which is all the time.
In the example above updating cucumber-rails will give you Capybara 2.0 (because capybara is a dependency of `cucumber-rail...
Running "bundle update" will update all gems without constraints
Calling bundle update (without arguments) updates all your gems at once. Given that many gems don't care about stable APIs, this might break your application in a million ways.
To stay sane, update your gems using the applicable way below:
Projects in active development
Update the entire bundle regularily (e.g. once a week). This ensures that your libraries are up-to-date while it's easy to spot major version bumps which may break the app.
Projects that have not been updated in a while
- [Update a single gem conservatively](htt...
Phusion Passenger 4 Technology Preview: Out-Of-Band Work – Phusion Corporate BlogPhusion Corporate Blog
The Out-of-Band Work feature allows one to perform arbitrary long-running work outside the request/response cycle without blocking HTTP clients. The primary use case is to run the garbage collector in between cycles so that your requests will finish faster because they will not be interrupted by the garbage collector.
randym/axlsx · GitHub
Axlsx is an incredible gem to generate "Office Open XML" spreadsheet files (XLSX). Does not break on large spreadsheets and supports a ton of features like graphs.
API looks mature and existing code is easy to migrate when coming from the spreadsheet gem.
The documentation of some methods is a bit out of date, but you'll find your way around the gem's code.
No support for reading files, however. :( If you want to open XLSX spreadsheets (for example to confirm your output in tests), you can use [roo](h...
Understanding database cleaning strategies in tests
TLDR: In tests you need to clean out the database before each example. Use :transaction where possible. Use :deletion for Selenium features or when you have a lot of MyISAM tables.
Understanding database cleaning
You want to clean out your test database after each test, so the next test can start from a blank database. To do so you have three options:
- Wrap each test in a transaction which is rolled back when you're done (through
DatabaseCleaner.strategy = :transactionor `config.use_transactional_fi...
How to provoke Selenium focus issues in parallel test processes
As attachments to this card you will find a Cucumber feature and supplementing step definition that you can use to provoke Selenium focus issues that only occur when two focus-sensitive Selenium scenarios run at the same time (probably with parallel_tests). This can help you to detect and fix flickering integration tests.
The attached feature works by going to your root_path and focusing a random form element every 5...
How to test if an element has scrollbars with JavaScript (Cucumber step inside)
The basic idea is pretty simple: an element's height is accessible via the offsetHeight property, its drawn height via scrollHeight -- if they are not the same, the browser shows scrollbars.
var hasScrollbars = element.scrollHeight != element.offsetHeight;
So, in order to say something like...
Then the element "#dialog_content" should not have scrollbars
... you can use this step (only for Selenium scenarios):
Then /^the element "([^\"]+)" should( not)? have scrollbars$/ do |selector, no_scrollbars|
scroll_heig...