selenium-webdriver 2.48.1 → 2.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. data/CHANGES +34 -0
  2. data/lib/selenium/webdriver/chrome/bridge.rb +2 -2
  3. data/lib/selenium/webdriver/chrome/service.rb +6 -3
  4. data/lib/selenium/webdriver/common/driver.rb +6 -2
  5. data/lib/selenium/webdriver/common/element.rb +1 -1
  6. data/lib/selenium/webdriver/common/error.rb +7 -2
  7. data/lib/selenium/webdriver/common/options.rb +1 -2
  8. data/lib/selenium/webdriver/common/socket_lock.rb +5 -0
  9. data/lib/selenium/webdriver/common/window.rb +8 -0
  10. data/lib/selenium/webdriver/edge/bridge.rb +3 -2
  11. data/lib/selenium/webdriver/edge/legacy_support.rb +117 -0
  12. data/lib/selenium/webdriver/edge/service.rb +3 -2
  13. data/lib/selenium/webdriver/firefox/binary.rb +1 -0
  14. data/lib/selenium/webdriver/firefox/bridge.rb +2 -0
  15. data/lib/selenium/webdriver/firefox/extension/prefs.json +2 -0
  16. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  17. data/lib/selenium/webdriver/firefox/w3c_bridge.rb +10 -41
  18. data/lib/selenium/webdriver/ie/bridge.rb +1 -1
  19. data/lib/selenium/webdriver/ie/server.rb +36 -12
  20. data/lib/selenium/webdriver/phantomjs/service.rb +44 -25
  21. data/lib/selenium/webdriver/remote/bridge.rb +14 -33
  22. data/lib/selenium/webdriver/remote/capabilities.rb +8 -6
  23. data/lib/selenium/webdriver/remote/commands.rb +0 -5
  24. data/lib/selenium/webdriver/remote/w3c_bridge.rb +68 -86
  25. data/lib/selenium/webdriver/remote/w3c_capabilities.rb +35 -16
  26. data/lib/selenium/webdriver/remote/w3c_commands.rb +1 -2
  27. data/lib/selenium/webdriver/safari/bridge.rb +1 -1
  28. data/lib/selenium/webdriver/safari/browser.rb +2 -0
  29. data/lib/selenium/webdriver/safari/options.rb +6 -4
  30. data/lib/selenium/webdriver/safari/resources/client.js +65 -51
  31. data/lib/selenium/webdriver/safari/server.rb +23 -2
  32. data/selenium-webdriver.gemspec +1 -1
  33. metadata +3 -2
@@ -49,6 +49,7 @@ module Selenium
49
49
  end
50
50
 
51
51
  alias_method :version, :browser_version
52
+ alias_method :platform, :platform_name
52
53
 
53
54
  #
54
55
  # Convenience methods for the common choices.
@@ -64,19 +65,19 @@ module Selenium
64
65
  end
65
66
 
66
67
  def firefox(opts = {})
68
+ opts[:browser_version] = opts.delete :version
69
+ opts[:platform_name] = opts.delete :platform
70
+
67
71
  new({
68
- :browser_name => "firefox"
72
+ :browser_name => "firefox",
73
+ :marionette => true
69
74
  }.merge(opts))
70
75
  end
71
76
 
72
77
  alias_method :ff, :firefox
73
78
 
74
79
  def w3c?(opts = {})
75
- return false unless opts[:desired_capabilities].is_a?(W3CCapabilities) || opts.delete(:marionette)
76
- Firefox::Binary.path = ENV['MARIONETTE_PATH'] if ENV['MARIONETTE_PATH']
77
- firefox_version = Firefox::Binary.version
78
- raise ArgumentError, "Firefox Version #{firefox_version} does not support W3CCapabilities" if firefox_version < 43
79
- true
80
+ opts[:desired_capabilities].is_a?(W3CCapabilities) || opts[:marionette]
80
81
  end
81
82
 
82
83
  #
@@ -86,20 +87,38 @@ module Selenium
86
87
  def json_create(data)
