Resource library

QA How-To

How to Use Selenium executeAsyncScript in Java (2026)

Learn selenium executeAsyncScript java syntax, callback rules, script timeouts, return types, error handling, and runnable Selenium 4 test patterns for QA.

22 min read | 3,688 words

TL;DR

Cast the driver to JavascriptExecutor, set driver.manage().timeouts().scriptTimeout(Duration), and call executeAsyncScript with JavaScript that invokes arguments[arguments.length - 1] exactly once. The callback's first value becomes the Java return value; if it is never called, Selenium throws a script timeout.

Key Takeaways

  • executeAsyncScript waits until the injected callback is invoked or the WebDriver script timeout expires.
  • The completion callback is always the last JavaScript argument, after every value supplied from Java.
  • Set scriptTimeout with a Duration before running asynchronous JavaScript and keep it separate from element wait timeouts.
  • Return one serializable result through the callback, using a structured success or error envelope for reliable Java assertions.
  • A returned JavaScript Promise does not replace the executeAsyncScript callback contract.
  • Use executeAsyncScript for targeted browser-side asynchronous work, not as a substitute for normal WebDriver waits or application APIs.

The selenium executeAsyncScript java API runs JavaScript in the current browser context and blocks the WebDriver command until your script calls an injected completion callback. Set a script timeout first, retrieve the callback as the final JavaScript argument, invoke it exactly once with a serializable result, and cast the returned Object carefully in Java.

That small callback rule is the difference between a deterministic test and a ScriptTimeoutException. This guide covers the current Selenium 4 interface, runnable JUnit examples, Promise integration, typed result handling, diagnostics, and the situations where an explicit WebDriver wait is the better design.

TL;DR

driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(5));
JavascriptExecutor js = (JavascriptExecutor) driver;

Object result = js.executeAsyncScript("""
    const value = arguments[0];
    const done = arguments[arguments.length - 1];
    setTimeout(() => done({ok: true, value: value.toUpperCase()}), 100);
    """, "ready");
Rule Practical meaning
Callback is last Read arguments[arguments.length - 1] after your supplied arguments
One callback value Pass one string, number, boolean, element, list, map-like object, or null
Explicit script timeout Configure scriptTimeout(Duration) before the command
Current frame and window The script executes where WebDriver is currently focused
Callback must be invoked Returning a Promise or ordinary value alone does not complete the command
One completion path Guard success and failure so only one callback wins

1. Selenium executeAsyncScript Java: The Execution Contract

JavascriptExecutor is Selenium's Java interface for running browser JavaScript. Most WebDriver implementations, including ChromeDriver, FirefoxDriver, EdgeDriver, SafariDriver, and RemoteWebDriver, implement it. executeScript handles synchronous JavaScript. executeAsyncScript adds a completion callback as the last argument and waits until the callback is called or the script timeout is reached.

The script is evaluated as the body of an anonymous function in the currently selected window or frame. document refers to that context's document. Values passed after the script string become JavaScript arguments in order. Selenium adds one more argument at the end, the completion callback. The first value supplied to that callback becomes the return value of executeAsyncScript on the Java side.

The method name can be misleading if you read it from the Java test's perspective. The browser-side work can be asynchronous, but the Java call is blocking. Your test thread waits for command completion. If the callback runs after 200 milliseconds, the Java method returns after that callback. If no callback path runs, the command waits until the configured script timeout and fails.

Use this API when the browser owns an asynchronous primitive that is difficult or inappropriate to observe through normal elements, such as an application callback, a small Promise-based browser operation, or controlled instrumentation in a test harness. Do not use it merely because a page is slow. UI readiness is usually better expressed with WebDriverWait and an ExpectedCondition.

2. executeAsyncScript Versus executeScript and WebDriverWait

These tools solve different synchronization problems.

Tool Completion rule Best use Frequent misuse
executeScript JavaScript function returns synchronously Read DOM state, call a synchronous browser API Starting async work and expecting Selenium to await it
executeAsyncScript Injected callback is invoked Await a timer, event, callback API, or Promise wrapper Forgetting callback or setting no useful script timeout
WebDriverWait A Java condition returns a truthy or non-null result Wait for user-visible or application state Hiding a wrong locator with a long timeout
Thread.sleep A fixed duration ends Rare protocol pacing with a documented reason General page synchronization

