0
# JavaScript Execution
1
2
JavaScript engine integration for executing JavaScript code within web pages, handling browser API calls, and managing JavaScript events. Critical for modern web application automation and testing dynamic content.
3
4
## Capabilities
5
6
### JavaScript Execution in Pages
7
8
Execute JavaScript code directly within HtmlPage context.
9
10
```java { .api }
11
/**
12
* JavaScript execution methods in HtmlPage
13
*/
14
public class HtmlPage extends SgmlPage {
15
/** Execute JavaScript code in page context */
16
public ScriptResult executeJavaScript(String sourceCode);
17
18
/** Execute JavaScript with source file information */
19
public ScriptResult executeJavaScript(String sourceCode, String sourceName, int startLine);
20
21
/** Execute JavaScript and return specific type */
22
public <T> T executeJavaScriptFunction(String functionCall, Class<T> returnType);
23
24
/** Check if JavaScript is enabled for this page */
25
public boolean isJavaScriptEnabled();
26
27
/** Get JavaScript engine for this page */
28
public AbstractJavaScriptEngine<?> getJavaScriptEngine();
29
30
/** Get window object for JavaScript context */
31
public Window getJavaScriptWindow();
32
}
33
```
34
35
**Usage Examples:**
36
37
```java
38
import com.gargoylesoftware.htmlunit.WebClient;
39
import com.gargoylesoftware.htmlunit.html.HtmlPage;
40
import com.gargoylesoftware.htmlunit.ScriptResult;
41
42
try (WebClient webClient = new WebClient()) {
43
// Enable JavaScript
44
webClient.getOptions().setJavaScriptEnabled(true);
45
46
HtmlPage page = webClient.getPage("https://example.com");
47
48
// Execute simple JavaScript
49
ScriptResult result = page.executeJavaScript("document.title");
50
String title = result.getJavaScriptResult().toString();
51
System.out.println("Page title: " + title);
52
53
// Execute complex JavaScript
54
String jsCode = """
55
var elements = document.querySelectorAll('.menu-item');
56
var texts = [];
57
for (var i = 0; i < elements.length; i++) {
58
texts.push(elements[i].textContent.trim());
59
}
60
texts;
61
""";
62
63
ScriptResult menuResult = page.executeJavaScript(jsCode);
64
Object menuItems = menuResult.getJavaScriptResult();
65
66
// Execute JavaScript function
67
page.executeJavaScript("function greet(name) { return 'Hello, ' + name + '!'; }");
68
ScriptResult greeting = page.executeJavaScript("greet('World')");
69
System.out.println(greeting.getJavaScriptResult());
70
71
// Modify page content with JavaScript
72
page.executeJavaScript("document.getElementById('myButton').style.display = 'none';");
73
74
// Check for navigation after JavaScript execution
75
if (result.getNewPage() != null) {
76
System.out.println("JavaScript caused navigation to: " + result.getNewPage().getUrl());
77
}
78
}
79
```
80
81
### ScriptResult Class
82
83
Result object returned from JavaScript execution.
84
85
```java { .api }
86
/**
87
* Result from JavaScript execution
88
*/
89
public class ScriptResult {
90
/** Get JavaScript execution result value */
91
public Object getJavaScriptResult();
92
93
/** Get new page if JavaScript caused navigation */
94
public Page getNewPage();
95
96
/** Check if JavaScript caused page navigation */
97
public boolean hasNewPage();
98
}
99
```
100
101
### JavaScript Engine Classes
102
103
```java { .api }
104
/**
105
* Main JavaScript execution engine
106
*/
107
public class JavaScriptEngine extends AbstractJavaScriptEngine<HtmlUnitScriptable> {
108
/** Execute JavaScript code */
109
public Object execute(HtmlPage page, String sourceCode, String sourceName, int startLine);
110
111
/** Call JavaScript function */
112
public Object callFunction(HtmlPage page, Function function, Scriptable scope, Scriptable thisObj, Object[] args);
113
114
/** Initialize engine for page */
115
public void initialize(WebWindow webWindow, Page page);
116
117
/** Shutdown engine */
118
public void shutdown();
119
120
/** Get JavaScript configuration */
121
public JavaScriptConfiguration getConfiguration();
122
123
/** Set JavaScript configuration */
124
public void setJavaScriptConfiguration(JavaScriptConfiguration config);
125
126
/** Get JavaScript job manager for background tasks */
127
public JavaScriptJobManager getJavaScriptJobManager();
128
129
/** Check if JavaScript is enabled */
130
public boolean isScriptEnabled();
131
132
/** Set JavaScript enabled state */
133
public void setScriptEnabled(boolean enabled);
134
135
/** Get script preprocessor */
136
public ScriptPreProcessor getScriptPreProcessor();
137
138
/** Set script preprocessor */
139
public void setScriptPreProcessor(ScriptPreProcessor scriptPreProcessor);
140
}
141
142
/**
143
* Abstract base for JavaScript engines
144
*/
145
public abstract class AbstractJavaScriptEngine<T extends Scriptable> {
146
/** Execute script and return result */
147
public abstract ScriptResult execute(HtmlPage page, String code, String sourceName);
148
149
/** Call function with arguments */
150
public abstract Object callFunction(HtmlPage page, Function function, Scriptable scope, Scriptable thisObj, Object[] args);
151
152
/** Get timeout for JavaScript execution */
153
public long getJavaScriptTimeout();
154
155
/** Set timeout for JavaScript execution */
156
public void setJavaScriptTimeout(long timeout);
157
158
/** Add script exception listener */
159
public void addScriptExceptionListener(ScriptExceptionListener listener);
160
161
/** Remove script exception listener */
162
public void removeScriptExceptionListener(ScriptExceptionListener listener);
163
}
164
```
165
166
### JavaScript Error Handling
167
168
```java { .api }
169
/**
170
* Interface for handling JavaScript errors
171
*/
172
public interface JavaScriptErrorListener {
173
/** Handle JavaScript runtime exception */
174
void scriptException(HtmlPage page, ScriptException scriptException);
175
176
/** Handle JavaScript timeout error */
177
void timeoutError(HtmlPage page, long allowedTime, long executionTime);
178
179
/** Handle malformed script URL */
180
void malformedScriptURL(HtmlPage page, String url, MalformedURLException malformedURLException);
181
182
/** Handle script load error */
183
void loadScriptError(HtmlPage page, URL scriptUrl, Exception exception);
184
185
/** Handle script warning */
186
void warn(String message, String sourceName, int line, String lineSource, int lineOffset);
187
}
188
189
/**
190
* Default JavaScript error listener
191
*/
192
public class DefaultJavaScriptErrorListener implements JavaScriptErrorListener {
193
/** Log script exception to console */
194
public void scriptException(HtmlPage page, ScriptException scriptException);
195
196
/** Log timeout error */
197
public void timeoutError(HtmlPage page, long allowedTime, long executionTime);
198
199
/** Log malformed URL error */
200
public void malformedScriptURL(HtmlPage page, String url, MalformedURLException malformedURLException);
201
202
/** Log script load error */
203
public void loadScriptError(HtmlPage page, URL scriptUrl, Exception exception);
204
205
/** Log warning */
206
public void warn(String message, String sourceName, int line, String lineSource, int lineOffset);
207
}
208
209
/**
210
* Silent JavaScript error listener (ignores all errors)
211
*/
212
public class SilentJavaScriptErrorListener implements JavaScriptErrorListener {
213
/** Silently ignore script exception */
214
public void scriptException(HtmlPage page, ScriptException scriptException);
215
216
/** Silently ignore timeout error */
217
public void timeoutError(HtmlPage page, long allowedTime, long executionTime);
218
219
/** Silently ignore malformed URL */
220
public void malformedScriptURL(HtmlPage page, String url, MalformedURLException malformedURLException);
221
222
/** Silently ignore load error */
223
public void loadScriptError(HtmlPage page, URL scriptUrl, Exception exception);
224
225
/** Silently ignore warning */
226
public void warn(String message, String sourceName, int line, String lineSource, int lineOffset);
227
}
228
```
229
230
**Usage Examples:**
231
232
```java
233
// Set up JavaScript error handling
234
webClient.setJavaScriptErrorListener(new JavaScriptErrorListener() {
235
@Override
236
public void scriptException(HtmlPage page, ScriptException scriptException) {
237
System.err.println("JavaScript error on " + page.getUrl() + ": " + scriptException.getMessage());
238
}
239
240
@Override
241
public void timeoutError(HtmlPage page, long allowedTime, long executionTime) {
242
System.err.println("JavaScript timeout on " + page.getUrl() +
243
" (allowed: " + allowedTime + "ms, actual: " + executionTime + "ms)");
244
}
245
246
@Override
247
public void malformedScriptURL(HtmlPage page, String url, MalformedURLException malformedURLException) {
248
System.err.println("Malformed script URL: " + url);
249
}
250
251
@Override
252
public void loadScriptError(HtmlPage page, URL scriptUrl, Exception exception) {
253
System.err.println("Failed to load script: " + scriptUrl + " - " + exception.getMessage());
254
}
255
256
@Override
257
public void warn(String message, String sourceName, int line, String lineSource, int lineOffset) {
258
System.out.println("JavaScript warning: " + message + " at " + sourceName + ":" + line);
259
}
260
});
261
262
// Or use silent listener to ignore all JavaScript errors
263
webClient.setJavaScriptErrorListener(new SilentJavaScriptErrorListener());
264
```
265
266
### Background JavaScript Jobs
267
268
```java { .api }
269
/**
270
* Manager for background JavaScript tasks (setTimeout, setInterval, etc.)
271
*/
272
public class JavaScriptJobManager {
273
/** Get count of pending jobs */
274
public int getJobCount();
275
276
/** Wait for all jobs to complete */
277
public int waitForJobs(long timeoutMillis);
278
279
/** Wait for jobs started before specified time */
280
public int waitForJobsStartingBefore(long delayMillis);
281
282
/** Cancel all pending jobs */
283
public void shutdown();
284
285
/** Check if job manager is shutdown */
286
public boolean isShutdown();
287
288
/** Add job to queue */
289
public void addJob(JavaScriptJob job, Page page);
290
291
/** Remove job from queue */
292
public void removeJob(JavaScriptJob job);
293
294
/** Get number of completed jobs */
295
public int getCompletedJobCount();
296
297
/** Clear completed job history */
298
public void clearCompletedJobs();
299
}
300
301
/**
302
* Background JavaScript job interface
303
*/
304
public interface JavaScriptJob {
305
/** Execute the job */
306
void run();
307
308
/** Get job ID */
309
Integer getId();
310
311
/** Get target execution time */
312
long getTargetExecutionTime();
313
314
/** Check if job is recurring (setInterval) */
315
boolean isPeriodic();
316
317
/** Get period for recurring jobs */
318
Long getPeriod();
319
}
320
```
321
322
**Usage Examples:**
323
324
```java
325
// Wait for background JavaScript to complete
326
try (WebClient webClient = new WebClient()) {
327
webClient.getOptions().setJavaScriptEnabled(true);
328
329
HtmlPage page = webClient.getPage("https://example.com/ajax-page");
330
331
// Execute JavaScript that starts background jobs
332
page.executeJavaScript("""
333
setTimeout(function() {
334
document.getElementById('status').textContent = 'Loaded';
335
}, 1000);
336
337
setInterval(function() {
338
console.log('Heartbeat');
339
}, 5000);
340
""");
341
342
// Wait for background jobs to complete (up to 10 seconds)
343
int jobsRemaining = webClient.waitForBackgroundJavaScript(10000);
344
if (jobsRemaining == 0) {
345
System.out.println("All JavaScript jobs completed");
346
} else {
347
System.out.println(jobsRemaining + " JavaScript jobs still running");
348
}
349
350
// Or wait for jobs that started before a delay
351
webClient.waitForBackgroundJavaScriptStartingBefore(2000);
352
}
353
```
354
355
### Script Preprocessing
356
357
```java { .api }
358
/**
359
* Interface for preprocessing JavaScript before execution
360
*/
361
public interface ScriptPreProcessor {
362
/** Preprocess JavaScript source code */
363
String preProcess(HtmlPage htmlPage, String sourceCode, String sourceName, int lineNumber, HtmlElement htmlElement);
364
}
365
```
366
367
**Usage Example:**
368
369
```java
370
// Custom script preprocessor
371
webClient.getJavaScriptEngine().setScriptPreProcessor(new ScriptPreProcessor() {
372
@Override
373
public String preProcess(HtmlPage htmlPage, String sourceCode, String sourceName, int lineNumber, HtmlElement htmlElement) {
374
// Add debugging information to all scripts
375
String debug = "console.log('Executing script from " + sourceName + " at line " + lineNumber + "');";
376
return debug + "\n" + sourceCode;
377
}
378
});
379
```
380
381
### JavaScript Host Objects
382
383
HtmlUnit provides JavaScript implementations of browser APIs through host objects:
384
385
```java { .api }
386
/**
387
* JavaScript window object
388
*/
389
public class Window extends EventTarget {
390
/** Show alert dialog */
391
public void alert(String message);
392
393
/** Show confirm dialog */
394
public boolean confirm(String message);
395
396
/** Show prompt dialog */
397
public String prompt(String message, String defaultText);
398
399
/** Set timeout for function execution */
400
public int setTimeout(Function function, int timeout);
401
402
/** Set interval for repeated function execution */
403
public int setInterval(Function function, int interval);
404
405
/** Clear timeout */
406
public void clearTimeout(int timeoutId);
407
408
/** Clear interval */
409
public void clearInterval(int intervalId);
410
411
/** Open new window */
412
public Window open(String url, String windowName, String windowFeatures);
413
414
/** Close window */
415
public void close();
416
417
/** Get document object */
418
public HTMLDocument getDocument();
419
420
/** Get location object */
421
public Location getLocation();
422
423
/** Get navigator object */
424
public Navigator getNavigator();
425
426
/** Get history object */
427
public History getHistory();
428
429
/** Get screen object */
430
public Screen getScreen();
431
432
/** Get console object */
433
public Console getConsole();
434
435
/** Get window name */
436
public String getName();
437
438
/** Set window name */
439
public void setName(String name);
440
441
/** Get parent window */
442
public Window getParent();
443
444
/** Get top window */
445
public Window getTop();
446
447
/** Execute eval */
448
public Object eval(String script);
449
}
450
451
/**
452
* JavaScript document object
453
*/
454
public class HTMLDocument extends Document {
455
/** Get element by ID */
456
public Element getElementById(String elementId);
457
458
/** Get elements by tag name */
459
public NodeList getElementsByTagName(String tagName);
460
461
/** Get elements by class name */
462
public NodeList getElementsByClassName(String className);
463
464
/** Query selector (first match) */
465
public Element querySelector(String selectors);
466
467
/** Query selector all */
468
public NodeList querySelectorAll(String selectors);
469
470
/** Create element */
471
public Element createElement(String tagName);
472
473
/** Create text node */
474
public Text createTextNode(String data);
475
476
/** Get document title */
477
public String getTitle();
478
479
/** Set document title */
480
public void setTitle(String title);
481
482
/** Get/set document cookie */
483
public String getCookie();
484
public void setCookie(String cookie);
485
486
/** Document.write */
487
public void write(String text);
488
489
/** Document.writeln */
490
public void writeln(String text);
491
492
/** Get document URL */
493
public String getURL();
494
495
/** Get document ready state */
496
public String getReadyState();
497
498
/** Get document body */
499
public HTMLElement getBody();
500
501
/** Get document head */
502
public HTMLElement getHead();
503
}
504
```
505
506
### JavaScript Configuration
507
508
```java { .api }
509
/**
510
* Configuration options for JavaScript engine
511
*/
512
public class JavaScriptConfiguration {
513
/** Create default configuration */
514
public JavaScriptConfiguration();
515
516
/** Get classes allowed in JavaScript */
517
public Set<String> getClassesBeingExtended();
518
519
/** Add class to be extended */
520
public void addClassToExtend(String className);
521
522
/** Check if class can be extended */
523
public boolean isClassExtendable(String className);
524
525
/** Get disabled classes */
526
public Set<String> getDisabledClasses();
527
528
/** Disable class in JavaScript */
529
public void disableClass(String className);
530
531
/** Check if class is disabled */
532
public boolean isClassDisabled(String className);
533
}
534
```
535
536
### Common JavaScript Patterns
537
538
**Waiting for Elements:**
539
540
```java
541
// Wait for element to appear using JavaScript
542
String waitForElementScript = """
543
(function() {
544
var element = document.getElementById('dynamicContent');
545
var attempts = 0;
546
var maxAttempts = 50;
547
548
function checkElement() {
549
element = document.getElementById('dynamicContent');
550
attempts++;
551
552
if (element) {
553
return element.textContent;
554
} else if (attempts < maxAttempts) {
555
setTimeout(checkElement, 100);
556
return null;
557
} else {
558
return 'TIMEOUT';
559
}
560
}
561
562
return checkElement();
563
})();
564
""";
565
566
ScriptResult result = page.executeJavaScript(waitForElementScript);
567
```
568
569
**AJAX Request Simulation:**
570
571
```java
572
// Execute AJAX request through JavaScript
573
String ajaxScript = """
574
var xhr = new XMLHttpRequest();
575
xhr.open('GET', '/api/data', false); // Synchronous for simplicity
576
xhr.send();
577
578
if (xhr.status === 200) {
579
JSON.parse(xhr.responseText);
580
} else {
581
{error: 'HTTP ' + xhr.status};
582
}
583
""";
584
585
ScriptResult ajaxResult = page.executeJavaScript(ajaxScript);
586
Object data = ajaxResult.getJavaScriptResult();
587
```
588
589
**Form Manipulation:**
590
591
```java
592
// Fill and submit form via JavaScript
593
String formScript = """
594
var form = document.forms['loginForm'];
595
form.username.value = 'testuser';
596
form.password.value = 'testpass';
597
598
// Trigger events
599
var event = new Event('change', { bubbles: true });
600
form.username.dispatchEvent(event);
601
form.password.dispatchEvent(event);
602
603
// Submit form
604
form.submit();
605
606
'Form submitted';
607
""";
608
609
page.executeJavaScript(formScript);
610
```