selenium-webdriver 2.43.5 → 2.44.0

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 (219) hide show
  1. package/CHANGES.md +20 -0
  2. package/README.md +8 -13
  3. package/builder.js +4 -3
  4. package/docs/class_webdriver_Alert.html +6 -6
  5. package/docs/class_webdriver_AlertPromise.html +6 -6
  6. package/docs/class_webdriver_UnhandledAlertError.html +4 -4
  7. package/docs/class_webdriver_WebDriver.html +39 -37
  8. package/docs/class_webdriver_WebDriver_Logs.html +3 -3
  9. package/docs/class_webdriver_WebDriver_Navigation.html +5 -5
  10. package/docs/class_webdriver_WebDriver_Options.html +9 -9
  11. package/docs/class_webdriver_WebDriver_TargetLocator.html +6 -6
  12. package/docs/class_webdriver_WebDriver_Timeouts.html +4 -4
  13. package/docs/class_webdriver_WebDriver_Window.html +6 -6
  14. package/docs/class_webdriver_WebElement.html +23 -23
  15. package/docs/class_webdriver_WebElementPromise.html +22 -22
  16. package/docs/class_webdriver_promise_CancellationError.html +3 -0
  17. package/docs/class_webdriver_promise_ControlFlow.html +32 -32
  18. package/docs/class_webdriver_promise_Deferred.html +7 -8
  19. package/docs/class_webdriver_promise_Frame_.html +14 -30
  20. package/docs/class_webdriver_promise_Promise.html +2 -2
  21. package/docs/class_webdriver_promise_Task_.html +12 -12
  22. package/docs/class_webdriver_until_Condition.html +3 -0
  23. package/docs/enum_webdriver_Key.html +1 -1
  24. package/docs/enum_webdriver_promise_ControlFlow_EventType.html +1 -1
  25. package/docs/enum_webdriver_promise_Deferred_State_.html +1 -1
  26. package/docs/index.html +8 -13
  27. package/docs/interface_webdriver_promise_Thenable.html +8 -10
  28. package/docs/license.html +1 -1
  29. package/docs/module_selenium-webdriver.html +2 -2
  30. package/docs/module_selenium-webdriver__base.html +1 -1
  31. package/docs/module_selenium-webdriver__base_class_Context.html +1 -1
  32. package/docs/module_selenium-webdriver_builder.html +1 -1
  33. package/docs/module_selenium-webdriver_builder_class_Builder.html +1 -1
  34. package/docs/module_selenium-webdriver_chrome.html +1 -1
  35. package/docs/module_selenium-webdriver_chrome_class_Driver.html +2 -2
  36. package/docs/module_selenium-webdriver_chrome_class_Options.html +2 -2
  37. package/docs/module_selenium-webdriver_chrome_class_ServiceBuilder.html +1 -1
  38. package/docs/module_selenium-webdriver_error.html +1 -1
  39. package/docs/module_selenium-webdriver_executors.html +1 -1
  40. package/docs/module_selenium-webdriver_firefox.html +1 -1
  41. package/docs/module_selenium-webdriver_firefox_binary.html +1 -1
  42. package/docs/module_selenium-webdriver_firefox_binary_class_Binary.html +1 -1
  43. package/docs/module_selenium-webdriver_firefox_class_Driver.html +2 -2
  44. package/docs/module_selenium-webdriver_firefox_class_Options.html +1 -1
  45. package/docs/module_selenium-webdriver_firefox_extension.html +1 -1
  46. package/docs/module_selenium-webdriver_firefox_profile.html +1 -1
  47. package/docs/module_selenium-webdriver_firefox_profile_class_Profile.html +1 -1
  48. package/docs/module_selenium-webdriver_http.html +1 -1
  49. package/docs/module_selenium-webdriver_http_class_HttpClient.html +1 -1
  50. package/docs/module_selenium-webdriver_http_util.html +1 -1
  51. package/docs/module_selenium-webdriver_io.html +1 -1
  52. package/docs/module_selenium-webdriver_io_exec.html +1 -1
  53. package/docs/module_selenium-webdriver_net.html +1 -1
  54. package/docs/module_selenium-webdriver_net_portprober.html +1 -1
  55. package/docs/module_selenium-webdriver_phantomjs.html +1 -1
  56. package/docs/module_selenium-webdriver_phantomjs_class_Driver.html +2 -2
  57. package/docs/module_selenium-webdriver_proxy.html +1 -1
  58. package/docs/module_selenium-webdriver_remote.html +1 -1
  59. package/docs/module_selenium-webdriver_remote_class_DriverService.html +2 -2
  60. package/docs/module_selenium-webdriver_remote_class_SeleniumServer.html +2 -2
  61. package/docs/module_selenium-webdriver_testing.html +16 -29
  62. package/docs/module_selenium-webdriver_testing_assert.html +1 -1
  63. package/docs/namespace_webdriver_promise.html +18 -20
  64. package/docs/namespace_webdriver_stacktrace.html +15 -15
  65. package/docs/namespace_webdriver_until.html +32 -0
  66. package/docs/source/_base.js.src.html +1 -1
  67. package/docs/source/builder.js.src.html +1 -1
  68. package/docs/source/chrome.js.src.html +1 -1
  69. package/docs/source/error.js.src.html +1 -1
  70. package/docs/source/executors.js.src.html +1 -1
  71. package/docs/source/firefox/binary.js.src.html +1 -1
  72. package/docs/source/firefox/extension.js.src.html +1 -1
  73. package/docs/source/firefox/index.js.src.html +1 -1
  74. package/docs/source/firefox/profile.js.src.html +1 -1
  75. package/docs/source/http/index.js.src.html +1 -1
  76. package/docs/source/http/util.js.src.html +1 -1
  77. package/docs/source/index.js.src.html +1 -1
  78. package/docs/source/io/exec.js.src.html +1 -1
  79. package/docs/source/io/index.js.src.html +1 -1
  80. package/docs/source/lib/atoms/error.js.src.html +1 -1
  81. package/docs/source/lib/atoms/json.js.src.html +1 -1
  82. package/docs/source/lib/atoms/response.js.src.html +1 -1
  83. package/docs/source/lib/atoms/userAgent.js.src.html +1 -1
  84. package/docs/source/lib/goog/array/array.js.src.html +1 -1
  85. package/docs/source/lib/goog/asserts/asserts.js.src.html +1 -1
  86. package/docs/source/lib/goog/async/nexttick.js.src.html +1 -1
  87. package/docs/source/lib/goog/async/run.js.src.html +1 -1
  88. package/docs/source/lib/goog/base.js.src.html +1 -1
  89. package/docs/source/lib/goog/debug/debug.js.src.html +1 -1
  90. package/docs/source/lib/goog/debug/entrypointregistry.js.src.html +1 -1
  91. package/docs/source/lib/goog/debug/error.js.src.html +1 -1
  92. package/docs/source/lib/goog/debug/logbuffer.js.src.html +1 -1
  93. package/docs/source/lib/goog/debug/logger.js.src.html +1 -1
  94. package/docs/source/lib/goog/debug/logrecord.js.src.html +1 -1
  95. package/docs/source/lib/goog/deps.js.src.html +1 -1
  96. package/docs/source/lib/goog/disposable/disposable.js.src.html +1 -1
  97. package/docs/source/lib/goog/disposable/idisposable.js.src.html +1 -1
  98. package/docs/source/lib/goog/dom/browserfeature.js.src.html +1 -1
  99. package/docs/source/lib/goog/dom/dom.js.src.html +1 -1
  100. package/docs/source/lib/goog/dom/nodetype.js.src.html +1 -1
  101. package/docs/source/lib/goog/dom/tagname.js.src.html +1 -1
  102. package/docs/source/lib/goog/dom/vendor.js.src.html +1 -1
  103. package/docs/source/lib/goog/events/browserevent.js.src.html +1 -1
  104. package/docs/source/lib/goog/events/browserfeature.js.src.html +1 -1
  105. package/docs/source/lib/goog/events/event.js.src.html +1 -1
  106. package/docs/source/lib/goog/events/eventid.js.src.html +1 -1
  107. package/docs/source/lib/goog/events/events.js.src.html +1 -1
  108. package/docs/source/lib/goog/events/eventtarget.js.src.html +1 -1
  109. package/docs/source/lib/goog/events/eventtype.js.src.html +1 -1
  110. package/docs/source/lib/goog/events/keycodes.js.src.html +1 -1
  111. package/docs/source/lib/goog/events/listenable.js.src.html +1 -1
  112. package/docs/source/lib/goog/events/listener.js.src.html +1 -1
  113. package/docs/source/lib/goog/events/listenermap.js.src.html +1 -1
  114. package/docs/source/lib/goog/functions/functions.js.src.html +1 -1
  115. package/docs/source/lib/goog/iter/iter.js.src.html +1 -1
  116. package/docs/source/lib/goog/json/json.js.src.html +1 -1
  117. package/docs/source/lib/goog/labs/testing/assertthat.js.src.html +1 -1
  118. package/docs/source/lib/goog/labs/testing/logicmatcher.js.src.html +1 -1
  119. package/docs/source/lib/goog/labs/testing/matcher.js.src.html +1 -1
  120. package/docs/source/lib/goog/labs/testing/numbermatcher.js.src.html +1 -1
  121. package/docs/source/lib/goog/labs/testing/objectmatcher.js.src.html +1 -1
  122. package/docs/source/lib/goog/labs/testing/stringmatcher.js.src.html +1 -1
  123. package/docs/source/lib/goog/labs/useragent/browser.js.src.html +1 -1
  124. package/docs/source/lib/goog/labs/useragent/engine.js.src.html +1 -1
  125. package/docs/source/lib/goog/labs/useragent/util.js.src.html +1 -1
  126. package/docs/source/lib/goog/math/box.js.src.html +1 -1
  127. package/docs/source/lib/goog/math/coordinate.js.src.html +1 -1
  128. package/docs/source/lib/goog/math/math.js.src.html +1 -1
  129. package/docs/source/lib/goog/math/rect.js.src.html +1 -1
  130. package/docs/source/lib/goog/math/size.js.src.html +1 -1
  131. package/docs/source/lib/goog/net/wrapperxmlhttpfactory.js.src.html +1 -1
  132. package/docs/source/lib/goog/net/xhrlike.js.src.html +1 -1
  133. package/docs/source/lib/goog/net/xmlhttp.js.src.html +1 -1
  134. package/docs/source/lib/goog/net/xmlhttpfactory.js.src.html +1 -1
  135. package/docs/source/lib/goog/object/object.js.src.html +1 -1
  136. package/docs/source/lib/goog/reflect/reflect.js.src.html +1 -1
  137. package/docs/source/lib/goog/string/string.js.src.html +1 -1
  138. package/docs/source/lib/goog/structs/collection.js.src.html +1 -1
  139. package/docs/source/lib/goog/structs/map.js.src.html +1 -1
  140. package/docs/source/lib/goog/structs/set.js.src.html +1 -1
  141. package/docs/source/lib/goog/structs/structs.js.src.html +1 -1
  142. package/docs/source/lib/goog/style/style.js.src.html +1 -1
  143. package/docs/source/lib/goog/testing/asserts.js.src.html +1 -1
  144. package/docs/source/lib/goog/testing/asynctestcase.js.src.html +1 -1
  145. package/docs/source/lib/goog/testing/events/events.js.src.html +1 -1
  146. package/docs/source/lib/goog/testing/functionmock.js.src.html +1 -1
  147. package/docs/source/lib/goog/testing/jsunit.js.src.html +1 -1
  148. package/docs/source/lib/goog/testing/loosemock.js.src.html +1 -1
  149. package/docs/source/lib/goog/testing/mock.js.src.html +1 -1
  150. package/docs/source/lib/goog/testing/mockclock.js.src.html +1 -1
  151. package/docs/source/lib/goog/testing/mockcontrol.js.src.html +1 -1
  152. package/docs/source/lib/goog/testing/mockinterface.js.src.html +1 -1
  153. package/docs/source/lib/goog/testing/mockmatchers.js.src.html +1 -1
  154. package/docs/source/lib/goog/testing/objectpropertystring.js.src.html +1 -1
  155. package/docs/source/lib/goog/testing/propertyreplacer.js.src.html +1 -1
  156. package/docs/source/lib/goog/testing/recordfunction.js.src.html +1 -1
  157. package/docs/source/lib/goog/testing/stacktrace.js.src.html +1 -1
  158. package/docs/source/lib/goog/testing/strictmock.js.src.html +1 -1
  159. package/docs/source/lib/goog/testing/testcase.js.src.html +1 -1
  160. package/docs/source/lib/goog/testing/testrunner.js.src.html +1 -1
  161. package/docs/source/lib/goog/testing/watchers.js.src.html +1 -1
  162. package/docs/source/lib/goog/uri/uri.js.src.html +1 -1
  163. package/docs/source/lib/goog/uri/utils.js.src.html +1 -1
  164. package/docs/source/lib/goog/useragent/product.js.src.html +1 -1
  165. package/docs/source/lib/goog/useragent/product_isversion.js.src.html +1 -1
  166. package/docs/source/lib/goog/useragent/useragent.js.src.html +1 -1
  167. package/docs/source/lib/webdriver/abstractbuilder.js.src.html +1 -1
  168. package/docs/source/lib/webdriver/actionsequence.js.src.html +1 -1
  169. package/docs/source/lib/webdriver/builder.js.src.html +1 -1
  170. package/docs/source/lib/webdriver/button.js.src.html +1 -1
  171. package/docs/source/lib/webdriver/capabilities.js.src.html +1 -1
  172. package/docs/source/lib/webdriver/command.js.src.html +1 -1
  173. package/docs/source/lib/webdriver/events.js.src.html +1 -1
  174. package/docs/source/lib/webdriver/firefoxdomexecutor.js.src.html +1 -1
  175. package/docs/source/lib/webdriver/http/corsclient.js.src.html +1 -1
  176. package/docs/source/lib/webdriver/http/http.js.src.html +1 -1
  177. package/docs/source/lib/webdriver/http/xhrclient.js.src.html +1 -1
  178. package/docs/source/lib/webdriver/key.js.src.html +1 -1
  179. package/docs/source/lib/webdriver/locators.js.src.html +1 -1
  180. package/docs/source/lib/webdriver/logging.js.src.html +1 -1
  181. package/docs/source/lib/webdriver/process.js.src.html +1 -1
  182. package/docs/source/lib/webdriver/promise.js.src.html +1 -1
  183. package/docs/source/lib/webdriver/session.js.src.html +1 -1
  184. package/docs/source/lib/webdriver/stacktrace.js.src.html +1 -1
  185. package/docs/source/lib/webdriver/testing/asserts.js.src.html +1 -1
  186. package/docs/source/lib/webdriver/testing/testcase.js.src.html +1 -1
  187. package/docs/source/lib/webdriver/until.js.src.html +1 -0
  188. package/docs/source/lib/webdriver/webdriver.js.src.html +1 -1
  189. package/docs/source/net/index.js.src.html +1 -1
  190. package/docs/source/net/portprober.js.src.html +1 -1
  191. package/docs/source/phantomjs.js.src.html +1 -1
  192. package/docs/source/proxy.js.src.html +1 -1
  193. package/docs/source/remote/index.js.src.html +1 -1
  194. package/docs/source/testing/assert.js.src.html +1 -1
  195. package/docs/source/testing/index.js.src.html +1 -1
  196. package/docs/types.js +1 -1
  197. package/example/google_search.js +9 -17
  198. package/example/google_search_generator.js +6 -7
  199. package/example/google_search_test.js +10 -18
  200. package/example/parallel_flows.js +4 -7
  201. package/index.js +6 -0
  202. package/lib/firefox/webdriver.xpi +0 -0
  203. package/lib/goog/deps.js +7 -5
  204. package/lib/test/index.js +0 -8
  205. package/lib/webdriver/promise.js +263 -251
  206. package/lib/webdriver/stacktrace.js +15 -1
  207. package/lib/webdriver/test/promise_flow_test.js +82 -76
  208. package/lib/webdriver/test/promise_test.js +22 -62
  209. package/lib/webdriver/test/stacktrace_test.js +18 -0
  210. package/lib/webdriver/test/until_test.js +388 -0
  211. package/lib/webdriver/test/webdriver_test.js +41 -0
  212. package/lib/webdriver/until.js +408 -0
  213. package/lib/webdriver/webdriver.js +91 -29
  214. package/package.json +2 -2
  215. package/test/element_finding_test.js +6 -6
  216. package/test/http/util_test.js +4 -5
  217. package/test/page_loading_test.js +7 -7
  218. package/test/stale_element_test.js +2 -10
  219. package/testing/index.js +9 -22
