selenium-webdriver 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/chrome/prebuilt/Win32/Release/npchromedriver.dll +0 -0
  2. data/chrome/prebuilt/x64/Release/npchromedriver.dll +0 -0
  3. data/chrome/src/extension/background.js +64 -48
  4. data/chrome/src/extension/content_script.js +253 -132
  5. data/chrome/src/extension/manifest-nonwin.json +1 -1
  6. data/chrome/src/extension/manifest-win.json +1 -1
  7. data/chrome/src/extension/utils.js +8 -8
  8. data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +9 -0
  9. data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +38 -280
  10. data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +119 -117
  11. data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +36 -26
  12. data/common/src/js/abstractcommandprocessor.js +9 -11
  13. data/common/src/js/command.js +159 -83
  14. data/common/src/js/core/RemoteRunner.html +2 -2
  15. data/common/src/js/core/TestRunner-splash.html +3 -3
  16. data/common/src/js/core/TestRunner.html +5 -17
  17. data/common/src/js/core/scripts/htmlutils.js +4208 -2506
  18. data/common/src/js/core/scripts/selenium-api.js +2 -2
  19. data/common/src/js/core/scripts/selenium-browserbot.js +66 -58
  20. data/common/src/js/core/scripts/selenium-version.js +1 -1
  21. data/common/src/js/localcommandprocessor.js +5 -19
  22. data/common/src/js/testcase.js +2 -0
  23. data/common/src/js/webdriver.js +63 -93
  24. data/common/src/js/webelement.js +40 -42
  25. data/common/src/rb/lib/selenium/webdriver.rb +23 -14
  26. data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +8 -35
  27. data/common/src/rb/lib/selenium/webdriver/child_process.rb +2 -0
  28. data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +1 -0
  29. data/common/src/rb/lib/selenium/webdriver/core_ext/string.rb +5 -0
  30. data/common/src/rb/lib/selenium/webdriver/driver.rb +20 -15
  31. data/common/src/rb/lib/selenium/webdriver/driver_extensions/takes_screenshot.rb +7 -2
  32. data/common/src/rb/lib/selenium/webdriver/element.rb +11 -2
  33. data/common/src/rb/lib/selenium/webdriver/error.rb +9 -5
  34. data/common/src/rb/lib/selenium/webdriver/keys.rb +1 -2
  35. data/common/src/rb/lib/selenium/webdriver/navigation.rb +16 -0
  36. data/common/src/rb/lib/selenium/webdriver/options.rb +32 -0
  37. data/common/src/rb/lib/selenium/webdriver/platform.rb +17 -1
  38. data/firefox/prebuilt/Win32/Release/webdriver-firefox.dll +0 -0
  39. data/firefox/src/extension/components/dispatcher.js +492 -0
  40. data/firefox/src/extension/components/driver-component.js +4 -1
  41. data/firefox/src/extension/components/errorcode.js +70 -0
  42. data/firefox/src/extension/components/firefoxDriver.js +173 -154
  43. data/firefox/src/extension/components/nsCommandProcessor.js +171 -132
  44. data/firefox/src/extension/components/promptService.js +5 -5
  45. data/firefox/src/extension/components/request.js +219 -0
  46. data/firefox/src/extension/components/response.js +276 -0
  47. data/firefox/src/extension/components/session.js +281 -0
  48. data/firefox/src/extension/components/sessionstore.js +226 -0
  49. data/firefox/src/extension/components/socketListener.js +350 -100
  50. data/firefox/src/extension/components/utils.js +166 -98
  51. data/firefox/src/extension/components/webdriverserver.js +9 -5
  52. data/firefox/src/extension/components/wrappedElement.js +189 -166
  53. data/firefox/src/extension/install.rdf +1 -1
  54. data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +2 -0
  55. data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +39 -33
  56. data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +7 -421
  57. data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +7 -64
  58. data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +2 -3
  59. data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +54 -10
  60. data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +2 -0
  61. data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +6 -0
  62. data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
  63. data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
  64. data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +2 -0
  65. data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +38 -13
  66. data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +9 -2
  67. data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +5 -0
  68. data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +2 -0
  69. data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +42 -38
  70. data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +56 -47
  71. data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +26 -26
  72. data/remote/client/src/rb/lib/selenium/webdriver/remote/patron_http_client.rb +58 -0
  73. data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +10 -12
  74. data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +2 -17
  75. metadata +44 -23
  76. data/common/src/js/context.js +0 -58
  77. data/firefox/src/extension/components/context.js +0 -37
