Visualforce testing

  December 19, 2013       Pierre Positiveur

Testing Visualforce pages is difficult and in a lot of cases means testing will be performed manually due to the overhead and complexity in supporting the custom framework required. The issue lies in creating locators or rather how to reliably find the field or button on a page. Let’s take a look at the problem and the potential solutions.

Issue
To understand the issue lets map the Stage field in the page below:

Provar 1

Selenium IDE
If we use the Selenium IDE this will generate a locator based upon the Id:
id=”j_id0:j_id1:j_id2:j_id32:j_id35”
We can also choose to locate our fields in css or xpath. However, as you can see below this doesn’t solve the problem.
css = "#j_id0:j_id1:j_id2:j_id32:j_id35"
xpath = "//*[@id="j_id0:j_id1:j_id2:j_id32:j_id35"]"
Salesforce will generate the j_Ids if the developer does not uniquely name every APEX tag. It cannot be relied upon as changes to the Visualforce page will change the locator leading to immediate maintenance.

What are the options?

Anchor your locators against Labels
An example can be seen below.
xpath = "//label[contains(text(),"Stage")]/following::input"
This will not work if you are testing in different languages (Internationalization) and is not always possible if fields do not have on-screen labels such as the second address line below. This can lead to very complex logic to identify a field reliably.

Provar 2

Add Ids for each APEX tag
If you uniquely name every tag (including all parent Apex tags) Salesforce will not need to use J_id within its Ids. These are included for the example Visual force page. However it is not always possible to update all pages to make them testable especially if the page is part of a Vendor package.

<apex:page standardController="Opportunity" extensions="ProductSelectorExtension" id="ProductSelectorPage">
    <apex:form id="form1">
        <apex:pageBlock mode="mainDetail" id="pb1">

            <apex:pageMessages />
            <apex:pageBlockButtons >
                <apex:commandButton value="Save" action="{!save}"/>
                <apex:commandButton value="Cancel" action="{!cancel}"/>
            </apex:pageBlockButtons>

            <apex:pageBlockSection title="Opportunity" id="OpportunityPageBlock">
                <apex:inputField value="{!Opportunity.Name}" id="OpportunityName"/>
                <apex:inputField value="{!Opportunity.CloseDate}" id="OpportunityCloseDate"/>
                <apex:inputField value="{!Opportunity.StageName}" id="OpportunityStageName"/>

</apex:pageBlockSection>

Anchor against Visualforce code
We can create reliable locators if we map to the field definition within the Visualforce code. This is possible as the code can be accessed via Metadata and the Id can be calculated at runtime. This approach is much more reliable as the definition will change less frequently. This has been implemented in PROVAR, a specialist Salesforce testing tool. Here is a quick description of the process:
1) Map the field using the browser to generate a Page Object.

Provar 3

2) View the generated Locator, at this stage you can choose standard Selenium locators such as css, xpath, id if you prefer (great for non-Salesforce GUI testing).

Provar 4

3) Use the Page Object in your test.  Notice the Field Type is also mapped so you can choose from the available Salesforce picklist values.

Provar 5

4) Execute your test & the id is generated using the Salesforce algorithm at run-time.

Provar 6

For Custom Objects it gets even easier as all locators are taken from Metadata.  Find out more here.