1. 概述

本文将介绍如何使用Selenium处理浏览器标签页。实际测试中,点击链接或按钮时经常会在新标签页打开页面。这种场景下,我们需要正确处理标签页才能继续执行测试。本文涵盖在新标签页打开页面、切换标签页和关闭标签页的操作。所有示例将基于测试站点 https://testpages.herokuapp.com

2. 环境准备

基于 WebDriver 设置,我们创建一个 SeleniumTestBase 基类,负责 WebDriver 的初始化和清理。测试类将继承该基类。同时定义一个标签页处理的辅助类 TabHelper,包含打开、切换和关闭标签页的方法。这些方法将在后续章节详细说明。我们在 SeleniumTestBase 中初始化 TabHelper 实例。所有示例使用 JUnit5。

初始化代码放在带 @BeforeAll 注解的 init() 方法中:

@BeforeAll
public static void init() {
    setupChromeDriver();
}

清理方法在所有测试结束后关闭整个浏览器:

@AfterAll
public static void cleanup() {
    if (driver != null) {
        driver.quit();
    }
}

3. 基础知识

3.1. 链接的 target 属性

当点击链接或按钮在新标签页打开页面时,就需要处理标签页。网站中设置了 target="_blank" 属性的链接会在新标签页打开,例如:

<a href="https://www.baeldung.com/" target="_blank">Baeldung.com</a>