87
88
  data = data.dup
88
89
 
90
+ # Convert due to Remote Driver implementation
91
+ data["browserVersion"] = data.delete("version") if data["version"]
92
+ data["platformName"] = data.delete("platform") if data["platform"]
93
+
89
94
  caps = new
90
- caps.browser_name = data.delete("browserName")
91
- caps.browser_version = data.delete("browserVersion")
92
- caps.platform_name = data.delete("platformName").downcase.to_sym if data.has_key?('platform')
93
- caps.platform_version = data.delete("platformVersion")
94
- caps.accept_ssl_certs = data.delete("acceptSslCerts")
95
- caps.takes_screenshot = data.delete("takesScreenshot ")
96
- caps.takes_element_screenshot = data.delete("takesElementScreenshot")
97
- caps.page_load_strategy = data.delete("pageLoadStrategy")
98
- caps.proxy = Proxy.json_create(data['proxy']) if data.has_key?('proxy')
95
+ caps.browser_name = data.delete("browserName") if data["browserName"]
96
+ caps.browser_version = data.delete("browserVersion") if data["browserVersion"]
97
+ caps.platform_name = data.delete("platformName") if data["platformName"]
98
+ caps.platform_version = data.delete("platformVersion") if data["platformVersion"]
99
+ caps.accept_ssl_certs = data.delete("acceptSslCerts") if data["acceptSslCerts"]
100
+ caps.takes_screenshot = data.delete("takesScreenshot") if data["takesScreenshot"]
101
+ caps.takes_element_screenshot = data.delete("takesElementScreenshot") if data["takesElementScreenshot"]
102
+ caps.page_load_strategy = data.delete("pageLoadStrategy") if data["pageloadStrategy"]
103
+ caps.proxy = Proxy.json_create(data['proxy']) if data['proxy']
104
+
105
+ # Remote Server Specific
106
+ caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')
107
+
108
+ # Obsolete capabilities returned by Remote Server
109
+ data.delete("javascriptEnabled")
110
+ data.delete('cssSelectorsEnabled')
111
+
112
+ # Marionette Specific
113
+ caps[:specification_level] = data.delete("specificaionLevel")
114
+ caps[:xul_app_id] = data.delete("XULappId")
115
+ caps[:raise_accessibility_exceptions] = data.delete('raisesAccessibilityExceptions')
116
+ caps[:rotatable] = data.delete('rotatable')
117
+ caps[:app_build_id] = data.delete('appBuildId')
118
+ caps[:device] = data.delete('device')
99
119
 
100
120
  # any remaining pairs will be added as is, with no conversion
101
121
  caps.merge!(data)
102
-
103
122
  caps
104
123
  end
105
124
  end
@@ -50,7 +50,7 @@ class Selenium::WebDriver::Remote::W3CBridge
50
50
  command :closeWindow, :delete, "session/:session_id/window"
51
51
  command :switchToWindow, :post, "session/:session_id/window"
52
52
  command :getWindowHandles, :get, "session/:session_id/window/handles"
53
- command :fullscreenWindow, :post, "session/:session_id/window/window/fullscreen"
53
+ command :fullscreenWindow, :post, "session/:session_id/window/fullscreen"
54
54
  command :maximizeWindow, :post, "session/:session_id/window/maximize"
55
55
  command :setWindowSize, :post, "session/:session_id/window/size"
56
56
  command :getWindowSize, :get, "session/:session_id/window/size"
@@ -66,7 +66,6 @@ class Selenium::WebDriver::Remote::W3CBridge
66
66
  command :findChildElement, :post, "session/:session_id/element/:id/element"
67
67
  command :findChildElements, :post, "session/:session_id/element/:id/elements"
68
68
  command :getActiveElement, :post, "session/:session_id/element/active"
69
- command :isElementDisplayed, :get, "session/:session_id/element/:id/displayed"
70
69
  command :isElementSelected, :get, "session/:session_id/element/:id/selected"
