selenium-webdriver 0.0.1

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