java - 如何将 WebElement 存储在 json 或属性中以便我可以轻松更改它

标签 java selenium automated-tests

@FindBy(xpath="//button[@class='submitButton']")
WebElement submit;

我在使用 POM 的测试框架中使用了这种类型的代码。

我想将这个 Xpath 存储在属性文件中,并且只想为其分配 key 。

例如:

@FindBy(xpath=config.getsubmit())
WebElement submit;

有什么方法可以存储 WebElement 或制作 WebElement 存储库吗?

最佳答案

您不能使用普通的 PageObjects 和 PageFactory 实现这一点。

您需要进行一些自定义,然后才能完成此操作。

要完成此操作,您基本上需要以下内容

  • org.openqa.selenium.support.pagefactory.ElementLocator 的自定义实现,以便您可以让它兑现对 findElementfindElements 的调用> 使用提供的 WebDriver 实例。默认实现只是从注释中查询。
  • org.openqa.selenium.support.pagefactory.ElementLocatorFactory 的自定义实现,以便它可以生成您自定义的 ElementLocator 实例,而不是默认实例。
  • 自定义注释解析器,以便您可以通过扩展 org.openqa.selenium.support.pagefactory.AbstractAnnotations 来解析添加到 WebElement 对象的自定义注释
  • 最后但并非最不重要的一点是,捕获一些元数据的自定义注释可用于从给定 Web 元素的 JSON 文件中读取定位器

有了这些你可以做以下事情

  • 定义您的自定义注释,这样您就可以从文件中唯一地识别定位器。
  • 定义一个自定义注释解析器,它将读取自定义注释的属性并构造一个 By 对象
  • 定义一个自定义 ElementLocator,以便它使用自定义注释解析器来查找元素。
  • 定义一个自定义 ElementLocatorFactory,以便它生成自定义 ElementLocator 的实例。

我之前曾将整个概念写成博客。请看一下here

要全面了解 PageFactory 的工作原理,请查看 this。我创建的博客。

有人以我的博文为起点并构建了一个库,它也可以为您完成所有这些工作。你可以从这里消费它https://github.com/shchukax/search-with

为了完整起见,我包含了我博客中的所有代码片段

json 看起来像这样

[
  {
    "pageName": "HomePage",
    "name": "abTesting",
    "locateUsing": "xpath",
    "locator": "//a[contains(@href,'abtest')]"
  },
  {
    "pageName": "HomePage",
    "name": "checkBox",
    "locateUsing": "xpath",
    "locator": "//a[contains(@href,'checkboxes')]"
  },
  {
    "pageName": "CheckboxPage",
    "name": "checkBox1",
    "locateUsing": "xpath",
    "locator": "//input[@type='checkbox'][1]"
  },
  {
    "pageName": "CheckboxPage",
    "name": "checkBox2",
    "locateUsing": "xpath",
    "locator": "//input[@type='checkbox'][2]"
  }
]

自定义注释看起来像这样

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.FIELD)
public @interface SearchWith {
    String inPage() default "";

    String locatorsFile() default "";

    String name() default "";
}

自定义ElementLocator实现

import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.pagefactory.AbstractAnnotations;
import org.openqa.selenium.support.pagefactory.ElementLocator;

import java.util.List;

public class FileBasedElementLocator implements ElementLocator {

    private final SearchContext searchContext;
    private final boolean shouldCache;
    private final By by;
    private WebElement cachedElement;
    private List<WebElement> cachedElementList;


    public FileBasedElementLocator(SearchContext searchContext, AbstractAnnotations annotations) {
        this.searchContext = searchContext;
        this.shouldCache = annotations.isLookupCached();
        this.by = annotations.buildBy();
    }

    @Override
    public WebElement findElement() {
        if (cachedElement != null && shouldCache) {
            return cachedElement;
        }

        WebElement element = searchContext.findElement(by);
        if (shouldCache) {
            cachedElement = element;
        }

        return element;

    }

    @Override
    public List<WebElement> findElements() {
        if (cachedElementList != null && shouldCache) {
            return cachedElementList;
        }

        List<WebElement> elements = searchContext.findElements(by);
        if (shouldCache) {
            cachedElementList = elements;
        }

        return elements;
    }
}

自定义元素定位器工厂如下所示

import org.openqa.selenium.SearchContext;
import org.openqa.selenium.support.pagefactory.ElementLocator;
import org.openqa.selenium.support.pagefactory.ElementLocatorFactory;

import java.lang.reflect.Field;

public class FileBasedElementLocatorFactory implements ElementLocatorFactory {
    private final SearchContext searchContext;

    public FileBasedElementLocatorFactory(SearchContext searchContext) {
        this.searchContext = searchContext;
    }

    @Override
    public ElementLocator createLocator(Field field) {
        return new FileBasedElementLocator(searchContext, new CustomAnnotations(field));
    }
}

AbstractAnnotations 的自定义实现

import com.google.common.base.Preconditions;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.openqa.selenium.By;
import org.openqa.selenium.support.CacheLookup;
import org.openqa.selenium.support.pagefactory.AbstractAnnotations;
import organized.chaos.annotations.SearchWith;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.util.Iterator;

class CustomAnnotations extends AbstractAnnotations {
    private final Field field;

    CustomAnnotations(Field field) {
        this.field = field;
    }

