selenium-webdriver 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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