1️⃣ What is AJAX?

AJAX (Asynchronous JavaScript and XML) is a technique used in web applications to send and receive data from a server without reloading the entire page. It is commonly used in dynamic websites where elements update in real-time without requiring a full page refresh.

2️⃣ Why is AJAX Handling Important in Selenium?

Selenium WebDriver interacts with web elements based on DOM state. However, since AJAX updates elements asynchronously, the elements may not be immediately available when Selenium attempts to interact with them.
This results in NoSuchElementException or StaleElementReferenceException.

To handle AJAX calls properly, we can use Explicit Waits, Fluent Waits, or JavaScriptExecutor.


3️⃣ How JavaScriptExecutor Helps in Handling AJAX?

JavaScriptExecutor in Selenium allows us to execute JavaScript code directly in the browser.
This is useful when AJAX elements take time to appear or update.

JavaScriptExecutor Syntax in Selenium

JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("return document.readyState").equals("complete");

βœ” This ensures that the AJAX request has completed and the page is fully loaded.


4️⃣ Methods to Handle AJAX Calls in Selenium

πŸ“Œ Method 1: Using document.readyState

document.readyState indicates whether the webpage has completely loaded. It returns one of the following values:

  • "loading" – The page is loading.
  • "interactive" – The document has been loaded but external resources (AJAX requests) are still loading.
  • "complete" – The page and AJAX calls have fully loaded.

Example Code

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class HandleAjaxWithJSExecutor {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        driver.get("https://example.com");

        // Create a JavaScriptExecutor instance
        JavascriptExecutor js = (JavascriptExecutor) driver;

        // Wait for AJAX to complete
        while (!(js.executeScript("return document.readyState").toString().equals("complete"))) {
            System.out.println("Waiting for AJAX to load...");
        }

        System.out.println("AJAX calls completed!");
        driver.quit();
    }
}

βœ” This ensures that AJAX requests are completed before proceeding.


πŸ“Œ Method 2: Using jQuery.active (for jQuery-based AJAX calls)

If the website uses jQuery for AJAX requests, we can check if jQuery.active is 0, meaning no AJAX calls are active.

Example Code

JavascriptExecutor js = (JavascriptExecutor) driver;
while ((Boolean) js.executeScript("return jQuery.active != 0")) {
    System.out.println("Waiting for AJAX calls to complete...");
}
System.out.println("AJAX requests completed!");

βœ” This is specific to websites using jQuery AJAX.


πŸ“Œ Method 3: Using Explicit Wait for AJAX Elements

Instead of waiting for the entire page to load, we can wait for specific AJAX elements.

Example Code

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.time.Duration;

public class HandleAjaxExplicitWait {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        driver.get("https://example.com");

        // Wait until a specific AJAX element is visible
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        WebElement ajaxElement = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("ajaxElement")));

        // Perform actions after AJAX is loaded
        ajaxElement.click();
        System.out.println("AJAX Element clicked!");

        driver.quit();
    }
}

βœ” This ensures that Selenium waits for AJAX elements to appear before interacting with them.


πŸ“Œ Method 4: Using Fluent Wait for Dynamic AJAX Elements

AJAX elements may load at random intervals, so Fluent Wait is useful for dynamically polling elements.

Example Code

import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.FluentWait;
import java.time.Duration;
import java.util.function.Function;

public class HandleAjaxFluentWait {
    public static void main(String[] args) {
        WebDriver driver = new ChromeDriver();
        driver.get("https://example.com");

        FluentWait<WebDriver> wait = new FluentWait<>(driver)
                .withTimeout(Duration.ofSeconds(15))
                .pollingEvery(Duration.ofSeconds(2))
                .ignoring(Exception.class);

        WebElement ajaxElement = wait.until(new Function<WebDriver, WebElement>() {
            public WebElement apply(WebDriver driver) {
                return driver.findElement(By.id("ajaxElement"));
            }
        });

        ajaxElement.click();
        System.out.println("AJAX Element Clicked!");

        driver.quit();
    }
}

βœ” Fluent Wait continuously checks for the AJAX element instead of waiting for a fixed time.


5️⃣ Handling Dynamic AJAX Elements

πŸ”Ή Challenge: Some AJAX elements change IDs or load dynamically.

πŸ”Ή Solution: Use CSS Selectors, XPath with contains(), or JavaScriptExecutor.

πŸ“Œ Example: Handling Dynamic Elements with XPath

WebElement dynamicElement = driver.findElement(By.xpath("//div[contains(@class,'ajax-loaded')]"));

βœ” This works even if the class changes dynamically.

πŸ“Œ Example: Using JavaScriptExecutor to Click an AJAX Element

JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].click();", driver.findElement(By.id("ajaxButton")));

βœ” This ensures that even hidden AJAX elements are clicked.


6️⃣ Summary

