VeriSoft framework supports object repositories. It is a very similar solution to the page factory pattern.
General
In order to use the Object repository feature you will need to do the following:
- Create an object repository, which is a JSON file with a specific format.
- Annotate your WebElement objects in your page object accordingly.
- Initialize the WebElements (not needed if you derive your page object from BasePage)
- Use the WebElement objects like in any other page object.
Repository Logic
Each object in the object repository has a unique id. This unique id is called objectId. For each object there can be several fitting locators. For each objectId there is a defined array of locators, each locator has a type, a value, and a grade. A higher grade means a stronger locator. You can use each locator strategy more than once. For instance, you can define 2 XPath locators.
When calling the WebElement, the framework will sort all the locators from the strongest (with a higher grade) to the weaker (with a lower grade) and try to apply the findElement method. Once a locator strategy finds an object on the DOM and the WebElement is created, the framework uses this locator for the current action. This logic repeats every time the WebElement is being used.
Structure of the object repository JSON file:
Currently, you will need to follow these instructions precisely:
Supported locator types — the type field of each locator (case-sensitive) must be one of the following values:
| type |
|---|
id |
xpath |
cssSelector |
name |
className |
linkText |
partialLinkText |
tagName |
accessibilityId |
Any other value is not recognized and the locator will be skipped.
accessibilityId (since 4.0.8) works with the Appium-based drivers only:
- Desktop (
VerisoftDesktopDriver) – matches the element's UI Automation AutomationId. - Mobile (
VerisoftMobileDriver) – matches the element's accessibility id:content-descon Android,accessibilityIdentifieron iOS.
The file structure look like this:
{
"objectsRepository": [
{
"objectId": "WIKI-MAIN-SEARCH",
"pageName": "WikiMainPage",
"locators": [
{
"type": "id",
"value": "searchInput",
"grade": 80
},
{
"type": "xpath",
"value": "//badXpath",
"grade": 90
},
{
"type": "cssSelector",
"value": "#NoCss",
"grade": 50
}
]
},
{
"objectId": "WIKI-SEARCH-BAR",
"pageName": "WikiMainPage",
"locators": [
{
"type": "xpath",
"value": "//input[@name='search']",
"grade": 10
},
{
"type": "id",
"value": "BadId",
"grade": 80
},
{
"type": "cssSelector",
"value": "#BadCss",
"grade": 50
}
]
},
{
"objectId": "CALC-NUM1",
"pageName": "CalculatorPage",
"locators": [
{
"type": "accessibilityId",
"value": "num1Button",
"grade": 100
}
]
}
]
}
The Page Object
In the page object, the only difference is the way we reference the WebElement:
@ObjectRepositoryItem(id = "WIKI-MAIN-SEARCH")
private WebElement searchBar;
If you extend VeriSoft’s BasePage (WebBasePage, MobileBasePage, BasePage) you don't need anything else. If you do not extend either of these classes you will have to call ObjectReporsitoryFactory.initObjects in your constructor like this:
public ObjectRepositoryStandAloneWikipediaPageObject(WebDriver driver) {
ObjectReporsitoryFactory.initObjects(driver, this);
}
A full-page object which uses the object repository should look like this:
public class ObjectRepoWikipediaMainPage extends WebBasePage {
@ObjectRepositoryItem(id = "WIKI-MAIN-SEARCH")
private WebElement searchBar;
public static final String pageUrl = "https://www.wikipedia.org/";
/**
* C-tor. Initializes generic properties such as timeOut and pollingInterval
*
* @param driver a WebDriver object to store and use
*/
public ObjectRepoWikipediaMainPage(WebDriver driver) {
super(driver);
}
@Override
public boolean isOnPage() {
return searchBar.isDisplayed();
}
public ObjectRepoWikipediaResultPage searchForTerm(String term){
searchBar.sendKeys(term);
new Actions(driver).sendKeys(Keys.ENTER).build().perform();
return new ObjectRepoWikipediaResultPage(driver);
}
public ObjectRepoWikipediaMainPage gotoPage(){
driver.get(pageUrl);
return this;
}
}
You can find this code, as well as a stand-alone page object here.
A test will look like this:
@Test
@DisplayName("Search Wikipedia with Page Objects using the Object Repository")
@Description("This test has a description")
public void searchWikipediaWithPageObjectsRepository(VerisoftDriver driver) {
String phraseToSearch = "Test Automation";
ObjectRepoWikipediaMainPage wikipediaMainPage = new ObjectRepoWikipediaMainPage(driver);
ObjectRepoWikipediaResultPage resultPage =
wikipediaMainPage.gotoPage().searchForTerm(phraseToSearch);
// Note!! Verisoft Assert
Asserts.assertTrue(resultPage.isOnPage(), "Should be on the result page");
Report.info("We reaeched the result page");
Asserts.assertTrue(resultPage.getPageTitle().toLowerCase(Locale.ROOT)
.contains(phraseToSearch.toLowerCase()),
"Title should containt the pharse " + phraseToSearch);
}
Locators with values
Available since version: 4.0.8
A locator can hold numbered placeholders – {0}, {1}, … – so one entry covers a whole family of similar elements, such as the cells of a grid. The values are supplied where the element is used.
In the repository:
{
"objectId": "grid_cell",
"pageName": "OrdersPage",
"locators": [
{ "type": "xpath", "value": "//tr[td='{0}']/td[@data-col='{1}']", "grade": 100 }
]
}
In a Page Object – pass the values on the annotation:
@ObjectRepositoryItem(id = "grid_cell", values = {"Row 3", "Total"})
private WebElement row3Total;
@ObjectRepositoryItem(id = "grid_cell", values = {"Row 4", "Total"})
private WebElement row4Total;
In a Cucumber feature file – add the values in parentheses after the key, separated by |:
Then user sees element "grid_cell(Row 3|Total)" is on page
See Using Cucumber Dictionary – Locators with values.
Rules
- Values are placed by position: the first value into
{0}, the second into{1}, and so on. A placeholder may appear more than once. - The number of values must match the placeholders in the locator, otherwise the element fails with an error that names it.
- When an entry is used with values, give all of its locators the same placeholders. A Page Object tries every locator of the entry in grade order, while the Cucumber dictionaries use only the highest-graded one.
- In an
xpathlocator, write the placeholder inside quotes –'{0}'– and a value that contains a quote, such asO'Brien, is still matched correctly. - An entry with no placeholders, used without values, works exactly as before.
Note: {0}, {1}, … are now always read as placeholders. If an existing locator contains such text literally, rewrite it so it no longer does – for example, in xpath, match the surrounding text with contains().
Repository file Location
The default path for the file is src/test/resources/objectRepository.json
To support another location or multiple locations for the object repository file in the VeriSoft framework, you can modify the implementation by following on of two options:
Option 1: Use root.config.properties Property
- Set a Property in the Configuration File: Add a property in
root.config.propertiesfile (located in the test/resources folder) for the path to the desired object repository file. the property name isobject.repository.path
object.repository.path=src/test/resources/myObjectRepository.json
Option 2: Pass the Path in the Constructor
- Define a Custom Page Class: Create a specialized page class that accepts an object repository path in its constructor.
public class SpecificObjectRepoWikipediaMainPage extends WebBasePage {
@ObjectRepositoryItem(id = "WIKI-MAIN-SEARCH")
private WebElement searchBar;
public static final String pageUrl = "https://www.wikipedia.org/";
/**
* Constructor that initializes the object repository with a specific path
*
* @param driver a WebDriver object to store and use
* @param objectRepositoryPath the custom path to the object repository file
*/
public SpecificObjectRepoWikipediaMainPage(WebDriver driver, String objectRepositoryPath) {
super(driver, objectRepositoryPath);
}
@Override
public boolean isOnPage() {
return searchBar.isDisplayed();
}
public ObjectRepoWikipediaResultPage searchForTerm(String term) {
searchBar.sendKeys(term);
new Actions(driver).sendKeys(Keys.ENTER).build().perform();
return new ObjectRepoWikipediaResultPage(driver);
}
public SpecificObjectRepoWikipediaMainPage gotoPage() {
driver.get(pageUrl);
return this;
}
}
- Use Custom Page Class in Your Tests: Instantiate your page class with a specific object repository path in your test.
@Test
@DisplayName("Search Wikipedia with Page Objects using Custom Object Repository Path")
public void searchWikipediaWithSpecificRepo(VerisoftDriver driver) {
String phraseToSearch = "Test Automation";
SpecificObjectRepoWikipediaMainPage wikipediaMainPage = new SpecificObjectRepoWikipediaMainPage(
driver, "path/to/your/objectRepository.json"
);
ObjectRepoWikipediaResultPage resultPage = wikipediaMainPage.gotoPage().searchForTerm(phraseToSearch);
Asserts.assertTrue(resultPage.isOnPage(), "Should be on the result page");
}
Default Object Repository Location
If no specific path is provided either via configuration or through the constructor, the framework falls back to the default path (src/test/resources/objectRepository.json).
Want to learn more about the mechanism? Read about it here.