@@ -29,7 +29,7 @@
29
29
  */
30
30
  (function() {
31
31
  var scripts = [
32
- 'context.js',
32
+ 'errorcode.js',
33
33
  'utils.js'
34
34
  ];
35
35
 
@@ -70,12 +70,15 @@ var Response = function(command, responseHandler) {
70
70
  this.statusBarLabel_ = null;
71
71
  this.responseHandler_ = responseHandler;
72
72
  this.json_ = {
73
- commandName: command ? command.commandName : 'Unknown command',
74
- isError: false,
75
- response: '',
76
- elementId: command.elementId,
77
- context: command.context
73
+ name: command ? command.name : 'Unknown command',
74
+ sessionId: command['sessionId'],
75
+ status: ErrorCode.SUCCESS,
76
+ value: ''
78
77
  };
78
+ if (this.json_['sessionId'] && this.json_['sessionId']['value']) {
79
+ this.json_['sessionId'] = this.json_['sessionId']['value'];
80
+ }
81
+ this.session = null;
79
82
  };
80
83
 
81
84
  Response.prototype = {
@@ -105,7 +108,6 @@ Response.prototype = {
105
108
  this.statusBarLabel_.style.color = 'black';
106
109
  }
107
110
 
108
- this.context = this.context.toString();
109
111
  this.responseHandler_.handleResponse(JSON.stringify(this.json_));
110
112
 
111
113
  // Neuter ourselves
@@ -113,32 +115,25 @@ Response.prototype = {
113
115
  },
114
116
 
115
117
  /**
116
- * Helper function for reporting internal errors to the client.
117
- * @param {Error} ex The internal error to report to the client.
118
+ * Sends a WebDriver error response.
119
+ * @param {WebDriverError} e The error to send.
118
120
  */
119
- reportError: function(ex) {
120
- Utils.dump(ex);
121
- this.response = 'Internal error: ' + JSON.stringify({
122
- fileName : ex.fileName,
123
- lineNumber : ex.lineNumber,
124
- message : ex.message,
125
- name : ex.name
126
- });
127
- this.isError = true;
121
+ sendError: function(e) {
122
+ // if (e instanceof WebDriverError) won't work here since
123
+ // WebDriverError is defined in the utils.js subscript which is
124
+ // loaded independently in this component and in the main driver
125
+ // component.
126
+ this.status = e.isWebDriverError ? e.code : ErrorCode.UNHANDLED_ERROR;
127
+ this.value = ErrorCode.toJSON(e);
128
128
  this.send();
129
129
  },
130
130
 
131
- setField: function(name, value) { this.json_[name] = value; },
132
- set commandName(name) { this.json_.commandName = name; },
133
- get commandName() { return this.json_.commandName; },
134
- set elementId(id) { this.json_.elementId = id; },
135
- get elementId() { return this.json_.elementId; },
136
- set isError(error) { this.json_.isError = error; },
137
- get isError() { return this.json_.isError; },
138
- set response(res) { this.json_.response = res; },
139
- get response() { return this.json_.response; },
140
- set context(c) { this.json_.context = c; },
141
- get context() { return this.json_.context; }
131
+ set name(name) { this.json_.name = name; },
132
+ get name() { return this.json_.name; },
133
+ set status(newStatus) { this.json_.status = newStatus; },
134
+ get status() { return this.json_.status; },
135
+ set value(val) { this.json_.value = val; },
136
+ get value() { return this.json_.value; },
142
137
  };
143
138
 
144
139
 
@@ -161,13 +156,22 @@ var DelayedCommand = function(driver, command, response, opt_sleepDelay) {
161
156
  this.onBlank_ = false;
162
157
  this.sleepDelay_ = opt_sleepDelay || DelayedCommand.DEFAULT_SLEEP_DELAY;
163
158
 
164
- var activeWindow =
165
- response.context.frame || response.context.fxbrowser.contentWindow;
166
- this.loadGroup_ = activeWindow.
167
- QueryInterface(Components.interfaces.nsIInterfaceRequestor).
168
- getInterface(Components.interfaces.nsIWebNavigation).
169
- QueryInterface(Components.interfaces.nsIInterfaceRequestor).
170
- getInterface(Components.interfaces.nsILoadGroup);
159
+ var activeWindow = response.session.getWindow();
160
+ try {
161
+ var webNav = activeWindow.
162
+ QueryInterface(Components.interfaces.nsIInterfaceRequestor).
163
+ getInterface(Components.interfaces.nsIWebNavigation);
164
+ this.loadGroup_ = webNav.
165
+ QueryInterface(Components.interfaces.nsIInterfaceRequestor).
166
+ getInterface(Components.interfaces.nsILoadGroup);
167
+ } catch (ex) {
168
+ // Well this sucks. This can happen if the DOM gets trashed or if the window
169
+ // is unexpectedly closed. We need to report this error to the user so they
170
+ // can let us (webdriver-eng) know that the FirefoxDriver is busted.
171
+ response.sendError(ex);
172
+ // Re-throw the error so the command will be aborted.
173
+ throw ex;
174
+ }
171
175
  };
172
176
 
173
177
 
@@ -229,6 +233,7 @@ DelayedCommand.prototype.shouldDelayExecutionForPendingRequest_ = function() {
229
233
  }
230
234
  } catch(e) {
231
235
  Utils.dumpn('Problem while checking if we should delay execution: ' + e);
236
+ return true;
232
237
  }
233
238
 
234
239
  return false;
@@ -254,30 +259,20 @@ DelayedCommand.prototype.executeInternal_ = function() {
254
259
  return this.execute(this.sleepDelay_);
255
260
  } else {
256
261
  try {
257
- this.response_.commandName = this.command_.commandName;
262
+ this.response_.name = this.command_.name;
258
263
  // TODO(simon): This is rampantly ugly, but allows an alert to kill the command
259
264
  // TODO(simon): This is never cleared, but _should_ be okay, because send wipes itself
260
265
  this.driver_.response_ = this.response_;
261
266
 
262
- this.driver_[this.command_.commandName](
267
+ this.driver_[this.command_.name](
263
268
  this.response_, this.command_.parameters);
264
269
  } catch (e) {
265
- // if (e instanceof StaleElementError) won't work here since
266
- // StaleElementError is defined in the utils.js subscript which is
267
- // loaded independently in this component and in the main driver
268
- // component.
269
- // TODO(jmleyba): Continue cleaning up the extension and replacing the
270
- // subscripts with proper components.
271
- if (e.isStaleElementError) {
272
- this.response_.isError = true;
273
- this.response_.response = 'element is obsolete';
274
- this.response_.send();
275
- } else {
270
+ if (!e.isWebDriverError) {
276
271
  Utils.dumpn(
277
- 'Exception caught by driver: ' + this.command_.commandName +
272
+ 'Exception caught by driver: ' + this.command_.name +
278
273
  '(' + this.command_.parameters + ')\n' + e);
279
- this.response_.reportError(e);
280
274
  }
275
+ this.response_.sendError(e);
281
276
  }
282
277
  }
283
278
  };
@@ -336,97 +331,84 @@ nsCommandProcessor.prototype.execute = function(jsonCommandString,
336
331
  command = JSON.parse(jsonCommandString);
337
332
  } catch (ex) {
338
333
  response = JSON.stringify({
339
- 'isError': true,
334
+ 'status': ErrorCode.UNHANDLED_ERROR,
340
335
  'value': 'Error parsing command: "' + jsonCommandString + '"'
341
336
  });
342
337
  responseHandler.handleResponse(response);
343
338
  return;
344
339
  }
345
340
 
346
- command.context = Context.fromString(command.context);
347
341
  response = new Response(command, responseHandler);
348
342
 
349
- // These are used to locate a new driver, and so not having one is a fine
350
- // thing to do
351
- if (command.commandName == 'newSession' ||
352
- command.commandName == 'switchToWindow' ||
353
- command.commandName == 'getWindowHandles' ||
354
- command.commandName == 'quit') {
355
- return this[command.commandName](response, command.parameters);
356
- }
357
-
358
- var win, fxbrowser, driver;
359
- var allWindows = this.wm.getEnumerator(null);
360
- while (allWindows.hasMoreElements()) {
361
- win = allWindows.getNext();
362
- if (win["fxdriver"] && win.fxdriver.id == response.context.windowId) {
363
- fxbrowser = win.getBrowser();
364
- driver = win.fxdriver;
365
- break;
343
+ // These commands do not require a session.
344
+ if (command.name == 'newSession' ||
345
+ command.name == 'quit' ||
346
+ command.name == 'getWindowHandles') {
347
+ try {
348
+ this[command.name](response, command.parameters);
349
+ } catch (ex) {
350
+ response.sendError(ex);
366
351
  }
352
+ return;
367
353
  }
368
354
 
369
- if (!fxbrowser) {
370
- response.isError = true;
371
- response.response = 'Unable to find browser with id ' +
372
- response.context.windowId;
373
- return response.send();
355
+ var sessionId = command.sessionId;
356
+ if (!sessionId) {
357
+ response.sendError(new WebDriverError(ErrorCode.UNHANDLED_ERROR,
358
+ 'No session ID specified'));
359
+ return;
374
360
  }
375
361
 
376
- if (!driver) {
377
- response.isError = true;
378
- response.response = 'Unable to find the driver for browser with id ' +
379
- response.context.windowId;
380
- return response.send();
362
+ sessionId = sessionId.value;
363
+ try {
364
+ response.session = Components.
365
+ classes['@googlecode.com/webdriver/wdsessionstoreservice;1'].
366
+ getService(Components.interfaces.nsISupports).
367
+ wrappedJSObject.
368
+ getSession(sessionId).
369
+ wrappedJSObject;
370
+ } catch (ex) {
371
+ response.sendError(new WebDriverError(ErrorCode.UNHANDLED_ERROR,
372
+ 'Session not found: ' + sessionId));
373
+ return;
381
374
  }
382
375
 
383
- if (typeof driver[command.commandName] != 'function') {
384
- response.isError = true;
385
- response.response = 'Unrecognised command: ' + command.commandName;
386
- return response.send();
376
+ if (command.name == 'deleteSession' ||
377
+ command.name == 'getSessionCapabilities' ||
378
+ command.name == 'switchToWindow') {
379
+ return this[command.name](response, command.parameters);
387
380
  }
388
381
 
389
- response.context.fxbrowser = fxbrowser;
390
-
391
- // Determine whether or not we need to care about frames.
392
- var frames = fxbrowser.contentWindow.frames;
393
- if ("?" == response.context.frameId) {
394
- if (frames && frames.length) {
395
- if ("FRAME" == frames[0].frameElement.tagName) {
396
- response.context.frameId = 0;
397
- } else {
398
- response.context.frameId = undefined;
399
- }
400
- } else {
401
- response.context.frameId = undefined;
402
- }
382
+ var sessionWindow = response.session.getChromeWindow();
383
+ var driver = sessionWindow.fxdriver; // TODO(jmleyba): We only need to store an ID on the window!
384
+ if (!driver) {
385
+ response.sendError(new WebDriverError(ErrorCode.UNHANDLED_ERROR,
386
+ 'Session has no driver: ' + response.session.getId()));
387
+ return;
403
388
  }
404
389
 
405
- if (response.context.frameId !== undefined) {
406
- response.context.frame = Utils.findFrame(
407
- fxbrowser, response.context.frameId);
390
+ if (typeof driver[command.name] != 'function') {
391
+ response.sendError(new WebDriverError(ErrorCode.UNKNOWN_COMMAND,
392
+ 'Unrecognised command: ' + command.name));
393
+ return;
408
394
  }
409
395
 
410
- response.startCommand(win);
396
+ response.startCommand(sessionWindow);
411
397
  new DelayedCommand(driver, command, response).execute(0);
412
398
  };
413
399
 
414
400
 
415
-
416
401
  /**
417
- * Changes the context of the caller to the window specified by the first
418
- * element of the {@code windowId} array.
402
+ * Changes the context of the caller to the specified window.
419
403
  * @param {Response} response The response object to send the command response
420
404
  * in.
421
- * @param {Array.<*>} windowId The parameters sent with the original command.
422
- * The first element in the array must be the ID of the window to switch to.
423
- * Note all other command parameters are ignored.
405
+ * @param {{name: string}} parameters The command parameters.
424
406
  * @param {number} opt_searchAttempt Which attempt this is at finding the
425
407
  * window to switch to.
426
408
  */
427
- nsCommandProcessor.prototype.switchToWindow = function(response, windowId,
409
+ nsCommandProcessor.prototype.switchToWindow = function(response, parameters,
428
410
  opt_searchAttempt) {
429
- var lookFor = windowId[0];
411
+ var lookFor = parameters.name;
430
412
  var matches = function(win, lookFor) {
431
413
  return !win.closed &&
432
414
  (win.content && win.content.name == lookFor) ||
@@ -442,12 +424,13 @@ nsCommandProcessor.prototype.switchToWindow = function(response, windowId,
442
424
 
443
425
  win.focus();
444
426
  if (win.top.fxdriver) {
445
- response.response = new Context(win.fxdriver.id).toString();
427
+ response.session.setChromeWindow(win.top);
428
+ response.value = response.session.getId();
429
+ response.send();
446
430
  } else {
447
- response.isError = true;
448
- response.response = 'No driver found attached to top window!';
431
+ response.sendError(new WebDriverError(ErrorCode.UNHANDLED_ERROR,
432
+ 'No driver found attached to top window!'));
449
433
  }
450
- response.send();
451
434
  // Found the desired window, stop the search.
452
435
  return true;
453
436
  }
@@ -463,14 +446,13 @@ nsCommandProcessor.prototype.switchToWindow = function(response, windowId,
463
446
  // one is still loading vs. a brute force "try again"
464
447
  var searchAttempt = opt_searchAttempt || 0;
465
448
  if (searchAttempt > 3) {
466
- response.isError = true;
467
- response.response = 'Unable to locate window "' + lookFor + '"';
468
- response.send();
449
+ response.sendError(new WebDriverError(ErrorCode.NO_SUCH_WINDOW,
450
+ 'Unable to locate window "' + lookFor + '"'));
469
451
  } else {
470
452
  var self = this;
471
453
  this.wm.getMostRecentWindow('navigator:browser').
472
454
  setTimeout(function() {
473
- self.switchToWindow(response, windowId, (searchAttempt + 1));
455
+ self.switchToWindow(response, parameters, (searchAttempt + 1));
474
456
  }, 500);
475
457
  }
476
458
  }
@@ -491,7 +473,7 @@ nsCommandProcessor.prototype.getWindowHandles = function(response) {
491
473
  res.push(win.content.name);
492
474
  }
493
475
  });
494
- response.response = res;
476
+ response.value = res;
495
477
  response.send();
496
478
  };
497
479
 
@@ -521,33 +503,90 @@ nsCommandProcessor.prototype.searchWindows_ = function(search_criteria,
521
503
 
522
504
  /**
523
505
  * Locates the most recently used FirefoxDriver window.
524
- * @param {Response} response The response object to send the command response
525
- * in.
506
+ * @param {Response} response The object to send the command response in.
526
507
  */
527
508
  nsCommandProcessor.prototype.newSession = function(response) {
528
509
  var win = this.wm.getMostRecentWindow("navigator:browser");
529
510
  var driver = win.fxdriver;
530
511
  if (!driver) {
531
- response.isError = true;
532
- response.response = 'No drivers associated with the window';
512
+ response.sendError(new WebDriverError(ErrorCode.UNHANDLED_ERROR,
513
+ 'No drivers associated with the window'));
533
514
  } else {
534
- response.context = new Context(driver.id);
535
- response.response = driver.id;
515
+ var sessionStore = Components.
516
+ classes['@googlecode.com/webdriver/wdsessionstoreservice;1'].
517
+ getService(Components.interfaces.nsISupports);
518
+
519
+ var session = sessionStore.wrappedJSObject.createSession();
520
+ session = session.wrappedJSObject; // XPConnect...
521
+ session.setChromeWindow(win);
522
+
523
+ response.session = session;
524
+ response.value = session.getId();
536
525
  }
537
526
  response.send();
538
527
  };
539
528
 
540
529
 
530
+ /**
531
+ * Describes a session.
532
+ * @param {Response} response The object to send the command response in.
533
+ */
534
+ nsCommandProcessor.prototype.getSessionCapabilities = function(response) {
535
+ var appInfo = Components.classes['@mozilla.org/xre/app-info;1'].
536
+ getService(Components.interfaces.nsIXULAppInfo);
537
+ var xulRuntime = Components.classes['@mozilla.org/xre/app-info;1'].
538
+ getService(Components.interfaces.nsIXULRuntime);
539
+ response.value = {
540
+ 'browserName': 'firefox',
541
+ 'version': appInfo.version,
542
+ 'javascriptEnabled': true,
543
+ 'platform': xulRuntime.OS // same as Platform.valueOf("name");
544
+ };
545
+ response.send();
546
+ };
547
+
548
+
549
+ /**
550
+ * Deletes the session associated with the current request.
551
+ * @param {Response} response The object to send the command response in.
552
+ */
553
+ nsCommandProcessor.prototype.deleteSession = function(response) {
554
+ var sessionStore = Components.
555
+ classes['@googlecode.com/webdriver/wdsessionstoreservice;1'].
556
+ getService(Components.interfaces.nsISupports);
557
+ sessionStore.wrappedJSObject.deleteSession(response.session.getId());
558
+ response.send();
559
+ };
560
+
561
+
541
562
  /**
542
563
  * Forcefully shuts down the Firefox application.
564
+ * @param {Response} response The object to send the command response in.
543
565
  */
544
- nsCommandProcessor.prototype.quit = function() {
545
- // Create a switch file so the native events library will
546
- // let all events through in case of a close.
547
- createSwitchFile("close:<ALL>");
548
- Components.classes['@mozilla.org/toolkit/app-startup;1'].
549
- getService(Components.interfaces.nsIAppStartup).
550
- quit(Components.interfaces.nsIAppStartup.eForceQuit);
566
+ nsCommandProcessor.prototype.quit = function(response) {
567
+ // Go ahead and respond to the command request to acknowledge that we are
568
+ // shutting down. We do this because once we force a quit, there's no way
569
+ // to respond. Clients will just have to trust that this shutdown didn't
570
+ // fail. Or they could monitor the PID. Either way, not much we can do about
571
+ // it in here.
572
+ response.send();
573
+
574
+ // Use an nsITimer to give the response time to go out.
575
+ var event = {
576
+ notify: function(timer) {
577
+ // Create a switch file so the native events library will
578
+ // let all events through in case of a close.
579
+ createSwitchFile("close:<ALL>");
580
+ Components.classes['@mozilla.org/toolkit/app-startup;1'].
581
+ getService(Components.interfaces.nsIAppStartup).
582
+ quit(Components.interfaces.nsIAppStartup.eForceQuit);
583
+ }
584
+ };
585
+
586
+ var timer = Components.classes['@mozilla.org/timer;1'].
587
+ createInstance(Components.interfaces.nsITimer);
588
+ timer.initWithCallback(event, 500, // milliseconds
589
+ Components.interfaces.nsITimer.TYPE_ONE_SHOT);
551
590
  };
552
591
 
553
592
 
@@ -100,11 +100,11 @@ DrivenPromptService.prototype.alert = function(aParent, aDialogTitle, aText) {
100
100
 
101
101
  if (driver && driver.response_) {
102
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;
103
+ res.value = {
104
+ title: aDialogTitle,
105
+ text: aText,
106
+ __webdriverType: 'alert'
107
+ };
108
108
  res.send();
109
109
  } else {
110
110
  // TODO(simon): we should prevent the next command from blocking.