Testing SproutCore with Cucumber + Selenium
This isn’t really a complete tutorial; just a few tricks to make the process a lot easier.
First, add the following code to features/support/env.rb, replacing existing bits as necessary:
Webrat.configure do |config|
config.mode = :selenium
config.application_environment = Rails.env
# Same as script/server, so SproutCore can proxy to the same port in both
# development and test modes.
config.application_port = 3000
# This is used for both the initial browser startup, and the maximum
# timeout for commands like 'open'. It needs to be very high, because we
# may need to wait for a SproutCore recompile at some point.
config.selenium_browser_startup_timeout = 40
end
require 'features/environments/selenium_locator_fix'
World(Webrat::Selenium::Methods)
World(Webrat::Selenium::Matchers)
def expect_element xpath
selenium.wait_for_element("xpath=#{xpath}", :timeout_in_seconds => 5)
end
def press_key(str)
chr = str[0]
chr.integer?.should == true # Breaks for Ruby 1.9?
key_arg = sprintf("\\%02d", chr)
# This works in all current browsers except Safari < 4.
# http://stackoverflow.com/questions/497094/how-do-i-find-out-which-javascript-element-has-focus
selenium.key_press("dom=document.activeElement", key_arg)
end
Here’s the locators fix:
# Make field_labeled work correctly with Selenium. This is based on the # discussion at # https://webrat.lighthouseapp.com/projects/10503/tickets/255-field_labeled-locator-missing-in-selenium-mode # but it has been changed in a number of ways to actually make it work again. module Webrat::Locators def field_labeled(label, *field_types) Webrat::Locators::FieldLabeledLocator.new(self, Webrat::XML.document(response_body), label, *field_types).locate! end end class Webrat::SeleniumSession def dom @dom ||= Webrat::XML.document(response_body) end def current_dom dom end def elements @elements ||= {} end end
Now, we need to add layerId properties to some of our globally-known views, so we have a chance of finding them:
// Needed so Cucumber can find this element. Note that this ID // actually applies to a wrapper element containing the actual input // element, so it's still pretty tricky to get at. layerId: 'searchBox'
Here are some sample step definitions:
When /^I run a search for "([^\"]*)"$/ do |query|
# SproutCore assigns random element IDs, and places those IDs on wrapper
# elements instead of the actual input elements. So we override the
# layerId property on our testable views, and write some messy XPath to
# extract the actual element we want.
locator = "xpath=id('searchBox')//input"
selenium.wait_for_element(locator, 5)
selenium.type(locator, "#{query}")
press_key("\r")
end
When /^I press tab$/ do
press_key("\t")
end
When /^I press return$/ do
press_key("\r")
end