web自動化框架—BasePage 類的簡單封裝

小葛師兄 發表於 2021-05-16

優秀的框架都有屬於自己的思想,在搭建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();
    }
}