web自动化框架—BasePage 类的简单封装

优秀的框架都有属于自己的思想,在搭建web自动化测试框架时,我们通常都遵循 PO(Page Object)思想。

简单理解就是我们会把每个页面看成一个对象,一切皆对象,面向对象编码,这样会让我们更好的解耦代码,也更好的进行封装和理解。

使用selenium框架来操作页面时,最常用的都是一些点击,输入内容,页面切换等方法,如果每个页面我们都要写一遍这样的操作代码,重复性高,代码冗余。所以我们一般都会把这些共性的操作提取成一个基础类:BasePage。

以下是对该类的简单封装,还有其他的方法欢迎大家留言补充:

BasePage类:

import com.ggf.selenium.taxcp.utils.BrowserUtil;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.util.Set;

/**
 * @Description: 页面基础类,将公共方法提取出来,如:获取元素内容,点击,等待。。。
 * @Author: ggf
 * @Date: 2021/05/15
 */
public class BasePage {
    /**
     * 对元素进行点击
     * @param by 定位信息
     */
    public void click(By by) {
        waitElementClickable(by).click();
    }

    /**
     * 对元素输入内容
     * @param by 定位信息
     * @param datas 输入的内容
     */
    public void sendKeys(By by, String datas) {
        waitElementVisible(by).sendKeys(datas);
    }

    /**
     * 清除元素内容
     * @param by
     */
    public void clear(By by) {
        waitElementVisible(by).clear();
    }

    /**
     * 判断元素是否存在。
     * 使用isDisplayed() 方法,该方法判断某个元素是否在页面中存在,包含了:
     * visibility=hidden 或 display=none 时,只要在HTML代码中存在,
     * 就会返回true。
     * 扩展:
     * isEnable()-->用于判断input、select等元素是否可编辑。
     * isSelected()-->判断元素是否被选中。
     * @param by 定位信息
     * @return 存在:true 不存在:false
     */
    public boolean isElementExist(By by) {
        return waitElementVisible(by).isDisplayed();
    }

    /**
     * 获取元素文本内容
     * @param by 定位信息
     * @return 返回文本内容
     */
    public String getElementText(By by) {
        return waitElementVisible(by).getText();
    }

    /**
     * 获取元素属性值
     * @param by 定位信息
     * @param attributeName 属性名称
     * @return 返回属性值
     */
    public String getElementAttributeValue(By by, String attributeName) {
        return waitElementVisible(by).getAttribute(attributeName);
    }

    /**
     * 等待元素可见,显式等待10秒。
     * @param by 定位信息
     * @return 返回element对象
     */
    public WebElement waitElementVisible(By by) {
        WebDriverWait webDriverWait = new WebDriverWait(BrowserUtil.getDriver(),10);
        return webDriverWait.until(ExpectedConditions.visibilityOfElementLocated(by));
    }

    /**
     * 等待元素可点击,显式等待10秒。
     * @param by 定位信息
     * @return 返回element对象
     */
    public WebElement waitElementClickable(By by) {
        WebDriverWait webDriverWait = new WebDriverWait(BrowserUtil.getDriver(), 10);
        return webDriverWait.until(ExpectedConditions.elementToBeClickable(by));
    }

