Skip to content

Commit

Permalink
rb: Initial attempt at supporting Microsoft Edge
Browse files Browse the repository at this point in the history
  • Loading branch information
titusfortner committed Jul 31, 2015
1 parent e37ad82 commit 24e20e0
Show file tree
Hide file tree
Showing 11 changed files with 312 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,9 @@ task :test_rb => [
"//rb:remote-test",
"//rb:rc-client-integration-test",
("//rb:ie-test" if windows?),
("//rb:edge-test" if windows?),
"//rb:chrome-test",
"//rb:safari-test",
("//rb:safari-test" if mac?),
"//rb:phantomjs-test"
].compact

Expand Down
22 changes: 22 additions & 0 deletions rb/build.desc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ rubygem(
"//rb:chrome",
"//rb:common",
"//rb:support",
"//rb:edge",
"//rb:firefox",
"//rb:ie",
"//rb:iphone",
Expand Down Expand Up @@ -90,6 +91,26 @@ ruby_test(name = "chrome",
deps = [ ":chrome" ]
)

ruby_library(name = "edge",
srcs = [
"lib/selenium/webdriver/edge/**/*.rb",
"lib/selenium/webdriver/edge.rb"
],
deps = [
":common",
":remote"
]
)

ruby_test(name = "edge",
srcs = [
"spec/integration/selenium/webdriver/*_spec.rb",
"spec/integration/selenium/webdriver/edge/**/*_spec.rb"
],
include = ["rb/spec/integration", "build/rb/lib"],
deps = [ ":edge" ]
)

ruby_library(name = "firefox",
srcs = [
"lib/selenium/webdriver/firefox/**/*.rb",
Expand Down Expand Up @@ -245,6 +266,7 @@ ruby_test(name = "unit",
":android",
":chrome",
":common",
":edge",
":firefox",
":ie",
":iphone",
Expand Down
4 changes: 3 additions & 1 deletion rb/lib/selenium/webdriver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ module WebDriver

autoload :Android, 'selenium/webdriver/android'
autoload :Chrome, 'selenium/webdriver/chrome'
autoload :Edge, 'selenium/webdriver/edge'
autoload :Firefox, 'selenium/webdriver/firefox'
autoload :IE, 'selenium/webdriver/ie'
autoload :IPhone, 'selenium/webdriver/iphone'
Expand All @@ -52,7 +53,7 @@ def self.root
#
# Create a new Driver instance with the correct bridge for the given browser
#
# @param browser [:ie, :internet_explorer, :remote, :chrome, :firefox, :ff, :android, :iphone, :phantomjs, :safari]
# @param browser [:ie, :internet_explorer, :edge, :remote, :chrome, :firefox, :ff, :android, :iphone, :phantomjs, :safari]
# the driver type to use
# @param *rest
# arguments passed to Bridge.new
Expand All @@ -62,6 +63,7 @@ def self.root
# @see Selenium::WebDriver::Remote::Bridge
# @see Selenium::WebDriver::Firefox::Bridge
# @see Selenium::WebDriver::IE::Bridge
# @see Selenium::WebDriver::Edge::Bridge
# @see Selenium::WebDriver::Chrome::Bridge
# @see Selenium::WebDriver::Android::Bridge
# @see Selenium::WebDriver::IPhone::Bridge
Expand Down
2 changes: 2 additions & 0 deletions rb/lib/selenium/webdriver/common/driver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ def for(browser, opts = {})
IE::Bridge.new(opts)
when :chrome
Chrome::Bridge.new(opts)
when :edge
Edge::Bridge.new(opts)
when :android
Android::Bridge.new(opts)
when :iphone
Expand Down
44 changes: 44 additions & 0 deletions rb/lib/selenium/webdriver/edge.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# encoding: utf-8
#
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

require 'net/http'

require 'selenium/webdriver/edge/service'
require 'selenium/webdriver/edge/bridge'

module Selenium
module WebDriver

module Edge
def self.driver_path=(path)
Service.executable_path = path
end

def self.path=(path)
Platform.assert_executable path
@path = path
end

def self.path
@path ||= nil
end

end # Edge
end # WebDriver
end # Selenium
102 changes: 102 additions & 0 deletions rb/lib/selenium/webdriver/edge/bridge.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# encoding: utf-8
#
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

module Selenium
module WebDriver
module Edge

# @api private
class Bridge < Remote::Bridge

def initialize(opts = {})
http_client = opts.delete(:http_client)

if opts.has_key?(:url)
url = opts.delete(:url)
else
@service = Service.default_service(*extract_service_args(opts))
@service.start

url = @service.uri
end

caps = create_capabilities(opts)

remote_opts = {
:url => url,
:desired_capabilities => caps
}

remote_opts.merge!(:http_client => http_client) if http_client

super(remote_opts)
end

def browser
:edge
end

def driver_extensions
[
DriverExtensions::TakesScreenshot,
DriverExtensions::HasInputDevices
]
end

def capabilities
@capabilities ||= Remote::Capabilities.edge
end

def quit
super
ensure
@service.stop if @service
end

private

def create_capabilities(opts)
caps = opts.delete(:desired_capabilities) { Remote::Capabilities.edge }
page_load_strategy = opts.delete(:page_load_strategy) || "normal"

unless opts.empty?
raise ArgumentError, "unknown option#{'s' if opts.size != 1}: #{opts.inspect}"
end

edge_options = caps['edgeOptions'] || {}
caps['edgeOptions'] = edge_options
caps['page_load_strategy'] = page_load_strategy

caps
end

def extract_service_args(opts)
args = []

if opts.has_key?(:service_log_path)
args << "--log-path=#{opts.delete(:service_log_path)}"
end

args
end

end # Bridge
end # Edge
end # WebDriver
end # Selenium
120 changes: 120 additions & 0 deletions rb/lib/selenium/webdriver/edge/service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# encoding: utf-8
#
# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The SFC licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

module Selenium
module WebDriver
module Edge

#
# @api private
#
class Service
START_TIMEOUT = 20
SOCKET_LOCK_TIMEOUT = 45
STOP_TIMEOUT = 5
DEFAULT_PORT = 17556
MISSING_TEXT = "Unable to find MicrosoftWebDriver. Please download the server from https://www.microsoft.com/en-us/download/details.aspx?id=48212. More info at https://github.com/SeleniumHQ/selenium/wiki/MicrosoftWebDriver."

def self.executable_path
@executable_path ||= (
path = Platform.find_binary "MicrosoftWebDriver"
path or raise Error::WebDriverError, MISSING_TEXT
Platform.assert_executable path

path
)
end

def self.executable_path=(path)
Platform.assert_executable path
@executable_path = path
end

def self.default_service(*extra_args)
new executable_path, DEFAULT_PORT, *extra_args
end

def initialize(executable_path, port, *extra_args)
@executable_path = executable_path
@host = Platform.localhost
@port = Integer(port)

raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1

@extra_args = extra_args
end

def start
Platform.exit_hook { stop } # make sure we don't leave the server running

socket_lock.locked do
find_free_port
start_process
connect_until_stable
end
end

def stop
return if @process.nil? || @process.exited?

Net::HTTP.start(@host, @port) do |http|
http.open_timeout = STOP_TIMEOUT / 2
http.read_timeout = STOP_TIMEOUT / 2

http.head("/shutdown")
end

@process.poll_for_exit STOP_TIMEOUT
rescue ChildProcess::TimeoutError
# ok, force quit
@process.stop STOP_TIMEOUT
end

def uri
URI.parse "http://#{@host}:#{@port}"
end

def find_free_port
@port = PortProber.above @port
end

def start_process
server_command = [@executable_path, "--port=#{@port}", *@extra_args]
@process = ChildProcess.build(*server_command)

@process.io.inherit! if $DEBUG == true
@process.start
end

def connect_until_stable
@socket_poller = SocketPoller.new @host, @port, START_TIMEOUT

unless @socket_poller.connected?
raise Error::WebDriverError, "unable to connect to MicrosoftWebDriver #{@host}:#{@port}"
end
end

def socket_lock
@socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
end

end # Service
end # Edge
end # WebDriver
end # Service
7 changes: 7 additions & 0 deletions rb/lib/selenium/webdriver/remote/capabilities.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ def chrome(opts = {})
}.merge(opts))
end

def edge(opts = {})
new({
:browser_name => "edge",
:platform => :windows
}.merge(opts))
end

def firefox(opts = {})
new({
:browser_name => "firefox",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ def create_chrome_driver
WebDriver::Driver.for :chrome,
:native_events => native_events?,
:args => args
# :http_client => keep_alive_client || http_client
end

def create_phantomjs_driver
Expand Down
5 changes: 5 additions & 0 deletions rb/spec/unit/selenium/client/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ class BaseClient
client.chrome_backend?.should be true
end

it "returns true when the browser string is *edge" do
client = BaseClient.new :host, 24, "*edge", :url
client.chrome_backend?.should be true
end

it "returns true when the browser string is *firefox2" do
client = BaseClient.new :host, 24, "*firefox2", :url
client.chrome_backend?.should be true
Expand Down
Loading

0 comments on commit 24e20e0

Please sign in to comment.