71
70
  command :getElementAttribute, :get, "session/:session_id/element/:id/attribute/:name"
72
71
  command :getElementProperty, :get, "session/:session_id/element/:id/property/:name"
@@ -104,7 +104,7 @@ module Selenium
104
104
 
105
105
  def prepare_connect_file
106
106
  # TODO: use tempfile?
107
- path = File.join(Dir.tmpdir, "safaridriver-#{Time.now.to_i}.html")
107
+ path = File.join(Dir.tmpdir, "safaridriver-#{Time.now.usec}.html")
108
108
 
109
109
  File.open(path, 'w') do |io|
110
110
  io << "<!DOCTYPE html><script>window.location = '#{@server.uri}';</script>"
@@ -23,6 +23,8 @@ module Selenium
23
23
 
24
24
  class Browser
25
25
  def start(*args)
26
+ Platform.exit_hook { stop } # make sure we don't leave the browser running
27
+
26
28
  @process = ChildProcess.new(Safari.path, *args)
27
29
  @process.io.inherit! if $DEBUG
28
30
  @process.start
@@ -21,6 +21,8 @@ module Selenium
21
21
  module WebDriver
22
22
  module Safari
23
23
  class Options
24
+ DEFAULT_PORT = 56485
25
+
24
26
  attr_accessor :port, :data_dir, :skip_extension_installation
25
27
 
26
28
  def initialize(opts = {})
@@ -40,16 +42,16 @@ module Selenium
40
42
 
41
43
  def as_json
42
44
  {
43
- 'port' => port,
44
- 'dataDir' => data_dir,
45
- 'cleanSession' => clean_session?,
45
+ 'port' => port,
46
+ 'dataDir' => data_dir,
47
+ 'cleanSession' => clean_session?,
46
48
  }
47
49
  end
48
50
 
49
51
  private
50
52
 
51
53
  def extract_options(opts)
52
- @port = Integer(opts[:port] || PortProber.random)
54
+ @port = Integer(opts[:port] || DEFAULT_PORT)
53
55
  @data_dir = opts[:custom_data_dir] || opts[:data_dir]
54
56
  @clean_session = opts[:clean_session]
55
57
  end
@@ -1,4 +1,4 @@
1
- var COMPILED = !0, goog = goog || {};
1
+ 'use strict';var COMPILED = !0, goog = goog || {};
2
2
  goog.global = this;
