You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Selenium/Jest在同一会话的新Chrome窗口中运行并发测试

解决方案:基于会话复用的Jest并发Selenium测试

针对Jest test.concurrent 不等待beforeAll执行完成的问题,我们可以通过全局预初始化认证会话+会话复用的方式实现并发测试,同时避免重复执行认证与发布操作。

核心思路

  1. 在所有测试(包括并发测试)启动前,提前完成一次认证和站点发布,保存Selenium会话的核心信息(会话ID、服务器地址)。
  2. 每个并发测试用例基于已保存的会话信息,创建独立的Selenium Driver实例,共享已认证的会话状态,无需重复认证。
  3. 全局清理阶段统一关闭初始会话,避免资源泄漏。

步骤1:实现全局初始化脚本(Setup)

创建global-setup.js,在Jest启动所有测试前完成认证和会话信息保存:

const { Builder, Browser } = require('selenium-webdriver');
const fs = require('fs').promises;
const path = require('path');

module.exports = async () => {
  // 初始化Driver并完成认证、发布
  const driver = new Builder().forBrowser(Browser.CHROME).build();
  try {
    await authticateAndReleaseSite(driver);
    
    // 获取会话关键信息:会话ID、Selenium服务器地址、原始窗口句柄
    const session = await driver.getSession();
    const executor = driver.getExecutor();
    const sessionInfo = {
      sessionId: session.getId(),
      browserUrl: executor.getAddress(),
      originalWindow: await driver.getWindowHandle()
    };

    // 写入临时文件供测试用例读取
    await fs.writeFile(
      path.join(__dirname, '.session-cache.json'),
      JSON.stringify(sessionInfo)
    );
    // 注意:此处不要调用driver.quit(),需保留会话供后续测试复用
  } catch (error) {
    await driver.quit();
    throw error;
  }
};

步骤2:实现全局清理脚本(Teardown)

创建global-teardown.js,在所有测试完成后关闭初始会话:

const { Builder, Browser } = require('selenium-webdriver');
const fs = require('fs').promises;
const path = require('path');

module.exports = async () => {
  try {
    // 读取会话信息
    const sessionInfo = JSON.parse(
      await fs.readFile(path.join(__dirname, '.session-cache.json'), 'utf8')
    );

    // 连接到初始会话并关闭整个浏览器
    const driver = await new Builder()
      .forBrowser(Browser.CHROME)
      .usingServer(sessionInfo.browserUrl)
      .withSession(sessionInfo.sessionId)
      .build();
    await driver.quit();

    // 清理临时文件
    await fs.unlink(path.join(__dirname, '.session-cache.json'));
  } catch (error) {
    // 忽略清理阶段的非致命错误
    console.warn('清理会话时出现异常:', error.message);
  }
};

步骤3:配置Jest启用全局脚本

修改jest.config.js,指定全局初始化和清理脚本:

module.exports = {
  globalSetup: './global-setup.js',
  globalTeardown: './global-teardown.js',
  testTimeout: 30000, // 根据测试时长调整超时时间
  // 其他Jest配置...
};

步骤4:编写并发测试用例

在测试文件中,每个并发测试复用已认证的会话,独立创建Driver实例:

const { Builder, Browser } = require('selenium-webdriver');
const fs = require('fs').promises;
const path = require('path');
const Product = require('./Product');

describe('Test-Suite', () => {
  let sessionInfo;

  // 在当前测试块启动前读取会话缓存(此时全局Setup已完成)
  beforeAll(async () => {
    sessionInfo = JSON.parse(
      await fs.readFile(path.join(__dirname, '.session-cache.json'), 'utf8')
    );
  });

  // 并发执行测试用例
  test.concurrent.each(testCases)('$testcase', async (testCase) => {
    // 基于已认证会话创建独立Driver实例
    const driver = await new Builder()
      .forBrowser(Browser.CHROME)
      .usingServer(sessionInfo.browserUrl)
      .withSession(sessionInfo.sessionId)
      .build();

    const product = new Product(driver);
    let testWindow;

    try {
      // 打开独立窗口执行当前测试,避免并发干扰
      testWindow = await driver.switchTo().newWindow('window');
      
      // 执行具体测试逻辑
      // await product.runTest(testCase);
    } finally {
      // 清理当前测试的窗口
      if (testWindow) {
        await driver.switchTo().window(testWindow);
        await driver.close();
        await driver.switchTo().window(sessionInfo.originalWindow);
      }
      // 断开Driver连接(不关闭全局会话)
      await driver.dispose();
    }
  });
});

关键注意事项

  • 会话复用兼容性:确保使用的Selenium Driver(如ChromeDriver)支持会话复用,不同浏览器的配置可能略有差异。
  • 并发隔离:每个测试用例必须使用独立的窗口执行,避免多个并发测试操作同一个DOM导致的竞争问题。
  • 超时配置:并发测试可能需要更长的超时时间,需在Jest配置中调整testTimeout。
  • 资源限制:根据机器性能调整Jest并发测试的数量(通过--maxWorkers参数),避免浏览器资源耗尽。

内容的提问来源于stack exchange,提问作者GST

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 10:32:02