这类链接会将目标页面(如 https://www.baeldung.com)在新标签页打开。

3.2. 窗口句柄

在Selenium中,每个标签页都有一个唯一的窗口句柄(字符串)。Chrome标签页的句柄以 CDwindow 开头,后跟32个十六进制字符,例如 CDwindow-CDE9BEF919431FDAA0FC9CB7EBBD4E1A切换到特定标签页时必须使用窗口句柄,因此测试中需要存储这些句柄。

4. 标签页操作

4.1. 打开标签页

Selenium 4.0+ 版本无需使用JavaScript或浏览器快捷键即可打开新标签页WebDriver 提供以下方法:

driver.switchTo().newWindow(WindowType.TAB);

如前所述,某些链接设置了 target 属性。这种情况下无需手动打开标签页,但需要处理切换和关闭操作。虽然这类链接会在新标签页打开页面,但不会自动切换到新标签页,需要手动处理。一个简单粗暴的方案是:比较点击链接前后的窗口句柄集合,新增的句柄就是新标签页。

通过 WebDriver 的以下方法获取窗口句柄集合和当前标签页句柄:

driver.getWindowHandles();
driver.getWindowHandle()

利用这些方法,我们在 TabHelper 类中实现辅助方法:打开链接并切换到新标签页(仅当确实打开新标签页时才切换):

String openLinkAndSwitchToNewTab(By link) {
    String windowHandle = driver.getWindowHandle();
    Set<String> windowHandlesBefore = driver.getWindowHandles();

    driver.findElement(link).click();
    Set<String> windowHandlesAfter = driver.getWindowHandles();
    windowHandlesAfter.removeAll(windowHandlesBefore);

    Optional<String> newWindowHandle = windowHandlesAfter.stream().findFirst();
    newWindowHandle.ifPresent(s -> driver.switchTo().window(s));

    return windowHandle;
}

核心逻辑:通过点击前后的句柄集合差集找到新标签页句柄。方法还返回切换前的原始句柄,方便后续操作。

4.2. 切换标签页

存在多个标签页时,需要手动切换。使用以下语句切换到指定句柄的标签页(destinationWindowHandle 为目标句柄):

driver.switchTo().window(destinationWindowHandle)

实现辅助方法,接收目标句柄并切换,同时返回切换前的当前句柄:

public String switchToTab(String destinationWindowHandle) {
    String currentWindowHandle = driver.getWindowHandle();
    driver.switchTo().window(destinationWindowHandle);
    return currentWindowHandle;
}

4.3. 关闭标签页

测试结束后或不再需要某些标签页时,应将其关闭。Selenium 提供关闭当前标签页的方法(如果是最后一个标签页则关闭整个浏览器):

driver.close();

利用该方法可实现关闭除指定标签页外的所有标签页:

void closeAllTabsExcept(String windowHandle) {
    for (String handle : driver.getWindowHandles()) {
        if (!handle.equals(windowHandle)) {
            driver.switchTo().window(handle);
            driver.close();
        }
    }
    driver.switchTo().window(windowHandle);
}

逻辑:遍历所有句柄,关闭非目标标签页,最后确保切换回保留的标签页。

进一步封装关闭除当前标签页外的所有标签页:

void closeAllTabsExceptCurrent() {
    String currentWindow = driver.getWindowHandle();
    closeAllTabsExcept(currentWindow);
}

SeleniumTestBase@AfterEach 方法中调用此方法,确保每个测试后清理多余标签页,避免测试间相互影响:

@AfterEach
public void closeTabs() {
    tabHelper.closeAllTabsExceptCurrent();
}

4.4. 使用快捷键处理标签页

⚠️ 踩坑提示:过去可通过浏览器快捷键(如 Ctrl+T)处理标签页,但由于 ChromeDriver 的更新,此方法已失效

5. 测试用例

通过简单测试验证 TabHelper 的功能。测试类需继承 SeleniumTestBase

class SeleniumTabsLiveTest extends SeleniumTestBase {
    //...
}

在测试类中定义常量(URL 和定位器):

By LINK_TO_ATTRIBUTES_PAGE_XPATH = By.xpath("//a[.='Attributes in new page']");
By LINK_TO_ALERT_PAGE_XPATH = By.xpath("//a[.='Alerts In A New Window From JavaScript']");

String MAIN_PAGE_URL = "https://testpages.herokuapp.com/styled/windows-test.html";
String ATTRIBUTES_PAGE_URL = "https://testpages.herokuapp.com/styled/attributes-test.html";
String ALERT_PAGE_URL = "https://testpages.herokuapp.com/styled/alerts/alert-test.html";

测试场景1:打开新标签页并切换 验证打开新标签页后能正确切换,并保持两个标签页:

void givenOneTab_whenOpenTab_thenTwoTabsOpen() {
    driver.get(MAIN_PAGE_URL);

    String mainWindow = tabHelper.openLinkAndSwitchToNewTab(LINK_TO_ATTRIBUTES_PAGE_XPATH);
    assertEquals(ATTRIBUTES_PAGE_URL, driver.getCurrentUrl());

    tabHelper.switchToTab(mainWindow);
    assertEquals(MAIN_PAGE_URL, driver.getCurrentUrl());
    assertEquals(2, driver.getWindowHandles().size());
}

测试场景2:关闭多余标签页 验证关闭除主标签页外的所有标签页:

void givenTwoTabs_whenCloseAllExceptMainTab_thenOneTabOpen() {
    driver.get(MAIN_PAGE_URL);
    String mainWindow = tabHelper.openLinkAndSwitchToNewTab(LINK_TO_ATTRIBUTES_PAGE_XPATH);
    assertEquals(ATTRIBUTES_PAGE_URL, driver.getCurrentUrl());
    assertEquals(2, driver.getWindowHandles().size());

    tabHelper.closeAllTabsExcept(mainWindow);

    assertEquals(1, driver.getWindowHandles().size());
    assertEquals(MAIN_PAGE_URL, driver.getCurrentUrl());
}

6. 总结

本文介绍了使用Selenium处理浏览器标签页的核心操作:

  • ✅ 通过窗口句柄区分不同标签页
  • ✅ 打开新标签页(包括自动处理 target="_blank" 链接)
  • ✅ 在标签页间切换
  • ✅ 关闭指定或所有标签页

完整实现代码可在 GitHub 查看。


原始标题:Handle Browser Tabs With Selenium

» 下一篇: Java中的Functor