|
9 | 9 | import aquality.selenium.core.waitings.IConditionalWait;
|
10 | 10 | import com.google.inject.Inject;
|
11 | 11 | import org.openqa.selenium.By;
|
| 12 | +import org.openqa.selenium.By.ByTagName; |
12 | 13 | import org.openqa.selenium.By.ByXPath;
|
13 | 14 | import org.openqa.selenium.InvalidArgumentException;
|
14 | 15 | import org.openqa.selenium.WebElement;
|
|
26 | 27 | public class ElementFactory implements IElementFactory {
|
27 | 28 |
|
28 | 29 | private static final int XPATH_SUBSTRING_BEGIN_INDEX = 10;
|
| 30 | + private static final int TAGNAME_SUBSTRING_BEGIN_INDEX = 12; |
| 31 | + private static final String TAGNAME_XPATH_PREFIX = "//"; |
29 | 32 | private static final Duration ZERO_TIMEOUT = Duration.ZERO;
|
30 | 33 |
|
31 | 34 | private final IConditionalWait conditionalWait;
|
@@ -59,10 +62,23 @@ public <T extends IElement> T findChildElement(IElement parentElement, By childL
|
59 | 62 | @Override
|
60 | 63 | public <T extends IElement> T findChildElement(IElement parentElement, By childLoc, String name, IElementSupplier<T> supplier, ElementState state) {
|
61 | 64 | String childName = name == null ? "Child element of ".concat(parentElement.getName()) : name;
|
62 |
| - By fullLocator = new ByChained(parentElement.getLocator(), childLoc); |
| 65 | + By fullLocator = generateAbsoluteChildLocator(parentElement.getLocator(), childLoc); |
63 | 66 | return supplier.get(fullLocator, childName, state);
|
64 | 67 | }
|
65 | 68 |
|
| 69 | + @Override |
| 70 | + public <T extends IElement> List<T> findChildElements(IElement parentElement, By childLoc, String name, Class<T> clazz, ElementsCount count, ElementState state) { |
| 71 | + IElementSupplier<T> elementSupplier = getDefaultElementSupplier(clazz); |
| 72 | + return findChildElements(parentElement, childLoc, name, elementSupplier, count, state); |
| 73 | + } |
| 74 | + |
| 75 | + @Override |
| 76 | + public <T extends IElement> List<T> findChildElements(IElement parentElement, By childLoc, String name, IElementSupplier<T> supplier, ElementsCount count, ElementState state) { |
| 77 | + String childName = name == null ? "Child element of ".concat(parentElement.getName()) : name; |
| 78 | + By fullLocator = generateAbsoluteChildLocator(parentElement.getLocator(), childLoc); |
| 79 | + return findElements(fullLocator, childName, supplier, count, state); |
| 80 | + } |
| 81 | + |
66 | 82 | @Override
|
67 | 83 | public <T extends IElement> List<T> findElements(By locator, String name, IElementSupplier<T> supplier,
|
68 | 84 | ElementsCount count, ElementState state) {
|
@@ -119,14 +135,63 @@ public <T extends IElement> List<T> findElements(By locator, String name, Class<
|
119 | 135 | * @return target element's locator
|
120 | 136 | */
|
121 | 137 | protected By generateXpathLocator(By multipleElementsLocator, WebElement webElement, int elementIndex) {
|
122 |
| - Class supportedLocatorType = ByXPath.class; |
123 |
| - if (multipleElementsLocator.getClass().equals(supportedLocatorType)) { |
| 138 | + if (isLocatorSupportedForXPathExtraction(multipleElementsLocator)) { |
124 | 139 | return By.xpath(
|
125 |
| - String.format("(%1$s)[%2$s]", multipleElementsLocator.toString().substring(XPATH_SUBSTRING_BEGIN_INDEX), elementIndex)); |
| 140 | + String.format("(%1$s)[%2$s]", extractXPathFromLocator(multipleElementsLocator), elementIndex)); |
126 | 141 | }
|
127 | 142 | throw new InvalidArgumentException(String.format(
|
128 |
| - "Cannot define unique baseLocator for element %1$s. Multiple elements' baseLocator %2$s is not %3$s, and is not supported yet", |
129 |
| - webElement.toString(), multipleElementsLocator, supportedLocatorType)); |
| 143 | + "Cannot define unique baseLocator for element %1$s. Multiple elements' baseLocator type %2$s is not supported yet", |
| 144 | + webElement.toString(), multipleElementsLocator.getClass())); |
| 145 | + } |
| 146 | + |
| 147 | + /** |
| 148 | + * Extracts XPath from passed locator. |
| 149 | + * Current implementation works only with ByXPath.class and ByTagName locator types, |
| 150 | + * but you can implement your own for the specific WebDriver type. |
| 151 | + * |
| 152 | + * @param locator locator to get xpath from. |
| 153 | + * @return extracted XPath. |
| 154 | + */ |
| 155 | + protected String extractXPathFromLocator(By locator) { |
| 156 | + Class supportedLocatorType = ByXPath.class; |
| 157 | + if (locator.getClass().equals(supportedLocatorType)) { |
| 158 | + return locator.toString().substring(XPATH_SUBSTRING_BEGIN_INDEX); |
| 159 | + } |
| 160 | + if (locator.getClass().equals(ByTagName.class)){ |
| 161 | + return TAGNAME_XPATH_PREFIX + locator.toString().substring(TAGNAME_SUBSTRING_BEGIN_INDEX); |
| 162 | + } |
| 163 | + throw new InvalidArgumentException(String.format( |
| 164 | + "Cannot define xpath from locator %1$s. Locator type %2$s is not %3$s, and is not supported yet", |
| 165 | + locator.toString(), locator.getClass(), supportedLocatorType)); |
| 166 | + } |
| 167 | + |
| 168 | + /** |
| 169 | + * Generates absolute child locator for target element. |
| 170 | + * |
| 171 | + * @param parentLoc parent locator |
| 172 | + * @param childLoc child locator relative to parent |
| 173 | + * @return absolute locator of the child |
| 174 | + */ |
| 175 | + protected By generateAbsoluteChildLocator(By parentLoc, By childLoc) { |
| 176 | + if (isLocatorSupportedForXPathExtraction(parentLoc) && isLocatorSupportedForXPathExtraction(childLoc)) { |
| 177 | + String childLocString = extractXPathFromLocator(childLoc); |
| 178 | + String parentLocString = extractXPathFromLocator(parentLoc); |
| 179 | + return By.xpath(parentLocString.concat( |
| 180 | + childLocString.startsWith(".") ? childLocString.substring(1) : childLocString)); |
| 181 | + } |
| 182 | + return new ByChained(parentLoc, childLoc); |
| 183 | + } |
| 184 | + |
| 185 | + /** |
| 186 | + * Defines is the locator can be transformed to xpath or not. |
| 187 | + * Current implementation works only with ByXPath.class and ByTagName locator types, |
| 188 | + * but you can implement your own for the specific WebDriver type. |
| 189 | + * |
| 190 | + * @param locator locator to transform |
| 191 | + * @return true if the locator can be transformed to xpath, false otherwise. |
| 192 | + */ |
| 193 | + protected boolean isLocatorSupportedForXPathExtraction(By locator) { |
| 194 | + return locator.getClass().equals(ByXPath.class) || locator.getClass().equals(ByTagName.class); |
130 | 195 | }
|
131 | 196 |
|
132 | 197 | /**
|
|
0 commit comments