selenium-webdriver 0.0.1

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 (86) 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.html +9 -0
  4. data/chrome/src/extension/background.js +933 -0
  5. data/chrome/src/extension/content_script.js +1286 -0
  6. data/chrome/src/extension/manifest-nonwin.json +15 -0
  7. data/chrome/src/extension/manifest-win.json +16 -0
  8. data/chrome/src/extension/toolstrip.html +28 -0
  9. data/chrome/src/extension/utils.js +196 -0
  10. data/chrome/src/rb/lib/selenium/webdriver/chrome.rb +8 -0
  11. data/chrome/src/rb/lib/selenium/webdriver/chrome/bridge.rb +324 -0
  12. data/chrome/src/rb/lib/selenium/webdriver/chrome/command_executor.rb +70 -0
  13. data/chrome/src/rb/lib/selenium/webdriver/chrome/launcher.rb +119 -0
  14. data/common/src/js/abstractcommandprocessor.js +161 -0
  15. data/common/src/js/asserts.js +296 -0
  16. data/common/src/js/by.js +147 -0
  17. data/common/src/js/command.js +274 -0
  18. data/common/src/js/context.js +58 -0
  19. data/common/src/js/extension/README +2 -0
  20. data/common/src/js/extension/dommessenger.js +152 -0
  21. data/common/src/js/factory.js +55 -0
  22. data/common/src/js/future.js +118 -0
  23. data/common/src/js/key.js +117 -0
  24. data/common/src/js/localcommandprocessor.js +181 -0
  25. data/common/src/js/logging.js +249 -0
  26. data/common/src/js/testrunner.js +605 -0
  27. data/common/src/js/timing.js +89 -0
  28. data/common/src/js/wait.js +199 -0
  29. data/common/src/js/webdriver.js +853 -0
  30. data/common/src/js/webelement.js +683 -0
  31. data/common/src/rb/lib/selenium-webdriver.rb +1 -0
  32. data/common/src/rb/lib/selenium/webdriver.rb +52 -0
  33. data/common/src/rb/lib/selenium/webdriver/bridge_helper.rb +88 -0
  34. data/common/src/rb/lib/selenium/webdriver/child_process.rb +85 -0
  35. data/common/src/rb/lib/selenium/webdriver/core_ext/dir.rb +41 -0
  36. data/common/src/rb/lib/selenium/webdriver/driver.rb +128 -0
  37. data/common/src/rb/lib/selenium/webdriver/element.rb +126 -0
  38. data/common/src/rb/lib/selenium/webdriver/error.rb +68 -0
  39. data/common/src/rb/lib/selenium/webdriver/find.rb +69 -0
  40. data/common/src/rb/lib/selenium/webdriver/navigation.rb +23 -0
  41. data/common/src/rb/lib/selenium/webdriver/options.rb +50 -0
  42. data/common/src/rb/lib/selenium/webdriver/platform.rb +82 -0
  43. data/common/src/rb/lib/selenium/webdriver/target_locator.rb +23 -0
  44. data/firefox/prebuilt/nsICommandProcessor.xpt +0 -0
  45. data/firefox/prebuilt/nsINativeEvents.xpt +0 -0
  46. data/firefox/prebuilt/nsIResponseHandler.xpt +0 -0
  47. data/firefox/src/extension/chrome.manifest +3 -0
  48. data/firefox/src/extension/components/context.js +37 -0
  49. data/firefox/src/extension/components/driver-component.js +127 -0
  50. data/firefox/src/extension/components/firefoxDriver.js +706 -0
  51. data/firefox/src/extension/components/json2.js +273 -0
  52. data/firefox/src/extension/components/keytest.html +554 -0
  53. data/firefox/src/extension/components/nsCommandProcessor.js +586 -0
  54. data/firefox/src/extension/components/screenshooter.js +70 -0
  55. data/firefox/src/extension/components/socketListener.js +185 -0
  56. data/firefox/src/extension/components/utils.js +1200 -0
  57. data/firefox/src/extension/components/webLoadingListener.js +57 -0
  58. data/firefox/src/extension/components/webdriverserver.js +101 -0
  59. data/firefox/src/extension/components/wrappedElement.js +609 -0
  60. data/firefox/src/extension/content/fxdriver.xul +30 -0
  61. data/firefox/src/extension/content/server.js +95 -0
  62. data/firefox/src/extension/idl/nsICommandProcessor.idl +38 -0
  63. data/firefox/src/extension/idl/nsIResponseHandler.idl +34 -0
  64. data/firefox/src/extension/install.rdf +29 -0
  65. data/firefox/src/rb/lib/selenium/webdriver/firefox.rb +21 -0
  66. data/firefox/src/rb/lib/selenium/webdriver/firefox/binary.rb +86 -0
  67. data/firefox/src/rb/lib/selenium/webdriver/firefox/bridge.rb +426 -0
  68. data/firefox/src/rb/lib/selenium/webdriver/firefox/extension_connection.rb +82 -0
  69. data/firefox/src/rb/lib/selenium/webdriver/firefox/launcher.rb +132 -0
  70. data/firefox/src/rb/lib/selenium/webdriver/firefox/profile.rb +174 -0
  71. data/firefox/src/rb/lib/selenium/webdriver/firefox/profiles_ini.rb +60 -0
  72. data/firefox/src/rb/lib/selenium/webdriver/firefox/util.rb +23 -0
  73. data/jobbie/prebuilt/Win32/Release/InternetExplorerDriver.dll +0 -0
  74. data/jobbie/prebuilt/x64/Release/InternetExplorerDriver.dll +0 -0
  75. data/jobbie/src/rb/lib/selenium/webdriver/ie.rb +14 -0
  76. data/jobbie/src/rb/lib/selenium/webdriver/ie/bridge.rb +552 -0
  77. data/jobbie/src/rb/lib/selenium/webdriver/ie/lib.rb +94 -0
  78. data/jobbie/src/rb/lib/selenium/webdriver/ie/util.rb +147 -0
  79. data/remote/client/src/rb/lib/selenium/webdriver/remote.rb +16 -0
  80. data/remote/client/src/rb/lib/selenium/webdriver/remote/bridge.rb +374 -0
  81. data/remote/client/src/rb/lib/selenium/webdriver/remote/capabilities.rb +105 -0
  82. data/remote/client/src/rb/lib/selenium/webdriver/remote/commands.rb +53 -0
  83. data/remote/client/src/rb/lib/selenium/webdriver/remote/default_http_client.rb +71 -0
  84. data/remote/client/src/rb/lib/selenium/webdriver/remote/response.rb +43 -0
  85. data/remote/client/src/rb/lib/selenium/webdriver/remote/server_error.rb +32 -0
  86. metadata +182 -0