executeScript can return the current value of document.readyState because that value is available immediately. It cannot directly wait for setTimeout, fetch, or an event listener. Returning a Promise from executeScript is not the Selenium Java asynchronous script contract. Use executeAsyncScript and explicitly bridge Promise resolution to the injected callback.

WebDriverWait is usually superior for UI behavior because it keeps the test focused on observable state. For example, click Save and wait for a saved status element rather than injecting script to monitor internal application variables. The Selenium ExpectedConditions Java guide shows that pattern.

A sound test may use both tools at separate boundaries. It can run a controlled asynchronous hook through executeAsyncScript, then use WebDriverWait to verify that the page reflects the result. Avoid nesting a long WebDriverWait around a long async script call because the combined maximum duration becomes harder to predict.

3. Set Up Script Timeouts Correctly

Set the asynchronous script timeout through WebDriver.Timeouts before calling executeAsyncScript:

driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(5));

This timeout belongs to the WebDriver session and applies to later asynchronous script commands until changed. It is different from pageLoadTimeout, which bounds navigation, and different from the polling timeout passed to WebDriverWait. Use java.time.Duration with the current Selenium 4 Java API.

Choose a timeout from the operation's expected behavior and the test environment's accepted budget. If a controlled browser timer should complete in under one second, a five-second script timeout creates room for CI scheduling while still failing promptly. If the operation depends on a product request with a known service objective, align the timeout with that objective and collect network evidence when it fails. Do not choose an extremely long value to make a flaky hook disappear.

Selenium's Java API documentation warns that asynchronous scripts generally require an explicit script timeout. Relying on a default is brittle across bindings, drivers, and framework configuration. Set it in driver creation or immediately before a specialized command. If a test temporarily changes it, restore the framework's standard value in a finally block so later tests do not inherit an unexpected budget.

A ScriptTimeoutException says only that the callback was not observed before the timeout. Possible causes include slow work, an exception before callback invocation, a never-settling Promise, a lost event, navigation that destroyed the context, or code that accidentally treated a supplied argument as the callback.

4. A Runnable Java executeAsyncScript Test

This JUnit Jupiter example opens a self-contained data page, schedules a browser timer, returns a structured object, and asserts it in Java. Selenium Manager can resolve the browser driver in a normal Selenium 4 setup when a supported local browser is available.

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.time.Duration;
import java.util.Map;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

class ExecuteAsyncScriptTest {
  private WebDriver driver;

  @BeforeEach
  void startBrowser() {
    driver = new ChromeDriver();
    driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(5));
    driver.get("data:text/html,<title>Async test</title><main>Ready</main>");
  }

  @AfterEach
  void stopBrowser() {
    if (driver != null) driver.quit();
  }

  @Test
  void receivesAResultFromBrowserTimer() {
    JavascriptExecutor js = (JavascriptExecutor) driver;

    Object raw = js.executeAsyncScript("""
        const input = arguments[0];
        const delayMs = arguments[1];
        const done = arguments[arguments.length - 1];

        setTimeout(() => {
          done({
            ok: true,
            original: input,
            normalized: input.trim().toLowerCase()
          });
        }, delayMs);
        """, "  QAJobFit  ", 100);

    Map<?, ?> result = (Map<?, ?>) raw;
    assertEquals(Boolean.TRUE, result.get("ok"));
    assertEquals("  QAJobFit  ", result.get("original"));
    assertEquals("qajobfit", result.get("normalized"));
    assertTrue(result.containsKey("normalized"));
  }
}

The supplied arguments occupy indexes 0 and 1. The callback is still read from the last index, which makes the code resilient when you add or remove ordinary arguments. The JavaScript object crosses the WebDriver protocol as a map-like value, so Map is a safe first cast. Validate its shape before converting it into a domain record.

The example is asynchronous for a real reason: completion occurs in a later event-loop task. It does not use a sleep in Java, and the test fails with a bounded script timeout if the callback never arrives.

5. Pass Arguments and Convert Return Values Safely

Selenium transports a defined set of JSON-compatible values plus element references. From Java, common arguments include String, Boolean, Number, WebElement, and lists composed of supported values. In JavaScript they appear in the same order through arguments. Do not interpolate test data into script source. Passing values as arguments avoids quoting bugs and keeps script logic readable.

WebElement status = driver.findElement(By.id("status"));
Object raw = js.executeAsyncScript("""
    const element = arguments[0];
    const expected = arguments[1];
    const done = arguments[arguments.length - 1];

    const observer = new MutationObserver(() => {
      if (element.textContent.trim() === expected) {
        observer.disconnect();
        done({matched: true, text: element.textContent.trim()});
      }
    });
    observer.observe(element, {childList: true, subtree: true});
    setTimeout(() => element.textContent = expected, 100);
    """, status, "complete");

A WebElement argument is unwrapped to its corresponding DOM element in the script. A DOM element supplied to the callback is wrapped back into a WebElement. Arrays become Java List values, object literals become Map values, booleans become Boolean, and null becomes null. Numeric wrapper details can vary with the value, so cast to Number first when the distinction between integral and decimal values is not central, then call longValue or doubleValue with an explicit expectation.

Keep callback payloads small. Returning a large application state object increases protocol work and couples the test to internals. Prefer a result envelope with fields such as ok, value, error, and diagnostic. Never return cyclic JavaScript objects, functions, symbols, or arbitrary platform objects that cannot be serialized.

6. Bridge Promises, fetch, and async Functions

executeAsyncScript does not complete merely because the script returns a Promise. Bridge the Promise to the injected callback with then and catch, or use an async immediately invoked function that calls the callback in its success and error paths.

Object raw = js.executeAsyncScript("""
    const done = arguments[arguments.length - 1];

    (async () => {
      try {
        const value = await Promise.resolve({name: 'qa', active: true});
        done({ok: true, value});
      } catch (error) {
        done({
          ok: false,
          error: String(error && error.message ? error.message : error)
        });
      }
    })();
    """);

Map<?, ?> result = (Map<?, ?>) raw;
if (!Boolean.TRUE.equals(result.get("ok"))) {
  throw new AssertionError("Browser async work failed: " + result.get("error"));
}

For fetch, apply the same shape: await fetch, check response.ok, read the intended body, and call done. Browser same-origin and content security policies still apply. executeAsyncScript runs inside the page, not outside browser security. A cross-origin request can fail even when the Java test process could call the URL directly. If your goal is API verification or test data setup, an HTTP client in Java is usually clearer and easier to observe.

Always settle the callback for controlled failure. If catch only throws a JavaScript Error, WebDriver may report a JavaScript exception or may wait until timeout depending on where and how the error occurs. Returning {ok: false, error: ...} makes application-level failures explicit. Do not include secrets or full response bodies in that payload.

7. Wait for Browser Events Without Leaking Listeners

An event listener is a legitimate executeAsyncScript use when the event is not conveniently observable in the DOM. Register the listener before triggering the behavior, use the once option when appropriate, clean up on every completion path, and add an internal deadline shorter than the WebDriver script timeout so you can return a meaningful error.

Map<?, ?> result = (Map<?, ?>) js.executeAsyncScript("""
    const eventName = arguments[0];
    const internalMs = arguments[1];
    const done = arguments[arguments.length - 1];
    let settled = false;

    const finish = value => {
      if (settled) return;
      settled = true;
      window.removeEventListener(eventName, onEvent);
      clearTimeout(timer);
      done(value);
    };
    const onEvent = event => finish({ok: true, detail: event.detail});
    const timer = setTimeout(
      () => finish({ok: false, error: 'event deadline exceeded'}),
      internalMs
    );

    window.addEventListener(eventName, onEvent, {once: true});
    setTimeout(() => {
      window.dispatchEvent(new CustomEvent(eventName, {detail: 'received'}));
    }, 100);
    """, "qa:ready", 1000);

The settled guard prevents a late timer and an event from calling done twice. WebDriver uses the first callback result, but double completion is a design smell and may leave listeners or timers behind. Cleanup matters because global page objects survive until navigation, and one test hook can influence another command in the same session.

For user-visible events, prefer a DOM state wait. If an upload finishes and displays a status, wait for the status. An internal custom event is appropriate only when that event itself is part of a supported test contract or an instrumentation seam.

8. Handle Errors, Timeouts, and Navigation

Separate three failure layers. A WebDriver ScriptTimeoutException means the completion callback was not observed within the session timeout. A JavascriptException means script evaluation failed in a way the driver reported. A structured {ok: false} callback means your script completed and deliberately reported an application or operation failure. Catch them at the layer where you can add evidence and preserve the original cause.

try {
  Object result = js.executeAsyncScript(script, arguments);
  // Validate the returned envelope here.
} catch (org.openqa.selenium.ScriptTimeoutException error) {
  byte[] screenshot = ((org.openqa.selenium.TakesScreenshot) driver)
      .getScreenshotAs(org.openqa.selenium.OutputType.BYTES);
  System.err.println("Async script timed out at " + driver.getCurrentUrl()
      + ", screenshot bytes=" + screenshot.length);
  throw error;
}

Do not immediately rerun an asynchronous script after a timeout. The browser work might still complete, and a second execution could register duplicate listeners or issue another request. First inspect state and determine whether the operation is idempotent. Navigation is especially important: if the page changes before callback execution, the old JavaScript realm can be destroyed and no callback will reach the command.

Place an internal timeout inside event or Promise wrappers when you can produce a better diagnostic than the outer protocol timeout. Keep the WebDriver timeout slightly larger so the internal deadline has time to call done. The outer timeout remains the safety net for coding mistakes and lost contexts.

Browser console logs and application telemetry are valuable for rejected Promises, content security violations, and cross-origin failures. Capture them according to browser and grid support rather than assuming every driver exposes identical logging.

9. Use Browser-Side Polling Only When It Adds Value

You can implement polling inside executeAsyncScript, but WebDriverWait is generally more maintainable for DOM and application state because its condition is Java code and its timeout integrates with test reporting. Browser-side polling makes sense when the predicate depends on a browser-only object that is cheap to inspect in the page and has no stable DOM representation.

A bounded browser poll should evaluate immediately, schedule modest intervals, clear its timer, and return diagnostics:

Map<?, ?> result = (Map<?, ?>) js.executeAsyncScript("""
    const deadlineMs = arguments[0];
    const done = arguments[arguments.length - 1];
    const started = performance.now();

    const check = () => {
      const ready = window.__qaHook && window.__qaHook.ready === true;
      if (ready) {
        done({ok: true, elapsedMs: Math.round(performance.now() - started)});
        return;
      }
      if (performance.now() - started >= deadlineMs) {
        done({ok: false, error: 'qa hook did not become ready'});
        return;
      }
      setTimeout(check, 50);
    };
    check();
    """, 1000);

An application hook such as __qaHook should be an intentional, documented test seam, not an accidental production global. Keep business assertions on user-observable results even when the hook helps synchronize a difficult integration.

For standard UI conditions, use the Selenium explicit waits guide. It provides clearer polling control through FluentWait without embedding a second mini wait framework in JavaScript.

10. Design Reusable Java Helpers Without Hiding Semantics

A small helper can centralize callback envelopes and timeout configuration, but it should not accept arbitrary scripts from every page object. Arbitrary script utilities spread internal DOM coupling and make failures hard to classify. Prefer feature-specific methods such as awaitEditorReadyHook or collectPerformanceEntry when browser script access is truly required.

A typed record can validate the generic Map boundary:

record AsyncResult(boolean ok, String value, String error) {
  static AsyncResult from(Object raw) {
    if (!(raw instanceof Map<?, ?> map)) {
      throw new IllegalArgumentException("Expected a map result, got " + raw);
    }
    boolean ok = Boolean.TRUE.equals(map.get("ok"));
    String value = map.get("value") == null ? null : map.get("value").toString();
    String error = map.get("error") == null ? null : map.get("error").toString();
    return new AsyncResult(ok, value, error);
  }
}

Keep timeout ownership explicit. A driver factory can set a standard script timeout. A helper that needs a special value can save the framework policy in configuration, set the special timeout, execute, and restore the standard value. Selenium does not expose a simple getter for every timeout policy in a way that should replace framework configuration, so keep the intended values in your test configuration.

Sanitize scripts and arguments in logs. Script arguments may contain credentials, tokens, or customer data. Log an operation name and safe metadata instead of dumping every value. Treat browser-returned error text as untrusted diagnostic data.

11. Selenium executeAsyncScript Java Decision Checklist

