mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-17 15:50:13 +01:00
Update selenium on rails using 'official' git repo
git://github.com/paytonrules/selenium-on-rails.git
This commit is contained in:
parent
198f3240b8
commit
9b504b3e47
159 changed files with 16409 additions and 11794 deletions
|
|
@ -1,210 +1,214 @@
|
|||
require File.dirname(__FILE__) + '/paths'
|
||||
require File.dirname(__FILE__) + '/../selenium_on_rails_config'
|
||||
require 'net/http'
|
||||
require 'tempfile'
|
||||
|
||||
|
||||
def c(var, default = nil) SeleniumOnRailsConfig.get var, default end
|
||||
def c_b(var, default = nil) SeleniumOnRailsConfig.get(var, default) { yield } end
|
||||
|
||||
BROWSERS = c :browsers, {}
|
||||
REUSE_EXISTING_SERVER = c :reuse_existing_server, true
|
||||
START_SERVER = c :start_server, false #TODO can't get it to work reliably on Windows, perhaps it's just on my computer, but I leave it off by default for now
|
||||
HOST = c :host, 'localhost'
|
||||
PORTS = c(:port_start, 3000)..c(:port_end, 3005)
|
||||
TEST_RUNNER_URL = c :test_runner_url, '/selenium/TestRunner.html'
|
||||
MAX_BROWSER_DURATION = c :max_browser_duration, 2*60
|
||||
MULTI_WINDOW = c :multi_window, false
|
||||
SERVER_COMMAND = c_b :server_command do
|
||||
server_path = File.expand_path(File.dirname(__FILE__) + '/../../../../../script/server')
|
||||
if RUBY_PLATFORM =~ /mswin/
|
||||
"ruby #{server_path} -p %d -e test > NUL 2>&1"
|
||||
else
|
||||
# don't use redirects to /dev/nul since it makes the fork return wrong pid
|
||||
# see UnixSubProcess
|
||||
"#{server_path} -p %d -e test"
|
||||
end
|
||||
end
|
||||
|
||||
module SeleniumOnRails
|
||||
class AcceptanceTestRunner
|
||||
include SeleniumOnRails::Paths
|
||||
|
||||
def run
|
||||
raise 'no browser specified, edit/create config.yml' if BROWSERS.empty?
|
||||
start_server
|
||||
has_error = false
|
||||
begin
|
||||
BROWSERS.each_pair do |browser, path|
|
||||
log_file = start_browser browser, path
|
||||
wait_for_completion log_file
|
||||
stop_browser
|
||||
result = YAML::load_file log_file
|
||||
print_result result
|
||||
has_error ||= result['numTestFailures'].to_i > 0
|
||||
File.delete log_file unless has_error
|
||||
end
|
||||
rescue
|
||||
stop_server
|
||||
raise
|
||||
end
|
||||
stop_server
|
||||
raise 'Test failures' if has_error
|
||||
end
|
||||
|
||||
private
|
||||
def start_server
|
||||
PORTS.each do |p|
|
||||
@port = p
|
||||
case server_check
|
||||
when :success
|
||||
return if REUSE_EXISTING_SERVER
|
||||
next
|
||||
when Fixnum
|
||||
next
|
||||
when :no_response
|
||||
next unless START_SERVER
|
||||
do_start_server
|
||||
return
|
||||
end
|
||||
end
|
||||
raise START_SERVER ? 'failed to start server': 'failed to find existing server, run script/server -e test'
|
||||
end
|
||||
|
||||
def do_start_server
|
||||
puts 'Starting server'
|
||||
@server = start_subprocess(format(SERVER_COMMAND, @port))
|
||||
while true
|
||||
print '.'
|
||||
r = server_check
|
||||
if r == :success
|
||||
puts
|
||||
return
|
||||
end
|
||||
raise "server returned error: #{r}" if r.instance_of? Fixnum
|
||||
sleep 3
|
||||
end
|
||||
end
|
||||
|
||||
def server_check
|
||||
begin
|
||||
res = Net::HTTP.get_response HOST, TEST_RUNNER_URL, @port
|
||||
return :success if (200..399).include? res.code.to_i
|
||||
return res.code.to_i
|
||||
rescue Errno::ECONNREFUSED
|
||||
return :no_response
|
||||
end
|
||||
end
|
||||
|
||||
def stop_server
|
||||
return unless defined? @server
|
||||
puts
|
||||
@server.stop 'server'
|
||||
end
|
||||
|
||||
def start_browser browser, path
|
||||
puts
|
||||
puts "Starting #{browser}"
|
||||
log = log_file browser
|
||||
command = "\"#{path}\" \"http://#{HOST}:#{@port}#{TEST_RUNNER_URL}?test=tests&auto=true&resultsUrl=postResults/#{log}&multiWindow=#{MULTI_WINDOW}\""
|
||||
@browser = start_subprocess command
|
||||
log_path log
|
||||
end
|
||||
|
||||
def stop_browser
|
||||
@browser.stop 'browser'
|
||||
end
|
||||
|
||||
def start_subprocess command
|
||||
if RUBY_PLATFORM =~ /mswin/
|
||||
SeleniumOnRails::AcceptanceTestRunner::Win32SubProcess.new command
|
||||
elsif RUBY_PLATFORM =~ /darwin/i && command =~ /safari/i
|
||||
SeleniumOnRails::AcceptanceTestRunner::SafariSubProcess.new command
|
||||
else
|
||||
SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess.new command
|
||||
end
|
||||
end
|
||||
|
||||
def log_file browser
|
||||
(0..100).each do |i|
|
||||
name = browser + (i==0 ? '' : "(#{i})") + '.yml'
|
||||
return name unless File.exist?(log_path(name))
|
||||
end
|
||||
raise 'there are way too many files in the log directory...'
|
||||
end
|
||||
|
||||
def wait_for_completion log_file
|
||||
duration = 0
|
||||
while true
|
||||
raise 'browser takes too long' if duration > MAX_BROWSER_DURATION
|
||||
print '.'
|
||||
break if File.exist? log_file
|
||||
sleep 5
|
||||
duration += 5
|
||||
end
|
||||
puts
|
||||
end
|
||||
|
||||
def print_result result
|
||||
puts "Finished in #{result['totalTime']} seconds."
|
||||
puts
|
||||
puts "#{result['numTestPasses']} tests passed, #{result['numTestFailures']} tests failed"
|
||||
puts "(Results stored in '#{result['resultDir']}')" if result['resultDir']
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
class SeleniumOnRails::AcceptanceTestRunner::SubProcess
|
||||
def stop what
|
||||
begin
|
||||
puts "Stopping #{what} (pid=#{@pid}) ..."
|
||||
Process.kill 9, @pid
|
||||
rescue Errno::EPERM #such as the process is already closed (tabbed browser)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class SeleniumOnRails::AcceptanceTestRunner::Win32SubProcess < SeleniumOnRails::AcceptanceTestRunner::SubProcess
|
||||
def initialize command
|
||||
require 'win32/open3' #win32-open3 http://raa.ruby-lang.org/project/win32-open3/
|
||||
|
||||
puts command
|
||||
input, output, error, @pid = Open4.popen4 command, 't', true
|
||||
end
|
||||
end
|
||||
|
||||
class SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess < SeleniumOnRails::AcceptanceTestRunner::SubProcess
|
||||
def initialize command
|
||||
puts command
|
||||
@pid = fork do
|
||||
# Since we can't use shell redirects without screwing
|
||||
# up the pid, we'll reopen stdin and stdout instead
|
||||
# to get the same effect.
|
||||
[STDOUT,STDERR].each {|f| f.reopen '/dev/null', 'w' }
|
||||
exec command
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# The path to Safari should look like this: /Applications/Safari.app/Contents/MacOS/Safari
|
||||
class SeleniumOnRails::AcceptanceTestRunner::SafariSubProcess < SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess
|
||||
def initialize command
|
||||
f = File.open(Tempfile.new('selenium-on-rails').path, 'w')
|
||||
f.puts <<-HTML
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
window.location.href = #{command.split.last};
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
HTML
|
||||
f.close
|
||||
|
||||
super "#{command.split.first} #{f.path}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
$: << File.expand_path(File.dirname(__FILE__) + "/")
|
||||
$: << File.expand_path(File.dirname(__FILE__) + "/../")
|
||||
require 'paths'
|
||||
require 'net/http'
|
||||
require 'tempfile'
|
||||
|
||||
|
||||
def c(var, default = nil) SeleniumOnRailsConfig.new.get var, default end
|
||||
def c_b(var, default = nil) SeleniumOnRailsConfig.new.get(var, default) { yield } end
|
||||
|
||||
BROWSERS = c :browsers, {}
|
||||
REUSE_EXISTING_SERVER = c :reuse_existing_server, true
|
||||
START_SERVER = c :start_server, false #TODO can't get it to work reliably on Windows, perhaps it's just on my computer, but I leave it off by default for now
|
||||
HOST = c :host, 'localhost'
|
||||
PORTS = c(:port_start, 3000)..c(:port_end, 3005)
|
||||
BASE_URL_PATH = c :base_url_path, '/'
|
||||
TEST_RUNNER_URL = c :test_runner_url, '/selenium/TestRunner.html'
|
||||
MAX_BROWSER_DURATION = c :max_browser_duration, 2*60
|
||||
MULTI_WINDOW = c :multi_window, false
|
||||
SERVER_COMMAND = c_b :server_command do
|
||||
server_path = File.expand_path(File.dirname(__FILE__) + '/../../../../../script/server')
|
||||
if RUBY_PLATFORM =~ /mswin/
|
||||
"ruby #{server_path} webrick -p %d -e test > NUL 2>&1"
|
||||
else
|
||||
# don't use redirects to /dev/nul since it makes the fork return wrong pid
|
||||
# see UnixSubProcess
|
||||
"#{server_path} webrick -p %d -e test"
|
||||
end
|
||||
end
|
||||
|
||||
module SeleniumOnRails
|
||||
class AcceptanceTestRunner
|
||||
include SeleniumOnRails::Paths
|
||||
|
||||
def run
|
||||
raise 'no browser specified, edit/create config.yml' if BROWSERS.empty?
|
||||
start_server
|
||||
has_error = false
|
||||
begin
|
||||
BROWSERS.each_pair do |browser, path|
|
||||
log_file = start_browser browser, path
|
||||
wait_for_completion log_file
|
||||
stop_browser
|
||||
result = YAML::load_file log_file
|
||||
print_result result
|
||||
has_error ||= result['numTestFailures'].to_i > 0
|
||||
# File.delete log_file unless has_error
|
||||
end
|
||||
rescue
|
||||
stop_server
|
||||
raise
|
||||
end
|
||||
stop_server
|
||||
raise 'Test failures' if has_error
|
||||
end
|
||||
|
||||
private
|
||||
def start_server
|
||||
PORTS.each do |p|
|
||||
@port = p
|
||||
case server_check
|
||||
when :success
|
||||
return if REUSE_EXISTING_SERVER
|
||||
next
|
||||
when Fixnum
|
||||
next
|
||||
when :no_response
|
||||
next unless START_SERVER
|
||||
do_start_server
|
||||
return
|
||||
end
|
||||
end
|
||||
raise START_SERVER ? 'failed to start server': 'failed to find existing server, run script/server -e test'
|
||||
end
|
||||
|
||||
def do_start_server
|
||||
puts 'Starting server'
|
||||
@server = start_subprocess(format(SERVER_COMMAND, @port))
|
||||
while true
|
||||
print '.'
|
||||
r = server_check
|
||||
if r == :success
|
||||
puts
|
||||
return
|
||||
end
|
||||
raise "server returned error: #{r}" if r.instance_of? Fixnum
|
||||
sleep 3
|
||||
end
|
||||
end
|
||||
|
||||
def server_check
|
||||
begin
|
||||
res = Net::HTTP.get_response HOST, TEST_RUNNER_URL, @port
|
||||
return :success if (200..399).include? res.code.to_i
|
||||
return res.code.to_i
|
||||
rescue Errno::ECONNREFUSED
|
||||
return :no_response
|
||||
end
|
||||
end
|
||||
|
||||
def stop_server
|
||||
return unless defined? @server
|
||||
puts
|
||||
@server.stop 'server'
|
||||
end
|
||||
|
||||
def start_browser browser, path
|
||||
puts
|
||||
puts "Starting #{browser}"
|
||||
base_url = "http://#{HOST}:#{@port}#{BASE_URL_PATH}"
|
||||
log = log_file browser
|
||||
command = "\"#{path}\" \"http://#{HOST}:#{@port}#{TEST_RUNNER_URL}?test=tests&auto=true&baseUrl=#{base_url}&resultsUrl=postResults/#{log}&multiWindow=#{MULTI_WINDOW}\""
|
||||
@browser = start_subprocess command
|
||||
log_path log
|
||||
end
|
||||
|
||||
def stop_browser
|
||||
@browser.stop 'browser'
|
||||
end
|
||||
|
||||
def start_subprocess command
|
||||
if RUBY_PLATFORM =~ /mswin/
|
||||
SeleniumOnRails::AcceptanceTestRunner::Win32SubProcess.new command
|
||||
elsif RUBY_PLATFORM =~ /darwin/i && command =~ /safari/i
|
||||
SeleniumOnRails::AcceptanceTestRunner::SafariSubProcess.new command
|
||||
else
|
||||
SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess.new command
|
||||
end
|
||||
end
|
||||
|
||||
def log_file browser
|
||||
FileUtils.mkdir_p(log_path(''))
|
||||
(0..100).each do |i|
|
||||
name = browser + (i==0 ? '' : "(#{i})") + '.yml'
|
||||
return name unless File.exist?(log_path(name))
|
||||
end
|
||||
raise 'there are way too many files in the log directory...'
|
||||
end
|
||||
|
||||
def wait_for_completion log_file
|
||||
duration = 0
|
||||
while true
|
||||
raise 'browser takes too long' if duration > MAX_BROWSER_DURATION
|
||||
print '.'
|
||||
break if File.exist? log_file
|
||||
sleep 5
|
||||
duration += 5
|
||||
end
|
||||
puts
|
||||
end
|
||||
|
||||
def print_result result
|
||||
puts "Finished in #{result['totalTime']} seconds."
|
||||
puts
|
||||
puts "#{result['numTestPasses']} tests passed, #{result['numTestFailures']} tests failed"
|
||||
puts "(Results stored in '#{result['resultDir']}')" if result['resultDir']
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
class SeleniumOnRails::AcceptanceTestRunner::SubProcess
|
||||
def stop what
|
||||
begin
|
||||
puts "Stopping #{what} (pid=#{@pid}) ..."
|
||||
Process.kill 9, @pid
|
||||
rescue Errno::EPERM #such as the process is already closed (tabbed browser)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class SeleniumOnRails::AcceptanceTestRunner::Win32SubProcess < SeleniumOnRails::AcceptanceTestRunner::SubProcess
|
||||
def initialize command
|
||||
require 'win32/open3' #win32-open3 http://raa.ruby-lang.org/project/win32-open3/
|
||||
|
||||
puts command
|
||||
input, output, error, @pid = Open4.popen4 command, 't', true
|
||||
end
|
||||
end
|
||||
|
||||
class SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess < SeleniumOnRails::AcceptanceTestRunner::SubProcess
|
||||
def initialize command
|
||||
puts command
|
||||
@pid = fork do
|
||||
# Since we can't use shell redirects without screwing
|
||||
# up the pid, we'll reopen stdin and stdout instead
|
||||
# to get the same effect.
|
||||
[STDOUT,STDERR].each {|f| f.reopen '/dev/null', 'w' }
|
||||
exec command
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# The path to Safari should look like this: /Applications/Safari.app/Contents/MacOS/Safari
|
||||
class SeleniumOnRails::AcceptanceTestRunner::SafariSubProcess < SeleniumOnRails::AcceptanceTestRunner::UnixSubProcess
|
||||
def initialize command
|
||||
f = File.open(Tempfile.new('selenium-on-rails').path, 'w')
|
||||
f.puts <<-HTML
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
window.location.href = #{command.split.last};
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
HTML
|
||||
f.close
|
||||
|
||||
super "#{command.split.first} #{f.path}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,54 +1,57 @@
|
|||
require 'active_record/fixtures'
|
||||
|
||||
module SeleniumOnRails::FixtureLoader
|
||||
include SeleniumOnRails::Paths
|
||||
|
||||
def available_fixtures
|
||||
fixtures = {}
|
||||
path = fixtures_path + '/'
|
||||
files = Dir["#{path}**/*.{yml,csv}"]
|
||||
files.each do |file|
|
||||
rel_path = file.sub(path, '')
|
||||
next if skip_file? rel_path
|
||||
fixture_set = File.dirname(rel_path)
|
||||
fixture_set = '' if fixture_set == '.'
|
||||
fixture = rel_path.sub /\.[^.]*$/, ''
|
||||
fixtures[fixture_set] ||= []
|
||||
fixtures[fixture_set] << fixture
|
||||
end
|
||||
|
||||
fixtures
|
||||
end
|
||||
|
||||
def load_fixtures fixtures_param
|
||||
available = nil
|
||||
fixtures = fixtures_param.split(/\s*,\s*/).collect do |f|
|
||||
fixture_set = File.dirname f
|
||||
fixture_set = '' if fixture_set == '.'
|
||||
fixture = File.basename f
|
||||
if fixture == 'all'
|
||||
available ||= available_fixtures
|
||||
available[fixture_set]
|
||||
else
|
||||
f
|
||||
end
|
||||
end
|
||||
fixtures.flatten!
|
||||
fixtures.reject! {|f| f.blank? }
|
||||
|
||||
if fixtures.any?
|
||||
Fixtures.create_fixtures fixtures_path, fixtures
|
||||
end
|
||||
fixtures
|
||||
end
|
||||
|
||||
def clear_tables tables
|
||||
table_names = tables.split /\s*,\s*/
|
||||
connection = ActiveRecord::Base.connection
|
||||
table_names.each do |table|
|
||||
connection.execute "DELETE FROM #{table}"
|
||||
end
|
||||
table_names
|
||||
end
|
||||
|
||||
end
|
||||
require 'test/unit'
|
||||
require 'active_record'
|
||||
require 'active_record/fixtures'
|
||||
|
||||
module SeleniumOnRails::FixtureLoader
|
||||
include SeleniumOnRails::Paths
|
||||
|
||||
def available_fixtures
|
||||
fixtures = {}
|
||||
path = fixtures_path + '/'
|
||||
files = Dir["#{path}**/*.{yml,csv}"]
|
||||
files.each do |file|
|
||||
rel_path = file.sub(path, '')
|
||||
next if skip_file? rel_path
|
||||
fixture_set = File.dirname(rel_path)
|
||||
fixture_set = '' if fixture_set == '.'
|
||||
fixture = rel_path.sub /\.[^.]*$/, ''
|
||||
fixtures[fixture_set] ||= []
|
||||
fixtures[fixture_set] << fixture
|
||||
end
|
||||
|
||||
fixtures
|
||||
end
|
||||
|
||||
def load_fixtures fixtures_param
|
||||
available = nil
|
||||
fixtures = fixtures_param.split(/\s*,\s*/).collect do |f|
|
||||
fixture_set = File.dirname f
|
||||
fixture_set = '' if fixture_set == '.'
|
||||
fixture = File.basename f
|
||||
if fixture == 'all'
|
||||
available ||= available_fixtures
|
||||
available[fixture_set]
|
||||
else
|
||||
f
|
||||
end
|
||||
end
|
||||
fixtures.flatten!
|
||||
fixtures.reject! {|f| f.blank? }
|
||||
|
||||
if fixtures.any?
|
||||
Fixtures.reset_cache # in case they've already been loaded and things have changed
|
||||
Fixtures.create_fixtures fixtures_path, fixtures
|
||||
end
|
||||
fixtures
|
||||
end
|
||||
|
||||
def clear_tables tables
|
||||
table_names = tables.split /\s*,\s*/
|
||||
connection = ActiveRecord::Base.connection
|
||||
table_names.each do |table|
|
||||
connection.execute "DELETE FROM #{table}"
|
||||
end
|
||||
table_names
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,38 +1,36 @@
|
|||
# Provides partials support to test cases so they can include other partial test
|
||||
# cases.
|
||||
#
|
||||
# The partial's commands are returned as html table rows.
|
||||
module SeleniumOnRails::PartialsSupport
|
||||
include SeleniumOnRails::Paths
|
||||
|
||||
# Overrides where the partial is searched for, and returns only the command table rows.
|
||||
def render_partial partial_path = default_template_name, object = nil, local_assigns = nil, status = nil
|
||||
pattern = partial_pattern partial_path
|
||||
filename = Dir[pattern].first
|
||||
raise "Partial '#{partial_path}' cannot be found! (Looking for file: '#{pattern}')" unless filename
|
||||
partial = render :file => filename, :use_full_path => false, :locals => local_assigns
|
||||
extract_commands_from_partial partial
|
||||
end
|
||||
|
||||
# Extracts the commands from a partial. The partial must contain a html table
|
||||
# and the first row is ignored since it cannot contain a command.
|
||||
def extract_commands_from_partial partial
|
||||
partial = partial.match(/.*<table>.*?<tr>.*?<\/tr>(.*?)<\/table>/im)[1]
|
||||
raise "Partial '#{name}' doesn't contain any table" unless partial
|
||||
partial
|
||||
end
|
||||
|
||||
private
|
||||
# Generates the file pattern from the provided partial path.
|
||||
# The starting _ and file extension don't have too be provided.
|
||||
def partial_pattern partial_path
|
||||
path = partial_path.split '/'
|
||||
filename = path.delete_at(-1)
|
||||
filename = '_' + filename unless filename.starts_with? '_'
|
||||
filename << '.*' unless filename.include? '.'
|
||||
pattern = selenium_tests_path + '/'
|
||||
pattern << path.join('/') + '/' if path
|
||||
pattern << filename
|
||||
end
|
||||
|
||||
require 'selenium_on_rails/paths'
|
||||
|
||||
module SeleniumOnRails::PartialsSupport
|
||||
include SeleniumOnRails::Paths
|
||||
|
||||
# Overrides where the partial is searched for, and returns only the command table rows.
|
||||
def render_partial(options)
|
||||
pattern = partial_pattern options[:partial]
|
||||
filename = Dir[pattern].first
|
||||
raise "Partial '#{partial_path}' cannot be found! (Looking for file: '#{pattern}')" unless filename
|
||||
partial = render :file => filename, :use_full_path => false, :locals => options[:locals]
|
||||
extract_commands_from_partial partial
|
||||
end
|
||||
|
||||
# Extracts the commands from a partial. The partial must contain a html table
|
||||
# and the first row is ignored since it cannot contain a command.
|
||||
def extract_commands_from_partial partial
|
||||
partial = partial.match(/.*<table>.*?<tr>.*?<\/tr>(.*?)<\/table>/im)[1]
|
||||
raise "Partial '#{name}' doesn't contain any table" unless partial
|
||||
partial
|
||||
end
|
||||
|
||||
private
|
||||
# Generates the file pattern from the provided partial path.
|
||||
# The starting _ and file extension don't have too be provided.
|
||||
def partial_pattern partial_path
|
||||
path = partial_path.split '/'
|
||||
filename = path.delete_at(-1)
|
||||
filename = '_' + filename unless filename.starts_with? '_'
|
||||
filename << '.*' unless filename.include? '.'
|
||||
pattern = selenium_tests_path + '/'
|
||||
pattern << path.join('/') + '/' if path
|
||||
pattern << filename
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
require 'selenium_on_rails_config'
|
||||
|
||||
module SeleniumOnRails
|
||||
module Paths
|
||||
attr_accessor :config
|
||||
|
||||
def selenium_path
|
||||
@@selenium_path ||= find_selenium_path
|
||||
@@selenium_path
|
||||
|
|
@ -13,8 +17,11 @@ module SeleniumOnRails
|
|||
File.expand_path(File.dirname(__FILE__) + '/../views/' + view)
|
||||
end
|
||||
|
||||
# Returns the path to the layout template. The path is relative in relation
|
||||
# to the app/views/ directory since Rails doesn't support absolute paths
|
||||
# to layout templates.
|
||||
def layout_path
|
||||
'/layout.rhtml'
|
||||
'layout.rhtml'
|
||||
end
|
||||
|
||||
def fixtures_path
|
||||
|
|
@ -32,25 +39,22 @@ module SeleniumOnRails
|
|||
false
|
||||
end
|
||||
|
||||
private
|
||||
def find_selenium_path
|
||||
sel_dirs = SeleniumOnRailsConfig.get :selenium_path do
|
||||
ds = [File.expand_path(File.join(RAILS_ROOT, 'vendor/selenium')),
|
||||
File.expand_path(File.join(RAILS_ROOT, 'vendor/selenium-core'))]
|
||||
gems = Gem.source_index.find_name 'selenium', nil
|
||||
ds << gems.last.full_gem_path unless gems.empty?
|
||||
ds
|
||||
end
|
||||
private ###############################################
|
||||
|
||||
sel_dirs.to_a.each do |seleniumdir|
|
||||
['', 'core', 'selenium', 'javascript'].each do |subdir|
|
||||
path = File.join seleniumdir, subdir
|
||||
return path if File.exist?(File.join(path, 'TestRunner.html'))
|
||||
end
|
||||
end
|
||||
|
||||
raise 'Could not find Selenium Core installation'
|
||||
def find_selenium_path
|
||||
sel_dirs = @config.get :selenium_path do
|
||||
File.expand_path(File.dirname(__FILE__) + '/../../selenium-core')
|
||||
end
|
||||
|
||||
sel_dirs.to_a.each do |seleniumdir|
|
||||
['', 'core', 'selenium', 'javascript'].each do |subdir|
|
||||
path = File.join seleniumdir, subdir
|
||||
return path if File.exist?(File.join(path, 'TestRunner.html'))
|
||||
end
|
||||
end
|
||||
|
||||
raise 'Could not find Selenium Core installation'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
module SeleniumOnRails::Renderer
|
||||
include SeleniumOnRails::Paths
|
||||
include SeleniumHelper
|
||||
|
||||
def render_test_case filename
|
||||
@template.extend SeleniumOnRails::PartialsSupport
|
||||
@page_title = test_case_name filename
|
||||
output = render_to_string :file => filename
|
||||
layout = (output =~ /<html>/i ? false : layout_path)
|
||||
render :text => output, :layout => layout
|
||||
|
||||
headers['Cache-control'] = 'no-cache'
|
||||
headers['Pragma'] = 'no-cache'
|
||||
headers['Expires'] = '-1'
|
||||
end
|
||||
|
||||
module SeleniumOnRails::Renderer
|
||||
include SeleniumOnRails::Paths
|
||||
|
||||
def render_test_case filename
|
||||
@template.extend SeleniumOnRails::PartialsSupport
|
||||
@page_title = test_case_name filename
|
||||
output = render_to_string :file => filename, :locals => {"page_title" => @page_title}
|
||||
layout = (output =~ /<html>/i ? false : layout_path)
|
||||
render :text => output, :layout => layout
|
||||
|
||||
headers['Cache-control'] = 'no-cache'
|
||||
headers['Pragma'] = 'no-cache'
|
||||
headers['Expires'] = '-1'
|
||||
end
|
||||
|
||||
def test_case_name filename
|
||||
File.basename(filename).sub(/\..*/,'').humanize
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -13,23 +13,24 @@ ActionView::Template.register_template_handler 'rsel', SeleniumOnRails::RSelenes
|
|||
class SeleniumOnRails::RSelenese < SeleniumOnRails::TestBuilder
|
||||
attr_accessor :view
|
||||
|
||||
# Create a new RSelenese renderer bound to _view_.
|
||||
def initialize view
|
||||
super view
|
||||
@view = view
|
||||
end
|
||||
|
||||
# Render _template_ using _local_assigns_.
|
||||
def render template
|
||||
title = @view.assigns['page_title']
|
||||
def render template, local_assigns
|
||||
title = (@view.assigns['page_title'] or local_assigns['page_title'])
|
||||
table(title) do
|
||||
test = self #to enable test.command
|
||||
eval template.source
|
||||
|
||||
assign_locals_code = ''
|
||||
local_assigns.each_key {|key| assign_locals_code << "#{key} = local_assigns[#{key.inspect}];"}
|
||||
|
||||
eval assign_locals_code + "\n" + template.source
|
||||
end
|
||||
end
|
||||
|
||||
def compilable?
|
||||
false
|
||||
def self.call(template)
|
||||
"#{name}.new(self).render(template, local_assigns)"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
require 'selenium_on_rails/partials_support'
|
||||
|
||||
class SeleniumOnRails::Selenese
|
||||
end
|
||||
ActionView::Template.register_template_handler 'sel', SeleniumOnRails::Selenese
|
||||
|
||||
|
||||
class SeleniumOnRails::Selenese
|
||||
class SeleniumOnRails::Selenese
|
||||
def initialize view
|
||||
@view = view
|
||||
end
|
||||
|
||||
def render template
|
||||
name = @view.assigns['page_title']
|
||||
lines = template.strip.split "\n"
|
||||
def render template, local_assigns = {}
|
||||
name = (@view.assigns['page_title'] or local_assigns['page_title'])
|
||||
lines = template.source.strip.split "\n"
|
||||
html = ''
|
||||
html << extract_comments(lines)
|
||||
html << extract_commands(lines, name)
|
||||
|
|
@ -19,10 +21,6 @@ class SeleniumOnRails::Selenese
|
|||
html
|
||||
end
|
||||
|
||||
def compilable?
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
def next_line lines, expects
|
||||
while lines.any?
|
||||
|
|
@ -36,6 +34,10 @@ class SeleniumOnRails::Selenese
|
|||
return l
|
||||
end
|
||||
end
|
||||
|
||||
def self.call(template)
|
||||
"#{name}.new(self).render(template, local_assigns)"
|
||||
end
|
||||
|
||||
def extract_comments lines
|
||||
comments = ''
|
||||
|
|
|
|||
|
|
@ -1,51 +1,56 @@
|
|||
module SeleniumOnRails::SuiteRenderer
|
||||
def test_suite_name path
|
||||
return 'All test cases' if [nil, '/'].include? path_to_relative_url(path)
|
||||
File.split(path)[-1].humanize
|
||||
end
|
||||
|
||||
def test_suites path
|
||||
suites = []
|
||||
|
||||
parent_path = File.join(File.split(path).slice(0..-2)) #all but last
|
||||
parent_path = path_to_relative_url parent_path
|
||||
suites << ['..', parent_path] unless parent_path.nil?
|
||||
|
||||
visit_all_tests path, '', Proc.new {|n, p| suites << [n,path_to_relative_url(p)]}, nil
|
||||
suites
|
||||
end
|
||||
|
||||
def test_cases path
|
||||
tests = []
|
||||
visit_all_tests path, '', nil, Proc.new {|n, p| tests << [n,p]}
|
||||
tests
|
||||
end
|
||||
|
||||
def link_to_test_case suite_name, filename
|
||||
name = suite_name + test_case_name(filename)
|
||||
link_to name, :action => :test_file, :testname => path_to_relative_url(filename).sub(/^\//,'')
|
||||
end
|
||||
|
||||
private
|
||||
def path_to_relative_url path
|
||||
slt = @controller.selenium_tests_path
|
||||
return nil unless path.index slt
|
||||
path.sub slt, ''
|
||||
end
|
||||
|
||||
def visit_all_tests path, suite_name, suite_consumer, test_consumer
|
||||
dirs = [] #add dirs to an array in order for files to be processed before dirs
|
||||
Dir.entries(path).sort.each do |e|
|
||||
next if skip_file?(e) or ['.','..'].include?(e)
|
||||
filename = File.join path, e
|
||||
if File.directory? filename
|
||||
dirs << [filename, "#{suite_name}#{e.humanize}."]
|
||||
suite_consumer.call("#{suite_name}#{e.humanize}", filename) if suite_consumer
|
||||
else
|
||||
test_consumer.call(suite_name, filename) if test_consumer
|
||||
end
|
||||
end
|
||||
#recurse through dirs
|
||||
dirs.each {|p, n| visit_all_tests p, n, suite_consumer, test_consumer }
|
||||
end
|
||||
end
|
||||
require 'selenium_on_rails'
|
||||
|
||||
module SeleniumOnRails
|
||||
module SuiteRenderer
|
||||
def test_suite_name path
|
||||
return 'All test cases' if [nil, '/'].include? path_to_relative_url(path)
|
||||
File.split(path)[-1].humanize
|
||||
end
|
||||
|
||||
def test_suites path
|
||||
suites = []
|
||||
|
||||
parent_path = File.join(File.split(path).slice(0..-2)) #all but last
|
||||
parent_path = path_to_relative_url parent_path
|
||||
suites << ['..', parent_path] unless parent_path.nil?
|
||||
|
||||
visit_all_tests path, '', Proc.new {|n, p| suites << [n,path_to_relative_url(p)]}, nil
|
||||
suites
|
||||
end
|
||||
|
||||
def test_cases path
|
||||
tests = []
|
||||
visit_all_tests path, '', nil, Proc.new {|n, p| tests << [n,p]}
|
||||
tests
|
||||
end
|
||||
|
||||
def link_to_test_case suite_name, filename
|
||||
name = suite_name + test_case_name(filename)
|
||||
link_to name, :action => :test_file, :testname => path_to_relative_url(filename).sub(/^\//,'')
|
||||
end
|
||||
|
||||
private ###############################################
|
||||
|
||||
def path_to_relative_url path
|
||||
slt = @controller.selenium_tests_path
|
||||
return nil unless path.index slt
|
||||
path.sub slt, ''
|
||||
end
|
||||
|
||||
def visit_all_tests path, suite_name, suite_consumer, test_consumer
|
||||
dirs = [] #add dirs to an array in order for files to be processed before dirs
|
||||
Dir.entries(path).sort.each do |e|
|
||||
next if skip_file?(e) or ['.','..'].include?(e)
|
||||
filename = File.join path, e
|
||||
if File.directory? filename
|
||||
dirs << [filename, "#{suite_name}#{e.humanize}."]
|
||||
suite_consumer.call("#{suite_name}#{e.humanize}", filename) if suite_consumer
|
||||
else
|
||||
test_consumer.call(suite_name, filename) if test_consumer
|
||||
end
|
||||
end
|
||||
#recurse through dirs
|
||||
dirs.each {|p, n| visit_all_tests p, n, suite_consumer, test_consumer }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,92 +1,116 @@
|
|||
# Builds Selenium test table using a high-level Ruby interface. Normally
|
||||
# invoked through SeleniumOnRails::RSelenese.
|
||||
#
|
||||
# See SeleniumOnRails::TestBuilderActions for the available actions and
|
||||
# SeleniumOnRails::TestBuilderAccessors for the available checks.
|
||||
#
|
||||
# For more information on the commands supported by TestBuilder, see the
|
||||
# Selenium Commands Documentation at
|
||||
# http://release.openqa.org/selenium-core/nightly/reference.html.
|
||||
class SeleniumOnRails::TestBuilder
|
||||
include SeleniumOnRails::TestBuilderActions
|
||||
include SeleniumOnRails::TestBuilderAccessors
|
||||
|
||||
# Convert _str_ to a Selenium command name.
|
||||
def self.selenize str
|
||||
str.camelize.gsub(/^[A-Z]/) {|s| s.downcase }
|
||||
end
|
||||
|
||||
# Prepends _pattern_ with 'exact:' if it would be considered containing
|
||||
# string-match pattern otherwise.
|
||||
def exactize pattern
|
||||
pattern.include?(':') ? "exact:#{pattern}" : pattern
|
||||
end
|
||||
|
||||
# Create a new TestBuilder for _view_.
|
||||
def initialize view
|
||||
@view = view
|
||||
@output = ''
|
||||
@xml = Builder::XmlMarkup.new :indent => 2, :target => @output
|
||||
end
|
||||
|
||||
# Add a new table of tests, and return the HTML.
|
||||
def table title
|
||||
@xml.table do
|
||||
@xml.tr do @xml.th(title, :colspan => 3) end
|
||||
yield self
|
||||
end
|
||||
end
|
||||
|
||||
# Add a new test command using _cmd_, _target_ and _value_.
|
||||
def command cmd, target=nil, value=nil
|
||||
@xml.tr do
|
||||
_tdata cmd
|
||||
_tdata target
|
||||
_tdata value
|
||||
end
|
||||
end
|
||||
# :nodoc
|
||||
alias_method :command_verbatim, :command
|
||||
|
||||
# Same as _command_ but add _AndWait_ to the name of _cmd_.
|
||||
def command_and_wait cmd, target=nil, value=nil
|
||||
command_verbatim cmd.to_s + 'AndWait', target, value
|
||||
end
|
||||
|
||||
# Re routes commands in the provided block to #command_and_wait instead of
|
||||
# #command.
|
||||
def make_command_waiting
|
||||
self.class.send :alias_method, :command, :command_and_wait
|
||||
yield
|
||||
self.class.send :alias_method, :command, :command_verbatim
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# If _url_ is a string, return unchanged. Otherwise, pass it to
|
||||
# ActionView#UrlHelper#url_for.
|
||||
def url_arg url
|
||||
if url.instance_of?(String) then url else exactize(@view.url_for(url)) end
|
||||
end
|
||||
|
||||
# If _arg_ is an array formats _arg_ to a textual representation.
|
||||
# Otherwise return unchanged.
|
||||
def collection_arg arg
|
||||
if arg.is_a? Array
|
||||
arg.collect {|e| e.gsub(/[\\,]/) {|s| "\\#{s}" } }.join(',')
|
||||
else
|
||||
arg
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Output a single TD element.
|
||||
def _tdata value
|
||||
if value
|
||||
@xml.td(value.to_s)
|
||||
else
|
||||
@xml.td do @xml.target! << ' ' end
|
||||
end
|
||||
end
|
||||
end
|
||||
require 'selenium_on_rails/test_builder_actions'
|
||||
require 'selenium_on_rails/test_builder_accessors'
|
||||
|
||||
# Create test_builder_user_actions.rb to support actions included
|
||||
# in selenium-core's user-extensions.js
|
||||
#
|
||||
# See test_builder_user_actions.rb.example for examples matching
|
||||
# selenium-core's user-extensions.js.sample
|
||||
module SeleniumOnRails::TestBuilderUserActions
|
||||
end
|
||||
require 'selenium_on_rails/test_builder_user_actions' if File.exist?(File.expand_path(File.join(File.dirname(__FILE__), 'test_builder_user_actions.rb')))
|
||||
|
||||
|
||||
# Create test_builder_user_accessors.rb to support accessors
|
||||
# included in selenium-core's user-extensions.js
|
||||
#
|
||||
# See test_builder_user_accessors.rb.example for examples matching
|
||||
# selenium-core's user-extensions.js.sample
|
||||
module SeleniumOnRails::TestBuilderUserAccessors
|
||||
end
|
||||
require 'selenium_on_rails/test_builder_user_accessors' if File.exist?(File.expand_path(File.join(File.dirname(__FILE__), 'test_builder_user_accessors.rb')))
|
||||
|
||||
# Builds Selenium test table using a high-level Ruby interface. Normally
|
||||
# invoked through SeleniumOnRails::RSelenese.
|
||||
#
|
||||
# See SeleniumOnRails::TestBuilderActions for the available actions and
|
||||
# SeleniumOnRails::TestBuilderAccessors for the available checks.
|
||||
#
|
||||
# For more information on the commands supported by TestBuilder, see the
|
||||
# Selenium Commands Documentation at
|
||||
# http://release.openqa.org/selenium-core/nightly/reference.html.
|
||||
class SeleniumOnRails::TestBuilder
|
||||
include SeleniumOnRails::TestBuilderActions
|
||||
include SeleniumOnRails::TestBuilderAccessors
|
||||
include SeleniumOnRails::TestBuilderUserActions
|
||||
include SeleniumOnRails::TestBuilderUserAccessors
|
||||
|
||||
# Convert _str_ to a Selenium command name.
|
||||
def self.selenize str
|
||||
str.camelize.gsub(/^[A-Z]/) {|s| s.downcase }
|
||||
end
|
||||
|
||||
# Prepends _pattern_ with 'exact:' if it would be considered containing
|
||||
# string-match pattern otherwise.
|
||||
def exactize pattern
|
||||
pattern.include?(':') ? "exact:#{pattern}" : pattern
|
||||
end
|
||||
|
||||
# Create a new TestBuilder for _view_.
|
||||
def initialize view
|
||||
@view = view
|
||||
@output = ''
|
||||
@xml = Builder::XmlMarkup.new :indent => 2, :target => @output
|
||||
end
|
||||
|
||||
# Add a new table of tests, and return the HTML.
|
||||
def table title
|
||||
@xml.table do
|
||||
@xml.tr do @xml.th(title, :colspan => 3) end
|
||||
yield self
|
||||
end
|
||||
end
|
||||
|
||||
# Add a new test command using _cmd_, _target_ and _value_.
|
||||
def command cmd, target=nil, value=nil
|
||||
@xml.tr do
|
||||
_tdata cmd
|
||||
_tdata target
|
||||
_tdata value
|
||||
end
|
||||
end
|
||||
# :nodoc
|
||||
alias_method :command_verbatim, :command
|
||||
|
||||
# Same as _command_ but add _AndWait_ to the name of _cmd_.
|
||||
def command_and_wait cmd, target=nil, value=nil
|
||||
command_verbatim cmd.to_s + 'AndWait', target, value
|
||||
end
|
||||
|
||||
# Re routes commands in the provided block to #command_and_wait instead of
|
||||
# #command.
|
||||
def make_command_waiting
|
||||
self.class.send :alias_method, :command, :command_and_wait
|
||||
yield
|
||||
self.class.send :alias_method, :command, :command_verbatim
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
# If _url_ is a string, return unchanged. Otherwise, pass it to
|
||||
# ActionView#UrlHelper#url_for.
|
||||
def url_arg url
|
||||
if url.instance_of?(String) then url else exactize(@view.url_for(url)) end
|
||||
end
|
||||
|
||||
# If _arg_ is an array formats _arg_ to a textual representation.
|
||||
# Otherwise return unchanged.
|
||||
def collection_arg arg
|
||||
if arg.is_a? Array
|
||||
arg.collect {|e| e.gsub(/[\\,]/) {|s| "\\#{s}" } }.join(',')
|
||||
else
|
||||
arg
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Output a single TD element.
|
||||
def _tdata value
|
||||
if value
|
||||
@xml.td(value.to_s)
|
||||
else
|
||||
@xml.td do @xml.target! << ' ' end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,286 +1,515 @@
|
|||
# The actions available for SeleniumOnRails::TestBuilder tests.
|
||||
#
|
||||
# For each action +foo+ there's also an action +foo_and_wait+.
|
||||
module SeleniumOnRails::TestBuilderActions
|
||||
# Tell Selenium on Rails to clear the session and load any fixtures. DO
|
||||
# NOT CALL THIS AGAINST NON-TEST DATABASES.
|
||||
# The supported +options+ are <code>:keep_session</code>,
|
||||
# <code>:fixtures</code> and <code>:clear_tables</code>
|
||||
# setup
|
||||
# setup :keep_session
|
||||
# setup :fixtures => :all
|
||||
# setup :keep_session, :fixtures => [:foo, :bar]
|
||||
# setup :clear_tables => [:foo, :bar]
|
||||
def setup options = {}
|
||||
options = {options => nil} unless options.is_a? Hash
|
||||
|
||||
opts = {:controller => 'selenium', :action => 'setup'}
|
||||
opts[:keep_session] = true if options.has_key? :keep_session
|
||||
|
||||
[:fixtures, :clear_tables].each do |key|
|
||||
if (f = options[key])
|
||||
f = [f] unless f.is_a? Array
|
||||
opts[key] = f.join ','
|
||||
end
|
||||
end
|
||||
|
||||
open opts
|
||||
end
|
||||
|
||||
# Includes a partial.
|
||||
# The path is relative to the Selenium tests root. The starting _ and the file
|
||||
# extension don't have to be specified.
|
||||
# #include test/selenium/_partial.*
|
||||
# include_partial 'partial'
|
||||
# #include test/selenium/suite/_partial.*
|
||||
# include_partial 'suite/partial'
|
||||
# #include test/selenium/suite/_partial.* and provide local assigns
|
||||
# include_partial 'suite/partial', :foo => bar
|
||||
def include_partial path, local_assigns = {}
|
||||
partial = @view.render :partial => path, :locals => local_assigns
|
||||
@output << partial
|
||||
end
|
||||
|
||||
# Clicks on a link, button, checkbox or radio button. If the click action
|
||||
# causes a new page to load (like a link usually does), call
|
||||
# +wait_for_page_to_load+.
|
||||
def click locator
|
||||
command 'click', locator
|
||||
end
|
||||
|
||||
# Explicitly simulate an event (e.g. <tt>"focus"</tt>, <tt>"blur"</tt>), to
|
||||
# trigger the corresponding <tt>"on_event_"</tt> handler.
|
||||
def fire_event locator, event_name
|
||||
command 'fireEvent', locator, event_name
|
||||
end
|
||||
|
||||
# Simulates a user pressing and releasing a key.
|
||||
#
|
||||
# +keycode+ is the numeric keycode of the key to be pressed, normally the
|
||||
# ASCII value of that key.
|
||||
def key_press locator, keycode
|
||||
command 'keyPress', locator, keycode
|
||||
end
|
||||
|
||||
# Simulates a user pressing a key (without releasing it yet).
|
||||
#
|
||||
# +keycode+ is the numeric keycode of the key to be pressed, normally the
|
||||
# ASCII value of that key.
|
||||
def key_down locator, keycode
|
||||
command 'keyDown', locator, keycode
|
||||
end
|
||||
|
||||
# Simulates a user releasing a key.
|
||||
#
|
||||
# +keycode+ is the numeric keycode of the key to be released, normally the
|
||||
# ASCII value of that key.
|
||||
def key_up locator, keycode
|
||||
command 'keyUp', locator, keycode
|
||||
end
|
||||
|
||||
# Simulates a user hovering a mouse over the specified element.
|
||||
def mouse_over locator
|
||||
command 'mouseOver', locator
|
||||
end
|
||||
|
||||
# Simulates a user pressing the mouse button (without releasing it yet) on the
|
||||
# specified element.
|
||||
def mouse_down locator
|
||||
command 'mouseDown', locator
|
||||
end
|
||||
|
||||
# Sets the value of an input field, as though you typed it in.
|
||||
#
|
||||
# Can also be used to set the value of combo boxes, check boxes, etc. In these
|
||||
# cases, +value+ should be the value of the option selected, not the visible
|
||||
# text.
|
||||
def type locator, value
|
||||
command 'type', locator, value
|
||||
end
|
||||
|
||||
# Check a toggle-button (checkbox/radio).
|
||||
def check locator
|
||||
command 'check', locator
|
||||
end
|
||||
|
||||
# Uncheck a toggle-button (checkbox/radio).
|
||||
def uncheck locator
|
||||
command 'uncheck', locator
|
||||
end
|
||||
|
||||
# Select an option from a drop-down using an option locator.
|
||||
#
|
||||
# Option locators provide different ways of specifying options of an HTML
|
||||
# Select element (e.g. for selecting a specific option, or for asserting that
|
||||
# the selected option satisfies a specification). There are several forms of
|
||||
# Select Option Locator.
|
||||
#
|
||||
# * label=labelPattern
|
||||
# matches options based on their labels, i.e. the visible text. (This is the
|
||||
# default.)
|
||||
# label=regexp:^[Oo]ther
|
||||
# * value=valuePattern
|
||||
# matches options based on their values.
|
||||
# value=other
|
||||
# * id=id
|
||||
# matches options based on their ids.
|
||||
# id=option1
|
||||
# * index=index
|
||||
# matches an option based on its index (offset from zero).
|
||||
# index=2
|
||||
#
|
||||
# If no option locator prefix is provided, the default behaviour is to match
|
||||
# on label.
|
||||
def select locator, option_locator
|
||||
command 'select', locator, option_locator
|
||||
end
|
||||
|
||||
# Add a selection to the set of selected options in a multi-select element
|
||||
# using an option locator.
|
||||
#
|
||||
# See the <tt>#select</tt> command for more information about option locators.
|
||||
def add_selection locator, option_locator
|
||||
command 'addSelection', locator, option_locator
|
||||
end
|
||||
|
||||
# Remove a selection from the set of selected options in a multi-select
|
||||
# element using an option locator.
|
||||
#
|
||||
# See the +select+ command for more information about option locators.
|
||||
def remove_selection locator, option_locator
|
||||
command 'removeSelection', locator, option_locator
|
||||
end
|
||||
|
||||
# Submit the specified form. This is particularly useful for forms without
|
||||
# submit buttons, e.g. single-input "Search" forms.
|
||||
def submit locator
|
||||
command 'submit', locator
|
||||
end
|
||||
|
||||
# Opens an URL in the test frame. This accepts both relative and absolute
|
||||
# URLs. The <tt>open</tt> command waits for the page to load before
|
||||
# proceeding, i.e. you don't have to call +wait_for_page_to_load+.
|
||||
#
|
||||
# Note: The URL must be on the same domain as the runner HTML due to security
|
||||
# restrictions in the browser (Same Origin Policy).
|
||||
def open url
|
||||
command 'open', url_arg(url)
|
||||
end
|
||||
|
||||
# Selects a popup window; once a popup window has been selected, all commands
|
||||
# go to that window. To select the main window again, use +nil+ as the target.
|
||||
def select_window window_id
|
||||
command 'selectWindow', window_id||'null'
|
||||
end
|
||||
|
||||
# Waits for a popup window to appear and load up.
|
||||
#
|
||||
# The +timeout+ is specified in milliseconds.
|
||||
def wait_for_popup window_id, timeout
|
||||
command 'waitForPopUp', window_id||'null', timeout
|
||||
end
|
||||
|
||||
# By default, Selenium's overridden <tt>window.confirm()</tt> function will return
|
||||
# +true+, as if the user had manually clicked OK. After running this command,
|
||||
# the next call to <tt>confirm()</tt> will return +false+, as if the user had clicked
|
||||
# Cancel.
|
||||
def choose_cancel_on_next_confirmation
|
||||
command 'chooseCancelOnNextConfirmation'
|
||||
end
|
||||
|
||||
# Instructs Selenium to return the specified answer string in response to the
|
||||
# next JavaScript prompt (<tt>window.prompt()</tt>).
|
||||
def answer_on_next_prompt answer
|
||||
command 'answerOnNextPrompt', answer
|
||||
end
|
||||
|
||||
# Simulates the user clicking the "back" button on their browser.
|
||||
def go_back
|
||||
command 'goBack'
|
||||
end
|
||||
|
||||
# Simulates the user clicking the "Refresh" button on their browser.
|
||||
def refresh
|
||||
command 'refresh'
|
||||
end
|
||||
|
||||
# Simulates the user clicking the "close" button in the titlebar of a popup
|
||||
# window or tab.
|
||||
def close
|
||||
command 'close'
|
||||
end
|
||||
|
||||
# Writes a message to the status bar and adds a note to the browser-side log.
|
||||
#
|
||||
# +context+ is the message sent to the browser.
|
||||
#
|
||||
# +log_level_threshold+ can be +nil+, <tt>:debug</tt>, <tt>:info</tt>,
|
||||
# <tt>:warn</tt> or <tt>:error</tt>.
|
||||
def set_context context, log_level_threshold = nil
|
||||
if log_level_threshold
|
||||
command 'setContext', context, log_level_threshold.to_s
|
||||
else
|
||||
command 'setContext', context
|
||||
end
|
||||
end
|
||||
|
||||
# Runs the specified JavaScript snippet repeatedly until it evaluates to
|
||||
# +true+. The snippet may have multiple lines, but only the result of the last
|
||||
# line will be considered.
|
||||
#
|
||||
# Note that, by default, the snippet will be run in the runner's test window,
|
||||
# not in the window of your application. To get the window of your
|
||||
# application, you can use the JavaScript snippet
|
||||
# <tt>selenium.browserbot.getCurrentWindow()</tt>, and then run your
|
||||
# JavaScript in there.
|
||||
#
|
||||
# +timeout+ is specified in milliseconds.
|
||||
def wait_for_condition script, timeout
|
||||
command 'waitForCondition', script, timeout
|
||||
end
|
||||
|
||||
# Specifies the amount of time that Selenium will wait for actions to
|
||||
# complete.
|
||||
#
|
||||
# Actions that require waiting include +open+ and the <tt>wait_for*</tt>
|
||||
# actions.
|
||||
#
|
||||
# The default timeout is 30 seconds.
|
||||
#
|
||||
# +timeout+ is specified in milliseconds.
|
||||
def set_timeout timeout
|
||||
command 'setTimeout', timeout
|
||||
end
|
||||
|
||||
# Waits for a new page to load.
|
||||
#
|
||||
# You can use this command instead of the +and_wait+ suffixes,
|
||||
# +click_and_wait+, +select_and_wait+, +type_and_wait+ etc. (which are only
|
||||
# available in the JS API).
|
||||
#
|
||||
# Selenium constantly keeps track of new pages loading, and sets a
|
||||
# +newPageLoaded+ flag when it first notices a page load. Running any other
|
||||
# Selenium command after turns the flag to +false+. Hence, if you want to wait
|
||||
# for a page to load, you must wait immediately after a Selenium command that
|
||||
# caused a page-load.
|
||||
#
|
||||
# +timeout+ is specified in milliseconds.
|
||||
def wait_for_page_to_load timeout
|
||||
command 'waitForPageToLoad', timeout
|
||||
end
|
||||
|
||||
private
|
||||
# Generates the corresponding +_and_wait+ for each action.
|
||||
def self.generate_and_wait_actions
|
||||
public_instance_methods.each do |method|
|
||||
define_method method + '_and_wait' do |*args|
|
||||
make_command_waiting do
|
||||
send method, *args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
generate_and_wait_actions
|
||||
end
|
||||
|
||||
# The actions available for SeleniumOnRails::TestBuilder tests.
|
||||
#
|
||||
# For each action +foo+ there's also an action +foo_and_wait+.
|
||||
module SeleniumOnRails::TestBuilderActions
|
||||
# Tell Selenium on Rails to clear the session and load any fixtures. DO
|
||||
# NOT CALL THIS AGAINST NON-TEST DATABASES.
|
||||
# The supported +options+ are <code>:keep_session</code>,
|
||||
# <code>:fixtures</code> and <code>:clear_tables</code>
|
||||
# setup
|
||||
# setup :keep_session
|
||||
# setup :fixtures => :all
|
||||
# setup :keep_session, :fixtures => [:foo, :bar]
|
||||
# setup :clear_tables => [:foo, :bar]
|
||||
def setup options = {}
|
||||
options = {options => nil} unless options.is_a? Hash
|
||||
|
||||
opts = {:controller => 'selenium', :action => 'setup'}
|
||||
opts[:keep_session] = true if options.has_key? :keep_session
|
||||
|
||||
[:fixtures, :clear_tables].each do |key|
|
||||
if (f = options[key])
|
||||
f = [f] unless f.is_a? Array
|
||||
opts[key] = f.join ','
|
||||
end
|
||||
end
|
||||
|
||||
open opts
|
||||
end
|
||||
|
||||
# Includes a partial.
|
||||
# The path is relative to the Selenium tests root. The starting _ and the file
|
||||
# extension don't have to be specified.
|
||||
# #include test/selenium/_partial.*
|
||||
# include_partial 'partial'
|
||||
# #include test/selenium/suite/_partial.*
|
||||
# include_partial 'suite/partial'
|
||||
# #include test/selenium/suite/_partial.* and provide local assigns
|
||||
# include_partial 'suite/partial', :foo => bar
|
||||
def include_partial path, local_assigns = {}
|
||||
partial = @view.render :partial => path, :locals => local_assigns
|
||||
@output << partial
|
||||
end
|
||||
|
||||
# Clicks on a link, button, checkbox or radio button. If the click action
|
||||
# causes a new page to load (like a link usually does), call
|
||||
# +wait_for_page_to_load+.
|
||||
def click locator
|
||||
command 'click', locator
|
||||
end
|
||||
|
||||
# Clicks on a link, button, checkbox or radio button. If the click action causes
|
||||
# a new page to load (like a link usually does), call wait_for_page_to_load.
|
||||
def click_at locator, coord_string
|
||||
command 'clickAt', locator, coord_string
|
||||
end
|
||||
|
||||
# Explicitly simulate an event (e.g. <tt>"focus"</tt>, <tt>"blur"</tt>), to
|
||||
# trigger the corresponding <tt>"on_event_"</tt> handler.
|
||||
def fire_event locator, event_name
|
||||
command 'fireEvent', locator, event_name
|
||||
end
|
||||
|
||||
# Simulates a user pressing and releasing a key.
|
||||
#
|
||||
# +keycode+ is the numeric keycode of the key to be pressed, normally the
|
||||
# ASCII value of that key.
|
||||
def key_press locator, keycode
|
||||
command 'keyPress', locator, keycode
|
||||
end
|
||||
|
||||
# Simulates a user pressing a key (without releasing it yet).
|
||||
#
|
||||
# +keycode+ is the numeric keycode of the key to be pressed, normally the
|
||||
# ASCII value of that key.
|
||||
def key_down locator, keycode
|
||||
command 'keyDown', locator, keycode
|
||||
end
|
||||
|
||||
# Simulates a user releasing a key.
|
||||
#
|
||||
# +keycode+ is the numeric keycode of the key to be released, normally the
|
||||
# ASCII value of that key.
|
||||
def key_up locator, keycode
|
||||
command 'keyUp', locator, keycode
|
||||
end
|
||||
|
||||
# Simulates a user hovering a mouse over the specified element.
|
||||
def mouse_over locator
|
||||
command 'mouseOver', locator
|
||||
end
|
||||
|
||||
# Simulates a user pressing the mouse button (without releasing it yet) on the
|
||||
# specified element.
|
||||
def mouse_down locator
|
||||
command 'mouseDown', locator
|
||||
end
|
||||
|
||||
# Sets the value of an input field, as though you typed it in.
|
||||
#
|
||||
# Can also be used to set the value of combo boxes, check boxes, etc. In these
|
||||
# cases, +value+ should be the value of the option selected, not the visible
|
||||
# text.
|
||||
def type locator, value
|
||||
command 'type', locator, value
|
||||
end
|
||||
|
||||
# Check a toggle-button (checkbox/radio).
|
||||
def check locator
|
||||
command 'check', locator
|
||||
end
|
||||
|
||||
# Uncheck a toggle-button (checkbox/radio).
|
||||
def uncheck locator
|
||||
command 'uncheck', locator
|
||||
end
|
||||
|
||||
# Select an option from a drop-down using an option locator.
|
||||
#
|
||||
# Option locators provide different ways of specifying options of an HTML
|
||||
# Select element (e.g. for selecting a specific option, or for asserting that
|
||||
# the selected option satisfies a specification). There are several forms of
|
||||
# Select Option Locator.
|
||||
#
|
||||
# * label=labelPattern
|
||||
# matches options based on their labels, i.e. the visible text. (This is the
|
||||
# default.)
|
||||
# label=regexp:^[Oo]ther
|
||||
# * value=valuePattern
|
||||
# matches options based on their values.
|
||||
# value=other
|
||||
# * id=id
|
||||
# matches options based on their ids.
|
||||
# id=option1
|
||||
# * index=index
|
||||
# matches an option based on its index (offset from zero).
|
||||
# index=2
|
||||
#
|
||||
# If no option locator prefix is provided, the default behaviour is to match
|
||||
# on label.
|
||||
def select locator, option_locator
|
||||
command 'select', locator, option_locator
|
||||
end
|
||||
|
||||
# Add a selection to the set of selected options in a multi-select element
|
||||
# using an option locator.
|
||||
#
|
||||
# See the <tt>#select</tt> command for more information about option locators.
|
||||
def add_selection locator, option_locator
|
||||
command 'addSelection', locator, option_locator
|
||||
end
|
||||
|
||||
# Remove a selection from the set of selected options in a multi-select
|
||||
# element using an option locator.
|
||||
#
|
||||
# See the +select+ command for more information about option locators.
|
||||
def remove_selection locator, option_locator
|
||||
command 'removeSelection', locator, option_locator
|
||||
end
|
||||
|
||||
# Submit the specified form. This is particularly useful for forms without
|
||||
# submit buttons, e.g. single-input "Search" forms.
|
||||
def submit locator
|
||||
command 'submit', locator
|
||||
end
|
||||
|
||||
# Opens an URL in the test frame. This accepts both relative and absolute
|
||||
# URLs. The <tt>open</tt> command waits for the page to load before
|
||||
# proceeding, i.e. you don't have to call +wait_for_page_to_load+.
|
||||
#
|
||||
# Note: The URL must be on the same domain as the runner HTML due to security
|
||||
# restrictions in the browser (Same Origin Policy).
|
||||
def open url
|
||||
command 'open', url_arg(url)
|
||||
end
|
||||
|
||||
# Selects a popup window; once a popup window has been selected, all commands
|
||||
# go to that window. To select the main window again, use +nil+ as the target.
|
||||
def select_window window_id
|
||||
command 'selectWindow', window_id||'null'
|
||||
end
|
||||
|
||||
# Waits for a popup window to appear and load up.
|
||||
#
|
||||
# The +timeout+ is specified in milliseconds.
|
||||
def wait_for_popup window_id, timeout
|
||||
command 'waitForPopUp', window_id||'null', timeout
|
||||
end
|
||||
|
||||
# By default, Selenium's overridden <tt>window.confirm()</tt> function will return
|
||||
# +true+, as if the user had manually clicked OK. After running this command,
|
||||
# the next call to <tt>confirm()</tt> will return +false+, as if the user had clicked
|
||||
# Cancel.
|
||||
def choose_cancel_on_next_confirmation
|
||||
command 'chooseCancelOnNextConfirmation'
|
||||
end
|
||||
|
||||
# Instructs Selenium to return the specified answer string in response to the
|
||||
# next JavaScript prompt (<tt>window.prompt()</tt>).
|
||||
def answer_on_next_prompt answer
|
||||
command 'answerOnNextPrompt', answer
|
||||
end
|
||||
|
||||
# Simulates the user clicking the "back" button on their browser.
|
||||
def go_back
|
||||
command 'goBack'
|
||||
end
|
||||
|
||||
# Simulates the user clicking the "Refresh" button on their browser.
|
||||
def refresh
|
||||
command 'refresh'
|
||||
end
|
||||
|
||||
# Simulates the user clicking the "close" button in the titlebar of a popup
|
||||
# window or tab.
|
||||
def close
|
||||
command 'close'
|
||||
end
|
||||
|
||||
# Simulates the user pressing the alt key and hold it down until do_alt_up()
|
||||
# is called or a new page is loaded.
|
||||
def alt_key_down
|
||||
command 'altKeyDown'
|
||||
end
|
||||
|
||||
# Simulates the user releasing the alt key.
|
||||
def alt_key_up
|
||||
command 'altKeyUp'
|
||||
end
|
||||
|
||||
# Halt the currently running test, and wait for the user to press the Continue
|
||||
# button. This command is useful for debugging, but be careful when using it,
|
||||
# because it will force automated tests to hang until a user intervenes manually.
|
||||
#
|
||||
# NOTE: <tt>break</tt> is a reserved word in Ruby, so we have to simulate
|
||||
# Selenium core's <tt>break()</tt> with <tt>brake()</tt>
|
||||
def brake
|
||||
command 'break'
|
||||
end
|
||||
|
||||
# Simulates the user pressing the alt key and hold it down until do_control_up()
|
||||
# is called or a new page is loaded.
|
||||
def control_key_down
|
||||
command 'controlKeyDown'
|
||||
end
|
||||
|
||||
# Simulates the user releasing the control key.
|
||||
def control_key_up
|
||||
command 'controlKeyUp'
|
||||
end
|
||||
|
||||
# Create a new cookie whose path and domain are same with those of current page
|
||||
# under test, unless you specified a path for this cookie explicitly.
|
||||
#
|
||||
# Arguments:
|
||||
# * <tt>name_value_pair</tt> - name and value of the cookie in a format "name=value"
|
||||
# * <tt>options_string</tt> - options for the cookie. Currently supported options
|
||||
# include 'path' and 'max_age'. The options_string's format is
|
||||
# <tt>"path=/path/, max_age=60"</tt>. The order of options are irrelevant, the
|
||||
# unit of the value of 'max_age' is second.
|
||||
def create_cookie name_value_pair, options_string
|
||||
command 'createCookie', name_value_pair, options_string
|
||||
end
|
||||
|
||||
# Delete a named cookie with specified path.
|
||||
def delete_cookie name, path
|
||||
command 'deleteCookie', name, path
|
||||
end
|
||||
|
||||
# Double clicks on a link, button, checkbox or radio button. If the double click action
|
||||
# causes a new page to load (like a link usually does), call <tt>wait_for_page_to_load</tt>.
|
||||
def double_click locator
|
||||
command 'doubleClick', locator
|
||||
end
|
||||
|
||||
# Doubleclicks on a link, button, checkbox or radio button. If the action causes a new page
|
||||
# to load (like a link usually does), call <tt>wait_for_page_to_load</tt>.
|
||||
def double_click_at locator, coord_string
|
||||
command 'doubleClickAt', locator, coord_string
|
||||
end
|
||||
|
||||
# Drags an element a certain distance and then drops it.
|
||||
def drag_and_drop locator, movements_string
|
||||
command 'dragAndDrop', locator, movements_string
|
||||
end
|
||||
|
||||
# Drags an element and drops it on another element.
|
||||
def drag_and_drop_to_object locator_of_object_to_be_dragged, locator_of_drag_destination_object
|
||||
command 'dragAndDropToObject', locator_of_object_to_be_dragged, locator_of_drag_destination_object
|
||||
end
|
||||
|
||||
# Prints the specified message into the third table cell in your Selenese
|
||||
# tables.
|
||||
# Useful for debugging.
|
||||
def echo message
|
||||
command 'echo', message
|
||||
end
|
||||
|
||||
# Briefly changes the backgroundColor of the specified element yellow.
|
||||
# Useful for debugging.
|
||||
def highlight locator
|
||||
command 'highlight', locator
|
||||
end
|
||||
|
||||
# Press the meta key and hold it down until <tt>doMetaUp()</tt> is called or
|
||||
# a new page is loaded.
|
||||
def meta_key_down
|
||||
command 'metaKeyDown'
|
||||
end
|
||||
|
||||
# Release the meta key.
|
||||
def meta_key_up
|
||||
command 'metaKeyUp'
|
||||
end
|
||||
|
||||
# Simulates a user pressing the mouse button (without releasing it yet) on the specified
|
||||
# element.
|
||||
def mouse_down_at locator, coord_string
|
||||
command 'mouseDownAt', locator, coord_string
|
||||
end
|
||||
|
||||
# Simulates a user moving the mouse.
|
||||
def mouse_move locator
|
||||
command 'mouseMove', locator
|
||||
end
|
||||
|
||||
# Simulates a user moving the mouse relative to the specified element.
|
||||
def mouse_move_at locator, coord_string
|
||||
command 'mouseMoveAt', locator, coord_string
|
||||
end
|
||||
|
||||
# Simulates the user moving the mouse off the specified element.
|
||||
def mouse_out locator
|
||||
command 'mouseOut', locator
|
||||
end
|
||||
|
||||
# Simulates the user releasing the mouse button on the specified element.
|
||||
def mouse_up locator
|
||||
command 'mouseUp', locator
|
||||
end
|
||||
|
||||
# Simulates a user pressing the mouse button (without releasing it yet) on the
|
||||
# specified element.
|
||||
def mouse_up_at locator, coord_string
|
||||
command 'mouseUpAt', locator, coord_string
|
||||
end
|
||||
|
||||
# Opens a popup window (if a window with that ID isn't already open). After opening the
|
||||
# window, you'll need to select it using the <tt>select_window</tt> command.
|
||||
#
|
||||
# This command can also be a useful workaround for bug SEL-339. In some cases, Selenium
|
||||
# will be unable to intercept a call to window.open (if the call occurs during or before
|
||||
# the "onLoad" event, for example). In those cases, you can force Selenium to notice the
|
||||
# open window's name by using the Selenium openWindow command, using an empty (blank) url,
|
||||
# like this: <tt>open_window("", "myFunnyWindow")</tt>.
|
||||
def open_window url, window_id
|
||||
command 'openWindow', url, window_id
|
||||
end
|
||||
|
||||
# Wait for the specified amount of time (in milliseconds).
|
||||
def pause wait_time
|
||||
command 'pause', wait_time
|
||||
end
|
||||
|
||||
# Unselects all of the selected options in a multi-select element.
|
||||
def remove_all_selections locator
|
||||
command 'removeAllSelections', locator
|
||||
end
|
||||
|
||||
# Selects a frame within the current window. (You may invoke this command multiple times
|
||||
# to select nested frames.) To select the parent frame, use "relative=parent" as a
|
||||
# locator; to select the top frame, use "relative=top".
|
||||
#
|
||||
# You may also use a DOM expression to identify the frame you want directly, like this:
|
||||
# <tt>dom=frames["main"].frames["subframe"]</tt>
|
||||
def select_frame locator
|
||||
command 'selectFrame', locator
|
||||
end
|
||||
|
||||
# Moves the text cursor to the specified position in the given input element or textarea.
|
||||
# This method will fail if the specified element isn't an input element or textarea.
|
||||
def set_cursor_position locator, position
|
||||
command 'setCursorPosition', locator, position
|
||||
end
|
||||
|
||||
# Configure the number of pixels between "mousemove" events during dragAndDrop commands
|
||||
# (default=10).
|
||||
# Setting this value to 0 means that we'll send a "mousemove" event to every single pixel
|
||||
# in between the start location and the end location; that can be very slow, and may
|
||||
# cause some browsers to force the JavaScript to timeout.
|
||||
#
|
||||
# If the mouse speed is greater than the distance between the two dragged objects, we'll
|
||||
# just send one "mousemove" at the start location and then one final one at the end location.
|
||||
def set_mouse_speed pixels
|
||||
command 'setMouseSpeed', pixels
|
||||
end
|
||||
|
||||
# Press the shift key and hold it down until <tt>doShiftUp()</tt> is called or a new page
|
||||
# is loaded.
|
||||
def shift_key_down
|
||||
command 'shiftKeyDown'
|
||||
end
|
||||
|
||||
# Release the shift key.
|
||||
def shift_key_up
|
||||
command 'shiftKeyUp'
|
||||
end
|
||||
|
||||
# This command is a synonym for <tt>store_expression</tt>.
|
||||
def store expression, variable_name
|
||||
command 'store', expression, variable_name
|
||||
end
|
||||
|
||||
# Simulates keystroke events on the specified element, as though you typed the value
|
||||
# key-by-key.
|
||||
#
|
||||
# This is a convenience method for calling <tt>key_down</tt>, <tt>key_up</tt>,
|
||||
# <tt>key_press</tt> for every character in the specified string; this is useful for
|
||||
# dynamic UI widgets (like auto-completing combo boxes) that require explicit key events.
|
||||
#
|
||||
# Unlike the simple "type" command, which forces the specified value into the page directly,
|
||||
# this command may or may not have any visible effect, even in cases where typing keys would
|
||||
# normally have a visible effect. For example, if you use "<tt>type_keys</tt>" on a form
|
||||
# element, you may or may not see the results of what you typed in the field.
|
||||
#
|
||||
# In some cases, you may need to use the simple "type" command to set the value of the field
|
||||
# and then the "<tt>type_keys</tt>" command to send the keystroke events corresponding to
|
||||
# what you just typed.
|
||||
def type_keys locator, value
|
||||
command 'typeKeys', locator, value
|
||||
end
|
||||
|
||||
# Gives focus to a window.
|
||||
def window_focus window_name
|
||||
command 'windowFocus', window_name
|
||||
end
|
||||
|
||||
# Resize window to take up the entire screen.
|
||||
def window_maximize window_name
|
||||
command 'windowMaximize', window_name
|
||||
end
|
||||
|
||||
# Writes a message to the status bar and adds a note to the browser-side log.
|
||||
#
|
||||
# +context+ is the message sent to the browser.
|
||||
#
|
||||
# +log_level_threshold+ can be +nil+, <tt>:debug</tt>, <tt>:info</tt>,
|
||||
# <tt>:warn</tt> or <tt>:error</tt>.
|
||||
def set_context context, log_level_threshold = nil
|
||||
if log_level_threshold
|
||||
command 'setContext', context, log_level_threshold.to_s
|
||||
else
|
||||
command 'setContext', context
|
||||
end
|
||||
end
|
||||
|
||||
# Runs the specified JavaScript snippet repeatedly until it evaluates to
|
||||
# +true+. The snippet may have multiple lines, but only the result of the last
|
||||
# line will be considered.
|
||||
#
|
||||
# Note that, by default, the snippet will be run in the runner's test window,
|
||||
# not in the window of your application. To get the window of your
|
||||
# application, you can use the JavaScript snippet
|
||||
# <tt>selenium.browserbot.getCurrentWindow()</tt>, and then run your
|
||||
# JavaScript in there.
|
||||
#
|
||||
# +timeout+ is specified in milliseconds.
|
||||
def wait_for_condition script, timeout
|
||||
command 'waitForCondition', script, timeout
|
||||
end
|
||||
|
||||
# Specifies the amount of time that Selenium will wait for actions to
|
||||
# complete.
|
||||
#
|
||||
# Actions that require waiting include +open+ and the <tt>wait_for*</tt>
|
||||
# actions.
|
||||
#
|
||||
# The default timeout is 30 seconds.
|
||||
#
|
||||
# +timeout+ is specified in milliseconds.
|
||||
def set_timeout timeout
|
||||
command 'setTimeout', timeout
|
||||
end
|
||||
|
||||
# Waits for a new page to load.
|
||||
#
|
||||
# You can use this command instead of the +and_wait+ suffixes,
|
||||
# +click_and_wait+, +select_and_wait+, +type_and_wait+ etc. (which are only
|
||||
# available in the JS API).
|
||||
#
|
||||
# Selenium constantly keeps track of new pages loading, and sets a
|
||||
# +newPageLoaded+ flag when it first notices a page load. Running any other
|
||||
# Selenium command after turns the flag to +false+. Hence, if you want to wait
|
||||
# for a page to load, you must wait immediately after a Selenium command that
|
||||
# caused a page-load.
|
||||
#
|
||||
# +timeout+ is specified in milliseconds.
|
||||
def wait_for_page_to_load timeout
|
||||
command 'waitForPageToLoad', timeout
|
||||
end
|
||||
|
||||
private
|
||||
# Generates the corresponding +_and_wait+ for each action.
|
||||
def self.generate_and_wait_actions
|
||||
public_instance_methods.each do |method|
|
||||
define_method method + '_and_wait' do |*args|
|
||||
make_command_waiting do
|
||||
send method, *args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
generate_and_wait_actions
|
||||
end
|
||||
|
||||
|
|
|
|||
91
vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_accessors.rb.example
vendored
Normal file
91
vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_accessors.rb.example
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Mirrors the accessors specified in user-extensions.js from the selenium-core
|
||||
module SeleniumOnRails::TestBuilderUserAccessors
|
||||
|
||||
# Return the length of text of a specified element.
|
||||
#
|
||||
# Related Assertions, automatically generated:
|
||||
# * <tt>assert_text_length(locator, variable)</tt>
|
||||
# * <tt>assert_not_text_length(locator, length)</tt>
|
||||
# * <tt>verify_text_length(locator, length)</tt>
|
||||
# * <tt>verify_not_text_length(locator, length)</tt>
|
||||
# * <tt>wait_for_text_length(locator, length)</tt>
|
||||
# * <tt>wait_for_not_text_length(locator, length)</tt>
|
||||
def store_text_length locator, variable_name
|
||||
command 'storeTextLength', locator, variable_name
|
||||
end
|
||||
|
||||
# Checks if value entered more than once in textbox.
|
||||
#
|
||||
# Related Assertions, automatically generated:
|
||||
# * <tt>assert_not_text_length(locator, text)</tt>
|
||||
# * <tt>verify_text_length(locator, text)</tt>
|
||||
# * <tt>verify_not_text_length(locator, text)</tt>
|
||||
# * <tt>wait_for_text_length(locator, text)</tt>
|
||||
# * <tt>wait_for_not_text_length(locator, text)</tt>
|
||||
def assert_value_repeated locator, text
|
||||
command 'assertValueRepeated', locator, text
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.generate_methods
|
||||
public_instance_methods.each do |method|
|
||||
case method
|
||||
when 'store_text_length'
|
||||
each_assertion method do |assertion_method, command_name|
|
||||
define_method assertion_method do |arg1, arg2|
|
||||
command command_name, arg1, arg2
|
||||
end
|
||||
end
|
||||
when 'assert_value_repeated'
|
||||
each_check method do |check_method, command_name|
|
||||
define_method check_method do |arg1, arg2|
|
||||
command command_name, arg1, arg2
|
||||
end
|
||||
end
|
||||
else
|
||||
raise "Internal error: Don't know how to process user accessor: #{method}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Generates all the assertions needed given a +store_method+.
|
||||
def self.each_assertion store_method
|
||||
before_negation = nil
|
||||
after_negation = store_method.split('_')[1..-1] #throw away 'store'
|
||||
if after_negation.last == 'present'
|
||||
before_negation, after_negation = after_negation, after_negation.pop
|
||||
end
|
||||
|
||||
['assert', 'verify', ['wait','for']].each do |action|
|
||||
[nil, 'not'].each do |negation|
|
||||
name = [action, before_negation, negation, after_negation].flatten.reject{|a|a.nil?}
|
||||
method_name = name.join '_'
|
||||
command = name.inject(name.shift.clone) {|n, p| n << p.capitalize}
|
||||
yield method_name, command
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.each_check assert_method
|
||||
before_negation = nil
|
||||
after_negation = assert_method.split('_')[1..-1] #throw away 'assert'
|
||||
if after_negation.last == 'present'
|
||||
before_negation, after_negation = after_negation, after_negation.pop
|
||||
end
|
||||
|
||||
['assert', 'verify', ['wait', 'for']].each do |action|
|
||||
[nil, 'not'].each do |negation|
|
||||
unless (action == 'assert' && negation.nil?)
|
||||
name = [action, before_negation, negation, after_negation].flatten.reject{|a|a.nil?}
|
||||
method_name = name.join '_'
|
||||
command = name.inject(name.shift.clone) {|n, p| n << p.capitalize}
|
||||
yield method_name, command
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
generate_methods
|
||||
|
||||
end
|
||||
24
vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_actions.rb.example
vendored
Normal file
24
vendor/plugins/selenium-on-rails/lib/selenium_on_rails/test_builder_user_actions.rb.example
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Mirrors the actions specified in user-extensions.js from the selenium-core
|
||||
module SeleniumOnRails::TestBuilderUserActions
|
||||
|
||||
# Types the text twice into a text box.
|
||||
def type_repeated locator, text
|
||||
command 'typeRepeated', locator, text
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Generates the corresponding +_and_wait+ for each action.
|
||||
def self.generate_and_wait_actions
|
||||
public_instance_methods.each do |method|
|
||||
define_method method + '_and_wait' do |*args|
|
||||
make_command_waiting do
|
||||
send method, *args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
generate_and_wait_actions
|
||||
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue