Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Learn how to perform Salesforce Selenium testing in 2026. Covers stable locators, Shadow DOM, MFA, local and cloud execution on TestMu AI with KaneAI. Java code included.

Saniya Gazala
April 29, 2025
On This Page
Every time Salesforce ships a seasonal release, something breaks in your test suite. A CSS class gets renamed. A Lightning component renders differently. A locator that worked perfectly last quarter now points to nothing. Somewhere on your team, a QA engineer spends three days manually re-clicking the same regression checklist that should have been automated months ago.
That is the reality of testing Salesforce in 2026. The platform updates itself three times a year, and automation testing cannot keep pace without the right strategy.
Salesforce Selenium testing is how high-performing QA teams break that cycle. But dynamic element IDs, asynchronous Lightning rendering, loading overlays, and Shadow DOM in Lightning Web Components make Salesforce a harder automation target than any standard web application.
TestMu AI (formerly LambdaTest), the world's first full-stack Agentic Quality Engineering Platform, is built for exactly this. Its GenAI-native agent KaneAI lets you describe a Salesforce scenario in plain English and export production-ready Selenium code without writing a single locator yourself.
Overview
What Is Salesforce Selenium Testing?
It is the use of Selenium WebDriver to automate browser-level checks against a Salesforce Lightning org. Since the platform pushes three mandatory releases a year while teams keep shipping custom Apex, flows, and components, manual regression simply cannot stay current, and automated browser testing fills that gap.
Why Is Salesforce Tougher to Automate with Selenium Than a Standard Web App?
Lightning Experience adds obstacles that ordinary web pages never present. Each one has a proven fix, but together they make Salesforce a demanding automation target:
How Do You Create and Run Salesforce Selenium Tests Locally?
A lead-creation flow is a representative scenario because it touches a dynamic button ID, asynchronous form fields, an overlay-blocked Save, and an async success toast all at once. To run such tests on your machine, you generally need Java 17 or later, Maven, and Chrome, with sandbox credentials stored as environment variables and WebDriverManager handling driver setup. Local runs let you debug locators and Lightning-specific behavior against a real org before wiring everything into a pipeline.
Where Do Cloud-Based Platforms Add Value to Salesforce Testing?
Local execution runs into MFA prompts, expiring sessions, dynamic-DOM flakiness, and limited scale, which makes unattended runs hard to sustain. Moving to a test automation cloud such as TestMu AI pairs scalable execution infrastructure with intelligent automation, including the KaneAI agent that turns plain-English descriptions into tests, while smoothing out authentication, session consistency, and cross-browser coverage.
Salesforce Selenium testing is the use of Selenium WebDriver to automate browser-based validation of your Salesforce Lightning org across its frequent platform releases.
As Salesforce ships three mandatory platform releases every year, and your team pushes custom Apex, flows, and Lightning components in between, manual regression testing can no longer keep pace.
| 150,000+ | 3x/year | 84% |
|---|---|---|
| Companies run on Salesforce in 2025 ibirdsservices.com, Jan 2026 | mandatory Salesforce platform releases Salesforce release calendar | of companies still rely on manual testing Synebo, Oct 2025 |
According to Synebo's 2025 Salesforce testing guide, 84 percent of companies still rely on manual testing despite Salesforce updating its platform three times per year.
The Capgemini World Quality Report found that only 15 to 20 percent of regression testing is actually automated, making it the most underserved test type for the scenario most in need of it.
Salesforce Selenium testing closes that gap by turning a 30-hour manual regression cycle into a repeatable automated suite.
To gain deeper practical insight into Salesforce Selenium testing, it is helpful to follow a Salesforce testing tutorial.
Note: Automate your Salesforce testing workflow and achieve faster, reliable, and scalable test automation. Book a KaneAI Demo.
Salesforce has two testing layers: Apex validates server-side logic such as triggers and SOQL, while Selenium validates what users see and do in the browser.
Before writing any test code, you need to understand which layer each tool owns.
Salesforce testing tools typically span multiple layers of the testing stack, including unit testing tools for Apex validation, Selenium-based tools for UI automation, and cloud platforms that support scalable end-to-end execution across Salesforce environments.
Apex testing validates server-side Salesforce logic, including triggers, classes, batch jobs, and governor limit compliance. Salesforce enforces a minimum of 75 percent Apex code coverage before any Apex can be deployed to production. This threshold is checked at the infrastructure level, and a single failing test class can block your entire deployment pipeline.
Note: Deployment blocker: Salesforce refuses to deploy Apex to production if org-wide code coverage falls below 75 percent. Target 85 percent or above to maintain a safe buffer.
Selenium WebDriver covers everything the Apex framework cannot reach: the browser. It validates Lightning page rendering, form interactions, navigation flows, toast confirmations, and cross-browser consistency.
Salesforce test automation with Selenium is recommended for its multi-browser support, CI/CD compatibility with Jenkins and Maven, and its ability to validate complete end-to-end user journeys across multiple Salesforce objects.
| Layer | Tool | Tests What | Enforced By |
|---|---|---|---|
| Server logic | Apex @isTest | Triggers, classes, SOQL, DML, governor limits | Salesforce platform. Required at deployment. |
| Browser and UI | Selenium | Lightning pages, forms, LWC components, navigation | Your QA process. Strongly recommended. |
| Cross-browser | Selenium Grid | Rendering across Chrome, Firefox, Edge, Safari | Your QA process. |
| API integration | REST + Apex | Data flows between Salesforce and external systems | Your QA process. |
Salesforce Lightning Experience introduces challenges that do not exist in standard web applications: dynamic content without fixed IDs, dynamic tables, iFrame navigation, and Shadow DOM. Each challenge has a working solution, and this guide covers all four with working Java code.
Salesforce Lightning generates element IDs at runtime using patterns like 940:1376;a. These IDs change on every page load and across every Salesforce release. As a result, any Selenium locator built on these dynamic IDs fails within the same session, making it one of the primary causes of test instability in Salesforce automation frameworks.
This becomes especially problematic after seasonal Salesforce releases, where even previously working test suites can break without any changes in the application logic.
By.id locators that rely on auto-generated Lightning IDs are unstable and break on every page refresh. These failures cannot be resolved using explicit waits or retry logic because the underlying identifiers are not consistent.These attributes are designed to remain consistent across sessions and Salesforce releases, making them far more reliable for building Selenium test automation frameworks.
Among these, aria-label is particularly important because it is part of Salesforce's accessibility layer and is less likely to change compared to dynamically generated DOM attributes.
It provides a stable and meaningful way to identify UI elements in Lightning applications, and it also improves accessibility by assigning a readable name to elements that do not have visible labels, such as icon-only buttons or input fields without captions.
Lightning Experience loads components via JavaScript and AJAX calls. Elements appear at different times after the page URL loads, which means a test that reaches for an element immediately after navigation will find it missing or in an intermediate state. This produces failures such as StaleElementReferenceException and NoSuchElementException, which are often misdiagnosed as locator problems.
One of the most common ways to handle this issue is by properly implementing explicit waits using ExpectedConditions in Selenium, which allows the test to wait until the element is present, visible, or clickable before interacting with it. You can explore this in detail in how to handle NoSuchElementException in Selenium using ExpectedConditions.
Thread.sleep calls with Selenium WebDriverWait plus ExpectedConditions. Set the global implicit wait to 5 seconds maximum.When you click Save on a Salesforce Lightning form, a spinner overlay renders on top of the page. Selenium detects the Save button as present and clickable underneath the overlay, attempts the click, and receives an ElementClickInterceptedException. Standard elementToBeClickable does not detect that an overlay is covering the target.
ElementClickInterceptedException.FluentWait with ElementClickInterceptedException ignored. Poll the overlay CSS selector before returning the target element. This kind of failure is common in UI automation when overlays interfere with user actions, and having a strong understanding of how to handle ElementClickInterceptedException in Selenium is important.Lightning Web Components encapsulate their markup inside shadow roots. Standard CSS selectors and XPath expressions cannot cross shadow boundaries. Since Salesforce moved to native shadow DOM in the Spring 24 release, older polyfill-based workarounds no longer work, and teams that built locators relying on the synthetic shadow leak saw tests break without any code change on their side.
getShadowRoot method for single shadow boundaries. Use JavaScript executor for nested shadow roots.To create a Lead in Salesforce Lightning, log into a sandbox, open the Leads list, click New, fill the name and company fields, click Save past the loading overlay, then check the success toast.
Creating a Lead in Salesforce Lightning is one of the most common real-world scenarios used to validate Selenium automation frameworks. It reflects how users interact with dynamic CRM interfaces that rely heavily on asynchronous loading and JavaScript-driven components.
This scenario exercises every major Salesforce Selenium testing challenge simultaneously. The New button uses a dynamic ID. The form inputs render asynchronously. The Save button is blocked by a loading overlay. The success toast appears asynchronously after submission. Automate this correctly, and you have the patterns for any Salesforce flow.
| Field | Value |
|---|---|
| Scenario Name | Create a New Lead in Salesforce Lightning Experience |
| Precondition | Logged into a Salesforce Developer Sandbox. Test user has Leads access. MFA is disabled on the test account. |
| Step 1 | Navigate to the Leads list view using the direct URL |
| Step 2 | Click the New button using a stable title attribute locator |
| Step 3 | Fill First Name, Last Name, and Company using name attribute locators |
| Step 4 | Click Save using FluentWait to handle the loading overlay |
| Step 5 | Assert the success toast message contains 'was created.' |
| Expected Result | Toast confirms Lead creation. Browser redirects to the new Lead detail page. |
Run Salesforce Selenium tests locally with Java, Maven, and Chrome, plus sandbox credentials and WebDriverManager, so you can debug locators and Lightning behavior before adding CI/CD.
Running tests locally lets you quickly debug locator issues, handle Lightning-specific UI behavior, and verify that your test flows work against a real Salesforce org in a controlled environment before integrating them into a CI/CD pipeline.
To run tests locally, you typically need Java 17 or later, Maven, and Google Chrome installed, with Salesforce sandbox credentials stored as environment variables and Selenium WebDriverManager for handling browser driver setup automatically.
You need three Maven dependencies to run Salesforce Selenium tests smoothly.
Make sure you use Selenium 4.x specifically, because methods like getShadowRoot() are not available in older versions.
// pom.xml
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.18.1</version>
</dependency>
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>The Page Object Model (POM) separates locators from test logic. When Salesforce updates a UI element in a seasonal release, you change one file in your page objects directory, not every test method that uses that element.
The LoginPage uses stable IDs because the Salesforce login page is the only place in Lightning where IDs are not auto-generated.
LoginPage.java
// Java: LoginPage.java
package pages;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.*;
import java.time.Duration;
public class LoginPage {
private final WebDriver driver;
private final WebDriverWait wait;
// Login page IDs are stable -- the ONLY safe place for By.id in Lightning
private final By usernameField = By.id("username");
private final By passwordField = By.id("password");
private final By loginButton = By.id("Login");
public LoginPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(20));
}
public void login(String url, String user, String pass) {
driver.get(url);
wait.until(ExpectedConditions.visibilityOfElementLocated(usernameField))
.sendKeys(user);
driver.findElement(passwordField).sendKeys(pass);
driver.findElement(loginButton).click();
}
}LeadsPage.java
// Java: LeadsPage.java
package pages;
import org.openqa.selenium.*;
import org.openqa.selenium.support.ui.*;
import java.time.Duration;
import java.util.List;
public class LeadsPage {
private final WebDriver driver;
private final WebDriverWait wait;
// Stable locators using title and name attributes.
// These survive Spring, Summer, and Winter releases.
// Never use auto-generated IDs like id="940:1376;a".
private final By newButton = By.cssSelector("a[title='New']");
private final By firstName = By.cssSelector("input[name='firstName']");
private final By lastName = By.cssSelector("input[name='lastName']");
private final By company = By.cssSelector("input[name='Company']");
private final By saveButton = By.cssSelector("button[name='SaveEdit']");
private final By toastMsg = By.cssSelector(".toastMessage");
private final By spinner = By.cssSelector(".loadingSpinner,.slds-spinner_container");
public LeadsPage(WebDriver driver) {
this.driver = driver;
this.wait = new WebDriverWait(driver, Duration.ofSeconds(30));
}
public void navigateToLeads() {
// Direct URL navigation -- faster and more stable than the App Launcher.
String base = driver.getCurrentUrl().split("/lightning")[0];
driver.get(base + "/lightning/o/Lead/list");
}
public void clickNew() {
wait.until(ExpectedConditions.elementToBeClickable(newButton)).click();
}
public void fillForm(String fn, String ln, String co) {
wait.until(ExpectedConditions.visibilityOfElementLocated(firstName)).sendKeys(fn);
driver.findElement(lastName).sendKeys(ln);
driver.findElement(company).sendKeys(co);
}
public String saveAndGetToast() {
// FluentWait handles the Lightning overlay that blocks the Save click.
Wait<WebDriver> fw = new FluentWait<>(driver)
.withTimeout(java.time.Duration.ofSeconds(60))
.pollingEvery(java.time.Duration.ofSeconds(2))
.ignoring(ElementClickInterceptedException.class)
.ignoring(NoSuchElementException.class);
fw.until(d -> {
List<WebElement> overlays = d.findElements(spinner);
if (!overlays.isEmpty() && overlays.get(0).isDisplayed()) return null;
return d.findElement(saveButton);
}).click();
// Toast is async -- WebDriverWait is mandatory, not optional.
return wait.until(
ExpectedConditions.visibilityOfElementLocated(toastMsg)).getText();
}
}CreateLeadTest.java — Local ChromeDriver
// Java: CreateLeadTest.java -- LOCAL
package tests;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.*;
import org.testng.Assert;
import org.testng.annotations.*;
import pages.*;
import java.time.Duration;
public class CreateLeadTest {
private WebDriver driver;
private static final String SF_URL = System.getenv("SF_SANDBOX_URL");
private static final String SF_USER = System.getenv("SF_USERNAME");
private static final String SF_PASS = System.getenv("SF_PASSWORD");
@BeforeClass
public void setUp() {
WebDriverManager.chromedriver().setup();
ChromeOptions opts = new ChromeOptions();
opts.addArguments("--incognito"); // Prevents Lightning session restore
opts.addArguments("--disable-notifications");
opts.addArguments("--window-size=1920,1080");
driver = new ChromeDriver(opts);
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(5));
}
@Test
public void testCreateLead() {
new LoginPage(driver).login(SF_URL, SF_USER, SF_PASS);
LeadsPage leads = new LeadsPage(driver);
leads.navigateToLeads();
leads.clickNew();
leads.fillForm("Jane", "Smith", "Acme Corp");
String toast = leads.saveAndGetToast();
Assert.assertTrue(toast.contains("was created"),
"Expected success toast. Got: " + toast);
}
@AfterClass
public void tearDown() { if (driver != null) driver.quit(); }
}Run the Local Test
# Shell: run locally
# macOS / Linux
export SF_SANDBOX_URL="https://yourorg--qa.sandbox.my.salesforce.com"
export SF_USERNAME="[email protected]"
export SF_PASSWORD="yourpassword"
# Windows
set SF_SANDBOX_URL=https://yourorg--qa.sandbox.my.salesforce.com
set [email protected]
set SF_PASSWORD=yourpassword
mvn test -Dtest=CreateLeadTestResult:

