This question probably belongs on StackOverflow instead of here, because it is purely a programming-related question…
but I am facing a slew of Errors from what looks like a combo of traits and inheritance…
I have this class, called MemberLeadListPage
, which is defined to be:
package com.signaturemd.pages.list
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import java.time.LocalDateTime
import org.openqa.selenium.By
import org.openqa.selenium.WebElement
import com.kms.katalon.core.model.FailureHandling
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.webui.common.WebUiCommonHelper
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import com.signaturemd.utils.ActionHandler
import com.signaturemd.utils.GeneralWebUIUtils
public class MemberLeadListPage extends BasePersonListPage {
public final String linkXpath = "//span[@title = 'Member Lead Name']/a";
public MemberLeadListPage() {
super("https://crm.zoho.com/crm/org724168703/tab/Potentials/custom-view/4623170000000087545/canvas/4623170000000293236");
}
@Override
public void deleteAllCreatedAfter(LocalDateTime time) {
((this) as BaseSublistActor).doActionsToAllCreatedAfter(time, [
{ List<WebElement> newlyCreatedRecords ->
newlyCreatedRecords.each { WebElement rowElement ->
GeneralWebUIUtils.OpenLinkInNewTab(WebUI.convertWebElementToTestObject(rowElement.findElement(By.xpath(linkXpath))))
WebUI.waitForPageLoad(5);
WebUI.waitForElementPresent(findTestObject('Page_Member Lead/First Row/Member Lead Name') , 5)
final TestObject openStageItem = findTestObject("Page_Member Lead/Second Row/Open step item")
GeneralWebUIUtils.ScrollDropdownOptionIntoView(openStageItem)
WebUI.click(openStageItem)
GeneralWebUIUtils.WaitForElementTextMatches(findTestObject("Page_Member Lead/First Row/Stage label"),
"Open",
5)
WebUI.click(findTestObject("Page_Member Lead/First Row/Delete button"))
GeneralWebUIUtils.HandleConfirmableModal(findTestObject("Page_Member Lead/Delete Modal/Modal"),
findTestObject("Page_Member Lead/Delete Modal/Confirm Delete button"))
GeneralWebUIUtils.CloseLastTab()
}
}
]);
}
@Override
public TestObject getFirstResult() {
return findTestObject("Page_Member Lead List/Member Table/First Result link");
}
@Override
public TestObject getOrganizationFilterCheckbox() {
return findTestObject('Page_Member Lead List/Filter Sidebar/Filter By Fields Subsection/Organization Filter/Organization checkbox')
}
@Override
public TestObject getOrganizationFilterTextField() {
return findTestObject('Page_Member Lead List/Filter Sidebar/Filter By Fields Subsection/Organization Filter/Organization text field');
}
@Override
public String getTableRowListXpath() {
return "${this.getTableDataXpath()}//tr[@data-zcqa = 'detailView']"
}
@Override
public String getTableDataXpath() {
return "//table[@data-zcqa = 'listViewTable']";
}
@Override
public String getTableRowCheckboxXpath(int rowNum) {
return "(${this.getTableDataXpath()}//span[@data-zcqa = 'selectEntity'])[${rowNum}]"
}
@Override
public String getTimestampRelativeXpath() {
return "//span[contains(@data-component, '\"COLUMNNAME\":\"CREATEDTIME\"')]";
}
}
…and BasePersonListPage
extends BaseListPage
…
…and BaseListPage
implements SublistDeleter
, the latter of which is defined to be:
package com.signaturemd.pages.list
import static com.kms.katalon.core.testobject.ObjectRepository.findTestObject
import java.time.LocalDateTime
import org.openqa.selenium.WebElement
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.util.KeywordUtil
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import com.signaturemd.utils.GeneralWebUIUtils
public trait SublistDeleter extends BaseSublistActor {
public void deleteAllCreatedAfter(LocalDateTime time) {
this.doActionsToAllCreatedAfter(time, [
this.onClickOnCheckboxes(),
this.onMassDelete(),
]);
}
public Closure<List<WebElement>> onMassDelete() {
return { List<WebElement> recordsToDelete ->
KeywordUtil.logInfo("Clicking the dropdown button and option to delete all selected records...");
WebUI.click(findTestObject("Shared repository/Zoho pages/CRM/List pages/Actions dropdown button"))
final TestObject deleteDropdownOption = findTestObject("Shared repository/Zoho pages/CRM/List pages/Actions dropdown/Delete dropdown option")
WebUI.waitForElementVisible(deleteDropdownOption, 2)
WebUI.click(deleteDropdownOption)
WebUI.waitForElementNotVisible(deleteDropdownOption, 2)
GeneralWebUIUtils.HandleConfirmableModal(findTestObject("Shared repository/Zoho pages/CRM/List pages/Modal/Modal"),
findTestObject("Shared repository/Zoho pages/CRM/List pages/Modal/Delete button"),
GeneralWebUIUtils.OnWaitForDisappear(WebUI.&waitForElementNotPresent, 4))
KeywordUtil.logInfo("All selected records successfully deleted!");
}
}
}
The BaseSublistActor
is defined to be:
package com.signaturemd.pages.list
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.stream.Stream
import org.openqa.selenium.By
import org.openqa.selenium.WebElement
import com.kms.katalon.core.testobject.ConditionType
import com.kms.katalon.core.testobject.TestObject
import com.kms.katalon.core.util.KeywordUtil
import com.kms.katalon.core.webui.driver.DriverFactory
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
import com.signaturemd.utils.SMDDateUtils
public trait BaseSublistActor {
public static final DateTimeFormatter DateTimeFormat = DateTimeFormatter.ofPattern("MM-dd-yyyy h:mm a");
public void doActionsToAllCreatedAfter(LocalDateTime time, List<Closure<List<WebElement>>> onActionsList) {
KeywordUtil.logInfo("Fetching all records created after or at ${time.toString()}...")
final List<TestObject> allNewlyCreatedRecords = this.getAllCreatedAfter(time);
if (allNewlyCreatedRecords.isEmpty()) {
KeywordUtil.markWarning("There are no newly created records for this logged-in user...");
return;
}
onActionsList.each { Closure<List<WebElement>> onAction ->
onAction(allNewlyCreatedRecords);
};
}
public List<TestObject> getAllCreatedAfter(LocalDateTime time) {
final Stream<WebElement> foundWebElementsStream = DriverFactory.getWebDriver()
.findElements(By.xpath(this.getTableRowListXpath()))
.stream()
// Get the timezone offset of the user
LocalDateTime earliestCreationTime = foundWebElementsStream
.map { WebElement rowElement ->
return this.getCreatedTimeFromRowElement(rowElement)
}
.min { LocalDateTime firstTime, LocalDateTime secondTime ->
return firstTime.compareTo(secondTime);
}
.orElse(LocalDateTime.now())
final int timezoneDifference = SMDDateUtils.GetHoursDifference(time, earliestCreationTime);
return foundWebElementsStream
.filter { WebElement rowElement ->
final LocalDateTime createdTime = this.getCreatedTimeFromRowElement(rowElement);
final LocalDateTime adjustedTime = time.minusHours(timezoneDifference);
return createdTime.isAfter(adjustedTime) || createdTime.equals(adjustedTime);
}
.collect { WebElement rowElement -> return WebUI.convertWebElementToTestObject(rowElement) }
}
public String getTableRowListXpath() {
return "${this.getTableDataXpath()}//lyte-exptable-tr";
}
public String getTableDataXpath() {
return "//lyte-yield[@yield-name = 'contentYield']";
}
public LocalDateTime getCreatedTimeFromRowElement(WebElement rowElement) {
return LocalDateTime.parse(rowElement
.findElement(By.xpath(this.getTimestampRelativeXpath()))
.getText(),
this.DateTimeFormat);
}
public String getTimestampRelativeXpath() {
return "//*[contains(concat(' ', @class, ' '), ' newDTField ')]";
}
public Closure<List<WebElement>> onClickOnCheckboxes() {
return { List<WebElement> allNewlyCreatedRecords ->
allNewlyCreatedRecords
.eachWithIndex { TestObject tableRow, int idx ->
final int rowNum = idx + 1;
KeywordUtil.logInfo("Scrolling to and clicking checkbox to delete for row #${rowNum}...")
WebUI.scrollToElement(tableRow, 2);
WebUI.click(getTableRowCheckbox(rowNum));
}
}
}
public TestObject getTableRowCheckbox(int rowNum) {
return new TestObject("Shared repository/Zoho pages/CRM/List pages/Results Table/#${rowNum} table row checkbox")
.addProperty("xpath",
ConditionType.EQUALS,
this.getTableRowCheckboxXpath(rowNum),
)
}
public String getTableRowCheckboxXpath(int rowNum) {
return "(${this.getTableDataXpath()}//*[@lt-prop-class = 'customCheckBox'])[${rowNum}]";
}
}
How’s come the IDE doesn’t recognize the implemented methods on the derived class that are coming from the base trait BaseSublistActor
, or even the concrete implementation of SublistDeleter.onMassDelete()
?