2

I created test framework with Selenium and setup ExtentReports for test report. Used page object model and @FindBy annotation for fields to create own store of WebElements for each page. Now I would like to create custom annotation @Name

@Name(description = "google main page")
@FindBy(linkText = "Gmail")
private WebElement gmail;

And implementation for it, to be able to use description of each WebElement later in my report. I have my own implementation of click() method

public static void click(WebElement element) {
    try{
        element.click();
        TestReport.addLog(LogStatus.INFO, "Element "+NameImpl.getDescription(element)+" clicked");
    } catch (NoSuchElementException e) {
        TestReport.addLog(LogStatus.ERROR, "Element "+NameImpl.getDescription(element)+" not found");
    }
}

I'm able to get description of all elements annotated in class with reflection like here

Is it possible to read the value of a annotation in java?

but cannot get description of specific element used in my click method.

Any ideas how to achieve that?

Community
  • 1
  • 1

1 Answers1

0

Just from the parameter passed to the click method, there's no way the get annotations. This reason is the annotation are on the gmail field, not on the WebElement class. So the only way to get the @Name annotation is to first get the Field representing your gmail field, and that will have to be done through the declaring class:

ClassWithGmailField.class.getField("gmail").getAnnotation(Name.class).description()

Just from the parameter of the click method, you could only reach annotations defined on the WebElement class itself e.g.:

@SomeAnnotation
public class WebElement {...}

but this is not useful for anything in your case.

To achieve something similar to what you want, you could potentially:

  • Reflectively analyze the class, extract all @Name'd fields and collect the meta together with the field values, perhaps into some kind of wrapper e.g. NamedElement that would have the description from @Name and the WebElement itself
  • Reflectively call the click method providing it with the meta it needs (the description in your case). But for this you'd need to somehow know which method to invoke for each field (e.g. by yet another annotation), making your logic encoded external to your actual code. Might make sense in some cases but probably a bad idea in general.

A quick (uncompiled, untested) code example of the first idea:

public class NamedElement extends WebElement {

  public String description;
  public WebElement element;

  public NamedElement(String description, WebElement element) {
     this.description = description;
     this.element = element;
  }
}

public class NamedElementExtractor {

   public static Collection<NamedElement> getNamedElements(Object instanceWithWebElements) {
   //instanceWithElements in your case would be an instance of the class that has the "gmail" field, i.e. the one I referred to as ClassWithGmailField above
     Collection<NamedElement> namedElements = new List<NamedElement>();
     for (Field field : instanceWithWebElements.getClass().getDeclaredFields()) {
        field.setAccessible(true);
        //maybe first check field.isAnnotationPresent(Name.class)
        String desc = field.getAnnotation(Name.class).description();
        WebElement element = field.getValue(instanceWithWebElements);
        namedElements.add(new NamedElement(desc, element));
     }
   }
}

...

for (NamedElement namedElement : NamedElementExtractor.getNamedElements(instanceWithWebElements))) {
   Click.click(namedElement);
}

...

public static void click(NamedElement namedElement) {
  try{
     namedElement.element.click();
     TestReport.addLog(LogStatus.INFO, "Element "+ namedElement.description +" clicked");
  } catch (NoSuchElementException e) {
     TestReport.addLog(LogStatus.ERROR, "Element "+ namedElement.description +" not found");
  }
}

No idea if this is appropriate/usable in your case, but it's food for thought.

kaqqao
  • 12,984
  • 10
  • 64
  • 118