While running Salesforce Selenium tests locally is useful for debugging and validation, testers often face several real-world challenges that make local execution unstable and time-consuming.
Cloud platforms improve Salesforce testing by removing local bottlenecks—handling MFA, session consistency, and cross-browser execution at scale—while adding AI-driven automation like KaneAI.
To overcome these limitations, many teams move from local execution to cloud-based testing platforms like TestMu AI. Unlike traditional cloud grids, TestMu AI (formerly LambdaTest) is a full-stack AI-agentic quality engineering platform that combines scalable execution infrastructure with intelligent automation capabilities.
Modern Salesforce test automation tools are increasingly shifting toward cloud-based architectures to support scalable execution, reduce local environment dependencies, and improve cross-browser reliability across Salesforce applications.
This platform offeres KaneAI, an AI testing agent that allows testers to create and execute tests using natural language, significantly reducing the dependency on manual scripting and complex setup.
TestMu AI helps eliminate local execution bottlenecks by providing stable, scalable, and intelligent test environments that handle authentication challenges, session consistency, and cross-browser execution seamlessly.
KaneAI is a Gen-AI testing agent: describe a Salesforce scenario in plain English and it runs the steps in a live browser, generating ready-to-use Selenium, Playwright, or Cypress code.
It is purpose-built for flows like Salesforce lead creation, executing each plain-English step in a real browser before exporting the corresponding production-ready test code.
The exported test already includes a framework-ready structure and smart waits and is immediately compatible with the TestMu AI automation cloud grid.
Each method suits a different team situation. Teams with existing Selenium code can use:
Before any of these approaches stabilize in practice, the underlying UAT environment needs to mirror production with masked data, integrations, and clear entry and exit criteria so business validation runs on the same surface QA is automating against.
This approach allows you to integrate LambdaTest capabilities into your existing Selenium test scripts without major code changes.
By adding the LT:Options configuration inside the browser capabilities, you can enable features such as cloud execution, browser selection, platform configuration, build tracking, network logs, video recording, and debugging support for your Salesforce test automation.
WebDriver instantiation (e.g., ChromeDriver) with RemoteWebDriver pointing to the TestMu AI Selenium Grid URL.LT:Options block to your desired capabilities, specifying the necessary configuration for your test execution.To get your desired capabilities configured correctly, you can use the TestMu AI Automation Capabilities Generator, which provides an intuitive interface to select your browser, platform, and additional options. Once you generate the capabilities, simply copy and paste the code snippet into your test setup.
Describe the scenario in plain English. KaneAI runs it in a live browser and exports Selenium Java, Playwright, or Cypress code that you plug directly into your existing Maven project.
With KaneAI, there is no setup required. You don't need to configure WebDriver, manage dependencies, or manually handle Salesforce login flows. You simply describe what you want to test, and KaneAI takes care of execution.
One of the major pain points in Salesforce Selenium testing is handling MFA authentication, where manual OTP entry or verification interrupts the automation flow. KaneAI eliminates this issue by intelligently managing authentication steps during execution, reducing test failures caused by login interruptions.
KaneAI includes auto-healing capabilities, meaning when Salesforce UI elements change due to seasonal releases, the test automatically adapts locators instead of breaking. This significantly reduces maintenance overhead and improves long-term test stability.
A complete Lead creation test in KaneAI feels intuitive and human-like, with each step closely matching how a tester would describe the flow in a real Salesforce demo.
The walkthrough below is based on an actual KaneAI session running against a real Salesforce org with MFA enabled and full Lightning component support.
The entire setup completes in under two minutes, and once finished, KaneAI is authenticated and ready to execute tests directly against your live environment.
The same approach can be applied to virtually any Salesforce workflow your team needs to test. Whether it's lead creation, contact updates, approval workflows, or custom business processes, KaneAI can execute the entire flow from a simple natural language prompt.
To get started, follow the support documentation on Why do we need KaneAI?
By leveraging TestMu AI agent-skills, developers can standardize how tests are generated across different AI development environments. Cloning the TestMu AI selenium-skill into tools like Claude Code, Cursor, or Copilot provides reusable automation patterns that accelerate test creation.
Selenium Skills acts as the implementation layer that connects AI-generated tests to real execution on the TestMu AI infrastructure, enabling the generation of POM-structured, production-grade Selenium tests that target the TestMu AI grid.
The Selenium Agent Skill supports six programming languages. To get started, follow this support documentation on running Selenium tests using Agent Skills.
Stable locators are the key skill in Salesforce Selenium testing: avoid auto-generated Lightning IDs and build them top-down from stable attributes like name, aria-label, and data-id.
Auto-generated Lightning IDs lead to brittle tests that break across sessions and seasonal releases, so always build locators using a top-down stability approach.
Locator Priority (Most to Least Stable)
Use Salesforce-provided stable attributes first, then fall back gradually:
| Priority | Strategy | Example | Survives Releases |
|---|---|---|---|
| 1 Best | data-id | data-id="force-page-global-header" | Yes |
| 2 | aria-label | aria-label="Search this list" | Yes |
| 3 | name attribute | input[name='lastName'] | Yes |
| 4 | title attribute | a[title='New'] | Yes |
| 5 | placeholder | input[placeholder='Search Salesforce'] | Yes |
| 6 | XPath by text | //button[text()='Save'] | Usually |
| 7 | XPath contains() | //span[contains(@class,'truncate')] | Sometimes |
| Avoid | SLDS class names | .slds-button--brand | No. Change between releases. |
| Never | Auto-generated ID | id="940:1376;a" | No. Changes every page load. |
Most Salesforce test failures come from incorrect wait handling. A proper wait strategy improves stability and reduces flakiness significantly.
Each wait type has a specific role in Salesforce Selenium testing. Using the wrong type for a given scenario is the leading cause of flaky tests. The table below maps each wait type to the Salesforce scenarios it is designed to handle.
| Wait Type | Salesforce Scenario | Implementation Note |
|---|---|---|
| Implicit Wait | Global setup for basic navigation between Lightning pages | Set at 5 seconds maximum. The SF Developer Blog confirms the Selenium click() call already waits for navigation to complete, so a low implicit wait is sufficient. |
WebDriverWait | Waiting for form inputs, buttons, and toast messages to appear | Your primary strategy. Use ExpectedConditions.elementToBeClickable for buttons and visibilityOfElementLocated for inputs and toasts. |
FluentWait | Handling the Lightning loading overlay that blocks Save clicks | Configure to ignore ElementClickInterceptedException. Poll every 2 seconds for up to 60 seconds. Check overlay visibility before returning the target element. |
Thread.sleep | Two narrow scenarios in Salesforce Lightning testing | After a JavaScript click() call only (1 second), or when Selenium outruns the browser renderer (2 seconds maximum). Never use it as a substitute for a proper wait condition. |
Although sleep methods like Thread.sleep() may appear simple, it pauses execution for a fixed duration regardless of whether the element is ready, which increases execution time and still leads to flaky behavior in dynamic Salesforce Lightning pages.
Modern Selenium synchronization strategies evolved beyond static delays by introducing implicit, explicit, and FluentWait mechanisms that respond to actual browser conditions instead of arbitrary timeouts.
You can learn more about configuring these synchronization strategies effectively in this guide on implicit and explicit waits in Selenium.
Salesforce Lightning often blocks interactions with loading spinners, causing click failures. FluentWait helps handle this by waiting until overlays disappear before interacting with elements.
Use FluentWait when Save or action buttons are intercepted by Lightning spinners. It polls until the overlay disappears and ensures safe element interaction before clicking. Since Lightning components render asynchronously, combining FluentWait with properly configured implicit and explicit waits is essential for reducing flaky Selenium behavior and improving test stability.
Handle Shadow DOM by crossing boundaries with Selenium 4's getShadowRoot for single LWC roots and a JavaScript executor for nested ones, since standard CSS and XPath can't reach inside.
Shadow DOM is listed as a challenge in every major Salesforce Selenium testing process. Since Salesforce moved to native shadow DOM in the Spring 24 release, the old document.querySelectorAll workarounds that relied on the synthetic polyfill no longer function.
The two methods below are current as of Spring 25.
Selenium 4 introduced native getShadowRoot() support, which crosses one shadow boundary without any JavaScript. This is the cleanest approach and should be your first choice for any single-level LWC shadow root. This is the approach to use before falling back to the JavaScript executor.
// Java: getShadowRoot
// Java: cross one shadow boundary using Selenium 4 native API.
// No JavaScript required. The cleanest approach for single LWC shadow roots.
WebElement lwcHost = driver.findElement(By.cssSelector("c-my-form"));
SearchContext shadow = lwcHost.getShadowRoot();
WebElement inputField = shadow.findElement(By.cssSelector("input[name='email']"));
inputField.sendKeys("[email protected]");When your LWC structure nests one component inside another (LWC inside LWC), you need to chain getShadowRoot calls per level, which becomes verbose. The JavaScript executor approach lets you chain multiple shadow root traversals in one call, making it more concise for deeply nested component trees.
// Java: JavaScript Executor for nested shadow DOM
// Java: JavaScript executor for nested shadow roots (LWC inside LWC).
JavascriptExecutor js = (JavascriptExecutor) driver;
// Two nested shadow roots in one call
WebElement deep = (WebElement) js.executeScript(
"return document.querySelector('c-parent').shadowRoot.querySelector('c-child').shadowRoot.querySelector('input[type=text]');");
// Reusable helper -- put this in a BasePage class
public WebElement fromShadow(String host, String target) {
return (WebElement) ((JavascriptExecutor) driver).executeScript(
"return document.querySelector(arguments[0]).shadowRoot.querySelector(arguments[1]);",
host, target);
}Handle MFA by exempting a dedicated automation service account from multi-factor authentication through a Permission Set, so Selenium can complete the login flow without OTP prompts.
Multi-Factor Authentication is the most common reason Salesforce Selenium test setups fail before the first test runs. If your org enforces MFA and your automation service account is not configured correctly, Selenium cannot complete the login flow, and every test fails at the authentication step.
The three options below cover every scenario in order of preference.
This is the cleanest solution and is officially supported by Salesforce. It exempts a dedicated automation service account from MFA without affecting any other users in the org.
selenium.qa service account onlySalesforce officially recommends this exemption approach for automation users running Selenium and similar testing frameworks. After configuration, verify the setup by logging in with the service account and confirming that no MFA prompt appears during authentication.
If your CI pipeline runs from a fixed IP address, such as a self-hosted Jenkins server, you can add that IP to Salesforce's trusted network access list. Logins from trusted IPs do not trigger MFA. This method does not work with GitHub-hosted runners, which rotate IP addresses on every run.
Refer to the official documentation for configuring trusted IP ranges on Salesforce Network Access.
If your organization does not allow MFA exemptions and your CI infrastructure uses dynamic IP addresses, you can automate Salesforce MFA by generating the current TOTP code programmatically during login. Salesforce officially supports third-party authenticator apps that generate standard RFC 6238 TOTP codes, making this approach compatible with Selenium-based automation workflows.
# Java: TOTP MFA automation
# Java: generate current TOTP code at runtime (aerogear-otp-java)
import pyotp, os
totp = pyotp.TOTP(os.getenv('SF_MFA_SECRET')) # base32 secret from Authenticator
mfa_code = totp.now() # valid for 30 seconds
driver.find_element(By.CSS_SELECTOR, "input[id*='totp']").send_keys(mfa_code)
driver.find_element(By.CSS_SELECTOR, "button[type='submit']").click()Store the MFA secret securely in a secrets manager rather than hardcoding it in source code or environment files.
Running Salesforce Selenium tests on every pull request ensures that every UI change is validated early in the development lifecycle. CI/CD integration helps teams detect failures in Lightning pages, locators, and flows before they reach production.
GitHub Actions is commonly used to automate Salesforce Selenium test execution as part of the build pipeline. On every push or pull request, tests are triggered automatically, executed on a cloud Selenium grid, and results are published back into the repository for immediate visibility.
With increasing adoption of CI/CD pipelines and Selenium AI in automation workflows, teams are shifting toward more intelligent and automated validation layers within their build pipelines.
This ensures that:
TestMu AI provides a GitHub App that integrates Selenium testing directly into pull request workflows. Instead of manually triggering pipelines, testers or developers can simply comment on a PR to initiate validation.
This shift enables concepts like Vibe Testing with Selenium, where test intent is validated dynamically based on application behavior and context rather than rigid scripted execution.
Once triggered, KaneAI-TestMu AI's AI testing agent automatically:
@KaneAI Validate this PR, and KaneAI takes it from there.To get started with TestMu AI GitHub integration into your AI testing workflow, follow this support documentation on TestMu AI GitHub App Integration.
TestMu AI GitHub Action Tunnel enables Selenium execution against applications that are not publicly accessible.
The checklist below consolidates every practice covered in this guide into a scannable reference. Use it to audit an existing Salesforce Selenium test suite or as a validation checklist before publishing a new test to your pipeline.
It serves as a quick validation of key Selenium best practices to ensure stability, maintainability, and release resilience across Salesforce automation projects.
WebDriverWait for all dynamic Lightning elements, FluentWait for overlays and intercepted clicks, keep implicit waits minimal, and avoid Thread.sleep except for rare synchronization scenarios.getShadowRoot for single-level access, JavaScript execution for nested shadow structures, and avoid deprecated selector-based workarounds removed in Spring '24.Test.startTest and Test.stopTest correctly, and avoid seeAllData by generating isolated test data.Salesforce Selenium testing is no longer just about writing automation scripts; it is about building a reliable validation strategy that can withstand constant platform updates, dynamic UI behavior, and enterprise-scale deployment cycles. From locator stability and wait strategies to Shadow DOM handling and MFA challenges, every layer of Salesforce automation requires deliberate design choices to maintain test reliability.
As teams shift toward continuous delivery, integrating Selenium tests into CI/CD pipelines becomes essential for early defect detection and faster release cycles. GitHub Actions enables this automation layer, ensuring that every change is validated as part of the development workflow. Extending this further, TestMu AI enhances the process by introducing secure tunneling for private environments and AI-driven test execution through KaneAI, which can analyze pull requests and trigger full test cycles with a simple command.
Together, these approaches transform Salesforce testing from a manual, reactive process into an intelligent, automated, and scalable quality assurance system. Organizations that adopt this model gain faster feedback loops, reduced maintenance overhead, and higher confidence in every Salesforce release.
Did you find this page helpful?
More Related Hubs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance