1

Am new to QAF and I need to implement self-healing in our test method using healenium. I have implemented it without QAF it's working fine. Please refer to the below code.

import com.epam.healenium.SelfHealingDriver;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.concurrent.TimeUnit;

public class BaseTest {
    static protected SelfHealingDriver driver;

    @BeforeAll
    static public void setUp() {
        WebDriverManager.chromedriver().setup();
        ChromeOptions options = new ChromeOptions();
        options.setHeadless(false);
        //declare delegate
        WebDriver delegate = new ChromeDriver(options);
        driver = SelfHealingDriver.create(delegate);
        driver.manage().timeouts().implicitlyWait(4, TimeUnit.SECONDS);
        driver.manage().window().setSize(new Dimension(1200, 800));
    }

    @AfterAll
    static public void afterAll() {
        if (driver != null) {
            driver.quit();
        }
    }
}

I just want to wrap this self-healing driver with a QAF web driver like above.

Ramesh
  • 11
  • 2

1 Answers1

0

QAF discourage to use static class variable for driver. The code provided in question will not work for parallel execution. Driver management is taken care by qaf with thread safety and with different behavior that can be set using property selenium.singletone.

You can try following way when you want SelfHealingDriver:

public class SampleTest extends WebDriverTestCase {

   @Test
   public void yourTestCase(){
      SelfHealingDriver driver = SelfHealingDriver.create(getDriver());
      //your code goes below
   }
}

SelfHealingDriver proxies actual driver. You can achieve the self heal functionality without driver proxy with listener for findelement/findChildelement. Driver listener should work without proxing driver. For example:

public class WDListener extends QAFWebDriverCommandAdapter {

private static final Map<String, Object> byToString = JSONUtil.toMap(
            "{'ByCssSelector':'css selector','ByClassName':'class name','ByXPath':'xpath','ByPartialLinkText':'partial link text','ById':'id','ByLinkText':'link text','ByName':'name'}");

   //this method will called when new driver object created
   public void onInitialize(QAFExtendedWebDriver driver){
        driver.manage().timeouts().implicitlyWait(4, TimeUnit.SECONDS);
        driver.manage().window().setSize(new Dimension(1200, 800));
   }

    @Override
    public void afterCommand(QAFExtendedWebDriver driver, CommandTracker commandTracker) {
        if (DriverCommand.FIND_ELEMENT.equalsIgnoreCase(commandTracker.getCommand())
                || DriverCommand.FIND_ELEMENTS.equalsIgnoreCase(commandTracker.getCommand())
                || DriverCommand.FIND_CHILD_ELEMENT.equalsIgnoreCase(commandTracker.getCommand())
                || DriverCommand.FIND_CHILD_ELEMENTS.equalsIgnoreCase(commandTracker.getCommand())) {
            Map<String, Object> parameters = commandTracker.getParameters();
            if (parameters != null && parameters.containsKey("using") && parameters.containsKey("value")) {
                By by = LocatorUtil
                        .getBy(String.format("%s=%s", parameters.get("using"), parameters.get("value")));
                
                HealingServiceImpl healingServiceImpl = new HealingServiceImpl(new SelfHealingEngine(driver));
                StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
                Object result = commandTracker.getResponce().getValue();
                List<WebElement> webElements = List.class.isAssignableFrom(result.getClass())?(List<WebElement>) result:Collections.singletonList((WebElement)result)
                healingServiceImpl.savePath(new PageAwareBy(driver.getTitle(),by),webElements);
            }

        }
    }

    @Override
    public void onFailure(QAFExtendedWebDriver driver, CommandTracker commandTracker) {
        // StackTraceElement[] stackTrace =
        // commandTracker.getException().getStackTrace();

        Map<String, Object> parameters = commandTracker.getParameters();
        if (parameters != null && parameters.containsKey("using") && parameters.containsKey("value")) {
            By by = LocatorUtil
                    .getBy(String.format("%s=%s", parameters.get("using"), parameters.get("value")));
            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
            HealingServiceImpl healingServiceImpl = new HealingServiceImpl(new SelfHealingEngine(driver));

            Optional<By> healedBy = healingServiceImpl.healLocators(new PageAwareBy(driver.getTitle(),by), null, stackTrace) ;
            if(healedBy.isPresent()) {
            commandTracker.getParameters().putAll(toParams(healedBy.get()));
            commandTracker.setRetry(true);
            }
        }
    }
}
user861594
  • 5,733
  • 3
  • 29
  • 45
  • Our goal is to use QAF common steps along with selfheling driver. public class SampleTest extends WebDriverTestCase { @Test public void testGoogleSearch() { SelfHealingDriver driver = SelfHealingDriver.create(getDriver()); get("/"); searchFor("qaf github infostretch"); verifyLinkWithPartialTextPresent("qaf");}} 1) How can I use QAF common method like get(), sendkeys(), verifyLinkWithPartialTextPresent()? above code is creating two driver instance. – Ramesh Feb 22 '21 at 14:18
  • public class WDListener extends QAFWebDriverCommandAdapter { public void onInitialize(QAFExtendedWebDriver driver) { System.out.println("Enter before onIntialize"); ChromeOptions options = new ChromeOptions(); options.setHeadless(false); WebDriver delegate = new ChromeDriver(options); driver.manage().timeouts().implicitlyWait(4, TimeUnit.SECONDS); driver.manage().window().maximize(); driver = (QAFExtendedWebDriver) SelfHealingDriver.create(delegate);}} – Ramesh Feb 22 '21 at 14:24
  • Following above comments 2) As per listener class approach, I have created onInitialize() and getting two driver instances. Also getting this exception. java.lang.ClassCastException: class com.sun.proxy.$Proxy16 cannot be cast to class com.qmetry.qaf.automation.ui.webdriver.QAFExtendedWebDriver (com.sun.proxy.$Proxy16 and com.qmetry.qaf.automation.ui.webdriver.QAFExtendedWebDriver are in unnamed module of loader 'app') Note: Revert me if still need any clarification. Also tried SelfHealingDriverdriver=SelfHealingDriver.create(getDriver()); but no reference found. – Ramesh Feb 22 '21 at 14:24
  • public class SampleTest extends WebDriverTestCase { @Test public void testGoogleSearch() { SelfHealingDriver driver = SelfHealingDriver.create(getDriver()); get("/"); searchFor("qaf github infostretch"); verifyLinkWithPartialTextPresent("qaf");}} – Ramesh Mar 01 '21 at 12:10
  • We are trying to map self-healing driver with the QAF driver which should get all QAF common steps. Above are the methods we are trying to implement in QAF using healenium. We are not able to get the QAF common methods. Request you to please provide us the detailed code as we are new to the QAF framework. – Ramesh Mar 01 '21 at 12:16
  • Refer updated answer, the example listener should do the needful. SelfHealingDriver proxies actual driver to store dom on successful element find operation in db and uses previously stored dom to retry with alternate locator on failure. You can achieve this with listener for findelemet/findChildelement and do the needful. – user861594 Jul 28 '21 at 22:36
  • when you use listener approach you don't need proxy driver (SelfHealingDriver) – user861594 Jul 28 '21 at 22:59