@@ -0,0 +1,408 @@
1
+ // Copyright 2014 Software Freedom Conservancy. All Rights Reserved.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ /**
16
+ * @fileoverview Defines common conditions for use with
17
+ * {@link webdriver.WebDriver#wait WebDriver wait}.
18
+ *
19
+ * <p>Sample usage:
20
+ * <code><pre>
21
+ * driver.get('http://www.google.com/ncr');
22
+ *
23
+ * var query = driver.wait(until.elementLocated(By.name('q')));
24
+ * query.sendKeys('webdriver\n');
25
+ *
26
+ * driver.wait(until.titleIs('webdriver - Google Search'));
27
+ * </pre></code>
28
+ *
29
+ * <p>To define a custom condition, simply call WebDriver.wait with a function
30
+ * that will eventually return a truthy-value (neither null, undefined, false,
31
+ * 0, or the empty string):
32
+ * <code><pre>
33
+ * driver.wait(function() {
34
+ * return driver.getTitle().then(function(title) {
35
+ * return title === 'webdriver - Google Search';
36
+ * });
37
+ * }, 1000);
38
+ * </pre></code>
39
+ */
40
+
41
+ goog.provide('webdriver.until');
42
+
43
+ goog.require('bot.ErrorCode');
44
+ goog.require('goog.array');
45
+ goog.require('goog.string');
46
+
47
+
48
+
49
+ goog.scope(function() {
50
+
51
+ var until = webdriver.until;
52
+
53
+
54
+ /**
55
+ * Defines a condition to
56
+ * @param {string} message A descriptive error message. Should complete the
57
+ * sentence "Waiting [...]"
58
+ * @param {function(!webdriver.WebDriver): OUT} fn The condition function to
59
+ * evaluate on each iteration of the wait loop.
60
+ * @constructor
61
+ * @struct
62
+ * @final
63
+ * @template OUT
64
+ */
65
+ until.Condition = function(message, fn) {
66
+ /** @private {string} */
67
+ this.description_ = 'Waiting ' + message;
68
+
69
+ /** @type {function(!webdriver.WebDriver): OUT} */
70
+ this.fn = fn;
71
+ };
72
+
73
+
74
+ /** @return {string} A description of this condition. */
75
+ until.Condition.prototype.description = function() {
76
+ return this.description_;
77
+ };
78
+
79
+
80
+ /**
81
+ * Creates a condition that will wait until the input driver is able to switch
82
+ * to the designated frame. The target frame may be specified as:
83
+ * <ol>
84
+ * <li>A numeric index into {@code window.frames} for the currently selected
85
+ * frame.
86
+ * <li>A {@link webdriver.WebElement}, which must reference a FRAME or IFRAME
87
+ * element on the current page.
88
+ * <li>A locator which may be used to first locate a FRAME or IFRAME on the
89
+ * current page before attempting to switch to it.
90
+ * </ol>
91
+ *
92
+ * <p>Upon successful resolution of this condition, the driver will be left
93
+ * focused on the new frame.
94
+ *
95
+ * @param {!(number|webdriver.WebElement|
96
+ * webdriver.Locator|webdriver.By.Hash|
97
+ * function(!webdriver.WebDriver): !webdriver.WebElement)} frame
98
+ * The frame identifier.
99
+ * @return {!until.Condition.<boolean>} A new condition.
100
+ */
101
+ until.ableToSwitchToFrame = function(frame) {
102
+ var condition;
103
+ if (goog.isNumber(frame) || frame instanceof webdriver.WebElement) {
104
+ condition = attemptToSwitchFrames;
105
+ } else {
106
+ condition = function(driver) {
107
+ var locator =
108
+ /** @type {!(webdriver.Locator|webdriver.By.Hash|Function)} */(frame);
109
+ return driver.findElements(locator).then(function(els) {
110
+ if (els.length) {
111
+ return attemptToSwitchFrames(driver, els[0]);
112
+ }
113
+ });
114
+ };
115
+ }
116
+
117
+ return new until.Condition('to be able to switch to frame', condition);
118
+
119
+ function attemptToSwitchFrames(driver, frame) {
120
+ return driver.switchTo().frame(frame).then(
121
+ function() { return true; },
122
+ function(e) {
123
+ if (e && e.code !== bot.ErrorCode.NO_SUCH_FRAME) {
124
+ throw e;
125
+ }
126
+ });
127
+ }
128
+ };
129
+
130
+
131
+ /**
132
+ * Creates a condition that waits for an alert to be opened. Upon success, the
133
+ * returned promise will be fulfilled with the handle for the opened alert.
134
+ *
135
+ * @return {!until.Condition.<!webdriver.Alert>} The new condition.
136
+ */
137
+ until.alertIsPresent = function() {
138
+ return new until.Condition('for alert to be present', function(driver) {
139
+ return driver.switchTo().alert().thenCatch(function(e) {
140
+ if (e && e.code !== bot.ErrorCode.NO_SUCH_ALERT) {
141
+ throw e;
142
+ }
143
+ });
144
+ });
145
+ };
146
+
147
+
148
+ /**
149
+ * Creates a condition that will wait for the current page's title to match the
150
+ * given value.
151
+ *
152
+ * @param {string} title The expected page title.
153
+ * @return {!until.Condition.<boolean>} The new condition.
154
+ */
155
+ until.titleIs = function(title) {
156
+ return new until.Condition(
157
+ 'for title to be ' + goog.string.quote(title),
158
+ function(driver) {
159
+ return driver.getTitle().then(function(t) {
160
+ return t === title;
161
+ });
162
+ });
163
+ };
164
+
165
+
166
+ /**
167
+ * Creates a condition that will wait for the current page's title to contain
168
+ * the given substring.
169
+ *
170
+ * @param {string} substr The substring that should be present in the page
171
+ * title.
172
+ * @return {!until.Condition.<boolean>} The new condition.
173
+ */
174
+ until.titleContains = function(substr) {
175
+ return new until.Condition(
176
+ 'for title to contain ' + goog.string.quote(substr),
177
+ function(driver) {
178
+ return driver.getTitle().then(function(title) {
179
+ return title.indexOf(substr) !== -1;
180
+ });
181
+ });
182
+ };
183
+
184
+
185
+ /**
186
+ * Creates a condition that will wait for the current page's title to match the
187
+ * given regular expression.
188
+ *
189
+ * @param {!RegExp} regex The regular expression to test against.
190
+ * @return {!until.Condition.<boolean>} The new condition.
191
+ */
192
+ until.titleMatches = function(regex) {
193
+ return new until.Condition('for title to match ' + regex, function(driver) {
194
+ return driver.getTitle().then(function(title) {
195
+ return regex.test(title);
196
+ });
197
+ });
198
+ };
199
+
200
+
201
+ /**
202
+ * Creates a condition that will loop until an element is
203
+ * {@link webdriver.WebDriver#findElement found} with the given locator.
204
+ *
205
+ * @param {!(webdriver.Locator|webdriver.By.Hash|Function)} locator The locator
206
+ * to use.
207
+ * @return {!until.Condition.<!webdriver.WebElement>} The new condition.
208
+ */
209
+ until.elementLocated = function(locator) {
210
+ var locatorStr = goog.isFunction(locator) ? 'function()' : locator + '';
211
+ return new until.Condition('element to be located by ' + locatorStr,
212
+ function(driver) {
213
+ return driver.findElements(locator).then(function(elements) {
214
+ return elements[0];
215
+ });
216
+ });
217
+ };
218
+
219
+
220
+ /**
221
+ * Creates a condition that will loop until at least one element is
222
+ * {@link webdriver.WebDriver#findElement found} with the given locator.
223
+ *
224
+ * @param {!(webdriver.Locator|webdriver.By.Hash|Function)} locator The locator
225
+ * to use.
226
+ * @return {!until.Condition.<!Array.<!webdriver.WebElement>>} The new
227
+ * condition.
228
+ */
229
+ until.elementsLocated = function(locator) {
230
+ var locatorStr = goog.isFunction(locator) ? 'function()' : locator + '';
231
+ return new until.Condition(
232
+ 'at least one element to be located by ' + locatorStr,
233
+ function(driver) {
234
+ return driver.findElements(locator).then(function(elements) {
235
+ return elements.length > 0 ? elements : null;
236
+ });
237
+ });
238
+ };
239
+
240
+
241
+ /**
242
+ * Creates a condition that will wait for the given element to become stale. An
243
+ * element is considered stale once it is removed from the DOM, or a new page
244
+ * has loaded.
245
+ *
246
+ * @param {!webdriver.WebElement} element The element that should become stale.
247
+ * @return {!until.Condition.<boolean>} The new condition.
248
+ */
249
+ until.stalenessOf = function(element) {
250
+ return new until.Condition('element to become stale', function() {
251
+ return element.getTagName().then(
252
+ function() { return false; },
253
+ function(e) {
254
+ if (e.code === bot.ErrorCode.STALE_ELEMENT_REFERENCE) {
255
+ return true;
256
+ }
257
+ throw e;
258
+ });
259
+ });
260
+ };
261
+
262
+
263
+ /**
264
+ * Creates a condition that will wait for the given element to become visible.
265
+ *
266
+ * @param {!webdriver.WebElement} element The element to test.
267
+ * @return {!until.Condition.<boolean>} The new condition.
268
+ * @see webdriver.WebDriver#isDisplayed
269
+ */
270
+ until.elementIsVisible = function(element) {
271
+ return new until.Condition('until element is visible', function() {
272
+ return element.isDisplayed();
273
+ });
274
+ };
275
+
276
+
277
+ /**
278
+ * Creates a condition that will wait for the given element to be in the DOM,
279
+ * yet not visible to the user.
280
+ *
281
+ * @param {!webdriver.WebElement} element The element to test.
282
+ * @return {!until.Condition.<boolean>} The new condition.
283
+ * @see webdriver.WebDriver#isDisplayed
284
+ */
285
+ until.elementIsNotVisible = function(element) {
286
+ return new until.Condition('until element is not visible', function() {
287
+ return element.isDisplayed().then(function(v) {
288
+ return !v;
289
+ });
290
+ });
291
+ };
292
+
293
+
294
+ /**
295
+ * Creates a condition that will wait for the given element to be enabled.
296
+ *
297
+ * @param {!webdriver.WebElement} element The element to test.
298
+ * @return {!until.Condition.<boolean>} The new condition.
299
+ * @see webdriver.WebDriver#isEnabled
300
+ */
301
+ until.elementIsEnabled = function(element) {
302
+ return new until.Condition('until element is enabled', function() {
303
+ return element.isEnabled();
304
+ });
305
+ };
306
+
307
+
308
+ /**
309
+ * Creates a condition that will wait for the given element to be disabled.
310
+ *
311
+ * @param {!webdriver.WebElement} element The element to test.
312
+ * @return {!until.Condition.<boolean>} The new condition.
313
+ * @see webdriver.WebDriver#isEnabled
314
+ */
315
+ until.elementIsDisabled = function(element) {
316
+ return new until.Condition('until element is disabled', function() {
317
+ return element.isEnabled().then(function(v) {
318
+ return !v;
319
+ });
320
+ });
321
+ };
322
+
323
+
324
+ /**
325
+ * Creates a condition that will wait for the given element to be selected.
326
+ * @param {!webdriver.WebElement} element The element to test.
327
+ * @return {!until.Condition.<boolean>} The new condition.
328
+ * @see webdriver.WebDriver#isSelected
329
+ */
330
+ until.elementIsSelected = function(element) {
331
+ return new until.Condition('until element is selected', function() {
332
+ return element.isSelected();
333
+ });
334
+ };
335
+
336
+
337
+ /**
338
+ * Creates a condition that will wait for the given element to be deselected.
339
+ *
340
+ * @param {!webdriver.WebElement} element The element to test.
341
+ * @return {!until.Condition.<boolean>} The new condition.
342
+ * @see webdriver.WebDriver#isSelected
343
+ */
344
+ until.elementIsNotSelected = function(element) {
345
+ return new until.Condition('until element is not selected', function() {
346
+ return element.isSelected().then(function(v) {
347
+ return !v;
348
+ });
349
+ });
350
+ };
351
+
352
+
353
+ /**
354
+ * Creates a condition that will wait for the given element's
355
+ * {@link webdriver.WebDriver#getText visible text} to match the given
356
+ * {@code text} exactly.
357
+ *
358
+ * @param {!webdriver.WebElement} element The element to test.
359
+ * @param {string} text The expected text.
360
+ * @return {!until.Condition.<boolean>} The new condition.
361
+ * @see webdriver.WebDriver#getText
362
+ */
363
+ until.elementTextIs = function(element, text) {
364
+ return new until.Condition('until element text is', function() {
365
+ return element.getText().then(function(t) {
366
+ return t === text;
367
+ });
368
+ });
369
+ };
370
+
371
+
372
+ /**
373
+ * Creates a condition that will wait for the given element's
374
+ * {@link webdriver.WebDriver#getText visible text} to contain the given
375
+ * substring.
376
+ *
377
+ * @param {!webdriver.WebElement} element The element to test.
378
+ * @param {string} substr The substring to search for.
379
+ * @return {!until.Condition.<boolean>} The new condition.
380
+ * @see webdriver.WebDriver#getText
381
+ */
382
+ until.elementTextContains = function(element, substr) {
383
+ return new until.Condition('until element text contains', function() {
384
+ return element.getText().then(function(t) {
385
+ return t.indexOf(substr) != -1;
386
+ });
387
+ });
388
+ };
389
+
390
+
391
+ /**
392
+ * Creates a condition that will wait for the given element's
393
+ * {@link webdriver.WebDriver#getText visible text} to match a regular
394
+ * expression.
395
+ *
396
+ * @param {!webdriver.WebElement} element The element to test.
397
+ * @param {!RegExp} regex The regular expression to test against.
398
+ * @return {!until.Condition.<boolean>} The new condition.
399
+ * @see webdriver.WebDriver#getText
400
+ */
401
+ until.elementTextMatches = function(element, regex) {
402
+ return new until.Condition('until element text matches', function() {
403
+ return element.getText().then(function(t) {
404
+ return regex.test(t);
405
+ });
406
+ });
407
+ };
408
+ }); // goog.scope
@@ -36,6 +36,7 @@ goog.require('webdriver.Locator');
36
36
  goog.require('webdriver.Session');
37
37
  goog.require('webdriver.logging');
38
38
  goog.require('webdriver.promise');
39
+ goog.require('webdriver.until');
39
40
 
40
41
 
41
42
  //////////////////////////////////////////////////////////////////////////////
@@ -179,32 +180,74 @@ webdriver.WebDriver.toWireValue_ = function(obj) {
179
180
  if (webdriver.promise.isPromise(obj)) {
180
181
  return obj.then(webdriver.WebDriver.toWireValue_);
181
182
  }
182
- switch (goog.typeOf(obj)) {
183
- case 'array':
184
- return webdriver.promise.all(
185
- goog.array.map(/** @type {!Array} */ (obj),
186
- webdriver.WebDriver.toWireValue_));
187
- case 'object':
188
- if (obj instanceof webdriver.WebElement) {
189
- return obj.getId();
183
+ return webdriver.promise.fulfilled(convertValue(obj));
184
+
185
+ function convertValue(value) {
186
+ switch (goog.typeOf(value)) {
187
+ case 'array':
188
+ return convertKeys(value, true);
189
+ case 'object':
190
+ if (value instanceof webdriver.WebElement) {
191
+ return value.getId();
192
+ }
193
+ if (goog.isFunction(value.toJSON)) {
194
+ return value.toJSON();
195
+ }
196
+ if (goog.isNumber(value.nodeType) && goog.isString(value.nodeName)) {
197
+ throw new TypeError(
198
+ 'Invalid argument type: ' + value.nodeName +
199
+ '(' + value.nodeType + ')');
200
+ }
201
+ return convertKeys(value, false);
202
+ case 'function':
203
+ return '' + value;
204
+ case 'undefined':
205
+ return null;
206
+ default:
207
+ return value;
208
+ }
209
+ }
210
+
211
+ function convertKeys(obj, isArray) {
212
+ var numKeys = isArray ? obj.length : goog.object.getCount(obj);
213
+ var ret = isArray ? new Array(numKeys) : {};
214
+ if (!numKeys) {
215
+ return webdriver.promise.fulfilled(ret);
216
+ }
217
+
218
+ var numResolved = 0;
219
+ var done = webdriver.promise.defer();
220
+
221
+ // forEach will stop iteration at undefined, where we want to convert
222
+ // these to null and keep iterating.
223
+ var forEachKey = !isArray ? goog.object.forEach : function(arr, fn) {
224
+ var n = arr.length;
225
+ for (var i = 0; i < n; i++) {
226
+ fn(arr[i], i);
190
227
  }
191
- if (goog.isFunction(obj.toJSON)) {
192
- return webdriver.promise.fulfilled(obj.toJSON());
228
+ };
229
+
230
+ forEachKey(obj, function(value, key) {
231
+ if (webdriver.promise.isPromise(value)) {
232
+ value.then(webdriver.WebDriver.toWireValue_).
233
+ then(setValue, done.reject);
234
+ } else {
235
+ webdriver.promise.asap(convertValue(value), setValue, done.reject);
193
236
  }
194
- if (goog.isNumber(obj.nodeType) && goog.isString(obj.nodeName)) {
195
- throw Error([
196
- 'Invalid argument type: ', obj.nodeName, '(', obj.nodeType, ')'
197
- ].join(''));
237
+
238
+ function setValue(value) {
239
+ ret[key] = value;
240
+ maybeFulfill();
198
241
  }
199
- return webdriver.promise.fullyResolved(
200
- goog.object.map(/** @type {!Object} */ (obj),
201
- webdriver.WebDriver.toWireValue_));
202
- case 'function':
203
- return webdriver.promise.fulfilled('' + obj);
204
- case 'undefined':
205
- return webdriver.promise.fulfilled(null);
206
- default:
207
- return webdriver.promise.fulfilled(obj);
242
+ });
243
+
244
+ return done.promise;
245
+
246
+ function maybeFulfill() {
247
+ if (++numResolved === numKeys) {
248
+ done.fulfill(ret);
249
+ }
250
+ }
208
251
  }
209
252
  };
210
253
 
@@ -443,10 +486,11 @@ webdriver.WebDriver.prototype.executeScript = function(script, var_args) {
443
486
  if (goog.isFunction(script)) {
444
487
  script = 'return (' + script + ').apply(null, arguments);';
445
488
  }
489
+ var args = arguments.length > 1 ? goog.array.slice(arguments, 1) : [];
446
490
  return this.schedule(
447
491
  new webdriver.Command(webdriver.CommandName.EXECUTE_SCRIPT).
448
492
  setParameter('script', script).
449
- setParameter('args', goog.array.slice(arguments, 1)),
493
+ setParameter('args', args),
450
494
  'WebDriver.executeScript()');
451
495
  };
452
496
 
@@ -578,15 +622,33 @@ webdriver.WebDriver.prototype.call = function(fn, opt_scope, var_args) {
578
622
  * evaluating whether the condition has been satisfied. The resolution time for
579
623
  * a promise is factored into whether a wait has timed out.
580
624
  *
581
- * @param {function():boolean} fn The function to evaluate as a wait condition.
625
+ * @param {!(webdriver.until.Condition.<T>|
626
+ * function(!webdriver.WebDriver): T)} condition Either a condition
627
+ * object, or a function to evaluate as a condition.
582
628
  * @param {number} timeout How long to wait for the condition to be true.
583
629
  * @param {string=} opt_message An optional message to use if the wait times
584
630
  * out.
585
- * @return {!webdriver.promise.Promise} A promise that will be resolved when the
586
- * wait condition has been satisfied.
631
+ * @return {!webdriver.promise.Promise.<T>} A promise that will be fulfilled
632
+ * with the first truthy value returned by the condition function, or
633
+ * rejected if the condition times out.
634
+ * @template T
587
635
  */
588
- webdriver.WebDriver.prototype.wait = function(fn, timeout, opt_message) {
589
- return this.flow_.wait(fn, timeout, opt_message);
636
+ webdriver.WebDriver.prototype.wait = function(
637
+ condition, timeout, opt_message) {
638
+ var message = opt_message;
639
+ var fn = /** @type {!Function} */(condition);
640
+ if (condition instanceof webdriver.until.Condition) {
641
+ message = message || condition.description();
642
+ fn = condition.fn;
643
+ }
644
+
645
+ var driver = this;
646
+ return this.flow_.wait(function() {
647
+ if (webdriver.promise.isGenerator(fn)) {
648
+ return webdriver.promise.consume(fn, null, [driver]);
649
+ }
650
+ return fn(driver);
651
+ }, timeout, message);
590
652
  };
591
653
 
592
654
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selenium-webdriver",
3
- "version": "2.43.5",
3
+ "version": "2.44.0",
4
4
  "description": "The official WebDriver JavaScript bindings from the Selenium project",
5
5
  "keywords": [
6
6
  "automation",
@@ -30,6 +30,6 @@
30
30
  "mocha" : "~1.10.0"
31
31
  },
32
32
  "scripts": {
33
- "test": "node_modules/.bin/mocha -t 600000 --recursive test"
33
+ "test": "node_modules/.bin/mocha --harmony -t 600000 --recursive test"
34
34
  }
35
35
  }
@@ -19,6 +19,7 @@ var fail = require('assert').fail;
19
19
 
20
20
  var By = require('..').By,
21
21
  error = require('..').error,
22
+ until = require('..').until,
22
23
  test = require('../lib/test'),
23
24
  assert = require('../testing/assert'),
24
25
  Browser = test.Browser,
@@ -26,8 +27,7 @@ var By = require('..').By,
26
27
 
27
28
 
28
29
  test.suite(function(env) {
29
- var browsers = env.browsers,
30
- waitForTitleToBe = env.waitForTitleToBe;
30
+ var browsers = env.browsers;
31
31
 
32
32
  var driver;
33
33
  beforeEach(function() { driver = env.driver; });
@@ -40,14 +40,14 @@ test.suite(function(env) {
40
40
  driver.get(Pages.formPage);
41
41
  driver.get(Pages.xhtmlTestPage);
42
42
  driver.findElement(By.linkText('click me')).click();
43
- waitForTitleToBe('We Arrive Here');
43
+ driver.wait(until.titleIs('We Arrive Here'), 5000);
44
44
  });
45
45
 
46
46
  describe('By.id()', function() {
47
47
  test.it('should work', function() {
48
48
  driver.get(Pages.xhtmlTestPage);
49
49
  driver.findElement(By.id('linkId')).click();
50
- waitForTitleToBe('We Arrive Here');
50
+ driver.wait(until.titleIs('We Arrive Here'), 5000);
51
51
  });
52
52
 
53
53
  test.it('should fail if ID not present on page', function() {
@@ -73,14 +73,14 @@ test.suite(function(env) {
73
73
  test.it('should be able to click on link identified by text', function() {
74
74
  driver.get(Pages.xhtmlTestPage);
75
75
  driver.findElement(By.linkText('click me')).click();
76
- waitForTitleToBe('We Arrive Here');
76
+ driver.wait(until.titleIs('We Arrive Here'), 5000);
77
77
  });
78
78
 
79
79
  test.it(
80
80
  'should be able to find elements by partial link text', function() {
81
81
  driver.get(Pages.xhtmlTestPage);
82
82
  driver.findElement(By.partialLinkText('ick me')).click();
83
- waitForTitleToBe('We Arrive Here');
83
+ driver.wait(until.titleIs('We Arrive Here'), 5000);
84
84
  });
85
85
 
86
86
  test.it('should work when link text contains equals sign', function() {
@@ -125,12 +125,12 @@ describe('selenium-webdriver/http/util', function() {
125
125
  var isReady = util.waitForServer(baseUrl, 200).
126
126
  then(function() { done('Did not expect to succeed'); }).
127
127
  then(null, function(e) {
128
- assert.equal(err, e);
128
+ assert.equal('cancelled!', e.message);
129
129
  }).
130
130
  then(function() { done(); }, done);
131
131
 
132
132
  setTimeout(function() {
133
- isReady.cancel(err);
133
+ isReady.cancel('cancelled!');
134
134
  }, 50);
135
135
  });
136
136
  });
@@ -165,16 +165,15 @@ describe('selenium-webdriver/http/util', function() {
165
165
 
166
166
  it('can cancel wait', function(done) {
167
167
  responseCode = 404;
168
- var err = Error('cancelled!');
169
168
  var isReady = util.waitForUrl(baseUrl, 200).
170
169
  then(function() { done('Did not expect to succeed'); }).
171
170
  then(null, function(e) {
172
- assert.equal(err, e);
171
+ assert.equal('cancelled!', e.message);
173
172
  }).
174
173
  then(function() { done(); }, done);
175
174
 
176
175
  setTimeout(function() {
177
- isReady.cancel(err);
176
+ isReady.cancel('cancelled!');
178
177
  }, 50);
179
178
  });
180
179
  });