Skip to content
This repository has been archived by the owner on Nov 23, 2021. It is now read-only.

Loadable Components

Michał Krzyżanowski edited this page Aug 3, 2018 · 9 revisions

Loadable Components. Bobcat Way.


⚠️ This functionality is deprecated since 1.5.0 and will be removed in Bobcat 2.0 ⚠️

Overview

The @LoadableComponent is an annotation that aims to make writing Page Objects with less boilerplate code for ensuring that some certain condition have been met before running some method. The annotation keeps information about condition implementation which should be evaluated before running method from WebElement interface. Consider the following scenario: we want to click on Confirm button but after it's got visible. The old approach would look like this:

@PageObject
public class CheckoutSection {

  @Inject
  private BobcatWait wait;

  @FindBy(css = "button.submit")
  private WebElement button;

  //..

  public void submitForm() {
    wait.withTimeout(Timeouts.MEDIUM).until(ignored -> button.isDisplayed());
    button.click();
  }
//...

}

Suppose that you have multiple buttons like this and each one of these needs the same verification before performing an action on it. Using Bobcat's Loadable Components you can extract this condition to an annotation.

@PageObject
public class CheckoutSection {

  @FindBy(css = "button.submit")
  @LoadableComponent(condClass = VisibilityCondition.class)
  private WebElement button;

  //..

  public void submitForm() {
    button.click();
  }
//...

Where VisibilityCondition class can be implemented like this:

public class VisibilityCondition implements LoadableComponentCondition {

  @Inject
  private BobcatWait wait;

  @Override
  public boolean check(Object subject, LoadableComponent data) {
    WebElement subject = (WebElement) object;
    return wait.withTimeout(data.timeout()).until(ignored -> subject.isDisplayed());
  }
}

From now on, each time before performing some action on button field, the provided Condition will be evaluated. The key is to implement the LoadableComponentCondition interface with check() method. The subject that you are getting form method parameters is fully initialized field on which you have put the @LoadableComponent annotation - in this case the button WebElement from CheckoutSection class. What we are getting here is less code with reusable component that we can put on any field we want. If you want you can put multiple @LoadableComponent annotations on a single field.

Loadable components hierarchy

You can put @LoadableComponent annotation also on Page Object fields. This entails support for hierarchical condition checking when we are using Loadable Components in multiple nested Page Objects. Let's consider the following class structure:

Page Objects

Condition classes are provided in the @LoadableComponent annotation like this:

@PageObject
public class A {
//...
  @FindBy(css = ".someClass")
  @LoadableComponent(condClass = Condition2.class)  
  private B b;
//...
}
@PageObject
public class B {
//...
  @FindBy(css = ".someOtherClass")
  @LoadableComponent(condClass = Condition3.class)  
  private C c;
//...
}

and so on. With such structure when invoking some method on Web Element button, the entire hierarchy of conditions is evaluated from the top to the bottom. In this case Condition4 would be evaluated as the last one.

Monitored methods

Note: this feature will be available since 1.1.5 release

By default, almost each of provided loadable conditions (except ClickabilityCondition) are listening to each of WebElement's method invocation. Invoking one of these is starting execution of loadable components condition hierarchy.

We can think of some situation where this is not needed - for example when we have visibility condition set and we're invoking WebElement::getAttribute method - in this case the visibility condition does not have to be met, as element can be present in the markup but not visible. Getting attributes from it won't break anything. For such cases we can determine which methods of WebElement class are monitored (loadable conditions hierarchy evaluations starts after invoking monitored method). The place in we can configure these methods is our LoadableComponentCondition implementation. The interface LoadableComponentCondition has method #getMonitoredMethods which can be overridden to provide a predefined set of metods (like interactive ones) or your full custom set of these. Take a look at the example:

public class ClickabilityCondition implements LoadableComponentCondition {

  @Inject
  private BobcatWait wait;

  @Override
  public boolean check(Object object, LoadableComponent data) {
    if (object instanceof WebElement) {
      WebElement subject = (WebElement) object;
      return wait.withTimeout(data.timeout()).until(ignored -> ExpectedConditions.
              elementToBeClickable(subject), data.delay()).apply(null) != null;
    }
    throw new LoadableConditionException("Loadable Component Condition placed on not applicable field");
  }

  @Override
  public List<String> getMonitoredMethods() {
    return CommonMonitoredMethods.INTERACTIVE_METHODS.getMethodNames();
  }
}

The below method is responsible for setting the monitored names to the particular loadable component condition.

 @Override
  public List<String> getMonitoredMethods() {
    return CommonMonitoredMethods.INTERACTIVE_METHODS.getMethodNames();
  }

This method tells that only interactive methods like: click, sendKeys, clear etc. should start evaluation of loadable conditions. You can provide your custom list of monitored method names here if you need.

Limitations

This feature has it's limitations which should be mentioned:

  1. Loadable Components are strongly connected to class fields which they are annotating. When functionality of some component depend on other (f.e. like before providing value to some text box, a certain button should be clickable) then assuring that dependency is met shouldn't be done using Loadable Components.
  2. The entire mechanism does not support the "lazy approach". It means that each condition or condition tree will be evaluated at each time.
  3. Implementations of LoadableComponentCondition should be public and have default public constructor only.

Getting started with Bobcat

  1. Getting started

AEM Related Features

  1. Authoring tutorial - Classic
  1. AEM Classic Authoring Advanced usage
  1. Authoring tutorial - Touch UI
Clone this wiki locally