Before using the API, ask:

  1. Is the required state observable through a stable WebDriver element or URL condition?
  2. Is the asynchronous browser operation part of a supported test seam?
  3. Does the script run in the correct window and frame?
  4. Is scriptTimeout explicitly configured with a bounded Duration?
  5. Are ordinary values passed as arguments rather than interpolated into source?
  6. Is the injected callback read from the final arguments index?
  7. Does every success and controlled failure path invoke it?
  8. Is completion guarded so it happens once?
  9. Are event listeners, observers, and timers cleaned up?
  10. Is the callback payload small, serializable, and shape-validated in Java?
  11. Could navigation destroy the script context?
  12. Is retry safe if the command times out after browser work began?

If the answer to the first question is yes, favor WebDriverWait. If the operation is API setup, favor a Java HTTP client. executeAsyncScript is most useful in the narrow middle: asynchronous work genuinely owned by the active browser context and not cleanly exposed through the user interface.

12. Testing and CI Practices for Async Scripts

Make asynchronous script tests deterministic. Use controlled inputs, bounded timers, a known browsing context, and explicit result assertions. Avoid external demo sites, public APIs, and third-party analytics in unit-like examples because their availability is unrelated to your product.

On a Selenium Grid, the Java command crosses the network to the remote end, the browser executes the script, and the result travels back. The script timeout governs browser command completion, while your test runner or infrastructure may impose additional outer timeouts. Set the outer test timeout larger than the WebDriver timeout so Selenium can return the more specific error and your cleanup can run.

Run scripts against each supported browser if they use browser APIs with compatibility differences. Feature-detect optional APIs inside the script and return a clear unsupported result. Do not fabricate a polyfill in the test unless production also uses it.

Keep async script usage visible in code review. Reviewers should be able to answer why JavaScript is necessary, what completes it, what data crosses the boundary, and how failure is diagnosed. A short script with a precise contract is easier to maintain than a general browser automation layer written inside strings.

For broader framework boundaries, see Selenium framework design in Java. Browser-side hooks should remain a small, intentional layer beside page components and business assertions.

Interview Questions and Answers

Q: How does executeAsyncScript know that JavaScript is complete?

Selenium injects a callback as the final JavaScript argument. The script must invoke that callback, and the first callback value becomes the Java return value. Returning from the script or returning a Promise does not satisfy this specific contract.

Q: What happens if the callback is never called?

The WebDriver command waits until the configured asynchronous script timeout, then throws ScriptTimeoutException. I inspect exceptions, pending Promises, lost events, navigation, and callback indexing before increasing the timeout.

Q: How is executeAsyncScript different from executeScript?

executeScript completes from the synchronous return of the JavaScript function body. executeAsyncScript waits for an injected callback, which allows timers, events, and Promises to settle. Both execute in the current window or frame.

Q: How do you pass a WebElement into asynchronous JavaScript?

Pass the WebElement as an argument after the script string. Selenium unwraps it to the corresponding DOM element, available at its arguments index. This is safer than building a selector or data value into the script source.

Q: How would you return an error from the script?

I call the completion callback with a structured envelope such as {ok: false, error: message}. Java validates the Map and throws an assertion or domain-specific error. That keeps controlled failures distinct from protocol timeouts and JavaScript syntax errors.

Q: Would you use executeAsyncScript to wait for an element?

Usually no. WebDriverWait with ExpectedConditions is clearer for visible UI state and produces familiar Selenium diagnostics. I reserve browser-side asynchronous scripts for browser-owned state or an intentional test hook that WebDriver cannot observe cleanly.

Q: Is it safe to retry after ScriptTimeoutException?

Not automatically. The browser operation may still have completed or may complete later, so a retry could duplicate listeners, requests, or mutations. I determine the resulting state and idempotency before re-execution.

Q: How do Promises work with executeAsyncScript?

I attach then and catch to the Promise, or await it inside an async function, and call the injected callback from both success and controlled failure paths. The callback remains required. I also add bounded cleanup for operations that may never settle.

Common Mistakes

  • Using the wrong callback index: The callback comes after all user-supplied arguments.
  • Returning a value instead of calling done: An ordinary return does not complete executeAsyncScript.
  • Returning a Promise without bridging it: Promise settlement must invoke the callback.
  • Leaving script timeout implicit: The resulting behavior can fail immediately or inherit an unsuitable framework value.
  • Calling the callback twice: Racing timers and events need a settled guard and cleanup.
  • Ignoring rejection paths: A rejected Promise can become a vague timeout instead of a useful result.
  • Interpolating values into JavaScript: Pass supported values as arguments to avoid quoting and injection errors.
  • Returning non-serializable objects: Functions, cyclic data, and many platform objects cannot cross WebDriver cleanly.
  • Using browser fetch for test setup: A Java API client is usually clearer and is not constrained by page origin policy.
  • Replacing WebDriverWait with script polling: UI state is better expressed as a normal Selenium condition.
  • Retrying a timed-out side effect: The first browser operation may have partially or fully completed.
  • Forgetting browsing context: The script runs only in the currently selected window and frame.