@@ -0,0 +1,2 @@
1
+ This directory contains Javascript files that are used in both the Chrome and
2
+ Firefox extensions.
@@ -0,0 +1,152 @@
1
+ /*
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+ Portions copyright 2007 ThoughtWorks, Inc
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ /**
20
+ * @fileoverview Messenger service used to communicate with the current web
21
+ * page through custom DOM events.
22
+ *
23
+ * <p>The DomMessenger will listen for {@code webdriverCommand} events on the
24
+ * document. The event target should be a node whose {@code command} attribute
25
+ * is a JSON string with the command to execute.
26
+ *
27
+ * <p>Once the command has been executed, the response will be stored as a JSON
28
+ * string in the {@code response} attribute of the node that dispatched the
29
+ * original {@code webdriverCommand} event. The DomMessenger will then dispatch
30
+ * a {@code webdriverResponse} event on that node to notify the page that a
31
+ * response is ready.
32
+ *
33
+ * @author jmleyba@gmail.com (Jason Leyba)
34
+ */
35
+
36
+
37
+ /**
38
+ * The DomMessenger is used to communicate with the current webpage through
39
+ * custom events fired on the DOM.
40
+ *
41
+ * @param { {execute: function(string, function(string))} } commandProcessor The
42
+ * object to send commands to for execution. The object should have a single
43
+ * method, {@code execute}, that takes two arguments: the command to execute
44
+ * as a JSON string, and a callback for the command response (specified as a
45
+ * JSON string).
46
+ * @constructor
47
+ */
48
+ var DomMessenger = function(commandProcessor) {
49
+
50
+ /**
51
+ * The object to use as a command processor.
52
+ * @type { {execute: function(string, function(string))} }
53
+ * @private
54
+ */
55
+ this.commandProcessor_ = commandProcessor;
56
+
57
+ var self = this; // TODO(jmleyba): bind
58
+
59
+ /**
60
+ * EventListener for {@code COMMAND_EVENT}s.
61
+ * @type {function(Event)}
62
+ * @private
63
+ */
64
+ this.commandEventListener_ = function(e) {
65
+ self.onCommand(e);
66
+ };
67
+ };
68
+
69
+
70
+ /**
71
+ * Attributes used to pass information between the extension and the current
72
+ * web page.
73
+ * @enum {string}
74
+ */
75
+ DomMessenger.Attribute = {
76
+ COMMAND: 'command',
77
+ RESPONSE: 'response'
78
+ };
79
+
80
+
81
+ /**
82
+ * Custom event types used to signal a new message either to or from the current
83
+ * web page.
84
+ * @enum {string}
85
+ */
86
+ DomMessenger.EventType = {
87
+ COMMAND: 'webdriverCommand',
88
+ RESPONSE: 'webdriverResponse'
89
+ };
90
+
91
+
92
+ /**
93
+ * Called when a page loads to
94
+ * Called when a page loads so an element can be injected for communicating with
95
+ * the web page.
96
+ */
97
+ DomMessenger.prototype.onPageLoad = function(e) {
98
+ // Annotate the documentElement to signal to the client that webdriver is
99
+ // installed.
100
+ var doc = e.originalTarget || e.target;
101
+ doc.documentElement.setAttribute('webdriver', true);
102
+ doc.addEventListener(
103
+ DomMessenger.EventType.COMMAND, this.commandEventListener_, true);
104
+ };
105
+
106
+
107
+ /**
108
+ * Called when a page unloads; removes the command event listener.
109
+ * @param {Event} e The unload event, whose target is the document that was
110
+ * unloaded.
111
+ */
112
+ DomMessenger.prototype.onPageUnload = function(e) {
113
+ var doc = e.originalTarget || e.target;
114
+ doc.removeEventListener(
115
+ DomMessenger.EventType.COMMAND, this.commandEventListener_, true);
116
+ };
117
+
118
+
119
+ /**
120
+ * Handles {@code COMMAND_EVENT}s. The command should be stored as a JSON string
121
+ * in the {@code COMMAND_ATTRIBUTE}.
122
+ * @param {Event} e The command event.
123
+ */
124
+ DomMessenger.prototype.onCommand = function(e) {
125
+ var client = e.target;
126
+ var command = client.getAttribute(DomMessenger.Attribute.COMMAND);
127
+
128
+ if (!command) {
129
+ throw Error('No command specified');
130
+ }
131
+
132
+ var self = this; // TODO(jmleyba): bind
133
+ this.commandProcessor_.execute(command, function(response) {
134
+ self.dispatchResponse(client, response);
135
+ });
136
+ };
137
+
138
+
139
+ /**
140
+ * Dispatches a {@code RESPONSE_EVENT} to notify the appropriate page that a
141
+ * command it gave completed execution.
142
+ * @param {Node} client The DOM node that issued the command this response is
143
+ * for.
144
+ * @param {string} response Response to a command as a JSON string.
145
+ */
146
+ DomMessenger.prototype.dispatchResponse = function(client, response) {
147
+ client.setAttribute(DomMessenger.Attribute.RESPONSE, response);
148
+ var evt = client.ownerDocument.createEvent('Event');
149
+ evt.initEvent(DomMessenger.EventType.RESPONSE,
150
+ /*canBubble=*/true, /*cancellable=*/true);
151
+ client.dispatchEvent(evt);
152
+ };
@@ -0,0 +1,55 @@
1
+ /** @license
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * @fileoverview Provides factory methods for creating new instances of
20
+ * {@code webdriver.WebDriver}.
21
+ * @author jmleyba@gmail.com (Jason Leyba)
22
+ */
23
+
24
+ goog.provide('webdriver.factory');
25
+
26
+ goog.require('goog.userAgent');
27
+ goog.require('webdriver.LocalCommandProcessor');
28
+ goog.require('webdriver.WebDriver');
29
+
30
+
31
+ /**
32
+ * Creates a new {@code webdriver.WebDriver} instance that uses an
33
+ * {@code webdriver.AbstractCommandProcessor}. This driver will only be able to
34
+ * perform the most basic of commands: sleeping and calling user defined
35
+ * functions.
36
+ * @return {webdriver.WebDriver} A new WebDriver instance.
37
+ */
38
+ webdriver.factory.createAbstractDriver = function() {
39
+ return new webdriver.WebDriver(new webdriver.AbstractCommandProcessor());
40
+ };
41
+
42
+
43
+ /**
44
+ * Creates a new {@code webdriver.WebDriver} instance that uses a
45
+ * CommandProcessor directly accessible to the current JavaScript engine.
46
+ * Currently, only Firefox is supported, but IE and Google Chrome support is
47
+ * planned.
48
+ * TODO(jmleyba): Add support for Internet Explorer and Goolge Chrome.
49
+ * @return {webdriver.WebDriver} A new WebDriver instance.
50
+ * @throws If called from a JavaScript engine that does not have support for a
51
+ * local CommandProcessor.
52
+ */
53
+ webdriver.factory.createLocalWebDriver = function() {
54
+ return new webdriver.WebDriver(new webdriver.LocalCommandProcessor());
55
+ };
@@ -0,0 +1,118 @@
1
+ /** @license
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * @fileoverview Defines a class for representing the result of an asynchronous
20
+ * {@code webdriver.Command}.
21
+ * @author jmleyba@gmail.com (Jason Leyba)
22
+ */
23
+
24
+ goog.provide('webdriver.Future');
25
+
26
+ goog.require('goog.events.EventType');
27
+ goog.require('goog.events.EventTarget');
28
+
29
+
30
+ /**
31
+ * Represents the result of an asynchronous {@code webdriver.Command}. Methods
32
+ * are provided to check if the result has been set and to retrieve the result.
33
+ * <p/>
34
+ * This instance will dispatch a {@code goog.events.EventType.CHANGE} event when
35
+ * its value is set. An {@code Error} will be thrown if {@code #getValue()} is
36
+ * called before the value has been set.
37
+ * @param {webdriver.WebDriver} driver The WebDriver instance that will
38
+ * eventually set this instance's value.
39
+ * @constructor
40
+ * @extends {goog.events.EventTarget}
41
+ */
42
+ webdriver.Future = function(driver) {
43
+ goog.events.EventTarget.call(this);
44
+
45
+ /**
46
+ * The WebDriver that will eventaully set this instance's value.
47
+ * @type {webdriver.WebDriver}
48
+ * @private
49
+ */
50
+ this.driver_ = driver;
51
+
52
+ /**
53
+ * The value of this Future.
54
+ * @type {*}
55
+ * @private
56
+ */
57
+ this.value_ = webdriver.Future.NOT_SET_;
58
+ };
59
+ goog.inherits(webdriver.Future, goog.events.EventTarget);
60
+
61
+
62
+ /**
63
+ * A special place-holder value used to represent that the result for a future
64
+ * has not been computed yet.
65
+ * @type {Object}
66
+ * @private
67
+ */
68
+ webdriver.Future.NOT_SET_ = {};
69
+
70
+
71
+ /**
72
+ * @return {*} The value of this Future.
73
+ * @throws If the value has not been set yet.
74
+ */
75
+ webdriver.Future.prototype.getValue = function() {
76
+ if (this.value_ === webdriver.Future.NOT_SET_) {
77
+ throw new Error('Value has not been set yet');
78
+ }
79
+ return this.value_;
80
+ };
81
+
82
+
83
+ /**
84
+ * @return {webdriver.WebDriver} The WebDriver that set/will set this Future's
85
+ * value.
86
+ */
87
+ webdriver.Future.prototype.getDriver = function() {
88
+ return this.driver_;
89
+ };
90
+
91
+
92
+ /**
93
+ * Sets the value of this Future. Dispatches a
94
+ * {@code goog.events.EventType.CHANGE} event.
95
+ * @param {*} value The new value.
96
+ */
97
+ webdriver.Future.prototype.setValue = function(value) {
98
+ this.value_ = value;
99
+ this.dispatchEvent(goog.events.EventType.CHANGE);
100
+ };
101
+
102
+
103
+ /**
104
+ * Sets the value of this future from the value of a Response object.
105
+ * @param {webdriver.Response} response The webdriver.Response to set the value
106
+ * from.
107
+ */
108
+ webdriver.Future.prototype.setValueFromResponse = function(response) {
109
+ this.setValue(response.value);
110
+ };
111
+
112
+
113
+ /**
114
+ * @return {boolean} Whether this future has had its value set.
115
+ */
116
+ webdriver.Future.prototype.isSet = function() {
117
+ return this.value_ !== webdriver.Future.NOT_SET_;
118
+ };
@@ -0,0 +1,117 @@
1
+ /** @license
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ goog.provide('webdriver.Key');
19
+
20
+ goog.require('goog.array');
21
+
22
+
23
+ /**
24
+ * Representations of pressable keys that aren't text. These are stored in
25
+ * the Unicode PUA (Private Use Area) code points, 0xE000-0xF8FF. Refer to
26
+ * http://www.google.com.au/search?&q=unicode+pua&btnG=Search
27
+ * @enum {string}
28
+ */
29
+ webdriver.Key = {
30
+ NULL: '\uE000',
31
+ CANCEL: '\uE001', // ^break
32
+ HELP: '\uE002',
33
+ BACK_SPACE: '\uE003',
34
+ TAB: '\uE004',
35
+ CLEAR: '\uE005',
36
+ RETURN: '\uE006',
37
+ ENTER: '\uE007',
38
+ SHIFT: '\uE008',
39
+ LEFT_SHIFT: '\uE008', // alias
40
+ CONTROL: '\uE009',
41
+ LEFT_CONTROL: '\uE009', // alias
42
+ ALT: '\uE00A',
43
+ LEFT_ALT: '\uE00A', // alias
44
+ PAUSE: '\uE00B',
45
+ ESCAPE: '\uE00C',
46
+ SPACE: '\uE00D',
47
+ PAGE_UP: '\uE00E',
48
+ PAGE_DOWN: '\uE00F',
49
+ END: '\uE010',
50
+ HOME: '\uE011',
51
+ LEFT: '\uE012',
52
+ ARROW_LEFT: '\uE012', // alias
53
+ UP: '\uE013',
54
+ ARROW_UP: '\uE013', // alias
55
+ RIGHT: '\uE014',
56
+ ARROW_RIGHT: '\uE014', // alias
57
+ DOWN: '\uE015',
58
+ ARROW_DOWN: '\uE015', // alias
59
+ INSERT: '\uE016',
60
+ DELETE: '\uE017',
61
+ SEMICOLON: '\uE018',
62
+ EQUALS: '\uE019',
63
+
64
+ NUMPAD0: '\uE01A', // number pad keys
65
+ NUMPAD1: '\uE01B',
66
+ NUMPAD2: '\uE01C',
67
+ NUMPAD3: '\uE01D',
68
+ NUMPAD4: '\uE01E',
69
+ NUMPAD5: '\uE01F',
70
+ NUMPAD6: '\uE020',
71
+ NUMPAD7: '\uE021',
72
+ NUMPAD8: '\uE022',
73
+ NUMPAD9: '\uE023',
74
+ MULTIPLY: '\uE024',
75
+ ADD: '\uE025',
76
+ SEPARATOR: '\uE026',
77
+ SUBTRACT: '\uE027',
78
+ DECIMAL: '\uE028',
79
+ DIVIDE: '\uE029',
80
+
81
+ F1: '\uE031', // function keys
82
+ F2: '\uE032',
83
+ F3: '\uE033',
84
+ F4: '\uE034',
85
+ F5: '\uE035',
86
+ F6: '\uE036',
87
+ F7: '\uE037',
88
+ F8: '\uE038',
89
+ F9: '\uE039',
90
+ F10: '\uE03A',
91
+ F11: '\uE03B',
92
+ F12: '\uE03C',
93
+
94
+ COMMAND: '\uE03D', // Apple command key
95
+ META: '\uE03D' // alias for Windows key
96
+ };
97
+
98
+ /**
99
+ * Simulate pressing many keys at once in a "chord". Takes a sequence of
100
+ * Keys.XXXX or strings; appends each of the values to a string, and adds the
101
+ * chord termination key (Keys.NULL) and returns the resultant string.
102
+ *
103
+ * Note: when the low-level webdriver key handlers see Keys.NULL, active
104
+ * modifier keys (CTRL/ALT/SHIFT/etc) release via a keyup event.
105
+ *
106
+ * @param {string|webdriver.Key} var_args The key sequence to concatenate.
107
+ * @see http://code.google.com/p/webdriver/issues/detail?id=79
108
+ */
109
+ webdriver.Key.chord = function(var_args) {
110
+ var sequence = goog.array.reduce(
111
+ goog.array.slice(arguments, 0),
112
+ function(str, key) {
113
+ return str + key;
114
+ }, '');
115
+ sequence += webdriver.Key.NULL;
116
+ return sequence;
117
+ };
@@ -0,0 +1,181 @@
1
+ /** @license
2
+ Copyright 2007-2009 WebDriver committers
3
+ Copyright 2007-2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ /**
19
+ * @fileoverview Defines a command processor that uses a browser
20
+ * extension/plugin object available to the Javascript on the page.
21
+ * @author jmleyba@gmail.com (Jason Leyba)
22
+ */
23
+
24
+ goog.provide('webdriver.LocalCommandProcessor');
25
+
26
+ goog.require('goog.array');
27
+ goog.require('goog.dom');
28
+ goog.require('goog.events');
29
+ goog.require('goog.json');
30
+ goog.require('goog.object');
31
+ goog.require('webdriver.AbstractCommandProcessor');
32
+ goog.require('webdriver.CommandName');
33
+ goog.require('webdriver.Context');
34
+ goog.require('webdriver.Response');
35
+
36
+
37
+ /**
38
+ * Command processor that uses a browser extension/plugin exposed to the page
39
+ * for executing WebDriver commands.
40
+ * @param {goog.dom.DomHelper} opt_dom The DomHelper for this instance to use;
41
+ * defaults to a DomHelper for the current document.
42
+ * @constructor
43
+ * @extends {webdriver.AbstractCommandProcessor}
44
+ */
45
+ webdriver.LocalCommandProcessor = function(opt_dom) {
46
+ webdriver.AbstractCommandProcessor.call(this);
47
+ // TODO(jmleyba): IE, Chrome, et al. support
48
+
49
+ /**
50
+ * The DomHelper for this instance to use.
51
+ * @type {goog.dom.DomHelper}
52
+ * @private
53
+ */
54
+ this.dom_ = opt_dom || goog.dom.getDomHelper();
55
+
56
+ /**
57
+ * The element to use for communicating with the extension.
58
+ * @type {Element}
59
+ * @private
60
+ */
61
+ this.documentElement_ = this.dom_.getDocument().documentElement;
62
+
63
+ // Verify the extension is installed by checking for the webdriver attribute
64
+ // on the documentElement.
65
+ var webdriverAttribute = this.documentElement_.getAttribute('webdriver');
66
+ if (!webdriverAttribute) {
67
+ throw Error(
68
+ 'The current browser does not support a LocalCommandProcessor');
69
+ }
70
+ };
71
+ goog.inherits(webdriver.LocalCommandProcessor,
72
+ webdriver.AbstractCommandProcessor);
73
+
74
+
75
+ /**
76
+ * The custom event types used to communicate with the browser extension.
77
+ * @enum {string}
78
+ */
79
+ webdriver.LocalCommandProcessor.EventType_ = {
80
+ COMMAND: 'webdriverCommand',
81
+ RESPONSE: 'webdriverResponse'
82
+ };
83
+
84
+
85
+ /**
86
+ * The attributes used to store information passed to the browser extension.
87
+ * @enum {string}
88
+ */
89
+ webdriver.LocalCommandProcessor.MessageAttribute_ = {
90
+ COMMAND: 'command',
91
+ RESPONSE: 'response'
92
+ };
93
+
94
+
95
+ /**
96
+ * @override
97
+ */
98
+ webdriver.LocalCommandProcessor.prototype.dispose = function() {
99
+ goog.events.removeAll(this.documentElement_,
100
+ webdriver.LocalCommandProcessor.EventType_.RESPONSE);
101
+ webdriver.LocalCommandProcessor.superClass_.dispose.call(this);
102
+ };
103
+
104
+
105
+ /**
106
+ * Event handler for command responses.
107
+ * @param {webdriver.Command} command The initiating command.
108
+ * @param {Event} e The response event. The target should be a node with a
109
+ * {@code response} attribute.
110
+ */
111
+ webdriver.LocalCommandProcessor.onResponse_ = function(command, e) {
112
+ // It is technically possible that the response could be for a different
113
+ // command, but this should be prevented by code higher in the WebDriverJS
114
+ // stack, so we don't do any error checking here.
115
+ if (e.type != webdriver.LocalCommandProcessor.EventType_.RESPONSE) {
116
+ throw Error('Not a response event!');
117
+ }
118
+
119
+ var jsonResponse = e.target.getAttribute(
120
+ webdriver.LocalCommandProcessor.MessageAttribute_.RESPONSE);
121
+ if (!jsonResponse) {
122
+ throw Error('Empty response!');
123
+ }
124
+
125
+ var rawResponse = goog.json.parse(jsonResponse);
126
+ webdriver.logging.info(
127
+ 'receiving:\n' +
128
+ webdriver.logging.describe(rawResponse, ' '));
129
+
130
+ var response = new webdriver.Response(
131
+ rawResponse['isError'],
132
+ webdriver.Context.fromString(rawResponse['context']),
133
+ rawResponse['response']);
134
+ response.extraData['resultType'] = rawResponse['resultType'];
135
+
136
+ // Only code in this file should be dispatching command events and listening
137
+ // for response events, so this is safe. If someone else decided to attach a
138
+ // listener anyway, tough luck.
139
+ goog.events.removeAll(
140
+ e.target, webdriver.LocalCommandProcessor.EventType_.RESPONSE);
141
+ command.setResponse(response);
142
+ };
143
+
144
+
145
+ /**
146
+ * @override
147
+ */
148
+ webdriver.LocalCommandProcessor.prototype.executeDriverCommand = function(
149
+ command, sessionId, context) {
150
+ if (command.name == webdriver.CommandName.SEND_KEYS) {
151
+ command.parameters = [command.parameters.join('')];
152
+ }
153
+
154
+ var jsonCommand = {
155
+ 'commandName': command.name,
156
+ 'context': context.toString(),
157
+ 'parameters': command.parameters
158
+ };
159
+
160
+ if (command.element) {
161
+ jsonCommand['elementId'] = command.element.getId().getValue();
162
+ }
163
+
164
+ webdriver.logging.info(
165
+ 'sending:\n' +
166
+ webdriver.logging.describe(jsonCommand, ' '));
167
+
168
+ this.documentElement_.setAttribute(
169
+ webdriver.LocalCommandProcessor.MessageAttribute_.COMMAND,
170
+ goog.json.serialize(jsonCommand));
171
+
172
+ goog.events.listen(this.documentElement_,
173
+ webdriver.LocalCommandProcessor.EventType_.RESPONSE,
174
+ goog.bind(webdriver.LocalCommandProcessor.onResponse_, null, command));
175
+
176
+ var commandEvent = this.dom_.getDocument().createEvent('Event');
177
+ commandEvent.initEvent(
178
+ webdriver.LocalCommandProcessor.EventType_.COMMAND,
179
+ /*canBubble=*/true, /*cancelable=*/true);
180
+ this.documentElement_.dispatchEvent(commandEvent);
181
+ };