3
3
  goog.isDef = function(a) {
4
4
  return void 0 !== a;
@@ -158,7 +158,7 @@ goog.loadedModules_ = {};
158
158
  goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER;
159
159
  goog.DEPENDENCIES_ENABLED && (goog.dependencies_ = {pathIsModule:{}, nameToPath:{}, requires:{}, visited:{}, written:{}, deferred:{}}, goog.inHtmlDocument_ = function() {
160
160
  var a = goog.global.document;
161
- return "undefined" != typeof a && "write" in a;
161
+ return null != a && "write" in a;
162
162
  }, goog.findBasePath_ = function() {
163
163
  if (goog.isDef(goog.global.CLOSURE_BASE_PATH)) {
164
164
  goog.basePath = goog.global.CLOSURE_BASE_PATH;
@@ -207,10 +207,12 @@ goog.DEPENDENCIES_ENABLED && (goog.dependencies_ = {pathIsModule:{}, nameToPath:
207
207
  delete goog.dependencies_.deferred[a];
208
208
  goog.globalEval(b);
209
209
  }
210
+ }, goog.loadModuleFromUrl = function(a) {
211
+ goog.retrieveAndExecModule_(a);
210
212
  }, goog.loadModule = function(a) {
211
213
  var b = goog.moduleLoaderState_;
212
214
  try {
213
- goog.moduleLoaderState_ = {moduleName:void 0};
215
+ goog.moduleLoaderState_ = {moduleName:void 0, declareLegacyNamespace:!1};
214
216
  var c;
215
217
  if (goog.isFunction(a)) {
216
218
  c = a.call(goog.global, {});
@@ -509,7 +511,7 @@ goog.setCssNameMapping = function(a, b) {
509
511
  !COMPILED && goog.global.CLOSURE_CSS_NAME_MAPPING && (goog.cssNameMapping_ = goog.global.CLOSURE_CSS_NAME_MAPPING);
510
512
  goog.getMsg = function(a, b) {
511
513
  b && (a = a.replace(/\{\$([^}]+)}/g, function(a, d) {
512
- return d in b ? b[d] : a;
514
+ return null != b && d in b ? b[d] : a;
513
515
  }));
514
516
  return a;
515
517
  };
@@ -714,8 +716,7 @@ goog.string.caseInsensitiveCompare = function(a, b) {
714
716
  var c = String(a).toLowerCase(), d = String(b).toLowerCase();
715
717
  return c < d ? -1 : c == d ? 0 : 1;
716
718
  };
717
- goog.string.numerateCompareRegExp_ = /(\.\d+)|(\d+)|(\D+)/g;
718
- goog.string.numerateCompare = function(a, b) {
719
+ goog.string.numberAwareCompare_ = function(a, b, c) {
719
720
  if (a == b) {
720
721
  return 0;
721
722
  }
@@ -725,14 +726,22 @@ goog.string.numerateCompare = function(a, b) {
725
726
  if (!b) {
726
727
  return 1;
727
728
  }
728
- for (var c = a.toLowerCase().match(goog.string.numerateCompareRegExp_), d = b.toLowerCase().match(goog.string.numerateCompareRegExp_), e = Math.min(c.length, d.length), f = 0;f < e;f++) {
729
- var g = c[f], h = d[f];
730
- if (g != h) {
731
- return c = parseInt(g, 10), !isNaN(c) && (d = parseInt(h, 10), !isNaN(d) && c - d) ? c - d : g < h ? -1 : 1;
729
+ for (var d = a.toLowerCase().match(c), e = b.toLowerCase().match(c), f = Math.min(d.length, e.length), g = 0;g < f;g++) {
730
+ c = d[g];
731
+ var h = e[g];
732
+ if (c != h) {
733
+ return a = parseInt(c, 10), !isNaN(a) && (b = parseInt(h, 10), !isNaN(b) && a - b) ? a - b : c < h ? -1 : 1;
732
734
  }
733
735
  }
734
- return c.length != d.length ? c.length - d.length : a < b ? -1 : 1;
736
+ return d.length != e.length ? d.length - e.length : a < b ? -1 : 1;
735
737
  };
738
+ goog.string.intAwareCompare = function(a, b) {
739
+ return goog.string.numberAwareCompare_(a, b, /\d+|\D+/g);
740
+ };
741
+ goog.string.floatAwareCompare = function(a, b) {
742
+ return goog.string.numberAwareCompare_(a, b, /\d+|\.\d+|\D+/g);
743
+ };
744
+ goog.string.numerateCompare = goog.string.floatAwareCompare;
736
745
  goog.string.urlEncode = function(a) {
737
746
  return encodeURIComponent(String(a));
738
747
  };
@@ -845,13 +854,10 @@ goog.string.truncateMiddle = function(a, b, c, d) {
845
854
  c && (a = goog.string.htmlEscape(a));
846
855
  return a;
847
856
  };
848
- goog.string.specialEscapeChars_ = {"\x00":"\\0", "\b":"\\b", "\f":"\\f", "\n":"\\n", "\r":"\\r", "\t":"\\t", "\x0B":"\\x0B", '"':'\\"', "\\":"\\\\"};
857
+ goog.string.specialEscapeChars_ = {"\x00":"\\0", "\b":"\\b", "\f":"\\f", "\n":"\\n", "\r":"\\r", "\t":"\\t", "\x0B":"\\x0B", '"':'\\"', "\\":"\\\\", "<":"<"};
849
858
  goog.string.jsEscapeCache_ = {"'":"\\'"};
850
859
  goog.string.quote = function(a) {
851
860
  a = String(a);
852
- if (a.quote) {
853
- return a.quote();
854
- }
855
861
  for (var b = ['"'], c = 0;c < a.length;c++) {
856
862
  var d = a.charAt(c), e = d.charCodeAt(0);
857
863
  b[c + 1] = goog.string.specialEscapeChars_[d] || (31 < e && 127 > e ? d : goog.string.escapeChar(d));
@@ -934,7 +940,7 @@ goog.string.getRandomString = function() {
934
940
  };
935
941
  goog.string.compareVersions = function(a, b) {
936
942
  for (var c = 0, d = goog.string.trim(String(a)).split("."), e = goog.string.trim(String(b)).split("."), f = Math.max(d.length, e.length), g = 0;0 == c && g < f;g++) {
937
- var h = d[g] || "", k = e[g] || "", l = RegExp("(\\d*)(\\D*)", "g"), p = RegExp("(\\d*)(\\D*)", "g");
943
+ var h = d[g] || "", k = e[g] || "", l = /(\d*)(\D*)/g, p = /(\d*)(\D*)/g;
938
944
  do {
939
945
  var m = l.exec(h) || ["", "", ""], n = p.exec(k) || ["", "", ""];
940
946
  if (0 == m[0].length && 0 == n[0].length) {
@@ -1497,16 +1503,16 @@ goog.array.zip = function(a) {
1497
1503
  if (!arguments.length) {
1498
1504
  return [];
1499
1505
  }
1500
- for (var b = [], c = 0;;c++) {
1501
- for (var d = [], e = 0;e < arguments.length;e++) {
1502
- var f = arguments[e];
1503
- if (c >= f.length) {
1504
- return b;
1505
- }
1506
- d.push(f[c]);
1506
+ for (var b = [], c = arguments[0].length, d = 1;d < arguments.length;d++) {
1507
+ arguments[d].length < c && (c = arguments[d].length);
1508
+ }
1509
+ for (d = 0;d < c;d++) {
1510
+ for (var e = [], f = 0;f < arguments.length;f++) {
1511
+ e.push(arguments[f][d]);
1507
1512
  }
1508
- b.push(d);
1513
+ b.push(e);
1509
1514
  }
1515
+ return b;
1510
1516
  };
1511
1517
  goog.array.shuffle = function(a, b) {
1512
1518
  for (var c = b || Math.random, d = a.length - 1;0 < d;d--) {
@@ -1598,7 +1604,7 @@ goog.object.getValueByKeys = function(a, b) {
1598
1604
  return a;
1599
1605
  };
1600
1606
  goog.object.containsKey = function(a, b) {
1601
- return b in a;
1607
+ return null !== a && b in a;
1602
1608
  };
1603
1609
  goog.object.containsValue = function(a, b) {
1604
1610
  for (var c in a) {
@@ -1635,13 +1641,13 @@ goog.object.remove = function(a, b) {
1635
1641
  return c;
1636
1642
  };
1637
1643
  goog.object.add = function(a, b, c) {
1638
- if (b in a) {
1644
+ if (null !== a && b in a) {
1639
1645
  throw Error('The object already contains the key "' + b + '"');
1640
1646
  }
1641
1647
  goog.object.set(a, b, c);
1642
1648
  };
1643
1649
  goog.object.get = function(a, b, c) {
1644
- return b in a ? a[b] : c;
1650
+ return null !== a && b in a ? a[b] : c;
1645
1651
  };
1646
1652
  goog.object.set = function(a, b, c) {
1647
1653
  a[b] = c;
@@ -1742,10 +1748,10 @@ goog.object.isImmutableView = function(a) {
1742
1748
  };
1743
1749
  goog.structs = {};
1744
1750
  goog.structs.getCount = function(a) {
1745
- return "function" == typeof a.getCount ? a.getCount() : goog.isArrayLike(a) || goog.isString(a) ? a.length : goog.object.getCount(a);
1751
+ return a.getCount && "function" == typeof a.getCount ? a.getCount() : goog.isArrayLike(a) || goog.isString(a) ? a.length : goog.object.getCount(a);
1746
1752
  };
1747
1753
  goog.structs.getValues = function(a) {
1748
- if ("function" == typeof a.getValues) {
1754
+ if (a.getValues && "function" == typeof a.getValues) {
1749
1755
  return a.getValues();
1750
1756
  }
1751
1757
  if (goog.isString(a)) {
@@ -1760,10 +1766,10 @@ goog.structs.getValues = function(a) {
1760
1766
  return goog.object.getValues(a);
1761
1767
  };
1762
1768
  goog.structs.getKeys = function(a) {
1763
- if ("function" == typeof a.getKeys) {
1769
+ if (a.getKeys && "function" == typeof a.getKeys) {
1764
1770
  return a.getKeys();
1765
1771
  }
1766
- if ("function" != typeof a.getValues) {
1772
+ if (!a.getValues || "function" != typeof a.getValues) {
1767
1773
  if (goog.isArrayLike(a) || goog.isString(a)) {
1768
1774
  var b = [];
1769
1775
  a = a.length;
@@ -1776,16 +1782,16 @@ goog.structs.getKeys = function(a) {
1776
1782
  }
1777
1783
  };
1778
1784
  goog.structs.contains = function(a, b) {
1779
- return "function" == typeof a.contains ? a.contains(b) : "function" == typeof a.containsValue ? a.containsValue(b) : goog.isArrayLike(a) || goog.isString(a) ? goog.array.contains(a, b) : goog.object.containsValue(a, b);
1785
+ return a.contains && "function" == typeof a.contains ? a.contains(b) : a.containsValue && "function" == typeof a.containsValue ? a.containsValue(b) : goog.isArrayLike(a) || goog.isString(a) ? goog.array.contains(a, b) : goog.object.containsValue(a, b);
1780
1786
  };
1781
1787
  goog.structs.isEmpty = function(a) {
1782
- return "function" == typeof a.isEmpty ? a.isEmpty() : goog.isArrayLike(a) || goog.isString(a) ? goog.array.isEmpty(a) : goog.object.isEmpty(a);
1788
+ return a.isEmpty && "function" == typeof a.isEmpty ? a.isEmpty() : goog.isArrayLike(a) || goog.isString(a) ? goog.array.isEmpty(a) : goog.object.isEmpty(a);
1783
1789
  };
1784
1790
  goog.structs.clear = function(a) {
1785
- "function" == typeof a.clear ? a.clear() : goog.isArrayLike(a) ? goog.array.clear(a) : goog.object.clear(a);
1791
+ a.clear && "function" == typeof a.clear ? a.clear() : goog.isArrayLike(a) ? goog.array.clear(a) : goog.object.clear(a);
1786
1792
  };
1787
1793
  goog.structs.forEach = function(a, b, c) {
1788
- if ("function" == typeof a.forEach) {
1794
+ if (a.forEach && "function" == typeof a.forEach) {
1789
1795
  a.forEach(b, c);
1790
1796
  } else {
1791
1797
  if (goog.isArrayLike(a) || goog.isString(a)) {
@@ -1985,19 +1991,26 @@ goog.functions.once = function(a) {
1985
1991
  goog.functions.debounce = function(a, b, c) {
1986
1992
  c && (a = goog.bind(a, c));
1987
1993
  var d = null;
1988
- return function() {
1994
+ return function(c) {
1989
1995
  goog.global.clearTimeout(d);
1990
- d = goog.global.setTimeout(a, b);
1996
+ var f = arguments;
1997
+ d = goog.global.setTimeout(function() {
1998
+ a.apply(null, f);
1999
+ }, b);
1991
2000
  };
1992
2001
  };
1993
2002
  goog.functions.throttle = function(a, b, c) {
1994
2003
  c && (a = goog.bind(a, c));
1995
- var d = null, e = !1, f = function() {
2004
+ var d = null, e = !1, f = [], g = function() {
1996
2005
  d = null;
1997
- e && (e = !1, d = goog.global.setTimeout(f, b), a());
2006
+ e && (e = !1, h());
2007
+ }, h = function() {
2008
+ d = goog.global.setTimeout(g, b);
2009
+ a.apply(null, f);
1998
2010
  };
1999
- return function() {
2000
- d ? e = !0 : (d = goog.global.setTimeout(f, b), a());
2011
+ return function(a) {
2012
+ f = arguments;
2013
+ d ? e = !0 : h();
2001
2014
  };
2002
2015
  };
2003
2016
  goog.math = {};
@@ -2105,7 +2118,7 @@ goog.math.isNegativeZero = function(a) {
2105
2118
  goog.math.log10Floor = function(a) {
2106
2119
  if (0 < a) {
2107
2120
  var b = Math.round(Math.log(a) * Math.LOG10E);
2108
- return b - (parseFloat("1e" + b) > a);
2121
+ return b - (parseFloat("1e" + b) > a ? 1 : 0);
2109
2122
  }
2110
2123
  return 0 == a ? -Infinity : NaN;
2111
2124
  };
@@ -2166,9 +2179,9 @@ goog.iter.forEach = function(a, b, c) {
2166
2179
  for (;;) {
2167
2180
  b.call(c, a.next(), void 0, a);
2168
2181
  }
2169
- } catch (d) {
2170
- if (d !== goog.iter.StopIteration) {
2171
- throw d;
2182
+ } catch (e) {
2183
+ if (e !== goog.iter.StopIteration) {
2184
+ throw e;
2172
2185
  }
2173
2186
  }
2174
2187
  }
@@ -4087,7 +4100,7 @@ goog.labs.userAgent.util.matchUserAgentIgnoreCase = function(a) {
4087
4100
  return goog.string.caseInsensitiveContains(b, a);
4088
4101
  };
4089
4102
  goog.labs.userAgent.util.extractVersionTuples = function(a) {
4090
- for (var b = RegExp("(\\w[\\w ]+)/([^\\s]+)\\s*(?:\\((.*?)\\))?", "g"), c = [], d;d = b.exec(a);) {
4103
+ for (var b = /(\w[\w ]+)\/([^\s]+)\s*(?:\((.*?)\))?/g, c = [], d;d = b.exec(a);) {
4091
4104
  c.push([d[1], d[2], d[3] || void 0]);
4092
4105
  }
4093
4106
  return c;
@@ -4489,7 +4502,7 @@ goog.debug.normalizeErrorObject = function(a) {
4489
4502
  }
4490
4503
  try {
4491
4504
  d = a.fileName || a.filename || a.sourceURL || goog.global.$googDebugFname || b;
4492
- } catch (f) {
4505
+ } catch (g) {
4493
4506
  d = "Not available", e = !0;
4494
4507
  }
4495
4508
  return !e && a.lineNumber && a.fileName && a.stack && a.message && a.name ? a : {message:a.message || "Not available", name:a.name || "UnknownError", lineNumber:c, fileName:d, stack:a.stack || "Not available"};
@@ -6824,9 +6837,10 @@ goog.userAgent.product.ASSUME_IPAD = !1;
6824
6837
  goog.userAgent.product.ASSUME_ANDROID = !1;
6825
6838
  goog.userAgent.product.ASSUME_CHROME = !1;
6826
6839
  goog.userAgent.product.ASSUME_SAFARI = !0;
6827
- goog.userAgent.product.PRODUCT_KNOWN_ = goog.userAgent.ASSUME_IE || goog.userAgent.ASSUME_OPERA || goog.userAgent.product.ASSUME_FIREFOX || goog.userAgent.product.ASSUME_IPHONE || goog.userAgent.product.ASSUME_IPAD || goog.userAgent.product.ASSUME_ANDROID || goog.userAgent.product.ASSUME_CHROME || goog.userAgent.product.ASSUME_SAFARI;
6840
+ goog.userAgent.product.PRODUCT_KNOWN_ = goog.userAgent.ASSUME_IE || goog.userAgent.ASSUME_EDGE || goog.userAgent.ASSUME_OPERA || goog.userAgent.product.ASSUME_FIREFOX || goog.userAgent.product.ASSUME_IPHONE || goog.userAgent.product.ASSUME_IPAD || goog.userAgent.product.ASSUME_ANDROID || goog.userAgent.product.ASSUME_CHROME || goog.userAgent.product.ASSUME_SAFARI;
6828
6841
  goog.userAgent.product.OPERA = goog.userAgent.OPERA;
6829
6842
  goog.userAgent.product.IE = goog.userAgent.IE;
6843
+ goog.userAgent.product.EDGE = goog.userAgent.EDGE;
6830
6844
  goog.userAgent.product.FIREFOX = goog.userAgent.product.PRODUCT_KNOWN_ ? goog.userAgent.product.ASSUME_FIREFOX : goog.labs.userAgent.browser.isFirefox();
6831
6845
  goog.userAgent.product.isIphoneOrIpod_ = function() {
6832
6846
  return goog.labs.userAgent.platform.isIphone() || goog.labs.userAgent.platform.isIpod();
@@ -6843,7 +6857,7 @@ goog.userAgent.product.determineVersion_ = function() {
6843
6857
  if (goog.userAgent.product.FIREFOX) {
6844
6858
  return goog.userAgent.product.getFirstRegExpGroup_(/Firefox\/([0-9.]+)/);
6845
6859
  }
6846
- if (goog.userAgent.product.IE || goog.userAgent.product.OPERA) {
6860
+ if (goog.userAgent.product.IE || goog.userAgent.product.EDGE || goog.userAgent.product.OPERA) {
6847
6861
  return goog.userAgent.VERSION;
6848
6862
  }
6849
6863
  if (goog.userAgent.product.CHROME) {
@@ -6976,7 +6990,7 @@ goog.json.Serializer.prototype.serializeInternal = function(a, b) {
6976
6990
  this.serializeNumber_(a, b);
6977
6991
  break;
6978
6992
  case "boolean":
6979
- b.push(a);
6993
+ b.push(String(a));
6980
6994
  break;
6981
6995
  case "function":
6982
6996
  b.push("null");
@@ -6996,7 +7010,7 @@ goog.json.Serializer.prototype.serializeString_ = function(a, b) {
6996
7010
  }), '"');
6997
7011
  };
6998
7012
  goog.json.Serializer.prototype.serializeNumber_ = function(a, b) {
6999
- b.push(isFinite(a) && !isNaN(a) ? a : "null");
7013
+ b.push(isFinite(a) && !isNaN(a) ? String(a) : "null");
7000
7014
  };
7001
7015
  goog.json.Serializer.prototype.serializeArray = function(a, b) {
7002
7016
  var c = a.length;
@@ -22,13 +22,20 @@ module Selenium
22
22
  module Safari
23
23
 
24
24
  class Server
25
+ SOCKET_LOCK_TIMEOUT = 45
26
+
25
27
  def initialize(port, command_timeout)
26
- @port = port
28
+ @port = port
27
29
  @command_timeout = command_timeout
28
30
  end
29
31
 
30
32
  def start
31
- @server = TCPServer.new(Platform.localhost, @port)
33
+ Platform.exit_hook { stop } # make sure we don't leave the server running
34
+
35
+ socket_lock.locked do
36
+ find_free_port
37
+ start_server
38
+ end
32
39
  end
33
40
 
34
41
  def stop
@@ -158,6 +165,20 @@ Server: safaridriver-ruby
158
165
  end
159
166
  end
160
167
 
168
+ private
169
+
170
+ def start_server
171
+ @server = TCPServer.new(Platform.localhost, @port)
172
+ end
173
+
174
+ def find_free_port
175
+ @port = PortProber.above @port
176
+ end
177
+
178
+ def socket_lock
179
+ @socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
180
+ end
181
+
161
182
  end # Server
162
183
  end # Safari
163
184
  end # WebDriver