jck28 - 小柒 - selenium - L2 网页 frame 与多窗口处理

一, 多窗口介绍

1,多窗口处理

  • 一个浏览器中同时打开多个窗口或选项卡。
  • 如果不进行窗口切换,就无法在新窗口中进行后续的操作。
    image

2,导入相应的依赖

 <!--    版本配置-->
    <properties>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>17</java.version>
        <junit.jupiter.version>5.9.2</junit.jupiter.version>
        <maven.compiler.version>3.11.0</maven.compiler.version>
        <maven-surefire-plugin.version>3.0.0</maven-surefire-plugin.version>
        <!-- log日志 -->
        <slf4j.version>2.0.7</slf4j.version>
        <logback.version>1.4.6</logback.version>
        <!-- allure报告 -->
        <allure.version>2.21.0</allure.version>
        <aspectj.version>1.9.19</aspectj.version>
        <allure.maven.version>2.12.0</allure.maven.version>
        <allure.cmd.download.url>
            https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline
        </allure.cmd.download.url>
        <!-- hamcrest断言 -->
        <hamcrest.version>2.2</hamcrest.version>
        <!-- yaml对应解析 -->
        <jackson.version>2.14.2</jackson.version>
        <!-- selenium安装 -->
        <selenium.verison>4.8.3</selenium.verison>
        <webdriver.manager.version>5.3.2</webdriver.manager.version>
    </properties>
    <dependencyManagement>
        <!--junit5 版本管理, 找到对应依赖关系的 pom 文件,为了解决依赖冲突问题-->
        <dependencies>
            <dependency>
                <groupId>org.junit</groupId>
                <artifactId>junit-bom</artifactId>
                <version>${junit.jupiter.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- junit 相关依赖下载-->
        <!-- junit5 -->
        <dependency>
            <!-- 组织的名称;仓库中唯一标识一个项目,确保项目的唯一性 -->
            <groupId>org.junit.jupiter</groupId>
            <!-- 项目的名称或模块的名称  -->
            <artifactId>junit-jupiter</artifactId>
            <!-- 依赖的作用范围
                    compile:默认的作用范围,表示在编译阶段和运行时都是可见的
                    test:表示依赖只在测试阶段 src/test下可见。
                    provided:表示依赖在编译阶段和测试阶段是可见的。
                    runtime:表示依赖在编译阶段不可见,但在运行时可见。-->
            <scope>test</scope>
        </dependency>
        <!-- junit5-suite -->
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 用做兼容老版本 -->
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- hamcrest断言 -->
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest</artifactId>
            <version>${hamcrest.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- yaml文件解析-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-yaml</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!-- log日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
            <scope>compile</scope>
        </dependency>
        <!-- allure报告-->
        <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-junit5</artifactId>
            <version>${allure.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <!-- selenium安装 -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>${selenium.verison}</version>
        </dependency>
        <!-- webdrivermanager -->
        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>${webdriver.manager.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- maven 命令行执行插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven-surefire-plugin.version}</version>
                <configuration>
                    <argLine>
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                    </argLine>
                    <includes>
                        <include>**/*Test</include>
                        <include>**/Test*</include>
                    </includes>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.junit.jupiter</groupId>
                        <artifactId>junit-jupiter-engine</artifactId>
                        <version>${junit.jupiter.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                        <version>${junit.jupiter.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
            <!--maven 编译使用插件-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.version}</version>
                <configuration>
                    <parameters>true</parameters>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${maven.compiler.encoding}</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>io.qameta.allure</groupId>
                <artifactId>allure-maven</artifactId>
                <version>${allure.maven.version}</version>
                <configuration>
                    <reportVersion>${allure.version}</reportVersion>
                    <allureDownloadUrl>${allure.cmd.download.url}/${allure.version}/allure-commandline-${allure.version}.zip</allureDownloadUrl>
                </configuration>
            </plugin>
        </plugins>
    </build>

3,窗口切换代码实现

package windowsHandle;

import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.jupiter.api.Assertions.assertAll;
import java.net.MalformedURLException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class WindowsHandlerTest {
    static WebDriver driver;
    List<Executable> executableList = new ArrayList<>();

    @BeforeAll
    static void setupClass() {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--remote-allow-origins=*");
        //1,使用WebDriverManager创建一个driver对象,WebDriverManager仅支持114版本以下,135不支持
//        driver = WebDriverManager.chromedriver().create();
        driver = new ChromeDriver(options);
        //2,声明隐式等待
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(8));
    }

    @AfterAll
    static void tearDownClass() throws InterruptedException {
        Thread.sleep(5000);
        driver.quit();
    }

    @Test
    void handlerTest() throws InterruptedException, MalformedURLException {
        //3,打开一个网页
        driver.get("https://vip.ceshiren.com/#/ui_study/frame");
        //4,获取打开页面的句柄
        String originHandle = driver.getWindowHandle();
        System.out.println("获取第一个页面句柄:" + originHandle);
        //5,进行业务操作,打开一个新的窗口
        driver.findElement(By.xpath("//*[text()='元素定位']")).click();
        //6,获取所有窗口的句柄
        Set<String> windowHandles = driver.getWindowHandles();
        //获取当前页面标题
        String title = driver.getTitle();
        System.out.println("当前页面标题为:" + title);
        //7,进行窗口切换操作
        for(String windowHandle : windowHandles) {
            if(!windowHandle.equals(originHandle)) {
                driver.switchTo().window(windowHandle);
                break;
            }
        }
        //8,新窗口的业务逻辑操作
        String title2 = driver.getTitle();
        System.out.println("新窗口页面标题为:" + title2);
        executableList.add(() ->assertThat(title2,containsString("测试人社区")));

        //9,切回默认页面
        driver.switchTo().window(originHandle);
        String title3 = driver.getTitle();
        System.out.println("切回默认窗口页面标题为:" + title3);
        executableList.add(() ->assertThat(title3,equalTo("霍格沃兹测试开发")));

        assertAll(executableList);

    }
}

二, frame 介绍

1,简介

  • (1)frame 是 html 中的框架。可以在同一个浏览器中显示不止一个页面。
  • (2)frame 标签包含 frameset、frame、iframe 三种。
    • frameset :frame必须嵌套frameset标签里面,frameset和普通的标签一样,不会影响正常的定位。
    • frame/iframe :直接嵌套在html里面,可以使用 index、id、name、webelement 任意种方式定位。
  • (3)如果不进行 frame 切换,就无法定位到 frame 中的元素进行后续的操作。

2,frame嵌套测试页面常见类型

3,常用方法

4代码示例

 @Test
    void frameTest(){
        //3,打开一个网页
        driver.get("https://vip.ceshiren.com/#/ui_study/frame");
        //进行业务操作,通过代码直接获取定位元素的文本信息会报错:NoSuchElementException
        //必须要切换到对应的frame才能获取到对应元素的文本
        driver.switchTo().frame("frame1");
        WebElement element = driver.findElement(By.id("frame_btn"));
        System.out.println("第1个按钮:" + element.getText());

        //切换到第二个frame
        //首先切换到父框架
        driver.switchTo().parentFrame();
        //再切换到第二个frame,方法值为frame标签的id或者name属性的值
        driver.switchTo().frame("Main");
        WebElement element2 = driver.findElement(By.id("frame_btn"));
        System.out.println("第2个按钮:" +element2.getText());
    }

    //多层嵌套frame:必须一层一层的切换,不然定位不到嵌套层的元素
    @Test
    void moreFrame(){
        //3,打开一个网页
        driver.get("https://vip.ceshiren.com/#/ui_study/iframe");
        //切换第一层frame  "//*[@class='iframe-div']")
        WebElement iframe1 = driver.findElement(By.xpath("//*[@class='iframe-div']/iframe"));
        driver.switchTo().frame(iframe1);
        //切换第二层
        WebElement iframe2 = driver.findElement(By.xpath("//*[@class='ma-2 frame2']/iframe"));
        driver.switchTo().frame(iframe2);
        //定位第二次嵌套frame的按钮元素并获取文本信息
        WebElement element = driver.findElement(By.xpath("//*[@class='VPNavBarTitle']"));
        System.out.println("嵌套层按钮元素:" + element.getText());
        //切换到最外层的frame
        driver.switchTo().defaultContent();
        //再切换到新窗口并点击新窗口
        driver.findElement(By.id("openWindows")).click();
    }