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

CodeceptJS BDD模式下如何在所有场景前执行浏览器前置操作?

可行方案整理

针对你在CodeceptJS并行测试中需要全局执行浏览器前置操作的需求,以下是几种落地性强的方案:

方案1:全局Bootstrap钩子+并发锁机制

利用CodeceptJS配置文件中的bootstrap钩子,结合文件锁避免并行进程重复执行前置操作,同时能直接访问浏览器上下文:

// codecept.conf.js
const fs = require('fs-extra');
const lockFile = './.setup.lock';
const setupFlag = './.setup.completed';

exports.config = {
  // 其他配置项...
  bootstrap: async function() {
    // 检查前置操作是否已完成
    if (await fs.pathExists(setupFlag)) return;

    // 处理并发冲突,等待锁释放后重试
    if (await fs.pathExists(lockFile)) {
      await new Promise(resolve => setTimeout(resolve, 1000));
      return await exports.config.bootstrap();
    }

    try {
      await fs.writeFile(lockFile, 'locked');
      // 获取浏览器实例执行前置操作
      const browser = await codeceptjs.container.get('browser');
      await browser.url('https://your-app.com');
      await browser.fill('#username', 'test-admin');
      await browser.fill('#password', 'test-pass');
      await browser.click('#login-btn');
      // 保存共享上下文(如登录Token)供测试用例使用
      const authToken = await browser.getCookie('auth-token');
      await fs.writeJson('./.auth-token.json', authToken);
      // 标记前置操作完成
      await fs.writeFile(setupFlag, 'done');
    } finally {
      // 释放锁
      await fs.remove(lockFile);
    }
  },
  teardown: async function() {
    // 构建结束后清理标记文件
    await fs.remove(setupFlag);
    await fs.remove('./.auth-token.json');
  }
};

Travis配置补充:将标记文件加入缓存,确保并行任务共享状态:

cache:
  directories:
    - .setup.completed
    - .auth-token.json

方案2:全局步骤+前置检查

在全局步骤文件中定义前置操作方法,结合全局Before钩子,仅在首次调用时执行浏览器操作:

// steps_file.js
const fs = require('fs-extra');
const setupFlag = './.setup.completed';

async function ensureGlobalSetup() {
  if (await fs.pathExists(setupFlag)) return;
  // 执行浏览器前置操作
  await I.amOnPage('/');
  await I.login('test-admin', 'test-pass');
  await I.createSharedTestData();
  // 标记完成
  await fs.writeFile(setupFlag, 'done');
}

module.exports = function() {
  return actor({
    ensureGlobalSetup,
    // 其他自定义步骤...
  });
};

在配置文件中绑定全局前置钩子:

// codecept.conf.js
exports.config = {
  hooks: {
    Before: async (I) => {
      await I.ensureGlobalSetup();
    }
  }
};

注意:同样需要添加并发锁机制,避免并行进程重复执行。

方案3:Travis前置任务独立执行

如果前置操作无需与测试用例共享浏览器上下文,可在Travis构建阶段单独执行一次:

  1. 编写独立的前置操作测试文件:
// setup.test.js
Feature('Global Precondition Setup');

Scenario('Create all shared test data', async (I) => {
  I.amOnPage('/');
  I.login('admin', 'admin');
  I.createTestUser();
  I.createTestProject();
});
  1. 修改Travis配置,在并行测试前执行前置任务:
# .travis.yml
cache:
  directories:
    - .setup
before_script:
  - if [ ! -f .setup/done ]; then npx codeceptjs run setup.test.js; mkdir -p .setup && touch .setup/done; fi
script:
  - npx codeceptjs run --parallel --grep "@group1" &
  - npx codeceptjs run --parallel --grep "@group2" &
  - wait

这种方式无需处理测试进程的并发冲突,前置操作仅执行一次,适合创建静态共享测试数据的场景。

内容的提问来源于stack exchange,提问作者Sarath Babu V S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 13:27:32