Method Use Case
document.readyState Waits for the entire page (including AJAX) to load.
jQuery.active Waits for jQuery-based AJAX requests to complete.
Explicit Wait Waits for specific AJAX elements to appear.
Fluent Wait Dynamically waits for changing AJAX elements.
JavaScriptExecutor Executes JavaScript for dynamic AJAX handling.

7️⃣ Final Thoughts

βœ” Handling AJAX elements is crucial for Selenium automation.
βœ” Using JavaScriptExecutor, Explicit Waits, and Fluent Waits ensures stability.
βœ” For dynamic AJAX elements, use XPath, CSS Selectors, and JavaScript clicks.


πŸ“Œ 1. AJAX Call Lifecycle Explanation

Before handling AJAX in Selenium, it's important to understand how AJAX works:

πŸ”Ή How AJAX Updates Elements Without Page Refresh

1️⃣ User action triggers AJAX request (e.g., clicking a button).
2️⃣ AJAX sends a request to the server asynchronously.
3️⃣ The server processes the request and sends a response.
4️⃣ AJAX updates the webpage dynamically without refreshing it.

πŸ”Ή Visual Representation of AJAX Working

Here's an illustration that shows AJAX working behind the scenes:



πŸ“Œ 2. Detecting AJAX Completion Using JavaScriptExecutor

πŸ”Ή Screenshot: document.readyState Method

This JavaScriptExecutor method checks when the page, including AJAX requests, has fully loaded.

JavascriptExecutor js = (JavascriptExecutor) driver;
while (!(js.executeScript("return document.readyState").toString().equals("complete"))) {
    System.out.println("Waiting for AJAX to load...");
}
System.out.println("AJAX calls completed!");

βœ… Below is a screenshot of how the browser console shows document.readyState values:

document.readyState Console

βœ” This ensures Selenium waits until AJAX requests are completed.


πŸ“Œ 3. Handling AJAX Calls Using jQuery

πŸ”Ή Screenshot: jQuery.active Property

Many modern websites use jQuery AJAX calls. To check if AJAX calls are active, use:

JavascriptExecutor js = (JavascriptExecutor) driver;
while ((Boolean) js.executeScript("return jQuery.active != 0")) {
    System.out.println("Waiting for AJAX calls to complete...");
}
System.out.println("AJAX requests completed!");

βœ… Below is an example of a jQuery AJAX loader indicator:
(Before the AJAX call completes, a loader appears on the webpage.)

jQuery AJAX Loading

βœ” This helps in waiting for AJAX requests before interacting with elements.


πŸ“Œ 4. Explicit Wait for AJAX Elements

πŸ”Ή Screenshot: Waiting for an AJAX Element

Instead of waiting for the entire page, we can wait for specific AJAX elements.

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement ajaxElement = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("ajaxElement")));
ajaxElement.click();

βœ… Below is an example of how elements appear after an AJAX call is completed:
AJAX Content Loading

βœ” This method ensures Selenium waits for dynamic elements before interacting with them.


πŸ“Œ 5. Fluent Wait for Unpredictable AJAX Elements

πŸ”Ή Screenshot: Using Fluent Wait

If AJAX elements load at random intervals, Fluent Wait keeps polling until they appear.

FluentWait<WebDriver> wait = new FluentWait<>(driver)
        .withTimeout(Duration.ofSeconds(15))
        .pollingEvery(Duration.ofSeconds(2))
        .ignoring(Exception.class);

WebElement ajaxElement = wait.until(driver -> driver.findElement(By.id("ajaxElement")));
ajaxElement.click();

βœ… Below is an example of AJAX elements loading at different times:
(Some items load faster than others due to different AJAX requests.)
Dynamic AJAX Loading

βœ” This ensures Selenium waits dynamically instead of using fixed sleep times.


πŸ“Œ 6. Handling Dynamic AJAX Elements Using JavaScript Click

Sometimes, AJAX elements remain hidden, and Selenium cannot click them normally.

JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("arguments[0].click();", driver.findElement(By.id("ajaxButton")));

βœ… Below is an example of hidden AJAX elements appearing on user action:
Hidden AJAX Elements

βœ” JavaScriptExecutor allows Selenium to click even hidden or dynamically generated AJAX elements.


πŸ“Œ 7. Summary Table

Method Use Case
document.readyState Wait for full page load, including AJAX.
jQuery.active Wait for jQuery AJAX calls to finish.
Explicit Wait Wait for specific AJAX elements.
Fluent Wait Dynamically wait for AJAX elements to appear.
JavaScriptExecutor Handle hidden AJAX elements.

πŸ“Œ 8. Conclusion

  • AJAX allows web pages to load dynamically, making Selenium automation challenging.
  • JavaScriptExecutor, Explicit Wait, and Fluent Wait help handle AJAX efficiently.
  • Use jQuery.active for jQuery-powered AJAX requests.
  • JavaScriptExecutor clicks help when AJAX elements remain hidden.