Conclusion

The reliable selenium executeAsyncScript java pattern has four parts: configure scriptTimeout, retrieve the injected final callback, invoke it once on every controlled completion path, and validate a small serializable result in Java. Promise syntax does not remove the callback requirement, and a timeout should trigger evidence collection rather than an automatic retry.

Use the runnable timer example to establish the contract in your framework. Then keep real async scripts narrow, named, and tied to browser state that ordinary WebDriver conditions cannot express more clearly.

Interview Questions and Answers

Explain the executeAsyncScript callback contract.

Selenium appends a callback to the JavaScript arguments. The script calls that callback when asynchronous work finishes, and its first argument becomes the Java return value. If callback invocation never occurs, the WebDriver script timeout ends the command.

How do executeScript and executeAsyncScript differ?

executeScript uses the synchronous JavaScript return value. executeAsyncScript waits for an injected completion callback and therefore supports timers, events, and Promise bridges. Both operate in the current browsing context.

How do you configure the timeout for an asynchronous script in Java?

I call driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(...)) before execution. I choose a bounded value based on the operation and keep the test runner timeout larger so Selenium can report and clean up normally.

How do you make callback handling reliable?

I read the callback from the last argument, route success and controlled failure to it, guard against double completion, and clean up timers, observers, and listeners. I return a small structured envelope that Java validates.

What Java type receives a JavaScript object?

It is returned as an Object whose runtime value can be treated as a Map for a plain object. I begin with Map<?, ?> because protocol values are dynamic, validate the shape, and then create a typed record or domain result.

When would you prefer WebDriverWait?

I prefer WebDriverWait for elements, URLs, titles, and other observable UI state. It communicates user-facing readiness and avoids embedding polling logic in a script string. executeAsyncScript is for browser-owned async behavior that lacks a clean WebDriver condition.

Why is retrying a script timeout risky?

Timeout does not prove the browser operation had no effect. A late callback, request, mutation, or registered listener may still exist. I inspect resulting state and confirm idempotency before any controlled retry.

How would you debug a Promise that causes a timeout?

I add explicit then and catch completion, an internal deadline, and a structured error envelope. I inspect browser console and network evidence, confirm the current frame, and check whether navigation destroys the JavaScript context.

Frequently Asked Questions

How do I use executeAsyncScript in Selenium Java?

Cast WebDriver to JavascriptExecutor, configure scriptTimeout with a Duration, and call executeAsyncScript. In the JavaScript, retrieve arguments[arguments.length - 1] and invoke that callback with the result.

What is the last argument in executeAsyncScript?

Selenium injects a completion callback as the final JavaScript argument. Any Java values you pass occupy earlier indexes, so reading the callback from the last index is the safest pattern.

Why does executeAsyncScript throw ScriptTimeoutException?

The callback was not observed before the configured script timeout. The work may be slow, a Promise may never settle, an exception may bypass completion, navigation may destroy the context, or the callback index may be wrong.

Can executeAsyncScript return a Java Map?

Yes. Pass a plain JavaScript object to the callback and Selenium returns a map-like Java value. Cast initially to Map<?, ?> and validate keys and value types before mapping it to a domain object.

Does Selenium automatically wait for a Promise?

Do not rely on a returned Promise for executeAsyncScript. Attach then and catch, or await the Promise inside an async function, and explicitly call the injected completion callback.

What is the difference between scriptTimeout and WebDriverWait?

scriptTimeout bounds one asynchronous JavaScript command in the browser. WebDriverWait repeatedly evaluates a Java condition until UI or application state satisfies it, and is usually preferable for element readiness.

Can executeAsyncScript make cross-origin fetch requests?

It runs inside the page and remains subject to browser origin and content security rules. For API testing or data setup, a Java HTTP client is generally a better fit.

Related Guides