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

Playwright中Session Storage配置异常,Cucumber并行测试重复登录求助

解决Cucumber并行测试中重复登录的问题

问题根源

你遇到的核心问题是并行进程之间的文件系统竞争:当多个Cucumber并行进程同时启动时,它们会几乎同时检查sessionStatePath是否存在。此时如果文件还未被第一个进程写入完成,所有进程都会判断文件不存在,进而各自执行登录流程。并行数为4时,这种竞争导致所有进程都触发登录;并行数为2时,前两个进程中有一个先完成文件写入,后续启动的进程就能读取到已存在的Session文件,从而复用登录状态。

解决方案:预先生成Session Storage

最可靠的方式是在所有并行测试执行前,单独生成一次Session Storage文件,确保所有并行进程启动时都能直接复用已有的登录状态,彻底避免重复登录。

步骤1:编写独立的Session生成脚本

创建一个单独的Node.js脚本(比如generate-session.js),专门负责登录并保存Session状态:

const playwright = require('playwright');
const fs = require('fs');
const PageObjectManager = require('./path-to-your-po-manager'); // 替换为你的PO路径
const sessionStatePath = './session-state.json'; // 和hooks中一致的路径

async function generateSession() {
  const browser = await playwright.chromium.launch({
    channel: 'chrome',
    headless: false
  });

  const context = await browser.newContext({
    permissions: ['clipboard-read', 'clipboard-write']
  });

  const page = await context.newPage();
  const poManager = new PageObjectManager(page);
  const loginPage = await poManager.fetchLoginPage();
  const landingPage = await poManager.fetchLandingPage();

  // 执行登录流程
  await loginPage.gotoLoginPage();
  await loginPage.loginToTheApplication();
  await landingPage.closeModalDialog();

  // 保存Session状态
  await context.storageState({ path: sessionStatePath });
  console.log('Session state generated successfully.');

  await browser.close();
}

generateSession().catch(err => {
  console.error('Failed to generate session:', err);
  process.exit(1);
});

步骤2:修改hooks.js,移除登录逻辑

修改你的Before钩子,直接加载已生成的Session文件,不再判断是否需要登录:

Before(async function (scenario) {
  log(`Starting Scenario: ${scenario.pickle.name}`)
  this.browser = await playwright.chromium.launch({
    channel: 'chrome',
    headless: false,
    isEnabled: () => true,
    log: logWrapper
  })

  // 直接加载预先生成的Session文件
  const context = await this.browser.newContext({
    storageState: sessionStatePath,
    permissions: ['clipboard-read', 'clipboard-write'],
    recordVideo: { dir: 'videos/' }
  })

  await context.setDefaultTimeout(60000)
  this.page = await context.newPage()
  this.poManager = new PageObjectManager(this.page)
  this.loginPage = await this.poManager.fetchLoginPage()
  this.landingPage = await this.poManager.fetchLandingPage()
  this.apiContext = await playwright.request.newContext()
  this.apiUtil = new APIUtil(this.apiContext)
  this.dataGenerator = new DataGenerator(this.apiContext)
  this.backEndHelper = new BackEndHelper(this.apiUtil)

  // 如果需要JWT Token,可以从Session文件中读取,或者在生成Session时单独保存
  // 示例:从Session文件中提取Token
  const sessionData = JSON.parse(fs.readFileSync(sessionStatePath, 'utf8'));
  this.jwtToken = sessionData.cookies.find(c => c.name === 'your-jwt-cookie-name')?.value;
})

步骤3:调整测试执行命令

先运行Session生成脚本,再启动Cucumber并行测试:

node generate-session.js && yarn cucumber-js path-to-feature.feature --parallel 4

你也可以把这个命令加到package.json的scripts中,方便执行:

{
  "scripts": {
    "test:parallel": "node generate-session.js && yarn cucumber-js path-to-feature.feature --parallel 4"
  }
}

额外优化建议

  • Session过期处理:如果登录Session有有效期,可以在生成脚本中添加过期检查,避免使用失效的Session。
  • 隔离测试数据:如果测试用例需要操作独立的数据,建议通过API在每个测试前初始化数据,而不是重新登录,确保复用Session的同时测试隔离性。
  • 避免重复启动浏览器:可以考虑在多个场景间复用浏览器上下文(但Cucumber并行模式下每个场景是独立进程,所以这个优化可能不适用,预先生成Session是更适合的方案)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 08:16:06