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