Dynamic Locators - dn0000001/test-automation GitHub Wiki

Sometimes you may only know part of a locator at compile time and it is only at runtime that you know the exact locator. For example, you have 2 locators, 1 generic locator that gives you the list of all the elements and a 2nd locator that you can get the specific element based on position and each element is a separate page object. There is AJAX on the page such that the elements will become stale after certain actions and you can only locate the elements for each page object (of the list) relative to a core element. Using the AjaxVisibleElementLocator to find the elements in this case is not useful because all @FindBy locators need to be static.

The solution to this problem is to use the DynamicElementLocator to find the elements. This allows you to have aliases in your locators which you can initialize at runtime such that you do not need to ensure that the 'core' element is not stale.

Examples:

  1. See HerokuappRow which models a row in a table
  2. See HerokuappRowTable1 which models a row in a table
  3. Another example:
    /**
    * Container page that uses dynamic locators
    */
    public class ContainerPage extends PageObject {
      Map<String, String> substitutions;

      @FindBy(css = ".overview.table [data-item-row]:nth-of-type(${POSITION})")
      WebComponent coreContainer;

      /**
      * Initialize page for dynamic locators
      *
      * @param context
      */
      public void initPage(TestContext context) {
        Utils.initPage(context, this, getSubstitutions());
      }

      private Map<String, String> getSubstitutions() {
        if (substitutions == null) {
          substitutions = new HashMap<String, String>();
        }

        return substitutions;
      }

      public void addSubstitution(String key, String value) {
        substitutions = getSubstitutions();
        substitutions.put(key, value);
      }

      ...
      ...
      ...
      }

    public class TestPage extends PageObject {
      @XStreamOmitField
      @FindBy(css = ".overview.table [data-item-row]")
      private List<WebElement> rowContainers;

      ...
      ...
      ...
      public List<ContainerPage> getContainers() {
        List<ContainerPage> rows = new ArrayList<ContainerPage>();

        int position = 1;
        for (WebElement element : rowContainers) {
          ContainerPage item = new ContainerPage();
          item.addSubstitution("POSITION", String.valueOf(position));
          // It is important to cast context for the correct method to be used
          item.initPage((TestContext) getContext());
          rows.add(item);
          position++;
        }

        return rows;
      }

    }
⚠️ **GitHub.com Fallback** ⚠️