    /**
     * 等待iframe可见并且根据By切换到iframe框架中
     * @param by 元素定位信息
     */
    public void waitIframeAndSwitch(By by) {
        WebDriverWait webDriverWait = new WebDriverWait(BrowserUtil.getDriver(), 10);
        webDriverWait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(by));
    }

    /**
     * 等待iframe可见并且根据名称切换。
     * @param frameName iframe名称
     */
    public void waitIframeAndSwitch(String frameName) {
        WebDriverWait webDriverWait = new WebDriverWait(BrowserUtil.getDriver(), 10);
        webDriverWait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frameName));
    }

    /**
     * 滑动列表找元素并且进行点击
     * @param selectedText  选中元素文本
     * @param by  正在加载类似元素的定位表达式
     * @throws InterruptedException
     */
    public static void clickElementInList(String selectedText, By by) throws InterruptedException {
        // 滑动之前的页面源代码信息
        String beforeSource = "";
        // 滑动之后的页面源代码信息
        String afterSource = "";
        // 获取webdriver
        WebDriver driver = BrowserUtil.getDriver();

        // 循环条件
        // 1、找到了元素,跳出循环
        // 2、如果没有找到元素???怎么跳出循环
        while (true) {
            WebElement webElement = driver.findElement(by);
            beforeSource = driver.getPageSource();
            JavascriptExecutor javascriptExecutor = (JavascriptExecutor) driver;
            javascriptExecutor.executeScript("arguments[0].scrollIntoView(0);", webElement);
            // 如果当前页面有想要找的元素,怎么判断是否有??--getPageSource
            if (driver.getPageSource().contains(selectedText)) {
                driver.findElement(By.linkText(selectedText)).click();
                break;
            }
            Thread.sleep(1000);
            afterSource = driver.getPageSource();
            // 页面元素没有变化---滑动到了最底部
            if (afterSource.equals(beforeSource)) {
                break;
            }
            Thread.sleep(1500);
        }
    }

    /**
     * 滚动到指定元素上的方法
     * @param by 定位信息
     */
    public void scrollIntoElement(By by){
        WebElement webElement= waitElementVisible(by);
        JavascriptExecutor javascriptExecutor = (JavascriptExecutor) BrowserUtil.getDriver();
        javascriptExecutor.executeScript("arguments[0].scrollIntoView(0);", webElement);
    }

    /**
     * 根据title切换窗口的方法
     * @param title 窗口的标题
     */
    public void switchWindowByTitle(String title){
        WebDriver driver = BrowserUtil.getDriver();
        Set<String> handles = driver.getWindowHandles();
        // 切换窗口的方式--循环遍历handles集合
        for (String handle : handles) {
            //判断是哪一个页面的句柄??--根据什么来判断???title
            if(driver.getTitle().equals(title)){
                break;
            }else{
                //切换窗口--根据窗口标识来切换
                driver.switchTo().window(handle);
            }

        }
    }

    /**
     * 根据url内容切换窗口的方法
     * @param urlFlag 窗口的标题
     */
    public void switchWindowByUrl(String urlFlag){
        WebDriver driver = BrowserUtil.getDriver();
        Set<String> handles = driver.getWindowHandles();

        for (String handle : handles) {
            //根据url内容判断句柄
            if(driver.getCurrentUrl().contains(urlFlag)){
                break;
            }else{
                //切换窗口
                driver.switchTo().window(handle);
            }

        }
    }
}

BrowserUtil类:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

/**
 * @Description: 浏览器工具类,控制浏览器的生命周期,浏览器启动,关闭
 * @Author: ggf
 * @Date: 2021/05/15
 */
public class BrowserUtil {

    /**
     *为解决多线程问题,通过ThreadLocal机制来控制
     */
    private static ThreadLocal<WebDriver> threadLocal = new ThreadLocal<WebDriver>();

    /**
     * 通过传入不同的浏览器名称,获取浏览器驱动
     * @param driverType 不同的浏览器 chrome ie Firefox
     */
    public static void setDriverType(String driverType) {
        // 判断输入内容是否为空。
        if (driverType != "" && driverType != null) {
            // 创建不同的浏览器驱动
            if ("chrome".equalsIgnoreCase(driverType)) {
                ChromeDriver chromeDriver = new ChromeDriver();
                setDriver(chromeDriver);
            }else if ("ie".equalsIgnoreCase(driverType)) {
                InternetExplorerDriver ieDriver = new InternetExplorerDriver();
                setDriver(ieDriver);
            }else if ("firefox".equalsIgnoreCase(driverType)) {
                FirefoxDriver fireDriver = new FirefoxDriver();
                setDriver(fireDriver);
            }
        }
    }

    /**
     * 从线程ThreadLocal中获取对象
     * @return
     */
    public static WebDriver getDriver() {
        return threadLocal.get();
    }

    /**
     * 设置对象到ThreadLocal中
     * @param driver
     */
    public static void setDriver(WebDriver driver) {
        threadLocal.set(driver);
    }

    /**
     * 关闭浏览器
     */
    public void closeBrowser() {
        getDriver().close();
    }
}