As you’ll have noticed if you made it to the end of my last post, there is a new release of Terminus. Terminus is a Capybara driver that is designed to let you control your app in any browser on any device, by sending all driver instructions to be executed on the client side in JavaScript.
This release is the first since Capybara 1.0, and supports the entire Capybara API. This includes:
- Reading response headers and status codes
- Handling cookies
- Running JavaScript and receiving the results
- Resynchronizing XHR requests (jQuery only)
- Switching between frames and windows
- Detecting infinite redirects
This is a superset of the supported features of the Rack::Test and Selenium drivers, and has the added bonus of letting you switch between browsers. When you have multiple browsers connected to your Terminus server, you can select which one you want to control by matching on the browser’s name, OS, version and current URL, for example:
Terminus.browser = {:name => /Safari/, :current_url => /pitchfork.com/}
You can select any browser that is ‘docked’, i.e. idling on the Terminus holding page:
Terminus.browser = :docked
Or simply by selecting one browser from the list:
Terminus.browser = Terminus.browsers.first
All this lets you control multiple browsers at once, for example I’ve been using it to automate some of the Faye integration tests:
#================================================================
# Acquire some browsers and log into each with a username
NAMES = %w[alice bob carol]
BROWSERS = {}
Terminus.ensure_browsers 3
Terminus.browsers.each_with_index do |browser, i|
name = NAMES[i]
puts "#{name} is using #{browser}"
BROWSERS[name] = browser
Terminus.browser = browser
visit '/'
fill_in 'username', :with => name
click_button 'Go'
end
#================================================================
# Send a message from each browser to every other browser,
# and check that it arrived. If it doesn't arrive, send all
# the browsers back to the dock and raise an exception
BROWSERS.each do |name, sender|
BROWSERS.each do |at, target|
next if at == name
Terminus.browser = sender
fill_in 'message', :with => "@#{at} Hello, world!"
click_button 'Send'
Terminus.browser = target
unless page.has_content?("#{name}: @#{at} Hello, world!")
Terminus.return_to_dock
raise "Message did not make it from #{sender} to #{target}"
end
end
end
#================================================================
# Re-dock all the browsers when we're finished
Terminus.return_to_dock
So what’s not supported? Internet Explorer is still not supported because I cannot find a decent way to run XPath queries on it. I was working on Pathology to solve this but I can’t get it to perform well enough for the workload Capybara throws at it. It might be possible to work around this by monkey-patching Capybara to pass through CSS selectors instead of compiling them to XPath, though. File attachments are not supported for security reasons, and there are still some bugs that show up if you do stuff you’re not supposed to, like using duplicate element IDs. These are particularly apparent on Opera. And finally visiting remote hosts outside your application is supported but is not particularly robust as yet.
You can find out more and see a video of it in action on its new website.