selenium-webdriver 0.0.6 → 0.0.7

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.
@@ -16,6 +16,10 @@ module Selenium
16
16
  :chrome
17
17
  end
18
18
 
19
+ def driver_extensions
20
+ []
21
+ end
22
+
19
23
  def get(url)
20
24
  execute :request => 'get',
21
25
  :url => url
@@ -465,7 +465,8 @@ webdriver.WebElement.prototype.getSize = function() {
465
465
  webdriver.WebElement.createCoordinatesFromResponse_ = function(future,
466
466
  response) {
467
467
  var xy = response.value.replace(/\s/g, '').split(',');
468
- response.value = new goog.math.Coordinate(xy[0], xy[1]);
468
+ response.value = new goog.math.Coordinate(
469
+ Number(xy[0]), Number(xy[1]));
469
470
  future.setValue(response.value);
470
471
  };
471
472
 
@@ -9,6 +9,7 @@ require "selenium/webdriver/target_locator"
9
9
  require "selenium/webdriver/navigation"
10
10
  require "selenium/webdriver/options"
11
11
  require "selenium/webdriver/find"
12
+ require "selenium/webdriver/driver_extensions/takes_screenshot"
12
13
  require "selenium/webdriver/keys"
13
14
  require "selenium/webdriver/bridge_helper"
14
15
  require "selenium/webdriver/driver"
@@ -30,7 +30,13 @@ module Selenium
30
30
  end
31
31
 
32
32
  def start
33
- @pid = fork { exec(*@args) }
33
+ @pid = fork do
34
+ unless $DEBUG
35
+ [STDOUT, STDERR].each { |io| io.reopen("/dev/null") }
36
+ end
37
+
38
+ exec(*@args)
39
+ end
34
40
 
35
41
  self
36
42
  end
@@ -6,19 +6,27 @@ module Selenium
6
6
  attr_reader :bridge
7
7
 
8
8
  class << self
9
- def for(driver, *args)
10
- case driver
11
- when :ie, :internet_explorer
12
- new WebDriver::IE::Bridge.new(*args)
13
- when :remote
14
- new WebDriver::Remote::Bridge.new(*args)
15
- when :chrome
16
- new WebDriver::Chrome::Bridge.new(*args)
17
- when :firefox, :ff
18
- new WebDriver::Firefox::Bridge.new(*args)
19
- else
20
- raise ArgumentError, "unknown driver: #{driver.inspect}"
21
- end
9
+ def for(browser, *args)
10
+ bridge = case browser
11
+ when :ie, :internet_explorer
12
+ WebDriver::IE::Bridge.new(*args)
13
+ when :remote
14
+ WebDriver::Remote::Bridge.new(*args)
15
+ when :chrome
16
+ WebDriver::Chrome::Bridge.new(*args)
17
+ when :firefox, :ff
18
+ WebDriver::Firefox::Bridge.new(*args)
19
+ else
20
+ raise ArgumentError, "unknown driver: #{driver.inspect}"
21
+ end
22
+
23
+ driver = new(bridge)
24
+
25
+ unless bridge.driver_extensions.empty?
26
+ driver.extend(*bridge.driver_extensions)
27
+ end
28
+
29
+ driver
22
30
  end
23
31
  end
24
32
 
@@ -0,0 +1,24 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module DriverExtensions
4
+ module TakesScreenshot
5
+
6
+ def save_screenshot(png_path)
7
+ File.open(png_path, 'w') { |f| f << screenshot_as(:png) }
8
+ end
9
+
10
+ def screenshot_as(format)
11
+ case format
12
+ when :base64
13
+ bridge.getScreenshotAsBase64
14
+ when :png
15
+ bridge.getScreenshotAsBase64.unpack("m")[0]
16
+ else
17
+ raise Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
18
+ end
19
+ end
20
+
21
+ end # TakesScreenshot
22
+ end # DriverExtensions
23
+ end # WebDriver
24
+ end # Selenium
@@ -86,11 +86,11 @@ var ServerFactory = {
86
86
 
87
87
  //module definition (xpcom registration)
88
88
  var ServerModule = {
89
- _firstTime: true,
89
+ firstTime_: true,
90
90
 
91
91
  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) {
92
- if (this._firstTime) {
93
- this._firstTime = false;
92
+ if (this.firstTime_) {
93
+ this.firstTime_ = false;
94
94
  throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
95
95
  }
96
96
  aCompMgr =
@@ -242,6 +242,7 @@ FirefoxDriver.ElementLocator = {
242
242
  ID: 'id',
243
243
  NAME: 'name',
244
244
  CLASS_NAME: 'class name',
245
+ CSS_SELECTOR: 'css selector',
245
246
  TAG_NAME: 'tag name',
246
247
  LINK_TEXT: 'link text',
247
248
  PARTIAL_LINK_TEXT: 'partial link text',
@@ -291,6 +292,16 @@ FirefoxDriver.prototype.findElementInternal_ = function(respond, method,
291
292
  selector + ' ")]', rootNode);
292
293
  break;
293
294
 
295
+ case FirefoxDriver.ElementLocator.CSS_SELECTOR:
296
+ if (rootNode['querySelector']) {
297
+ element = rootNode.querySelector(selector);
298
+ } else {
299
+ respond.isError = true;
300
+ respond.response = "CSS Selectors not supported natively";
301
+ respond.send();
302
+ }
303
+ break;
304
+
294
305
  case FirefoxDriver.ElementLocator.TAG_NAME:
295
306
  element = rootNode.getElementsByTagName(selector)[0];
296
307
  break;
@@ -401,6 +412,16 @@ FirefoxDriver.prototype.findElementsInternal_ = function(respond, method,
401
412
  theDocument, './/*[@name="' + selector + '"]', rootNode);
402
413
  break;
403
414
 
415
+ case FirefoxDriver.ElementLocator.CSS_SELECTOR:
416
+ if (rootNode['querySelector']) {
417
+ elements = rootNode.querySelectorAll(selector);
418
+ } else {
419
+ respond.isError = true;
420
+ respond.response = "CSS Selectors not supported natively";
421
+ respond.send();
422
+ }
423
+ break;
424
+
404
425
  case FirefoxDriver.ElementLocator.TAG_NAME:
405
426
  elements = rootNode.getElementsByTagName(selector);
406
427
  break;
@@ -704,3 +725,33 @@ FirefoxDriver.prototype.saveScreenshot = function(respond, pngFile) {
704
725
  }
705
726
  respond.send();
706
727
  };
728
+
729
+
730
+ FirefoxDriver.prototype.getScreenshotAsBase64 = function(respond) {
731
+ var window = Utils.getBrowser(respond.context).contentWindow;
732
+ try {
733
+ var canvas = Screenshooter.grab(window);
734
+ respond.isError = false;
735
+ respond.response = Screenshooter.toBase64(canvas);
736
+ } catch (e) {
737
+ respond.isError = true;
738
+ respond.response = 'Could not take screenshot of current page - ' + e;
739
+ }
740
+ respond.send();
741
+ };
742
+
743
+ FirefoxDriver.prototype.dismissAlert = function(respond, alertText) {
744
+ // TODO(simon): Is there a type for alerts?
745
+ var wm = Utils.getService("@mozilla.org/appshell/window-mediator;1", "nsIWindowMediator");
746
+ var allWindows = wm.getEnumerator("");
747
+ while (allWindows.hasMoreElements()) {
748
+ var alert = allWindows.getNext();
749
+ var doc = alert.document;
750
+ if (doc && doc.documentURI == "chrome://global/content/commonDialog.xul") {
751
+ var dialog = doc.getElementsByTagName("dialog")[0];
752
+ dialog.getButton("accept").click();
753
+ break;
754
+ }
755
+ }
756
+ respond.send();
757
+ };
@@ -96,12 +96,20 @@ Response.prototype = {
96
96
  * Sends the encapsulated response to the registered callback.
97
97
  */
98
98
  send: function() {
99
+ if (this.responseSent_) {
100
+ // We shouldn't ever send the same response twice.
101
+ return;
102
+ }
99
103
  // Indicate that we are no longer executing a command.
100
104
  if (this.statusBarLabel_) {
101
105
  this.statusBarLabel_.style.color = 'black';
102
106
  }
107
+
103
108
  this.context = this.context.toString();
104
109
  this.responseHandler_.handleResponse(JSON.stringify(this.json_));
110
+
111
+ // Neuter ourselves
112
+ this.responseSent_ = true;
105
113
  },
106
114
 
107
115
  /**
@@ -202,6 +210,10 @@ DelayedCommand.prototype.executeInternal_ = function() {
202
210
  } else {
203
211
  try {
204
212
  this.response_.commandName = this.command_.commandName;
213
+ // TODO(simon): This is rampantly ugly, but allows an alert to kill the command
214
+ // TODO(simon): This is never cleared, but _should_ be okay, because send wipes itself
215
+ this.driver_.response_ = this.response_;
216
+
205
217
  this.driver_[this.command_.commandName](
206
218
  this.response_, this.command_.parameters);
207
219
  } catch (e) {
@@ -0,0 +1,208 @@
1
+ // Spoof the prompt service. Interesting thread on mozillazine:
2
+ // http://www.mail-archive.com/dev-tech-xpcom@lists.mozilla.org/msg00193.html
3
+
4
+ const CC = Components.classes;
5
+ const CI = Components.interfaces;
6
+
7
+ const CONSOLE = CC["@mozilla.org/consoleservice;1"].getService(CI["nsIConsoleService"]);
8
+
9
+ function dumpn(message) {
10
+ try {
11
+ CONSOLE.logStringMessage(message + "\n");
12
+ } catch (e) {
13
+ dump(message + "\n");
14
+ }
15
+ }
16
+
17
+ // Spoof implementation
18
+ function DrivenPromptService() {
19
+ // as defined in nsPromptService.h
20
+ var ORIGINAL_PARENT_SERVICE_ID = "{A2112D6A-0E28-421f-B46A-25C0B308CBD0}";
21
+
22
+ // Keep a reference to the original service
23
+ var originalService = Components.classesByID[ORIGINAL_PARENT_SERVICE_ID].getService();
24
+
25
+ this.originalPromptService_ =
26
+ originalService.QueryInterface(Components.interfaces.nsIPromptService);
27
+
28
+ dumpn("Spoofing prompt service");
29
+ }
30
+
31
+ // Constants from nsIPromtService.idl
32
+ DrivenPromptService.prototype = {
33
+ BUTTON_POS_0: 1,
34
+ BUTTON_POS_1: 256,
35
+ BUTTON_POS_2: 65536,
36
+
37
+ // Button Title Flags (used to set the labels of buttons in the prompt)
38
+ BUTTON_TITLE_OK: 1,
39
+ BUTTON_TITLE_CANCEL: 2,
40
+ BUTTON_TITLE_YES: 3,
41
+ BUTTON_TITLE_NO: 4,
42
+ BUTTON_TITLE_SAVE: 5,
43
+ BUTTON_TITLE_DONT_SAVE: 6,
44
+ BUTTON_TITLE_REVERT: 7,
45
+ BUTTON_TITLE_IS_STRING: 127,
46
+
47
+ // Button Default Flags (used to select which button is the default one)
48
+ BUTTON_POS_0_DEFAULT: 0,
49
+ BUTTON_POS_1_DEFAULT: 16777216,
50
+ BUTTON_POS_2_DEFAULT: 33554432,
51
+
52
+ // Causes the buttons to be initially disabled. They are enabled after a
53
+ // timeout expires. The implementation may interpret this loosely as the
54
+ // intent is to ensure that the user does not click through a security dialog
55
+ // too quickly. Strictly speaking, the implementation could choose to ignore
56
+ // this flag.
57
+ BUTTON_DELAY_ENABLE: 67108864,
58
+
59
+ // Selects the standard set of OK/Cancel buttons.
60
+ STD_OK_CANCEL_BUTTONS: (this.BUTTON_TITLE_OK * this.BUTTON_POS_0) + (this.BUTTON_TITLE_CANCEL
61
+ * this.BUTTON_POS_1),
62
+
63
+ // Selects the standard set of Yes/No buttons.
64
+ STD_YES_NO_BUTTONS: (this.BUTTON_TITLE_YES * this.BUTTON_POS_0) + (this.BUTTON_TITLE_NO
65
+ * this.BUTTON_POS_1)
66
+ };
67
+
68
+ DrivenPromptService.prototype.findAssociatedDriver_ = function(window) {
69
+ var ww = CC["@mozilla.org/embedcomp/window-watcher;1"].getService(CI["nsIWindowWatcher"]);
70
+
71
+ // There might be an easy answer.
72
+ var win = ww.getChromeForWindow(window);
73
+ if (win) {
74
+ return win;
75
+ }
76
+
77
+ // There isn't. Grab the top window's default view
78
+ var parent = window ? window : ww.activeWindow;
79
+ if (parent.wrappedJSObject)
80
+ parent = parent.wrappedJSObject;
81
+ var top = parent.top;
82
+
83
+ // Now iterate over all open browsers to find the one we belong to
84
+ var wm = CC["@mozilla.org/appshell/window-mediator;1"].getService(CI["nsIWindowMediator"]);
85
+ var allWindows = wm.getEnumerator("navigator:browser");
86
+ while (allWindows.hasMoreElements()) {
87
+ var chrome = allWindows.getNext().QueryInterface(CI.nsIDOMWindow);
88
+ if (chrome.content == window) {
89
+ return chrome.fxdriver;
90
+ }
91
+ }
92
+
93
+ // There's no meaningful way we can reach this.
94
+ return undefined;
95
+ };
96
+
97
+ DrivenPromptService.prototype.alert = function(aParent, aDialogTitle, aText) {
98
+ // Try to grab the top level window
99
+ var driver = this.findAssociatedDriver_(aParent);
100
+
101
+ if (driver && driver.response_) {
102
+ var res = driver.response_;
103
+ // TODO(simon): We can't rely on the normal JSON library here because it might not be available
104
+ // Come up with a cleaner way of doing this.
105
+ var json = "{ title: \"" + aDialogTitle + "\", text: \"" + aText + "\", __webdriverType: 'alert' }";
106
+
107
+ res.response = json;
108
+ res.send();
109
+ } else {
110
+ // TODO(simon): we should prevent the next command from blocking.
111
+ }
112
+
113
+ return this.originalPromptService_.alert(aParent, aDialogTitle, aText);
114
+ };
115
+
116
+ DrivenPromptService.prototype.alertCheck =
117
+ function(aParent, aDialogTitle, aText, aCheckMsg, aCheckState) {
118
+ return this.originalPromptService_.alertCheck(aParent, aDialogTitle, aText, aCheckMsg, aCheckState);
119
+ };
120
+
121
+ DrivenPromptService.prototype.confirm = function(aParent, aDialogTitle, aText) {
122
+ return this.originalPromptService_.confirm(aParent, aDialogTitle, aText);
123
+ };
124
+
125
+ DrivenPromptService.prototype.confirmCheck =
126
+ function(aParent, aDialogTitle, aText, aCheckMsg, aCheckState) {
127
+ return this.originalPromptService_.confirmCheck(aParent, aDialogTitle, aText, aCheckMsg, aCheckState);
128
+ };
129
+
130
+ DrivenPromptService.prototype.confirmEx =
131
+ function(aParent, aDialogTitle, aText, aButtonFlags, aButton0Title, aButton1Title, aButton2Title, aCheckMsg, aCheckState) {
132
+ return this.originalPromptService_.confirmEx(aParent, aDialogTitle, aText, aButtonFlags, aButton0Title, aButton1Title, aButton2Title, aCheckMsg, aCheckState);
133
+ };
134
+
135
+ DrivenPromptService.prototype.prompt =
136
+ function(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState) {
137
+ return this.originalPromptService_.prompt(aParent, aDialogTitle, aText, aValue, aCheckMsg, aCheckState);
138
+ };
139
+
140
+ DrivenPromptService.prototype.promptUsernameAndPassword =
141
+ function(aParent, aDialogTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState) {
142
+ return this.originalPromptService_.promptUsernameAndPassword(aParent, aDialogTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState);
143
+ };
144
+
145
+ DrivenPromptService.prototype.promptPassword =
146
+ function(aParent, aDialogTitle, aText, aPassword, aCheckMsg, aCheckState) {
147
+ return this.originalPromptService_.promptPassword(aParent, aDialogTitle, aText, aPassword, aCheckMsg, aCheckState);
148
+ };
149
+
150
+ DrivenPromptService.prototype.select =
151
+ function(aParent, aDialogTitle, aText, aCount, aSelectList, aOutSelection) {
152
+ return this.originalPromptService_.select(aParent, aDialogTitle, aText, aCount, aSelectList, aOutSelection);
153
+ };
154
+
155
+ const PROMPT_CONTRACT_ID = "@mozilla.org/embedcomp/prompt-service;1";
156
+ const DRIVEN_PROMPT_SERVICE_CLASS_ID = Components.ID('{e26dbdcd-d3ba-4ded-88c3-6cb07ee3e9e0}');
157
+
158
+ var service = undefined;
159
+
160
+ var PromptServiceSpoofFactory = {
161
+ createInstance: function (aOuter, aIID) {
162
+ if (aOuter != null)
163
+ throw Components.results.NS_ERROR_NO_AGGREGATION;
164
+ if (service == undefined) {
165
+ service = new DrivenPromptService();
166
+ }
167
+ return service;
168
+ }
169
+ };
170
+
171
+ function PromptServiceSpoofModule() {
172
+ this.firstTime_ = true;
173
+ }
174
+
175
+ PromptServiceSpoofModule.prototype.registerSelf = function(aCompMgr, aFileSpec, aLocation, aType) {
176
+ if (this.firstTime_) {
177
+ this.firstTime_ = false;
178
+ throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
179
+ }
180
+ aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
181
+ aCompMgr.registerFactoryLocation(
182
+ DRIVEN_PROMPT_SERVICE_CLASS_ID, "Driven prompt service", PROMPT_CONTRACT_ID, aFileSpec, aLocation, aType);
183
+ };
184
+
185
+ PromptServiceSpoofModule.prototype.unregisterSelf = function(aCompMgr, aLocation, aType) {
186
+ dumpn("Unregistering\n");
187
+ aCompMgr =
188
+ aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
189
+ aCompMgr.unregisterFactoryLocation(DRIVEN_PROMPT_SERVICE_CLASS_ID, aLocation);
190
+ };
191
+
192
+ PromptServiceSpoofModule.prototype.getClassObject = function(aCompMgr, aCID, aIID) {
193
+ if (!aIID.equals(Components.interfaces.nsIFactory))
194
+ throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
195
+
196
+ if (aCID.equals(DRIVEN_PROMPT_SERVICE_CLASS_ID))
197
+ return PromptServiceSpoofFactory;
198
+
199
+ throw Components.results.NS_ERROR_NO_INTERFACE;
200
+ };
201
+
202
+ PromptServiceSpoofModule.prototype.canUnload = function(aCompMgr) {
203
+ return true;
204
+ };
205
+
206
+ function NSGetModule(comMgr, fileSpec) {
207
+ return new PromptServiceSpoofModule();
208
+ }
@@ -42,6 +42,17 @@ Screenshooter.grab = function(window) {
42
42
  };
43
43
 
44
44
 
45
+ Screenshooter.toBase64 = function(canvas) {
46
+ var dataUrl = canvas.toDataURL('image/png');
47
+ var index = dataUrl.indexOf('base64,');
48
+ if (index == -1) {
49
+ // No base64 data marker.
50
+ throw new Error("Invalid base64 data: " + dataUrl);
51
+ }
52
+ return dataUrl.substring(index + 'base64,'.length);
53
+ };
54
+
55
+
45
56
  Screenshooter.save = function(canvas, filepath) {
46
57
  var cc = Components.classes;
47
58
  var ci = Components.interfaces;
@@ -1086,7 +1086,11 @@ Utils.findElementsByXPath = function (xpath, contextNode, context) {
1086
1086
 
1087
1087
 
1088
1088
  Utils.getLocationOnceScrolledIntoView = function(element) {
1089
- element.scrollIntoView(true);
1089
+ // Some elements may not a scrollIntoView function - for example,
1090
+ // elements under an SVG element. Call those only if they exist.
1091
+ if (typeof element.scrollIntoView == 'function') {
1092
+ element.scrollIntoView(true);
1093
+ }
1090
1094
 
1091
1095
  var retrieval = Utils.newInstance(
1092
1096
  "@mozilla.org/accessibleRetrieval;1", "nsIAccessibleRetrieval");
@@ -1106,6 +1110,18 @@ Utils.getLocationOnceScrolledIntoView = function(element) {
1106
1110
  };
1107
1111
  }
1108
1112
 
1113
+ // Firefox 3.0.14 seems to have top, bottom attributes.
1114
+ if (clientRect['top'] !== undefined) {
1115
+ var retWidth = clientRect.right - clientRect.left;
1116
+ var retHeight = clientRect.bottom - clientRect.top;
1117
+ return {
1118
+ x : clientRect.left,
1119
+ y : clientRect.top,
1120
+ width: retWidth,
1121
+ height: retHeight
1122
+ }
1123
+ }
1124
+
1109
1125
  // Firefox 3.0
1110
1126
  Utils.dumpn("Falling back to firefox3 mechanism");
1111
1127
  var accessible = retrieval.getAccessibleFor(element);
@@ -1125,6 +1141,7 @@ Utils.getLocationOnceScrolledIntoView = function(element) {
1125
1141
 
1126
1142
  // Firefox 2.0
1127
1143
 
1144
+ Utils.dumpn("Falling back to firefox2 mechanism");
1128
1145
  // Fallback. Use the (deprecated) method to find out where the element is in
1129
1146
  // the viewport. This should be fine to use because we only fall down this
1130
1147
  // code path on older versions of Firefox (I think!)
@@ -22,8 +22,7 @@ function WebDriverServer() {
22
22
  this.serverSocket =
23
23
  Components.classes["@mozilla.org/network/server-socket;1"].
24
24
  createInstance(Components.interfaces.nsIServerSocket);
25
- this.generator =
26
- Utils.getService("@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
25
+ this.generator = Utils.getService("@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
27
26
  this.enableNativeEvents = null;
28
27
  }
29
28
 
@@ -43,6 +42,7 @@ WebDriverServer.prototype.newDriver = function(window) {
43
42
  window.fxdriver = new FirefoxDriver(this, this.enableNativeEvents);
44
43
  // Yuck. But it allows us to refer to it later.
45
44
  window.fxdriver.window = window;
45
+
46
46
  return window.fxdriver;
47
47
  };
48
48
 
@@ -76,8 +76,14 @@ FirefoxDriver.prototype.click = function(respond) {
76
76
  Utils.fireMouseEventOn(respond.context, element, "mousemove");
77
77
  Utils.fireMouseEventOn(respond.context, element, "mousedown");
78
78
  if (element != currentlyActive) {
79
- currentlyActive.blur();
80
- element.focus();
79
+ // Some elements may not have blur, focus functions - for example,
80
+ // elements under an SVG element. Call those only if they exist.
81
+ if (typeof currentlyActive.blur == 'function') {
82
+ currentlyActive.blur();
83
+ }
84
+ if (typeof element.focus == 'function') {
85
+ element.focus();
86
+ }
81
87
  }
82
88
 
83
89
  Utils.fireMouseEventOn(respond.context, element, "mouseup");
@@ -4,9 +4,15 @@ module Selenium
4
4
  class Bridge
5
5
  include BridgeHelper
6
6
 
7
- def initialize
7
+ def initialize(opts = {})
8
8
  @binary = Binary.new
9
- @launcher = Launcher.new(@binary).launch
9
+ @launcher = Launcher.new(
10
+ @binary,
11
+ opts[:port] || DEFAULT_PORT,
12
+ opts[:profile] || DEFAULT_PROFILE_NAME
13
+ )
14
+
15
+ @launcher.launch
10
16
  @connection = @launcher.connection
11
17
  @context = newSession
12
18
  end
@@ -15,6 +21,10 @@ module Selenium
15
21
  :firefox
16
22
  end
17
23
 
24
+ def driver_extensions
25
+ [DriverExtensions::TakesScreenshot]
26
+ end
27
+
18
28
  def quit
19
29
  @connection.quit
20
30
  @binary.wait
@@ -33,6 +43,9 @@ module Selenium
33
43
  execute :getCurrentWindowHandle
34
44
  end
35
45
 
46
+ def getScreenshotAsBase64
47
+ execute :getScreenshotAsBase64
48
+ end
36
49
 
37
50
  def get(url)
38
51
  execute :get,
@@ -366,8 +379,14 @@ module Selenium
366
379
  puts "<-- #{resp.inspect}" if $DEBUG
367
380
 
368
381
  if resp['isError']
369
- msg = resp['response']['message'] rescue nil
370
- msg ||= resp['response'] || resp.inspect
382
+ case resp['response']
383
+ when String
384
+ msg = resp['response']
385
+ when Hash
386
+ msg = resp['response']['message']
387
+ end
388
+
389
+ msg ||= resp.inspect
371
390
  raise Error::WebDriverError, msg
372
391
  end
373
392
 
@@ -66,8 +66,16 @@ HTTP
66
66
  end
67
67
  end
68
68
 
69
- length = resp.split(":")[1].lstrip!.to_i
70
- json_string = @socket.recv length
69
+ length = Integer(resp.split(":").last.strip)
70
+ json_string = ''
71
+ bytes_received = 0
72
+
73
+ until bytes_received == length
74
+ read_string = @socket.recv(length - bytes_received)
75
+
76
+ bytes_received += read_string.length
77
+ json_string << read_string
78
+ end
71
79
 
72
80
  if json_string.empty?
73
81
  raise Error::WebDriverError, "empty response from extension"
@@ -88,6 +88,10 @@ module Selenium
88
88
 
89
89
  def create_copy
90
90
  tmp_directory = Dir.mktmpdir("webdriver-rb-profilecopy")
91
+
92
+ # TODO: must be a better way..
93
+ FileUtils.rm_rf tmp_directory
94
+ FileUtils.mkdir_p File.dirname(tmp_directory), :mode => 0700
91
95
  FileUtils.cp_r @directory, tmp_directory
92
96
 
93
97
  Profile.new(tmp_directory)
@@ -19,6 +19,10 @@ module Selenium
19
19
  :internet_explorer
20
20
  end
21
21
 
22
+ def driver_extensions
23
+ []
24
+ end
25
+
22
26
  def get(url)
23
27
  check_error_code Lib.wdGet(@driver_pointer, wstring_ptr(url)),
24
28
  "Cannot get url #{url.inspect}"
@@ -60,6 +60,10 @@ module Selenium
60
60
  @browser ||= @capabilities.browser_name.gsub(" ", "_").to_sym
61
61
  end
62
62
 
63
+ def driver_extensions
64
+ []
65
+ end
66
+
63
67
  #
64
68
  # Returns the current session ID.
65
69
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: selenium-webdriver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jari Bakken
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-17 00:00:00 +01:00
12
+ date: 2009-11-22 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -66,6 +66,7 @@ files:
66
66
  - common/src/rb/lib/selenium/webdriver/child_process.rb
67
67
  - common/src/rb/lib/selenium/webdriver/core_ext/dir.rb
68
68
  - common/src/rb/lib/selenium/webdriver/driver.rb
69
+ - common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb
69
70
  - common/src/rb/lib/selenium/webdriver/element.rb
70
71
  - common/src/rb/lib/selenium/webdriver/error.rb
71
72
  - common/src/rb/lib/selenium/webdriver/find.rb
@@ -108,6 +109,7 @@ files:
108
109
  - firefox/src/extension/components/json2.js
109
110
  - firefox/src/extension/components/keytest.html
110
111
  - firefox/src/extension/components/nsCommandProcessor.js
112
+ - firefox/src/extension/components/promptService.js
111
113
  - firefox/src/extension/components/screenshooter.js
112
114
  - firefox/src/extension/components/socketListener.js
113
115
  - firefox/src/extension/components/utils.js