Нашел способ сохранить старый и новый локаторы в одном месте, используя собственный класс ElementLocatorFactory, ElementLocator and Annotations
. Они легко впишутся в объектную модель страницы. Он использует комбинацию полей using
и locator value (id,class,css,xpath etc)
аннотации FindBy. Это хак использования FindBy. Новая аннотация была бы лучше, но это слишком много работы.
Это будет интегрировано в метод initElements PageFactory с помощью приведенного ниже кода в конструкторе класса pageobject.
OldNewElementLocatorFactory onelf = new OldNewElementLocatorFactory(driver);
PageFactory.initElements(onelf, this);
Применение -
- Та же стратегия поиска для старого и нового. Например, изменился идентификатор.
@FindBy(using="id@@id", id="newid@@oldid") или @FindBy(using="name@@name", name="newname@@oldname")
использующая часть — первая часть перед разделителем — это стратегия локатора для нового локатора, а вторая часть — для старого локатора.
часть идентификатора. Первая часть представляет собой значение для новой стратегии поиска, а вторая — для старой.
- Разные стратегии поиска для старого и нового. Например, идентификатор теперь изменился на имя.
@FindBy(using="name@@id", name="newname", id="oldid") или @FindBy(using="xpath@@css", xpath="//div /input[@id='comboid2']", css="div input[id='comboid2']")
используя часть — то же, что и выше.
часть имени — значение локатора для новой стратегии имен.
часть идентификатора — значение локатора для старой стратегии идентификатора.
- То же самое относится к FindBy, используемому вместе с переменной типа списка
@FindBy(using="class@@tag", className="newClass", tagName="input") входные данные частного списка;
@FindBy(using="class@@class", className="newClass@@oldClass") private List sameInputs;
- Разрешает стандартный формат использования аннотации FindBy. Никаких изменений не требуется. @FindBy(how=How.ID, using="origid") или @FindBy(id="origid")
ElementLocatorFactory
— поля isNew and oldNewChecked
управляют вопросом, используются ли новые или старые локаторы. Они относятся к этому классу, поскольку локаторы могут различаться на уровне страницы. Если вы не используете Java8, вам нужно будет изменить метод verifyPageAge()
. Позаботьтесь о том, чтобы поиск старого нового переключателя локатора выполнялся только один раз.
public class OldNewElementLocatorFactory implements ElementLocatorFactory {
private final SearchContext searchContext;
private boolean isNew = false;
private boolean oldNewCecked = false;
public OldNewElementLocatorFactory(SearchContext searchContext) {
this.searchContext = searchContext;
}
public ElementLocator createLocator(Field field) {
OldNewElementLocator elemLoc = new OldNewElementLocator(searchContext, field);
elemLoc.setFactory(this);
return elemLoc;
}
public void verifyPageAge(Supplier<Boolean> newLoc) {
if (!oldNewCecked) {
oldNewCecked=true;
if (newLoc.get())
isNew=true;
}
}
public boolean isNew() {
return isNew;
}
public void setNew(boolean isNew) {
this.isNew = isNew;
}
public boolean isOldNewCecked() {
return oldNewCecked;
}
public void setOldNewCecked(boolean oldNewCecked) {
this.oldNewCecked = oldNewCecked;
}
}
ElementLocator
— обрабатывает поиск нового старого переключателя локатора в методе verifyNewLocators()
. Вам нужно будет изменить этот метод для поиска вашего флага. Я предположил любой элемент с идентификатором newloc. Если не на Java8, вам нужно будет изменить метод createOldNewBy()
.
public class OldNewElementLocator implements ElementLocator {
private final SearchContext searchContext;
private final boolean shouldCache;
private By by = null;
private WebElement cachedElement;
private List<WebElement> cachedElementList;
private OldNewAnnotations annotations;
private OldNewElementLocatorFactory factory;
public OldNewElementLocator(SearchContext searchContext, Field field) {
this(searchContext, new OldNewAnnotations(field));
}
public OldNewElementLocator(SearchContext searchContext, OldNewAnnotations annotations) {
this.searchContext = searchContext;
this.shouldCache = annotations.isLookupCached();
this.annotations = annotations;
this.by = annotations.buildBy();
}
public OldNewElementLocatorFactory getFactory() {
return factory;
}
public void setFactory(OldNewElementLocatorFactory factory) {
this.factory = factory;
}
protected boolean verifyNewLocators() {
return (searchContext.findElements(By.id("newloc")).size() == 1) ? true : false;
}
protected void createOldNewBy() {
factory.verifyPageAge(this::verifyNewLocators);
if(by==null) {
by = annotations.buildOldNewBy(factory.isNew());
}
System.out.println(by.getClass().getSimpleName());
}
public WebElement findElement() {
if (cachedElement != null && shouldCache) {
return cachedElement;
}
createOldNewBy();
WebElement element = searchContext.findElement(by);
if (shouldCache) {
cachedElement = element;
}
return element;
}
public List<WebElement> findElements() {
if (cachedElementList != null && shouldCache) {
return cachedElementList;
}
createOldNewBy();
List<WebElement> elements = searchContext.findElements(by);
if (shouldCache) {
cachedElementList = elements;
}
return elements;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + " '" + by + "'";
}
}
Annotations
— управляет логикой синтаксического анализа для создания объектов By. Также содержит жестко закодированный разделитель, который я использовал — @@. Измените его или создайте для этого статическое поле.
public class OldNewAnnotations extends Annotations {
public OldNewAnnotations(Field field) {
super(field);
}
public By buildBy() {
if (assertNewOldFind())
return null;
return super.buildBy();
}
public By buildOldNewBy(boolean isNew) {
if (!assertNewOldFind())
throw new IllegalArgumentException(
"If you set the 'using' property, you cannot also set 'how'");
FindBy findBy = getField().getAnnotation(FindBy.class);
String[] using = findBy.using().split("@@");
String strategy = isNew ? using[0] : using[1];
switch (strategy) {
case "id":
return By.id(getStrategyLocator(findBy.id(), isNew));
case "name":
return By.name(getStrategyLocator(findBy.name(), isNew));
case "class":
return By.className(getStrategyLocator(findBy.className(), isNew));
case "css":
return By.cssSelector(getStrategyLocator(findBy.css(), isNew));
case "xpath":
return By.xpath(getStrategyLocator(findBy.xpath(), isNew));
case "link":
return By.linkText(getStrategyLocator(findBy.linkText(), isNew));
case "partiallink":
return By.partialLinkText(getStrategyLocator(
findBy.partialLinkText(), isNew));
case "tag":
return By.tagName(getStrategyLocator(findBy.tagName(), isNew));
}
return null;
}
private String getStrategyLocator(String value, boolean isNew) {
if (value.contains("@@")) {
String[] val = value.split("@@");
return isNew ? val[0] : val[1];
}
return value;
}
protected boolean assertNewOldFind() {
FindBys findBys = getField().getAnnotation(FindBys.class);
if (findBys != null) return false;
FindAll findAll = getField().getAnnotation(FindAll.class);
if (findAll != null) return false;
FindBy findBy = getField().getAnnotation(FindBy.class);
if (findBy.how() == How.UNSET && !"".equals(findBy.using()))
return true;
return false;
}
}
Минусы -
Проверка ошибок при использовании нового формата аннотаций невелика. Вы можете посмотреть, как сделать его прочным.
Он не обрабатывает аннотации FindBys и FindAll вместе со старым и новым локатором. Это могло бы быть легко, но исходный код Selenium имеет некоторые частные методы, которые затрудняют использование переопределения путем наследования. Вы можете посмотреть на другой способ решить эту проблему. Хотя вряд ли когда-нибудь увидишь, что эти аннотации используются.
person
Grasshopper
schedule
20.02.2018