Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/java/test/org/openqa/selenium/ExecutingJavascriptTest.java
3995 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
String value = (String) executeScript("return '';");
375
assertThat(value).isEmpty();
376
377
value = (String) executeScript("return undefined;");
378
assertThat(value).isNull();
379
380
value = (String) executeScript("return ' '");
381
assertThat(value).isEqualTo(" ");
382
}
383
384
@Test
385
void testShouldBeAbleToExecuteABigChunkOfJavascriptCode() throws IOException {
386
driver.get(pages.javascriptPage);
387
388
Path jqueryFile = InProject.locate("common/src/web/js/jquery-3.5.1.min.js");
389
String jquery = Files.readString(jqueryFile, US_ASCII);
390
assertThat(jquery.length())
391
.describedAs("The javascript code should be at least 50 KB.")
392
.isGreaterThan(50000);
393
// This should not throw an exception ...
394
executeScript(jquery);
395
}
396
397
@SuppressWarnings("unchecked")
398
@Test
399
void testShouldBeAbleToExecuteScriptAndReturnElementsList() {
400
driver.get(pages.formPage);
401
String scriptToExec = "return document.getElementsByName('snack');";
402
403
List<WebElement> resultsList = (List<WebElement>) executeScript(scriptToExec);
404
405
assertThat(resultsList).isNotEmpty();
406
}
407
408
@NeedsFreshDriver
409
@Test
410
@Ignore(SAFARI)
411
public void testShouldBeAbleToExecuteScriptOnNoPage() {
412
String text = (String) executeScript("return 'test';");
413
assertThat(text).isEqualTo("test");
414
}
415
416
@Test
417
void testShouldBeAbleToCreateAPersistentValue() {
418
driver.get(pages.formPage);
419
420
executeScript("document.alerts = []");
421
executeScript("document.alerts.push('hello world');");
422
String text = (String) executeScript("return document.alerts.shift()");
423
424
assertThat(text).isEqualTo("hello world");
425
}
426
427
@Test
428
void testCanHandleAnArrayOfElementsAsAnObjectArray() {
429
driver.get(pages.formPage);
430
431
List<WebElement> forms = driver.findElements(By.tagName("form"));
432
Object[] args = new Object[] {forms};
433
434
String name =
435
(String)
436
((JavascriptExecutor) driver).executeScript("return arguments[0][0].tagName", args);
437
438
assertThat(name).isEqualToIgnoringCase("form");
439
}
440
441
@Test
442
void testCanPassAMapAsAParameter() {
443
driver.get(pages.simpleTestPage);
444
445
List<Integer> nums = List.of(1, 2);
446
Map<String, Object> args = Map.of("bar", "test", "foo", nums);
447
448
Object res = ((JavascriptExecutor) driver).executeScript("return arguments[0]['foo'][1]", args);
449
450
assertThat(((Number) res).intValue()).isEqualTo(2);
451
}
452
453
@Test
454
@NotYetImplemented(SAFARI)
455
public void testShouldThrowAnExceptionWhenArgumentsWithStaleElementPassed() {
456
driver.get(pages.simpleTestPage);
457
458
final WebElement el = driver.findElement(id("oneline"));
459
460
driver.get(pages.simpleTestPage);
461
462
Map<String, Object> args =
463
Map.of("key", List.of("a", new Object[] {"zero", 1, true, 42.4242, false, el}, "c"));
464
465
assertThatExceptionOfType(StaleElementReferenceException.class)
466
.isThrownBy(() -> executeScript("return undefined;", args));
467
}
468
469
@Test
470
@Ignore(IE)
471
@Ignore(value = CHROME, reason = "https://bugs.chromium.org/p/chromedriver/issues/detail?id=4395")
472
@Ignore(value = EDGE, reason = "https://bugs.chromium.org/p/chromedriver/issues/detail?id=4395")
473
public void testShouldBeAbleToReturnADateObject() throws ParseException {
474
driver.get(pages.simpleTestPage);
475
476
String date = (String) executeScript("return new Date();");
477
478
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").parse(date);
479
}
480
481
@Test
482
@Timeout(10)
483
@NotYetImplemented(CHROME)
484
@NotYetImplemented(EDGE)
485
@Ignore(IE)
486
@NotYetImplemented(SAFARI)
487
@NotYetImplemented(
488
value = FIREFOX,
489
reason = "https://bugzilla.mozilla.org/show_bug.cgi?id=1502656")
490
public void shouldReturnDocumentElementIfDocumentIsReturned() {
491
driver.get(pages.simpleTestPage);
492
493
Object value = executeScript("return document");
494
495
assertThat(value).isInstanceOf(WebElement.class);
496
assertThat(((WebElement) value).getText()).contains("A single line of text");
497
}
498
499
@Test
500
@Timeout(10)
501
@Ignore(value = IE, reason = "returns WebElement")
502
public void shouldHandleObjectThatThatHaveToJSONMethod() {
503
driver.get(pages.simpleTestPage);
504
505
Object value = executeScript("return window.performance.timing");
506
507
assertThat(value).isInstanceOf(Map.class);
508
}
509
510
@Test
511
@Timeout(10)
512
public void shouldHandleRecursiveStructures() {
513
driver.get(pages.simpleTestPage);
514
515
assertThatExceptionOfType(JavascriptException.class)
516
.isThrownBy(
517
() ->
518
executeScript(
519
"var obj1 = {}; var obj2 = {}; obj1['obj2'] = obj2; obj2['obj1'] = obj1; return"
520
+ " obj1"));
521
}
522
523
@Test
524
void shouldUnwrapDeeplyNestedWebElementsAsArguments() {
525
driver.get(pages.simpleTestPage);
526
527
WebElement expected = driver.findElement(id("oneline"));
528
529
Object args = Map.of("top", Map.of("key", singletonList(Map.of("subkey", expected))));
530
WebElement seen = (WebElement) executeScript("return arguments[0].top.key[0].subkey", args);
531
532
assertThat(seen).isEqualTo(expected);
533
}
534
}
535
536