Salesforce has become the dominant CRM platform in recent years with global 19.5% market share in 2018. That’s more than double the nearest alternative SAP and over three times that of Oracle. The success comes from targeting enterprise application development with its own Apex object-oriented programming language and Lightning Web Component framework.
Salesforce allows developers to define their business logic and UI elements in an abstract way so that Salesforce can implement those elements on the page. This flexibility comes at the expense of UI test automation because developers don’t have direct control over the final content in the browser. Salesforce enterprise apps are notoriously difficult to test with open source automation frameworks like Selenium. Let’s explore some reasons for the difficulty of testing Salesforce Enterprise apps and how to work around them.
Element identifiers are a common way to locate and automate web page interactions with Selenium. The @FindBy annotation in Selenium has a simple id=”something” attribute to locate a web element by unique id on the page.
Element identifiers in a Salesforce app look very strange: for example, id=”940:1376;a”. Worse than that, the identifiers change randomly between page visits. This makes the identifiers useless for test automation. Consider how a Selenium test should locate the <input> element in the following example when the id changes each time the test runs.
The <input> element has no other uniquely defining attributes. Fortunately, Salesforce complies with the latest web accessibility guidelines. WCAG section 1.3.1 on info and relationship mandates that a human readable <label> element be associated in code to its corresponding <input> by matching the label’s “for” attribute to the input’s “id” attribute. The element identifier may change each time the page is loaded, but the label text should always be the same.
In this example the “Company Name” text is contained inside a <label> with attribute for=”940:1376;a” which happens to match the identifier on the <input> element. A Selenium test can make the connection from label text to input element using a clever XPath: //input[@id=//label[normalize-space(.)=’Company Name’]/@for].
This XPath locates any <input> element on the page with an “id” attribute equal to the “for” attribute of a <label> displaying “Company Name.” The normalize-space(.) XPath function eliminates the extra whitespace from the text in this example being wrapped inside a <span> within the <label> element. It makes the Selenium test look a little more complicated, but it gets the job done.
Despite the name “Lightning,” Salesforce’s cloud-hosted enterprise apps can sometimes be quite slow. Test automation engineers are familiar with the challenges that come with applications that can be slow to respond. A test script will fail if it tries to perform the next step before the application is ready.
Hard coding several seconds of delay into the test might pause longer than is needed most of the time and increase the overall time that it takes the tests to run. In order to delay just long enough, the wait needs to be conditional. Salesforce makes it difficult to use typical Selenium fluent wait conditions by rendering a loading overlay mask on the page.
Selenium has built-in support for dynamic wait conditions. It checks for element presence or clickability several times per second — up to a maximum time before erroring out. The problem is that none of Selenium’s built-in wait conditions handle the loading overlay in Salesforce. Selenium detects that the element under the loading mask is indeed present and not disabled. It stops waiting and tries to click it. This results in an exception because the click is intercepted by the loading overlay.
Not all hope is lost. A few more lines of Selenium code make it possible to catch this click-intercepted exception and try again using the same wait loop and timeout.
Another thorn in the side of UI test automation is that Salesforce remembers which Lightning UI components were last open and reinitializes the last known state upon login. This means that the initial page layout available to the test is subject to change depending on saved history.
One way to reduce the effect of the previous state is for the test to launch the browser incognito. Selenium makes this easy to do with Google Chrome by passing options in the setup method of the test class.
These tips and tricks make it practical to use Selenium for automated UI testing of Salesforce enterprise applications. Test automation is an important way to quickly detect regressions after changing business logic or web components in the enterprise app. Salesforce itself also releases changes a few times every year. A suite of Selenium tests is a great way to quickly check compatibility with the latest Salesforce update in a sandbox before rolling out to production.
If putting these tips and tricks into action on your own seems like too much work, consider using Parasoft Selenic to efficiently automate your Selenium test creation and simplify test maintenance. With Selenic, you can record interactions with Salesforce enterprise apps in your browser. Then easily create Selenium test classes that leverage all these same techniques.
Parasoft Selenic’s integrated Recorder provides an application selection so you can choose to gather Salesforce-specific attributes while recording UI actions. Selenic then incorporates those attributes when creating Selenium UI tests and uses AI technology to apply self-healing to tests that are broken due to changes in locators or wait conditions. To learn more, check out our on-demand webinar and download a free trial.
A Product Lead Engineer at Parasoft, Matt manages the development of new functionality for environment management, API testing, service virtualization, and test data modeling.