Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/java/test/org/openqa/selenium/ExecutingJavascriptTest.java
4012 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 java.nio.charset.StandardCharsets.US_ASCII;
22
import static java.util.Collections.singletonList;
23
import static org.assertj.core.api.Assertions.assertThat;
24
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
25
import static org.junit.jupiter.api.Assumptions.assumeTrue;
26
import static org.openqa.selenium.By.id;
27
import static org.openqa.selenium.testing.drivers.Browser.CHROME;
28
import static org.openqa.selenium.testing.drivers.Browser.EDGE;
29
import static org.openqa.selenium.testing.drivers.Browser.FIREFOX;
30
import static org.openqa.selenium.testing.drivers.Browser.IE;
31
import static org.openqa.selenium.testing.drivers.Browser.SAFARI;
32
33
import java.io.IOException;
34
import java.nio.file.Files;
35
import java.nio.file.Path;
36
import java.text.ParseException;
37
import java.text.SimpleDateFormat;
38
import java.util.ArrayList;
39
import java.util.Collection;
40
import java.util.HashSet;
41
import java.util.List;
42
import java.util.Map;
43
import org.junit.jupiter.api.BeforeEach;
44
import org.junit.jupiter.api.Test;
45
import org.junit.jupiter.api.Timeout;
46
import org.openqa.selenium.build.InProject;
47
import org.openqa.selenium.testing.Ignore;
48
import org.openqa.selenium.testing.JupiterTestBase;
49
import org.openqa.selenium.testing.NeedsFreshDriver;
50
import org.openqa.selenium.testing.NotYetImplemented;
51
52
class ExecutingJavascriptTest extends JupiterTestBase {
53
54
@BeforeEach
55
public void setUp() {
56
assumeTrue(driver instanceof JavascriptExecutor);
57
}
58
59
private Object executeScript(String script, Object... args) {
60
return ((JavascriptExecutor) driver).executeScript(script, args);
61
}
62
63
@Test
64
void testShouldBeAbleToExecuteSimpleJavascriptAndReturnAString() {
65
driver.get(pages.xhtmlTestPage);
66
67
Object result = executeScript("return document.title;");
68
69
assertThat(result).isInstanceOf(String.class).isEqualTo("XHTML Test Page");
70
}
71
72
@Test
73
void testShouldBeAbleToExecuteSimpleJavascriptAndReturnALong() {
74
driver.get(pages.nestedPage);
75
76
Object result = executeScript("return document.getElementsByName('checky').length;");
77
78
assertThat(result).isInstanceOf(Long.class);
79
assertThat((Long) result).isGreaterThan(1);
80
}
81
82
@Test
83
void testShouldBeAbleToExecuteSimpleJavascriptAndReturnAWebElement() {
84
driver.get(pages.xhtmlTestPage);
85
86
Object result = executeScript("return document.getElementById('id1');");
87
88
assertThat(result).isInstanceOf(WebElement.class);
89
assertThat(((WebElement) result).getTagName()).isEqualToIgnoringCase("a");
90
}
91
92
@Test
93
void testShouldBeAbleToExecuteSimpleJavascriptAndReturnABoolean() {
94
driver.get(pages.xhtmlTestPage);
95
96
Object result = executeScript("return true;");
97
98
assertThat(result).isInstanceOf(Boolean.class).isEqualTo(true);
99
}
100
101
@Test
102
void testShouldBeAbleToExecuteSimpleJavascriptAndReturnAStringsArray() {
103
driver.get(pages.javascriptPage);
104
105
Object result = ((JavascriptExecutor) driver).executeScript("return ['zero', 'one', 'two'];");
106
107
assertThat(result).isInstanceOf(List.class);
108
assertThat((List<?>) result).isEqualTo(List.of("zero", "one", "two"));
109
}
110
111
@SuppressWarnings("unchecked")
112
@Test
113
void testShouldBeAbleToExecuteSimpleJavascriptAndReturnAnArray() {
114
driver.get(pages.javascriptPage);
115
List<Object> expectedResult = new ArrayList<>();
116
expectedResult.add("zero");
117
List<Object> subList = new ArrayList<>();
118
subList.add(true);
119
subList.add(false);
120
expectedResult.add(subList);
121
Object result = executeScript("return ['zero', [true, false]];");
122
assertThat(result).isInstanceOf(List.class);
123
assertThat((List<Object>) result).isEqualTo(expectedResult);
124
}
125
126
@SuppressWarnings("unchecked")
127
@Test
128
void testShouldBeAbleToExecuteJavascriptAndReturnABasicObjectLiteral() {
129
driver.get(pages.javascriptPage);
130
131
Object result = executeScript("return {abc: '123', tired: false};");
132
assertThat(result).isInstanceOf(Map.class);
133
Map<String, Object> map = (Map<String, Object>) result;
134
135
Map<String, Object> expected = Map.of("abc", "123", "tired", false);
136
137
// Cannot do an exact match; Firefox 4 inserts a few extra keys in our object; this is OK, as
138
// long as the expected keys are there.
139
assertThat(map.size()).isGreaterThanOrEqualTo(expected.size());
140
for (Map.Entry<String, Object> entry : expected.entrySet()) {
141
assertThat(map.get(entry.getKey()))
142
.as("Value by key %s, )", entry.getKey())
143
.isEqualTo(entry.getValue());
144
}
145
}
146
147
@SuppressWarnings("unchecked")
148
@Test
149
void testShouldBeAbleToExecuteSimpleJavascriptAndReturnAnObjectLiteral() {
150
driver.get(pages.javascriptPage);
151
152
Map<String, Object> expectedResult =
153
Map.of(
154
"foo",
155
"bar",
156
"baz",
157
List.of("a", "b", "c"),
158
"person",
159
Map.of(
160
"first", "John",
161
"last", "Doe"));
162
163
Object result =
164
executeScript(
165
"return {foo:'bar', baz: ['a', 'b', 'c'], " + "person: {first: 'John',last: 'Doe'}};");
166
assertThat(result).isInstanceOf(Map.class);
167
168
Map<String, Object> map = (Map<String, Object>) result;
169
assertThat(map.size()).isGreaterThanOrEqualTo(3);
170
assertThat(map.get("foo")).isEqualTo("bar");
171
assertThat((List<?>) map.get("baz")).isEqualTo(expectedResult.get("baz"));
172
173
Map<String, String> person = (Map<String, String>) map.get("person");
174
assertThat(person.size()).isGreaterThanOrEqualTo(2);
175
assertThat(person.get("first")).isEqualTo("John");
176
assertThat(person.get("last")).isEqualTo("Doe");
177
}
178
179
@SuppressWarnings("unchecked")
180
@Test
181
@Ignore(IE)
182
public void testShouldBeAbleToExecuteSimpleJavascriptAndReturnAComplexObject() {
183
driver.get(pages.javascriptPage);
184
185
Object result = executeScript("return window.location;");
186
187
assertThat(result).isInstanceOf(Map.class);
188
Map<String, Object> map = (Map<String, Object>) result;
189
assertThat(map.get("protocol")).isEqualTo("http:");
190
assertThat(map.get("href")).isEqualTo(pages.javascriptPage);
191
}
192
193
@Test
194
void testPassingAndReturningALongShouldReturnAWholeNumber() {
195
driver.get(pages.javascriptPage);
196
Long expectedResult = 1L;
197
Object result = executeScript("return arguments[0];", expectedResult);
198
assertThat(result).isInstanceOfAny(Integer.class, Long.class).isEqualTo(expectedResult);
199
}
200
201
@Test
202
void testReturningOverflownLongShouldReturnADouble() {
203
driver.get(pages.javascriptPage);
204
Double expectedResult = 6.02214129e+23;
205
Object result = executeScript("return arguments[0];", expectedResult);
206
assertThat(result).isInstanceOf(Double.class).isEqualTo(expectedResult);
207
}
208
209
@Test
210
void testPassingAndReturningADoubleShouldReturnADecimal() {
211
driver.get(pages.javascriptPage);
212
Double expectedResult = 1.2;
213
Object result = executeScript("return arguments[0];", expectedResult);
214
assertThat(result).isInstanceOfAny(Float.class, Double.class).isEqualTo(expectedResult);
215
}
216
217
@Test
218
void testShouldThrowAnExceptionWhenTheJavascriptIsBad() {
219
driver.get(pages.xhtmlTestPage);
220
221
assertThatExceptionOfType(WebDriverException.class)
222
.isThrownBy(() -> executeScript("return squiggle();"))
223
.satisfies(t -> assertThat(t.getMessage()).doesNotStartWith("null "));
224
}
225
226
@Test
227
@Ignore(CHROME)
228
@Ignore(EDGE)
229
@Ignore(IE)
230
@NotYetImplemented(SAFARI)
231
@Ignore(FIREFOX)
232
public void testShouldThrowAnExceptionWithMessageAndStacktraceWhenTheJavascriptIsBad() {
233
driver.get(pages.xhtmlTestPage);
234
235
String js =
236
"function functionB() { throw Error('errormessage'); };"
237
+ "function functionA() { functionB(); };"
238
+ "functionA();";
239
assertThatExceptionOfType(WebDriverException.class)
240
.isThrownBy(() -> executeScript(js))
241
.withMessageContaining("errormessage")
242
.satisfies(
243
t -> {
244
Throwable rootCause = getRootCause(t);
245
assertThat(rootCause).hasMessageContaining("errormessage");
246
assertThat(List.of(rootCause.getStackTrace()))
247
.extracting(StackTraceElement::getMethodName)
248
.contains("functionB");
249
});
250
}
251
252
@Test
253
void testShouldBeAbleToCallFunctionsDefinedOnThePage() {
254
driver.get(pages.javascriptPage);
255
executeScript("displayMessage('I like cheese');");
256
String text = driver.findElement(By.id("result")).getText();
257
258
assertThat(text.trim()).isEqualTo("I like cheese");
259
}
260
261
@Test
262
void testShouldBeAbleToPassAStringAnAsArgument() {
263
driver.get(pages.javascriptPage);
264
String value =
265
(String) executeScript("return arguments[0] == 'fish' ? 'fish' : 'not fish';", "fish");
266
267
assertThat(value).isEqualTo("fish");
268
}
269
270
@Test
271
void testShouldBeAbleToPassABooleanAsArgument() {
272
driver.get(pages.javascriptPage);
273
boolean value = (Boolean) executeScript("return arguments[0] == true;", true);
274
assertThat(value).isTrue();
275
}
276
277
@Test
278
void testShouldBeAbleToPassANumberAnAsArgument() {
279
driver.get(pages.javascriptPage);
280
boolean value = (Boolean) executeScript("return arguments[0] == 1 ? true : false;", 1);
281
assertThat(value).isTrue();
282
}
283
284
@Test
285
void testShouldBeAbleToPassAWebElementAsArgument() {
286
driver.get(pages.javascriptPage);
287
WebElement button = driver.findElement(By.id("plainButton"));
288
String value =
289
(String)
290
executeScript(
291
"arguments[0]['flibble'] = arguments[0].getAttribute('id'); return"
292
+ " arguments[0]['flibble'];",
293
button);
294
295
assertThat(value).isEqualTo("plainButton");
296
}
297
298
@Test
299
void testPassingArrayAsOnlyArgumentFlattensArray() {
300
driver.get(pages.javascriptPage);
301
Object[] array = new Object[] {"zero", 1, true, 42.4242, false};
302
String value = (String) executeScript("return arguments[0]", array);
303
assertThat(value).isEqualTo(array[0]);
304
}
305
306
@Test
307
void testShouldBeAbleToPassAnArrayAsAdditionalArgument() {
308
driver.get(pages.javascriptPage);
309
Object[] array = new Object[] {"zero", 1, true, 42.4242, false};
310
long length = (Long) executeScript("return arguments[1].length", "string", array);
311
assertThat(length).isEqualTo(array.length);
312
}
313
314
@Test
315
void testShouldBeAbleToPassACollectionAsArgument() {
316
driver.get(pages.javascriptPage);
317
Collection<Object> collection = new ArrayList<>();
318
collection.add("Cheddar");
319
collection.add("Brie");
320
collection.add(7);
321
long length = (Long) executeScript("return arguments[0].length", collection);
322
assertThat(length).isEqualTo(collection.size());
323
324
collection = new HashSet<>();
325
collection.add("Gouda");
326
collection.add("Stilton");
327
collection.add("Stilton");
328
collection.add(true);
329
length = (Long) executeScript("return arguments[0].length", collection);
330
assertThat(length).isEqualTo(collection.size());
331
}
332
333
@Test
334
void testShouldThrowAnExceptionIfAnArgumentIsNotValid() {
335
driver.get(pages.javascriptPage);
336
assertThatExceptionOfType(IllegalArgumentException.class)
337
.isThrownBy(() -> executeScript("return arguments[0];", driver));
338
}
339
340
@Test
341
void testShouldBeAbleToPassInMoreThanOneArgument() {
342
driver.get(pages.javascriptPage);
343
String result = (String) executeScript("return arguments[0] + arguments[1];", "one", "two");
344
assertThat(result).isEqualTo("onetwo");
345
}
346
347
@Test
348
void testShouldBeAbleToGrabTheBodyOfFrameOnceSwitchedTo() {
349
driver.get(pages.richTextPage);
350
351
driver.switchTo().frame("editFrame");
352
WebElement body = (WebElement) executeScript("return document.body");
353
String text = body.getText();
354
driver.switchTo().defaultContent();
355
356
assertThat(text).isEmpty();
357
}
358
359
@SuppressWarnings("unchecked")
360
@Test
361
void testShouldBeAbleToReturnAnArrayOfWebElements() {
362
driver.get(pages.formPage);
363
364
List<WebElement> items =
365
(List<WebElement>) executeScript("return document.getElementsByName('snack');");
366
367
assertThat(items).isNotEmpty();
368
}
369
370
@Test
371
void testJavascriptStringHandlingShouldWorkAsExpected() {
372
driver.get(pages.javascriptPage);
373
374
assertThat((String) executeScript("return '';")).isEmpty();
375
assertThat((String) executeScriptNullable("return undefined;")).isNull();
376
assertThat((String) executeScript("return ' '")).isEqualTo(" ");
377
}
378
379
@Test
380
void testShouldBeAbleToExecuteABigChunkOfJavascriptCode() throws IOException {
381
driver.get(pages.javascriptPage);
382
383
Path jqueryFile = InProject.locate("common/src/web/js/jquery-3.5.1.min.js");
384
String jquery = Files.readString(jqueryFile, US_ASCII);
385
assertThat(jquery.length())
386
.describedAs("The javascript code should be at least 50 KB.")
387
.isGreaterThan(50000);
388
// This should not throw an exception ...
389
executeScript(jquery);
390
}
391
392
@SuppressWarnings("unchecked")
393
@Test
394
void testShouldBeAbleToExecuteScriptAndReturnElementsList() {
395
driver.get(pages.formPage);
396
String scriptToExec = "return document.getElementsByName('snack');";
397
398
List<WebElement> resultsList = (List<WebElement>) executeScript(scriptToExec);
399
400
assertThat(resultsList).isNotEmpty();
401
}
402
403
@NeedsFreshDriver
404
@Test
405
@Ignore(SAFARI)
406
public void testShouldBeAbleToExecuteScriptOnNoPage() {
407
String text = (String) executeScript("return 'test';");
408
assertThat(text).isEqualTo("test");
409
}
410
411
@Test
412
void testShouldBeAbleToCreateAPersistentValue() {
413
driver.get(pages.formPage);
414
415
executeScript("document.alerts = []");
416
executeScript("document.alerts.push('hello world');");
417
String text = (String) executeScript("return document.alerts.shift()");
418
419
assertThat(text).isEqualTo("hello world");
420
}
421
422
@Test
423
void testCanHandleAnArrayOfElementsAsAnObjectArray() {
424
driver.get(pages.formPage);
425
426
List<WebElement> forms = driver.findElements(By.tagName("form"));
427
Object[] args = new Object[] {forms};
428
429
String name =
430
(String)
431
((JavascriptExecutor) driver).executeScript("return arguments[0][0].tagName", args);
432
433
assertThat(name).isEqualToIgnoringCase("form");
434
}
435
436
@Test
437
void testCanPassAMapAsAParameter() {
438
driver.get(pages.simpleTestPage);
439
440
List<Integer> nums = List.of(1, 2);
441
Map<String, Object> args = Map.of("bar", "test", "foo", nums);
442
443
Object res = ((JavascriptExecutor) driver).executeScript("return arguments[0]['foo'][1]", args);
444
445
assertThat(((Number) res).intValue()).isEqualTo(2);
446
}
447
448
@Test
449
@NotYetImplemented(SAFARI)
450
public void testShouldThrowAnExceptionWhenArgumentsWithStaleElementPassed() {
451
driver.get(pages.simpleTestPage);
452
453
final WebElement el = driver.findElement(id("oneline"));
454
455
driver.get(pages.simpleTestPage);
456
457
Map<String, Object> args =
458
Map.of("key", List.of("a", new Object[] {"zero", 1, true, 42.4242, false, el}, "c"));
459
460
assertThatExceptionOfType(StaleElementReferenceException.class)
461
.isThrownBy(() -> executeScript("return undefined;", args));
462
}
463
464
@Test
465
@Ignore(IE)
466
@Ignore(value = CHROME, reason = "https://bugs.chromium.org/p/chromedriver/issues/detail?id=4395")
467
@Ignore(value = EDGE, reason = "https://bugs.chromium.org/p/chromedriver/issues/detail?id=4395")
468
public void testShouldBeAbleToReturnADateObject() throws ParseException {
469
driver.get(pages.simpleTestPage);
470
471
String date = (String) executeScript("return new Date();");
472
473
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").parse(date);
474
}
475
476
@Test
477
@Timeout(10)
478
@NotYetImplemented(CHROME)
479
@NotYetImplemented(EDGE)
480
@Ignore(IE)
481
@NotYetImplemented(SAFARI)
482
@NotYetImplemented(
483
value = FIREFOX,
484
reason = "https://bugzilla.mozilla.org/show_bug.cgi?id=1502656")
485
public void shouldReturnDocumentElementIfDocumentIsReturned() {
486
driver.get(pages.simpleTestPage);
487
488
Object value = executeScript("return document");
489
490
assertThat(value).isInstanceOf(WebElement.class);
491
assertThat(((WebElement) value).getText()).contains("A single line of text");
492
}
493
494
@Test
495
@Timeout(10)
496
@Ignore(value = IE, reason = "returns WebElement")
497
public void shouldHandleObjectThatThatHaveToJSONMethod() {
498
driver.get(pages.simpleTestPage);
499
500
Object value = executeScript("return window.performance.timing");
501
502
assertThat(value).isInstanceOf(Map.class);
503
}
504
505
@Test
506
@Timeout(10)
507
public void shouldHandleRecursiveStructures() {
508
driver.get(pages.simpleTestPage);
509
510
assertThatExceptionOfType(JavascriptException.class)
511
.isThrownBy(
512
() ->
513
executeScript(
514
"var obj1 = {}; var obj2 = {}; obj1['obj2'] = obj2; obj2['obj1'] = obj1; return"
515
+ " obj1"));
516
}
517
518
@Test
519
void shouldUnwrapDeeplyNestedWebElementsAsArguments() {
520
driver.get(pages.simpleTestPage);
521
522
WebElement expected = driver.findElement(id("oneline"));
523
524
Object args = Map.of("top", Map.of("key", singletonList(Map.of("subkey", expected))));
525
WebElement seen = (WebElement) executeScript("return arguments[0].top.key[0].subkey", args);
526
527
assertThat(seen).isEqualTo(expected);
528
}
529
}
530
531