    @Override
    public By buildBy() {
        SearchWith search = field.getAnnotation(SearchWith.class);
        Preconditions.checkArgument(search != null, "Failed to locate the annotation @SearchWith");
        String elementName = search.name();
        String pageName = search.inPage();
        String locatorsFile = search.locatorsFile();
        Preconditions
            .checkArgument(isNotNullAndEmpty(elementName), "Element name is not found.");
        Preconditions.checkArgument(isNotNullAndEmpty(pageName), "Page name is missing.");
        Preconditions.checkArgument(isNotNullAndEmpty(locatorsFile), "Locators File name not provided");
        File file = new File(locatorsFile);
        Preconditions.checkArgument(file.exists(), "Unable to locate " + locatorsFile);
        try {
            JsonArray array = new JsonParser().parse(new FileReader(file)).getAsJsonArray();
            Iterator&amp;lt;JsonElement&amp;gt; iterator = array.iterator();
            JsonObject foundObject = null;
            while (iterator.hasNext()) {
                JsonObject object = iterator.next().getAsJsonObject();
                if (pageName.equalsIgnoreCase(object.get("pageName").getAsString()) &&
                    elementName.equalsIgnoreCase(object.get("name").getAsString())) {
                    foundObject = object;
                    break;
                }
            }
            Preconditions.checkState(foundObject != null, "No entry found for the page [" + pageName + "] in the "
                + "locators file [" + locatorsFile + "]");
            String locateUsing = foundObject.get("locateUsing").getAsString();
            if (! ("xpath".equalsIgnoreCase(locateUsing))) {
                throw new UnsupportedOperationException("Currently " + locateUsing + " is NOT supported. Only xPaths "
                    + "are supported");
            }

            String locator = foundObject.get("locator").getAsString();
            Preconditions.checkArgument(isNotNullAndEmpty(locator), "Locator cannot be null (or) empty.");
            return new By.ByXPath(locator);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public boolean isLookupCached() {
        return (field.getAnnotation(CacheLookup.class) != null);
    }

    private boolean isNotNullAndEmpty(String arg) {
        return ((arg != null) && (! arg.trim().isEmpty()));
    }
}

这是页面对象类的样子

import org.openqa.selenium.WebElement;
import organized.chaos.annotations.SearchWith;

public class HomePage {
    public static final String PAGE = "HomePage";
    @SearchWith (inPage = HomePage.PAGE, locatorsFile = "src/main/resources/locators.json", name = "abTesting")
    private WebElement abTestingLink = null;

    @SearchWith (inPage = HomePage.PAGE, locatorsFile = "src/main/resources/locators.json", name = "checkBox")
    private WebElement checkBoxLink = null;

    public HomePage() {
    }

    public CheckBoxPage navigateToCheckBoxPage() {
        checkBoxLink.click();
        return new CheckBoxPage();
    }
}

另一个页面类

import org.openqa.selenium.WebElement;
import organized.chaos.annotations.SearchWith;

public class CheckBoxPage {
    private static final String PAGE = "CheckBoxPage";

    @SearchWith (inPage = CheckBoxPage.PAGE, locatorsFile = "src/main/resources/locators.json", name = "checkBox1")
    private WebElement checkBoxOne;

    @SearchWith (inPage = CheckBoxPage.PAGE, locatorsFile = "src/main/resources/locators.json", name = "checkBox2")
    private WebElement checkBoxTwo;

    public void unCheckCheckBoxTwo() {
        if (checkBoxTwo.isSelected()) {
            checkBoxTwo.click();
        }
    }

    public boolean isCheckBoxTwoUnchecked() {
        return (! checkBoxTwo.isSelected());
    }
}

这是一个使用它的测试类

import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.ElementLocatorFactory;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import organized.chaos.pages.CheckBoxPage;
import organized.chaos.pages.HomePage;
import organized.chaos.support.FileBasedElementLocatorFactory;

public class AlteredPageFactoryDemo {

    private RemoteWebDriver driver;

    @BeforeClass
    public void setup() {
        driver = new ChromeDriver();
    }

    @AfterClass
    public void tearDown() {
        if (driver != null) {
            driver.quit();
        }
    }

    @Test
    public void testMethod() {
        driver.get("https://the-internet.herokuapp.com/");
        HomePage homePage = new HomePage();
        ElementLocatorFactory factory = new FileBasedElementLocatorFactory(driver);
        PageFactory.initElements(factory, homePage);
        CheckBoxPage checkboxPage = homePage.navigateToCheckBoxPage();
        PageFactory.initElements(factory, checkboxPage);
        checkboxPage.unCheckCheckBoxTwo();
        Assert.assertTrue(checkboxPage.isCheckBoxTwoUnchecked());
    }
}

关于java - 如何将 WebElement 存储在 json 或属性中以便我可以轻松更改它,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53850655/

相关文章:

java - 获取样式等于 x 的 id - Java - Selenium WebDriver

python - 如何避免 selenium webdriver 的套接字超时?

c# - Selenium Webdriver/C# - 如何在点击后确认页面加载?

css - 如何获得:before css element value

Java 8 : extract a substream from a stream

java - Spring Boot 和 Thymeleaf 中的 Action 监听器

java - 不同名称、相同内容的文件的哈希函数

javascript - JWPlayer 和 S3 : calculated signature does not match the provided one

python - RobotFramework:为什么要用关键字/机器人框架语法编写测试?

ios-simulator - Xcode 7 UI 测试失败,错误为 "Timed out waiting for key event to complete"