Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/java/test/org/openqa/selenium/ExecutingAsyncJavascriptTest.java
3992 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. 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,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
package org.openqa.selenium;
19
20
import static com.google.common.base.Throwables.getRootCause;
21
import static org.assertj.core.api.Assertions.assertThat;
22
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
23
import static org.assertj.core.api.InstanceOfAssertFactories.LIST;
24
import static org.assertj.core.api.InstanceOfAssertFactories.type;
25
import static org.junit.jupiter.api.Assumptions.assumeTrue;
26
import static org.openqa.selenium.testing.drivers.Browser.CHROME;
27
import static org.openqa.selenium.testing.drivers.Browser.EDGE;
28
import static org.openqa.selenium.testing.drivers.Browser.FIREFOX;
29
import static org.openqa.selenium.testing.drivers.Browser.IE;
30
import static org.openqa.selenium.testing.drivers.Browser.SAFARI;
31
32
import java.time.Duration;
33
import java.util.List;
34
import org.junit.jupiter.api.BeforeEach;
35
import org.junit.jupiter.api.Test;
36
import org.openqa.selenium.testing.Ignore;
37
import org.openqa.selenium.testing.JupiterTestBase;
38
import org.openqa.selenium.testing.NotYetImplemented;
39
40
class ExecutingAsyncJavascriptTest extends JupiterTestBase {
41
42
private JavascriptExecutor executor;
43
44
@BeforeEach
45
public void setUp() {
46
assumeTrue(driver instanceof JavascriptExecutor);
47
executor = (JavascriptExecutor) driver;
48
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(5000));
49
}
50
51
@Test
52
@NotYetImplemented(value = CHROME, reason = "Default to 5s")
53
@NotYetImplemented(value = EDGE, reason = "Default to 5s")
54
@NotYetImplemented(value = FIREFOX, reason = "Default to 5s")
55
@NotYetImplemented(value = SAFARI, reason = "Default to 5s")
56
public void shouldSetAndGetScriptTimeout() {
57
assertThat(driver.manage().timeouts().getScriptTimeout()).hasSeconds(30);
58
59
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(3000));
60
61
assertThat(driver.manage().timeouts().getScriptTimeout()).hasSeconds(3);
62
}
63
64
@Test
65
void shouldNotTimeoutIfCallbackInvokedImmediately() {
66
driver.get(pages.ajaxyPage);
67
Object result = executor.executeAsyncScript("arguments[arguments.length - 1]('123');");
68
assertThat(result).isEqualTo("123");
69
}
70
71
@Test
72
void shouldBeAbleToReturnJavascriptPrimitivesFromAsyncScripts_NeitherNullNorUndefined() {
73
driver.get(pages.ajaxyPage);
74
assertThat(executor.executeAsyncScript("arguments[arguments.length - 1](123456789012345);"))
75
.isEqualTo(123456789012345L);
76
assertThat(executor.executeAsyncScript("arguments[arguments.length - 1]('abc');"))
77
.isEqualTo("abc");
78
assertThat((Boolean) executor.executeAsyncScript("arguments[arguments.length - 1](false);"))
79
.isFalse();
80
assertThat((Boolean) executor.executeAsyncScript("arguments[arguments.length - 1](true);"))
81
.isTrue();
82
}
83
84
@Test
85
void shouldBeAbleToReturnJavascriptPrimitivesFromAsyncScripts_NullAndUndefined() {
86
driver.get(pages.ajaxyPage);
87
assertThat(executor.executeAsyncScript("arguments[arguments.length - 1](null)")).isNull();
88
assertThat(executor.executeAsyncScript("arguments[arguments.length - 1]()")).isNull();
89
}
90
91
@Test
92
void shouldBeAbleToReturnAnArrayLiteralFromAnAsyncScript() {
93
driver.get(pages.ajaxyPage);
94
95
Object result = executor.executeAsyncScript("arguments[arguments.length - 1]([]);");
96
assertThat(result).asInstanceOf(LIST).isEmpty();
97
}
98
99
@Test
100
void shouldBeAbleToReturnAnArrayObjectFromAnAsyncScript() {
101
driver.get(pages.ajaxyPage);
102
103
Object result = executor.executeAsyncScript("arguments[arguments.length - 1](new Array());");
104
assertThat(result).asInstanceOf(LIST).isEmpty();
105
}
106
107
@Test
108
void shouldBeAbleToReturnArraysOfPrimitivesFromAsyncScripts() {
109
driver.get(pages.ajaxyPage);
110
111
Object result =
112
executor.executeAsyncScript(
113
"arguments[arguments.length - 1]([null, 123456789012345, 'abc', true, false]);");
114
115
assertThat(result)
116
.asInstanceOf(LIST)
117
.containsExactly(null, 123456789012345L, "abc", true, false);
118
}
119
120
@Test
121
void shouldBeAbleToReturnWebElementsFromAsyncScripts() {
122
driver.get(pages.ajaxyPage);
123
124
Object result = executor.executeAsyncScript("arguments[arguments.length - 1](document.body);");
125
assertThat(result)
126
.asInstanceOf(type(WebElement.class))
127
.satisfies(webElement -> assertThat(webElement.getTagName()).isEqualToIgnoringCase("body"));
128
}
129
130
@Test
131
@Ignore(value = CHROME, reason = "https://bugs.chromium.org/p/chromedriver/issues/detail?id=4525")
132
void shouldBeAbleToReturnArraysOfWebElementsFromAsyncScripts() {
133
driver.get(pages.ajaxyPage);
134
135
Object result =
136
executor.executeAsyncScript(
137
"arguments[arguments.length - 1]([document.body, document.body]);");
138
assertThat(result).isNotNull().isInstanceOf(List.class);
139
assertThat(result)
140
.asInstanceOf(LIST)
141
.hasSize(2)
142
.satisfies(
143
list -> {
144
assertThat(list.get(0))
145
.asInstanceOf(type(WebElement.class))
146
.satisfies(
147
element -> assertThat(element.getTagName()).isEqualToIgnoringCase("body"));
148
assertThat(list.get(1))
149
.asInstanceOf(type(WebElement.class))
150
.satisfies(
151
element -> assertThat(element.getTagName()).isEqualToIgnoringCase("body"));
152
assertThat(list.get(1)).isEqualTo(list.get(0));
153
});
154
}
155
156
@Test
157
@NotYetImplemented(SAFARI)
158
public void shouldTimeoutIfScriptDoesNotInvokeCallback() {
159
driver.get(pages.ajaxyPage);
160
// Script is expected to be async and explicitly callback, so this should timeout.
161
assertThatExceptionOfType(ScriptTimeoutException.class)
162
.isThrownBy(() -> executor.executeAsyncScript("return 1 + 2;"));
163
}
164
165
@Test
166
@NotYetImplemented(SAFARI)
167
public void shouldTimeoutIfScriptDoesNotInvokeCallbackWithAZeroTimeout() {
168
driver.get(pages.ajaxyPage);
169
assertThatExceptionOfType(ScriptTimeoutException.class)
170
.isThrownBy(() -> executor.executeAsyncScript("window.setTimeout(function() {}, 0);"));
171
}
172
173
@Test
174
@Ignore(FIREFOX)
175
public void shouldNotTimeoutIfScriptCallsbackInsideAZeroTimeout() {
176
driver.get(pages.ajaxyPage);
177
executor.executeAsyncScript(
178
"var callback = arguments[arguments.length - 1];"
179
+ "window.setTimeout(function() { callback(123); }, 0)");
180
}
181
182
@Test
183
@NotYetImplemented(SAFARI)
184
public void shouldTimeoutIfScriptDoesNotInvokeCallbackWithLongTimeout() {
185
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(500));
186
driver.get(pages.ajaxyPage);
187
assertThatExceptionOfType(ScriptTimeoutException.class)
188
.isThrownBy(
189
() ->
190
executor.executeAsyncScript(
191
"var callback = arguments[arguments.length - 1];"
192
+ "window.setTimeout(callback, 1500);"));
193
}
194
195
@Test
196
@Ignore(IE)
197
public void shouldDetectPageLoadsWhileWaitingOnAnAsyncScriptAndReturnAnError() {
198
driver.get(pages.ajaxyPage);
199
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(100));
200
assertThatExceptionOfType(WebDriverException.class)
201
.isThrownBy(
202
() -> executor.executeAsyncScript("window.location = '" + pages.dynamicPage + "';"));
203
}
204
205
@Test
206
void shouldCatchErrorsWhenExecutingInitialScript() {
207
driver.get(pages.ajaxyPage);
208
assertThatExceptionOfType(WebDriverException.class)
209
.isThrownBy(() -> executor.executeAsyncScript("throw Error('you should catch this!');"));
210
}
211
212
@Test
213
void shouldNotTimeoutWithMultipleCallsTheFirstOneBeingSynchronous() {
214
driver.get(pages.ajaxyPage);
215
assertThat((Boolean) executor.executeAsyncScript("arguments[arguments.length - 1](true);"))
216
.isTrue();
217
assertThat(
218
(Boolean)
219
executor.executeAsyncScript(
220
"var cb = arguments[arguments.length - 1];"
221
+ " window.setTimeout(function(){cb(true);}, 9);"))
222
.isTrue();
223
}
224
225
@Test
226
@Ignore(CHROME)
227
@Ignore(EDGE)
228
@Ignore(IE)
229
@NotYetImplemented(SAFARI)
230
@Ignore(FIREFOX)
231
public void shouldCatchErrorsWithMessageAndStacktraceWhenExecutingInitialScript() {
232
driver.get(pages.ajaxyPage);
233
String js =
234
"function functionB() { throw Error('errormessage'); };"
235
+ "function functionA() { functionB(); };"
236
+ "functionA();";
237
assertThatExceptionOfType(WebDriverException.class)
238
.isThrownBy(() -> executor.executeAsyncScript(js))
239
.withMessageContaining("errormessage")
240
.satisfies(
241
t -> {
242
Throwable rootCause = getRootCause(t);
243
assertThat(rootCause).hasMessageContaining("errormessage");
244
assertThat(List.of(rootCause.getStackTrace()))
245
.extracting(StackTraceElement::getMethodName)
246
.contains("functionB");
247
});
248
}
249
250
@Test
251
void shouldBeAbleToExecuteAsynchronousScripts() {
252
driver.get(pages.ajaxyPage);
253
254
WebElement typer = driver.findElement(By.name("typer"));
255
typer.sendKeys("bob");
256
assertThat(typer.getAttribute("value")).isEqualTo("bob");
257
258
driver.findElement(By.id("red")).click();
259
driver.findElement(By.name("submit")).click();
260
261
assertThat(getNumDivElements())
262
.describedAs(
263
"There should only be 1 DIV at this point, which is used for the butter message")
264
.isEqualTo(1);
265
266
driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(15));
267
String text =
268
(String)
269
executor.executeAsyncScript(
270
"var callback = arguments[arguments.length - 1];"
271
+ "window.registerListener(arguments[arguments.length - 1]);");
272
assertThat(text).isEqualTo("bob");
273
assertThat(typer.getAttribute("value")).isEmpty();
274
275
assertThat(getNumDivElements())
276
.describedAs("There should be 1 DIV (for the butter message) + 1 DIV (for the new label)")
277
.isEqualTo(2);
278
}
279
280
@Test
281
void shouldBeAbleToPassMultipleArgumentsToAsyncScripts() {
282
driver.get(pages.ajaxyPage);
283
Number result =
284
(Number)
285
executor.executeAsyncScript(
286
"arguments[arguments.length - 1](arguments[0] + arguments[1]);", 1, 2);
287
assertThat(result.intValue()).isEqualTo(3);
288
}
289
290
@Test
291
void shouldBeAbleToMakeXMLHttpRequestsAndWaitForTheResponse() {
292
String script =
293
"var url = arguments[0];"
294
+ "var callback = arguments[arguments.length - 1];"
295
+
296
// Adapted from http://www.quirksmode.org/js/xmlhttp.html
297
"var XMLHttpFactories = ["
298
+ " function () {return new XMLHttpRequest()},"
299
+ " function () {return new ActiveXObject('Msxml2.XMLHTTP')},"
300
+ " function () {return new ActiveXObject('Msxml3.XMLHTTP')},"
301
+ " function () {return new ActiveXObject('Microsoft.XMLHTTP')}"
302
+ "];"
303
+ "var xhr = false;"
304
+ "while (!xhr && XMLHttpFactories.length) {"
305
+ " try {"
306
+ " xhr = XMLHttpFactories.shift().call();"
307
+ " } catch (e) {}"
308
+ "}"
309
+ "if (!xhr) throw Error('unable to create XHR object');"
310
+ "xhr.open('GET', url, true);"
311
+ "xhr.onreadystatechange = function() {"
312
+ " if (xhr.readyState == 4) callback(xhr.responseText);"
313
+ "};"
314
+ "xhr.send('');"; // empty string to stop firefox 3 from choking
315
316
driver.get(pages.ajaxyPage);
317
driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(3));
318
String response = (String) executor.executeAsyncScript(script, pages.sleepingPage + "?time=2");
319
assertThat(response.trim())
320
.isEqualTo("<html><head><title>Done</title></head><body>Slept for 2s</body></html>");
321
}
322
323
@Test
324
@Ignore(CHROME)
325
@Ignore(EDGE)
326
@Ignore(IE)
327
@Ignore(FIREFOX)
328
@Ignore(value = SAFARI, reason = "Does not support alerts yet")
329
public void throwsIfScriptTriggersAlert() {
330
driver.get(pages.simpleTestPage);
331
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(5000));
332
assertThatExceptionOfType(UnhandledAlertException.class)
333
.isThrownBy(
334
() ->
335
executor.executeAsyncScript(
336
"setTimeout(arguments[0], 200) ; setTimeout(function() { window.alert('Look! An"
337
+ " alert!'); }, 50);"));
338
// Shouldn't throw
339
driver.getTitle();
340
}
341
342
@Test
343
@Ignore(CHROME)
344
@Ignore(EDGE)
345
@Ignore(IE)
346
@Ignore(FIREFOX)
347
@Ignore(value = SAFARI, reason = "Does not support alerts yet")
348
public void throwsIfAlertHappensDuringScript() {
349
driver.get(pages.slowLoadingAlertPage);
350
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(5000));
351
assertThatExceptionOfType(UnhandledAlertException.class)
352
.isThrownBy(() -> executor.executeAsyncScript("setTimeout(arguments[0], 1000);"));
353
// Shouldn't throw
354
driver.getTitle();
355
}
356
357
@Test
358
@Ignore(CHROME)
359
@Ignore(EDGE)
360
@Ignore(IE)
361
@Ignore(FIREFOX)
362
@Ignore(value = SAFARI, reason = "Does not support alerts yet")
363
public void throwsIfScriptTriggersAlertWhichTimesOut() {
364
driver.get(pages.simpleTestPage);
365
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(5000));
366
assertThatExceptionOfType(UnhandledAlertException.class)
367
.isThrownBy(
368
() ->
369
executor.executeAsyncScript(
370
"setTimeout(function() { window.alert('Look! An alert!'); }, 50);"));
371
// Shouldn't throw
372
driver.getTitle();
373
}
374
375
@Test
376
@Ignore(CHROME)
377
@Ignore(EDGE)
378
@Ignore(IE)
379
@Ignore(FIREFOX)
380
@Ignore(value = SAFARI, reason = "Does not support alerts yet")
381
public void throwsIfAlertHappensDuringScriptWhichTimesOut() {
382
driver.get(pages.slowLoadingAlertPage);
383
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(5000));
384
assertThatExceptionOfType(UnhandledAlertException.class)
385
.isThrownBy(() -> executor.executeAsyncScript(""));
386
// Shouldn't throw
387
driver.getTitle();
388
}
389
390
@Test
391
@Ignore(CHROME)
392
@Ignore(EDGE)
393
@Ignore(IE)
394
@Ignore(FIREFOX)
395
@Ignore(value = SAFARI, reason = "Does not support alerts yet")
396
public void includesAlertTextInUnhandledAlertException() {
397
driver.manage().timeouts().scriptTimeout(Duration.ofMillis(5000));
398
String alertText = "Look! An alert!";
399
assertThatExceptionOfType(UnhandledAlertException.class)
400
.isThrownBy(
401
() ->
402
executor.executeAsyncScript(
403
"setTimeout(arguments[0], 200) ; setTimeout(function() { window.alert('"
404
+ alertText
405
+ "'); }, 50);"))
406
.satisfies(t -> assertThat(t.getAlertText()).isEqualTo(alertText));
407
}
408
409
private long getNumDivElements() {
410
// Selenium does not support "findElements" yet, so we have to do this through a script.
411
return (Long)
412
((JavascriptExecutor) driver)
413
.executeScript("return document.getElementsByTagName('div').length;");
414
}
415
}
416
417