selenium-webdriver 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
- data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
- data/chrome/src/extension/background.html +9 -0
- data/chrome/src/extension/background.js +933 -0
- data/chrome/src/extension/content_script.js +1286 -0
- data/chrome/src/extension/manifest-nonwin.json +15 -0
- data/chrome/src/extension/manifest-win.json +16 -0
- data/chrome/src/extension/toolstrip.html +28 -0
- data/chrome/src/extension/utils.js +196 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +8 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +324 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +70 -0
- data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +119 -0
- data/common/src/js/abstractcommandprocessor.js +161 -0
- data/common/src/js/asserts.js +296 -0
- data/common/src/js/by.js +147 -0
- data/common/src/js/command.js +274 -0
- data/common/src/js/context.js +58 -0
- data/common/src/js/extension/README +2 -0
- data/common/src/js/extension/dommessenger.js +152 -0
- data/common/src/js/factory.js +55 -0
- data/common/src/js/future.js +118 -0
- data/common/src/js/key.js +117 -0
- data/common/src/js/localcommandprocessor.js +181 -0
- data/common/src/js/logging.js +249 -0
- data/common/src/js/testrunner.js +605 -0
- data/common/src/js/timing.js +89 -0
- data/common/src/js/wait.js +199 -0
- data/common/src/js/webdriver.js +853 -0
- data/common/src/js/webelement.js +683 -0
- data/common/src/rb/lib/selenium-webdriver.rb +1 -0
- data/common/src/rb/lib/selenium/webdriver.rb +52 -0
- data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +88 -0
- data/common/src/rb/lib/selenium/webdriver/child_process.rb +85 -0
- data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +41 -0
- data/common/src/rb/lib/selenium/webdriver/driver.rb +128 -0
- data/common/src/rb/lib/selenium/webdriver/element.rb +126 -0
- data/common/src/rb/lib/selenium/webdriver/error.rb +68 -0
- data/common/src/rb/lib/selenium/webdriver/find.rb +69 -0
- data/common/src/rb/lib/selenium/webdriver/navigation.rb +23 -0
- data/common/src/rb/lib/selenium/webdriver/options.rb +50 -0
- data/common/src/rb/lib/selenium/webdriver/platform.rb +82 -0
- data/common/src/rb/lib/selenium/webdriver/target_locator.rb +23 -0
- data/firefox/prebuilt/nsICommandProcessor.xpt +0 -0
- data/firefox/prebuilt/nsINativeEvents.xpt +0 -0
- data/firefox/prebuilt/nsIResponseHandler.xpt +0 -0
- data/firefox/src/extension/chrome.manifest +3 -0
- data/firefox/src/extension/components/context.js +37 -0
- data/firefox/src/extension/components/driver-component.js +127 -0
- data/firefox/src/extension/components/firefoxDriver.js +706 -0
- data/firefox/src/extension/components/json2.js +273 -0
- data/firefox/src/extension/components/keytest.html +554 -0
- data/firefox/src/extension/components/nsCommandProcessor.js +586 -0
- data/firefox/src/extension/components/screenshooter.js +70 -0
- data/firefox/src/extension/components/socketListener.js +185 -0
- data/firefox/src/extension/components/utils.js +1200 -0
- data/firefox/src/extension/components/webLoadingListener.js +57 -0
- data/firefox/src/extension/components/webdriverserver.js +101 -0
- data/firefox/src/extension/components/wrappedElement.js +609 -0
- data/firefox/src/extension/content/fxdriver.xul +30 -0
- data/firefox/src/extension/content/server.js +95 -0
- data/firefox/src/extension/idl/nsICommandProcessor.idl +38 -0
- data/firefox/src/extension/idl/nsIResponseHandler.idl +34 -0
- data/firefox/src/extension/install.rdf +29 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +21 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +86 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +426 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +82 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +132 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +174 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +60 -0
- data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +23 -0
- data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
- data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +14 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +552 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +94 -0
- data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +147 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +16 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +374 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/capabilities.rb +105 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +53 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +71 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +43 -0
- data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +32 -0
- metadata +182 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
module Firefox
|
4
|
+
class ExtensionConnection
|
5
|
+
|
6
|
+
def initialize(host, port)
|
7
|
+
@host = host
|
8
|
+
@port = port
|
9
|
+
end
|
10
|
+
|
11
|
+
def connect(timeout = 20)
|
12
|
+
Timeout.timeout(timeout) {
|
13
|
+
loop do
|
14
|
+
begin
|
15
|
+
return new_socket
|
16
|
+
rescue Errno::ECONNREFUSED => e
|
17
|
+
$stderr.puts "#{self} caught #{e.message}" if $DEBUG
|
18
|
+
sleep 0.250
|
19
|
+
end
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_socket
|
25
|
+
@socket = TCPSocket.new(@host, @port)
|
26
|
+
@socket.sync = true
|
27
|
+
|
28
|
+
@socket
|
29
|
+
end
|
30
|
+
|
31
|
+
def connected?
|
32
|
+
@socket && !@socket.closed?
|
33
|
+
end
|
34
|
+
|
35
|
+
def send_string(str)
|
36
|
+
str = <<-HTTP
|
37
|
+
GET / HTTP/1.1
|
38
|
+
Host: localhost
|
39
|
+
Content-Length: #{str.length}
|
40
|
+
|
41
|
+
#{str}
|
42
|
+
HTTP
|
43
|
+
@socket.write str
|
44
|
+
@socket.flush
|
45
|
+
end
|
46
|
+
|
47
|
+
def quit
|
48
|
+
command = {'commandName' => 'quit', 'context' => ''}
|
49
|
+
send_string(command.to_json)
|
50
|
+
ensure
|
51
|
+
@socket.close
|
52
|
+
end
|
53
|
+
|
54
|
+
def close
|
55
|
+
@socket.close
|
56
|
+
end
|
57
|
+
|
58
|
+
def read_response
|
59
|
+
resp = ""
|
60
|
+
received = ""
|
61
|
+
|
62
|
+
until resp.include?("\n\n")
|
63
|
+
received = @socket.recv 1
|
64
|
+
if received
|
65
|
+
resp += received
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
length = resp.split(":")[1].lstrip!.to_i
|
70
|
+
json_string = @socket.recv length
|
71
|
+
|
72
|
+
if json_string.empty?
|
73
|
+
raise Error::WebDriverError, "empty response from extension"
|
74
|
+
end
|
75
|
+
|
76
|
+
JSON.parse json_string
|
77
|
+
end
|
78
|
+
|
79
|
+
end # ExtensionConnection
|
80
|
+
end # Firefox
|
81
|
+
end # WebDriver
|
82
|
+
end # Selenium
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
module Firefox
|
4
|
+
class Launcher
|
5
|
+
|
6
|
+
attr_reader :binary, :connection
|
7
|
+
|
8
|
+
def initialize(binary, port = DEFAULT_PORT, profile_name = DEFAULT_PROFILE_NAME)
|
9
|
+
@binary = binary
|
10
|
+
@port = port.to_i
|
11
|
+
@profile_name = profile_name
|
12
|
+
|
13
|
+
@profile = nil
|
14
|
+
@host = "localhost"
|
15
|
+
end
|
16
|
+
|
17
|
+
def launch
|
18
|
+
with_lock do
|
19
|
+
find_free_port
|
20
|
+
connect_and_kill
|
21
|
+
create_profile
|
22
|
+
start_silent_and_wait
|
23
|
+
start
|
24
|
+
connect_until_stable
|
25
|
+
end
|
26
|
+
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def with_lock
|
31
|
+
socket_lock = TCPServer.new(@host, @port - 1)
|
32
|
+
yield
|
33
|
+
ensure
|
34
|
+
socket_lock.close if socket_lock
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_free_port
|
38
|
+
port = @port
|
39
|
+
|
40
|
+
until free_port?(port)
|
41
|
+
port += 1
|
42
|
+
end
|
43
|
+
|
44
|
+
@port = port
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_profile
|
48
|
+
fetch_profile
|
49
|
+
|
50
|
+
@profile.delete_extensions_cache
|
51
|
+
|
52
|
+
if @profile.nil?
|
53
|
+
raise Error, WebDriverError, "could not find or create profile: #{profile.inspect}"
|
54
|
+
end
|
55
|
+
|
56
|
+
@profile.port = @port
|
57
|
+
@profile.add_extension(true)
|
58
|
+
@profile.update_user_prefs
|
59
|
+
end
|
60
|
+
|
61
|
+
def start
|
62
|
+
assert_profile
|
63
|
+
@binary.start_with @profile
|
64
|
+
end
|
65
|
+
|
66
|
+
def start_silent_and_wait
|
67
|
+
assert_profile
|
68
|
+
@binary.start_with @profile, "--silent"
|
69
|
+
@binary.wait
|
70
|
+
end
|
71
|
+
|
72
|
+
def connect_and_kill
|
73
|
+
connection = ExtensionConnection.new(@host, @port)
|
74
|
+
connection.connect(1)
|
75
|
+
connection.quit
|
76
|
+
rescue Errno::ECONNREFUSED, Timeout::Error => e
|
77
|
+
# ok
|
78
|
+
end
|
79
|
+
|
80
|
+
def connect
|
81
|
+
@connection = ExtensionConnection.new(@host, @port)
|
82
|
+
@connection.connect(5)
|
83
|
+
end
|
84
|
+
|
85
|
+
def connect_until_stable
|
86
|
+
max_time = Time.now + 60
|
87
|
+
|
88
|
+
until Time.now >= max_time
|
89
|
+
begin
|
90
|
+
connection = ExtensionConnection.new(@host, @port)
|
91
|
+
connection.connect(1)
|
92
|
+
connection.close
|
93
|
+
|
94
|
+
connect
|
95
|
+
return
|
96
|
+
rescue Timeout::Error => e
|
97
|
+
# ok
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
raise Error::WebDriverError, "unable to obtain stable firefox connection"
|
102
|
+
end
|
103
|
+
|
104
|
+
def free_port?(port)
|
105
|
+
s = TCPServer.new(@host, port)
|
106
|
+
s.close
|
107
|
+
true
|
108
|
+
rescue
|
109
|
+
false
|
110
|
+
end
|
111
|
+
|
112
|
+
def fetch_profile
|
113
|
+
existing = Profile.from_name @profile_name
|
114
|
+
|
115
|
+
unless existing
|
116
|
+
@binary.create_base_profile @profile_name
|
117
|
+
Profile.ini.refresh
|
118
|
+
existing = Profile.from_name @profile_name
|
119
|
+
raise "unable to find or create new profile" unless existing
|
120
|
+
end
|
121
|
+
|
122
|
+
@profile = existing.create_copy
|
123
|
+
end
|
124
|
+
|
125
|
+
def assert_profile
|
126
|
+
raise "must create_profile first" if @profile.nil?
|
127
|
+
end
|
128
|
+
|
129
|
+
end # Launcher
|
130
|
+
end # Firefox
|
131
|
+
end # WebDriver
|
132
|
+
end # Selenium
|
@@ -0,0 +1,174 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
module Firefox
|
4
|
+
class Profile
|
5
|
+
|
6
|
+
ANONYMOUS_PROFILE_NAME = "WEBDRIVER_ANONYMOUS_PROFILE"
|
7
|
+
EXTENSION_NAME = "fxdriver@googlecode.com"
|
8
|
+
EM_NAMESPACE_URI = "http://www.mozilla.org/2004/em-rdf#"
|
9
|
+
|
10
|
+
# TODO: hardcoded paths
|
11
|
+
DEFAULT_EXTENSION_SOURCE = File.expand_path("#{WebDriver.root}/firefox/src/extension")
|
12
|
+
|
13
|
+
XPTS = {
|
14
|
+
"#{WebDriver.root}/firefox/prebuilt/nsINativeEvents.xpt" => "components/nsINativeEvents.xpt",
|
15
|
+
"#{WebDriver.root}/firefox/prebuilt/nsICommandProcessor.xpt" => "components/nsICommandProcessor.xpt",
|
16
|
+
"#{WebDriver.root}/firefox/prebuilt/nsIResponseHandler.xpt" => "components/nsIResponseHandler.xpt"
|
17
|
+
}
|
18
|
+
|
19
|
+
SHARED = {
|
20
|
+
"#{WebDriver.root}/common/src/js/extension/dommessenger.js" => "content/dommessenger.js"
|
21
|
+
}
|
22
|
+
|
23
|
+
attr_reader :name, :directory
|
24
|
+
attr_accessor :port
|
25
|
+
|
26
|
+
class << self
|
27
|
+
|
28
|
+
def ini
|
29
|
+
@ini ||= ProfilesIni.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def from_name(name)
|
33
|
+
ini[name]
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(directory = nil)
|
39
|
+
if directory
|
40
|
+
@directory = directory
|
41
|
+
else
|
42
|
+
@directory = Dir.mktmpdir("webdriver-profile")
|
43
|
+
end
|
44
|
+
|
45
|
+
unless File.directory?(@directory)
|
46
|
+
raise Error::WebDriverError, "Profile directory does not exist: #{@directory.inspect}"
|
47
|
+
end
|
48
|
+
|
49
|
+
@extension_source = DEFAULT_EXTENSION_SOURCE # make configurable?
|
50
|
+
end
|
51
|
+
|
52
|
+
def absolute_path
|
53
|
+
if Platform.win?
|
54
|
+
directory.gsub("/", "\\")
|
55
|
+
else
|
56
|
+
directory
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def update_user_prefs
|
61
|
+
prefs = existing_user_prefs.merge DEFAULT_PREFERENCES
|
62
|
+
prefs['webdriver.firefox_port'] = @port
|
63
|
+
|
64
|
+
write_prefs prefs
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_extension(force = false)
|
68
|
+
ext_path = File.join(extensions_dir, EXTENSION_NAME)
|
69
|
+
|
70
|
+
if File.exists?(ext_path)
|
71
|
+
return unless force
|
72
|
+
end
|
73
|
+
|
74
|
+
FileUtils.rm_rf ext_path
|
75
|
+
FileUtils.mkdir_p File.dirname(ext_path), :mode => 0700
|
76
|
+
FileUtils.cp_r @extension_source, ext_path
|
77
|
+
|
78
|
+
XPTS.each do |source, destination|
|
79
|
+
FileUtils.cp source, File.join(ext_path, destination)
|
80
|
+
end
|
81
|
+
|
82
|
+
SHARED.each do |source, destination|
|
83
|
+
FileUtils.cp source, File.join(ext_path, destination)
|
84
|
+
end
|
85
|
+
|
86
|
+
delete_extensions_cache
|
87
|
+
end
|
88
|
+
|
89
|
+
def create_copy
|
90
|
+
tmp_directory = Dir.mktmpdir("webdriver-rb-profilecopy")
|
91
|
+
FileUtils.cp_r @directory, tmp_directory
|
92
|
+
|
93
|
+
Profile.new(tmp_directory)
|
94
|
+
end
|
95
|
+
|
96
|
+
def port
|
97
|
+
@port ||= Firefox::DEFAULT_PORT
|
98
|
+
end
|
99
|
+
|
100
|
+
def extensions_dir
|
101
|
+
@extensions_dir ||= File.join(directory, "extensions")
|
102
|
+
end
|
103
|
+
|
104
|
+
def user_prefs_path
|
105
|
+
@user_prefs_js ||= File.join(directory, "user.js")
|
106
|
+
end
|
107
|
+
|
108
|
+
def delete_extensions_cache
|
109
|
+
cache = File.join(@directory, "extensions.cache")
|
110
|
+
FileUtils.rm_f cache if File.exist?(cache)
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def existing_user_prefs
|
116
|
+
return {} unless File.exist?(user_prefs_path)
|
117
|
+
|
118
|
+
prefs = {}
|
119
|
+
|
120
|
+
File.read(user_prefs_path).split("\n").each do |line|
|
121
|
+
if line =~ /user_pref\("([^"]+)"\s*,\s*(.+?)\);/
|
122
|
+
prefs[$1.strip] = $2.strip
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
prefs
|
127
|
+
end
|
128
|
+
|
129
|
+
def write_prefs(prefs)
|
130
|
+
File.open(user_prefs_path, "w") do |file|
|
131
|
+
prefs.each do |key, value|
|
132
|
+
file.puts "user_pref(#{key.inspect}, #{value});"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
DEFAULT_PREFERENCES = {
|
138
|
+
"app.update.auto" => 'false',
|
139
|
+
"app.update.enabled" => 'false',
|
140
|
+
"browser.download.manager.showWhenStarting" => 'false',
|
141
|
+
"browser.EULA.override" => 'true',
|
142
|
+
"browser.EULA.3.accepted" => 'true',
|
143
|
+
"browser.link.open_external" => '2',
|
144
|
+
"browser.link.open_newwindow" => '2',
|
145
|
+
"browser.safebrowsing.enabled" => 'false',
|
146
|
+
"browser.search.update" => 'false',
|
147
|
+
"browser.sessionstore.resume_from_crash" => 'false',
|
148
|
+
"browser.shell.checkDefaultBrowser" => 'false',
|
149
|
+
"browser.startup.page" => '0',
|
150
|
+
"browser.tabs.warnOnClose" => 'false',
|
151
|
+
"browser.tabs.warnOnOpen" => 'false',
|
152
|
+
"dom.disable_open_during_load" => 'false',
|
153
|
+
"extensions.update.enabled" => 'false',
|
154
|
+
"extensions.update.notifyUser" => 'false',
|
155
|
+
"security.warn_entering_secure" => 'false',
|
156
|
+
"security.warn_submit_insecure" => 'false',
|
157
|
+
"security.warn_entering_secure.show_once" => 'false',
|
158
|
+
"security.warn_entering_weak" => 'false',
|
159
|
+
"security.warn_entering_weak.show_once" => 'false',
|
160
|
+
"security.warn_leaving_secure" => 'false',
|
161
|
+
"security.warn_leaving_secure.show_once" => 'false',
|
162
|
+
"security.warn_submit_insecure" => 'false',
|
163
|
+
"security.warn_viewing_mixed" => 'false',
|
164
|
+
"security.warn_viewing_mixed.show_once" => 'false',
|
165
|
+
"signon.rememberSignons" => 'false',
|
166
|
+
"startup.homepage_welcome_url" => '"about:blank"',
|
167
|
+
"javascript.options.showInConsole" => 'true',
|
168
|
+
"browser.dom.window.dump.enabled" => 'true'
|
169
|
+
}
|
170
|
+
|
171
|
+
end # Profile
|
172
|
+
end # Firefox
|
173
|
+
end # WebDriver
|
174
|
+
end # Selenium
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
module Firefox
|
4
|
+
class ProfilesIni
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@path = File.join(Util.app_data_path, "profiles.ini")
|
8
|
+
@profiles = {}
|
9
|
+
parse if File.exist?(@path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](name)
|
13
|
+
@profiles[name]
|
14
|
+
end
|
15
|
+
|
16
|
+
def refresh
|
17
|
+
@profiles.clear
|
18
|
+
parse
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def parse
|
24
|
+
string = File.read @path
|
25
|
+
name = nil
|
26
|
+
is_relative = nil
|
27
|
+
path = nil
|
28
|
+
|
29
|
+
string.split("\n").each do |line|
|
30
|
+
case line
|
31
|
+
when /^\[Profile/
|
32
|
+
if p = new_profile(name, is_relative, path)
|
33
|
+
@profiles[name] = p
|
34
|
+
name, path = nil
|
35
|
+
end
|
36
|
+
when /^Name=(.+)$/
|
37
|
+
name = $1.strip
|
38
|
+
when /^IsRelative=(.+)$/
|
39
|
+
is_relative = $1.strip == "1"
|
40
|
+
when /^Path=(.+)$/
|
41
|
+
path = $1.strip
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if p = new_profile(name, is_relative, path)
|
46
|
+
@profiles[name] = p
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def new_profile(name, is_relative, path)
|
51
|
+
return unless [name, path].any?
|
52
|
+
path = is_relative ? File.join(Util.app_data_path, path) : path
|
53
|
+
|
54
|
+
Profile.new(path)
|
55
|
+
end
|
56
|
+
|
57
|
+
end # ProfilesIni
|
58
|
+
end # Firefox
|
59
|
+
end # WebDriver
|
60
|
+
end # Selenium
|