selenium_shots 0.2.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +47 -0
- data/examples/google.rb +4 -5
- data/lib/selenium_shots/cli/client.rb +1 -1
- data/lib/selenium_shots/cli/commands/auth.rb +2 -2
- data/lib/selenium_shots/cli/commands/base.rb +1 -1
- data/lib/selenium_shots/test_selenium_shots.rb +70 -51
- metadata +26 -15
- data/bin/selenium_shots_local_server +0 -16
- data/lib/selenium_shots/cli/commands/server.rb +0 -34
- data/vendor/selenium-server-1.0.2-SNAPSHOT-standalone.jar +0 -0
data/README.rdoc
CHANGED
@@ -3,6 +3,53 @@
|
|
3
3
|
http://www.seleniumshots.com
|
4
4
|
Selenium Shots is an Integration Testing Service that transparently distributes your integration tests across multiple operating systems with different versions of all major browsers AND captures a screen shot. This eliminates the need to have multiple vm's on your computer or the need for multiple machines on your test to test your web application. Running your tests remotely will dramatically speed up in-browser web testing and leave more time to and create a slide show available to confirm visuals making it easy for you to improve your web application.
|
5
5
|
|
6
|
+
== Install
|
7
|
+
|
8
|
+
=== Rails 3
|
9
|
+
|
10
|
+
Add this to your Gemfile:
|
11
|
+
|
12
|
+
group :development do
|
13
|
+
gem 'selenium_shots'
|
14
|
+
end
|
15
|
+
|
16
|
+
=== Rails 2
|
17
|
+
|
18
|
+
To install add teh following to config/environment.rb:
|
19
|
+
|
20
|
+
config.gem 'selenium_shots'
|
21
|
+
|
22
|
+
== Configure
|
23
|
+
|
24
|
+
In configure/selenium_shots.yml you will need to define the application
|
25
|
+
* api_key
|
26
|
+
* mode
|
27
|
+
* default_browser_url
|
28
|
+
* application_name
|
29
|
+
* local_browser
|
30
|
+
* browsers
|
31
|
+
|
32
|
+
== Creating Tests
|
33
|
+
|
34
|
+
|
35
|
+
class MyTest < SeleniumShots
|
36
|
+
|
37
|
+
@group = "MyTestGroup"
|
38
|
+
|
39
|
+
selenium_shot "Should run my test and pass." do
|
40
|
+
@name = "My Test Name"
|
41
|
+
browser.open "/my_site"
|
42
|
+
browser.type "search[query]", "Cats"
|
43
|
+
browser.click "find"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
== Selenium Setup
|
48
|
+
Download the latest version of selenium grid from http://seleniumhq.org/download/
|
49
|
+
|
50
|
+
===Using a Custom Selenium Server
|
51
|
+
`ant launch-remote-control -DcustomRemoteControl=/path/to/your/customer/selenium-server.jar`
|
52
|
+
|
6
53
|
== Copyright
|
7
54
|
|
8
55
|
Copyright (c) 2010 Kyle Ginavan. See LICENSE for details.
|
data/examples/google.rb
CHANGED
@@ -5,11 +5,10 @@ class Google < SeleniumShots
|
|
5
5
|
@group = "Google"
|
6
6
|
|
7
7
|
selenium_shot "should search on google" do
|
8
|
-
@name = "
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
@name = "Google search"
|
9
|
+
element = driver.find_element(:name, 'q')
|
10
|
+
element.send_keys "Hello WebDriver!"
|
11
|
+
element.submit
|
12
12
|
end
|
13
|
-
|
14
13
|
end
|
15
14
|
|
@@ -15,8 +15,8 @@ module SeleniumShots::Command
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def get_api_key_from_host
|
18
|
-
RestClient.post 'http://seleniumshots.com/selenium_tests/get_api_key',
|
19
|
-
|
18
|
+
RestClient.post 'http://www.seleniumshots.com/selenium_tests/get_api_key', :user_session => { :email => @api_key_hash[0],
|
19
|
+
:password => @api_key_hash[1]}
|
20
20
|
end
|
21
21
|
|
22
22
|
def api_key_file
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "test/unit"
|
2
2
|
require "rubygems"
|
3
3
|
require "selenium/client"
|
4
|
+
require "selenium-webdriver"
|
4
5
|
require 'active_support'
|
5
6
|
require 'active_support/test_case'
|
6
7
|
require 'ostruct'
|
@@ -17,7 +18,7 @@ end
|
|
17
18
|
|
18
19
|
class SeleniumShots < ActionController::IntegrationTest
|
19
20
|
|
20
|
-
attr_reader :
|
21
|
+
attr_reader :driver, :agent, :take_screenshot
|
21
22
|
cattr_accessor :expected_test_count
|
22
23
|
|
23
24
|
if SeleniumConfig.mode == "remote"
|
@@ -36,7 +37,7 @@ class SeleniumShots < ActionController::IntegrationTest
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def local_browsers
|
39
|
-
["
|
40
|
+
["firefox", "ie", "chrome"]
|
40
41
|
end
|
41
42
|
|
42
43
|
def selected_browsers
|
@@ -50,38 +51,20 @@ class SeleniumShots < ActionController::IntegrationTest
|
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
53
|
-
|
54
|
-
def
|
55
|
-
if(not self.class.expected_test_count)
|
56
|
-
self.class.expected_test_count = (self.class.instance_methods.reject{|method| method[0..3] != 'test'}).length
|
57
|
-
if SeleniumConfig.mode == "local"
|
58
|
-
FileUtils.rm(pid_file) if File.exists?(pid_file)
|
59
|
-
IO.popen("selenium_shots_local_server start 2>&1")
|
60
|
-
sleep(2)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def teardown
|
66
|
-
if((self.class.expected_test_count-=1) == 0)
|
67
|
-
if File.exists?(pid_file) && SeleniumConfig.mode == "local"
|
68
|
-
IO.popen("selenium_shots_local_server stop 2>&1")
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.selenium_shot(description, &block)
|
54
|
+
|
55
|
+
def self.core_test(description, take_screenshot = true, &block)
|
74
56
|
@@group = (@group || "Default")
|
75
57
|
test_name = "test_#{description.gsub(/\s+/,'_')}".to_sym
|
76
58
|
defined = instance_method(test_name) rescue false
|
77
59
|
raise "#{test_name} is already defined in #{self}" if defined
|
78
60
|
if block_given?
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
61
|
+
define_method(test_name) do
|
62
|
+
@description = description
|
63
|
+
@take_screenshot = take_screenshot
|
64
|
+
run_in_all_browsers do
|
65
|
+
instance_eval &block
|
66
|
+
end
|
67
|
+
end
|
85
68
|
else
|
86
69
|
define_method(test_name) do
|
87
70
|
flunk "No implementation provided for #{name}"
|
@@ -89,14 +72,22 @@ class SeleniumShots < ActionController::IntegrationTest
|
|
89
72
|
end
|
90
73
|
end
|
91
74
|
|
75
|
+
def self.selenium_test(description, &block)
|
76
|
+
core_test(description, nil, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.selenium_shot(description, &block)
|
80
|
+
core_test(description, true, &block)
|
81
|
+
end
|
82
|
+
|
92
83
|
def run_in_all_browsers(&block)
|
93
84
|
@error = nil
|
94
85
|
browsers = (@selected_browser || selected_browsers)
|
95
86
|
browsers.each do |browser_spec|
|
96
87
|
begin
|
97
|
-
|
88
|
+
run_webdriver(browser_spec, block)
|
98
89
|
rescue => error
|
99
|
-
@
|
90
|
+
@driver.quit if @driver
|
100
91
|
@error = error.message
|
101
92
|
if @error.match(/Failed to start new browser session/) && SeleniumConfig.mode == "local"
|
102
93
|
@tmp_browsers ||= local_browsers
|
@@ -111,48 +102,76 @@ class SeleniumShots < ActionController::IntegrationTest
|
|
111
102
|
end
|
112
103
|
assert @error.nil?, "Expected zero failures or errors, but got #{@error}\n"
|
113
104
|
end
|
105
|
+
|
106
|
+
def run_webdriver(browser_spec, block)
|
107
|
+
|
108
|
+
client = Selenium::WebDriver::Remote::Http::Default.new
|
109
|
+
client.timeout = 20 # seconds
|
110
|
+
|
111
|
+
if SeleniumConfig.mode == "local"
|
112
|
+
if /(firefox)/i.match(browser_spec)
|
113
|
+
profile = Selenium::WebDriver::Firefox::Profile.new
|
114
|
+
profile.native_events = false
|
115
|
+
@driver = Selenium::WebDriver.for(:firefox, :profile => profile, :http_client => client)
|
116
|
+
elsif /(chrome)/i.match(browser_spec)
|
117
|
+
@driver = Selenium::WebDriver.for(:chrome, :http_client => client)
|
118
|
+
elsif /(ie)/i.match(browser_spec)
|
119
|
+
@driver = Selenium::WebDriver.for(:ie, :http_client => client)
|
120
|
+
end
|
121
|
+
else
|
122
|
+
caps = nil
|
123
|
+
if /(firefox)/i.match(browser_spec)
|
124
|
+
caps = WebDriver::Remote::Capabilities.firefox
|
125
|
+
elsif /(chrome)/i.match(browser_spec)
|
126
|
+
caps = WebDriver::Remote::Capabilities.chrome
|
127
|
+
elsif /(ie)/i.match(browser_spec)
|
128
|
+
caps = WebDriver::Remote::Capabilities.internet_explorer
|
129
|
+
elsif /(safari)/i.match(browser_spec)
|
130
|
+
caps = WebDriver::Remote::Capabilities.safari
|
131
|
+
elsif /(htmlunit)/i.match(browser_spec)
|
132
|
+
caps = WebDriver::Remote::Capabilities.htmlunit
|
133
|
+
caps.javascript_enabled = true
|
134
|
+
end
|
135
|
+
|
136
|
+
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => caps, :http_client => client) if caps
|
137
|
+
end
|
138
|
+
|
139
|
+
@driver.manage.timeouts.implicit_wait = 2 #seconds
|
140
|
+
@driver.navigate.to SeleniumConfig.default_browser_url
|
114
141
|
|
115
|
-
def run_browser(browser_spec, block)
|
116
|
-
@browser = Selenium::Client::Driver.new(
|
117
|
-
:host => HOST,
|
118
|
-
:port => PORT,
|
119
|
-
:browser => browser_spec,
|
120
|
-
:url => SeleniumConfig.default_browser_url,
|
121
|
-
:timeout_in_second => 200)
|
122
|
-
@browser.start_new_browser_session
|
123
142
|
begin
|
124
|
-
block.call
|
143
|
+
block.call
|
125
144
|
rescue => error
|
126
145
|
@error = error.message
|
146
|
+
puts @error
|
127
147
|
ensure
|
128
148
|
save_test({:selenium_test_group_name => @@group, :selenium_test_name => @name,
|
129
149
|
:description => @description}) if SeleniumConfig.mode == "remote"
|
130
|
-
@
|
131
|
-
end
|
150
|
+
@driver.quit
|
151
|
+
end
|
132
152
|
end
|
133
153
|
|
134
154
|
def capture_screenshot_on(src)
|
135
155
|
browser.window_focus
|
136
156
|
browser.window_maximize
|
137
157
|
sleep(2)
|
138
|
-
if browser.
|
139
|
-
|
140
|
-
elsif browser.
|
141
|
-
|
142
|
-
elsif browser.
|
143
|
-
|
158
|
+
if @driver.browser.to_s.match(/XP/)
|
159
|
+
@driver.capture_entire_page_screenshot("#{PICS_WINDOWS_PATH}\\#{src}", "background=#FFFFFF")
|
160
|
+
elsif @driver.browser.to_s.match(/SnowLeopard/)
|
161
|
+
@driver.capture_entire_page_screenshot("#{PICS_MACOS_PATH}/#{src}", "background=#FFFFFF")
|
162
|
+
elsif @driver.browser.to_s.match(/Linux/)
|
163
|
+
@driver.capture_entire_page_screenshot("#{PICS_LINUX_PATH}/#{src}", "background=#FFFFFF")
|
144
164
|
end
|
145
165
|
end
|
146
166
|
|
147
167
|
def save_test(params)
|
148
168
|
src = "#{SeleniumConfig.application_name}_#{params[:selenium_test_group_name]}_#{params[:selenium_test_name]}_" +
|
149
|
-
|
169
|
+
"#{@driver.browser.to_s.gsub(/\s+/,"_").downcase}.png"
|
150
170
|
|
151
171
|
capture_screenshot_on(src)
|
152
172
|
|
153
173
|
SeleniumTest.create(:selenium_test_name => params[:selenium_test_name], :description => params[:description],
|
154
|
-
:url =>
|
174
|
+
:url => @driver.current_url, :error_message => @error, :is_error => !@error.nil?, :environment => @driver.browser.to_s,
|
155
175
|
:selenium_test_group_name => params[:selenium_test_group_name], :application_name => SeleniumConfig.application_name)
|
156
176
|
end
|
157
177
|
end
|
158
|
-
|
metadata
CHANGED
@@ -3,10 +3,10 @@ name: selenium_shots
|
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
|
+
- 1
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
|
9
|
-
version: 0.2.4
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Kyle J. Ginavan
|
@@ -15,8 +15,8 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
19
|
-
default_executable:
|
18
|
+
date: 2010-12-02 00:00:00 -06:00
|
19
|
+
default_executable: selenium_shots
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
22
|
name: thoughtbot-shoulda
|
@@ -31,23 +31,37 @@ dependencies:
|
|
31
31
|
type: :development
|
32
32
|
version_requirements: *id001
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
34
|
+
name: rspec
|
35
35
|
prerelease: false
|
36
36
|
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 1
|
42
|
+
- 1
|
43
|
+
- 12
|
44
|
+
version: 1.1.12
|
45
|
+
type: :development
|
46
|
+
version_requirements: *id002
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: selenium-webdriver
|
49
|
+
prerelease: false
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
37
51
|
requirements:
|
38
52
|
- - ">="
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
segments:
|
55
|
+
- 0
|
41
56
|
- 1
|
42
|
-
-
|
43
|
-
|
44
|
-
version: 1.2.18
|
57
|
+
- 0
|
58
|
+
version: 0.1.0
|
45
59
|
type: :runtime
|
46
|
-
version_requirements: *
|
60
|
+
version_requirements: *id003
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: rest-client
|
49
63
|
prerelease: false
|
50
|
-
requirement: &
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
@@ -57,12 +71,11 @@ dependencies:
|
|
57
71
|
- 2
|
58
72
|
version: 0.8.2
|
59
73
|
type: :runtime
|
60
|
-
version_requirements: *
|
74
|
+
version_requirements: *id004
|
61
75
|
description: Selenium Shots is an Integration Testing Service that transparently distributes your integration tests across multiple operating systems with different versions of all major browsers AND captures a screen shot
|
62
76
|
email: kyle@4rockets.com
|
63
77
|
executables:
|
64
78
|
- selenium_shots
|
65
|
-
- selenium_shots_local_server
|
66
79
|
extensions: []
|
67
80
|
|
68
81
|
extra_rdoc_files:
|
@@ -77,10 +90,8 @@ files:
|
|
77
90
|
- lib/selenium_shots/cli/commands/auth.rb
|
78
91
|
- lib/selenium_shots/cli/commands/base.rb
|
79
92
|
- lib/selenium_shots/cli/commands/help.rb
|
80
|
-
- lib/selenium_shots/cli/commands/server.rb
|
81
93
|
- lib/selenium_shots/cli/init.rb
|
82
94
|
- lib/selenium_shots/test_selenium_shots.rb
|
83
|
-
- vendor/selenium-server-1.0.2-SNAPSHOT-standalone.jar
|
84
95
|
- LICENSE
|
85
96
|
- LICENSE.orig
|
86
97
|
- README.rdoc
|
@@ -1,16 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'fileutils'
|
5
|
-
|
6
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib/selenium_shots/cli/')
|
7
|
-
|
8
|
-
require 'init'
|
9
|
-
|
10
|
-
args = ARGV.dup
|
11
|
-
ARGV.clear
|
12
|
-
|
13
|
-
command = args.shift.strip rescue 'help'
|
14
|
-
|
15
|
-
SeleniumShots::Command.run("server:#{command}", args)
|
16
|
-
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module SeleniumShots::Command
|
2
|
-
class Server < Base
|
3
|
-
|
4
|
-
GEM_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '/../../../../'))
|
5
|
-
SELENIUM_SERVER = File.join(GEM_ROOT, 'vendor', 'selenium-server-1.0.2-SNAPSHOT-standalone.jar')
|
6
|
-
|
7
|
-
def pid_file
|
8
|
-
'/tmp/selenium_shots.pid'
|
9
|
-
end
|
10
|
-
|
11
|
-
def start
|
12
|
-
if File.exists?(pid_file)
|
13
|
-
puts "the selenium shots server is running...."
|
14
|
-
else
|
15
|
-
pipe = IO.popen("java -jar #{SELENIUM_SERVER}")
|
16
|
-
File.open(pid_file, 'w') {|f| f.write(pipe.pid) }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def stop
|
21
|
-
if File.exists?(pid_file)
|
22
|
-
process_id = File.open(pid_file,'r').readline
|
23
|
-
Process.kill 9, process_id.to_i
|
24
|
-
FileUtils.rm(pid_file)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def help
|
29
|
-
puts "selenium_shots_local_server {start|stop}"
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
Binary file
|