PAYATHON 2026

Cucumber JS step definition timeout 设置不生效

支付老李

结论

在支持 step 级超时配置的 Cucumber-JS 版本中,{ timeout: 30 * 1000 } 的写法是正确的。timeout 的单位是毫秒,因此这里表示 30 秒。

如果测试仍然总是在 15 秒时失败,触发的通常不是当前 step 的 Cucumber 超时,而是 confirmation.isDisplayed() 内部或浏览器自动化框架设置的 15 秒等待超时。也可能是项目使用的 Cucumber-JS 版本较旧,不支持 step 级配置。

推荐设置方式

可以先在 Cucumber support 文件中设置全局默认超时:

const { setDefaultTimeout } = require('@cucumber/cucumber');

setDefaultTimeout(30 * 1000);

使用 ES Module 时:

import { setDefaultTimeout } from '@cucumber/cucumber';

setDefaultTimeout(30 * 1000);

这段代码需要在场景执行前加载,一般放在 features/support 下的初始化文件中。

如果当前版本支持 step 级 timeout,也可以保留单独配置:

Then(
  /^The "(.*)" page is displayed$/,
  { timeout: 30 * 1000 },
  async function (name) {
    let result;

    switch (name.toLowerCase()) {
      case 'home':
        result = await confirmation.isDisplayed();
        break;
      default:
        throw new Error('Please specify a valid page name: ' + name);
    }

    expect(result).to.equal(true);
  }
);

检查真正超时的位置

先查看失败信息和调用栈。如果错误类似:

function timed out, ensure the promise resolves within 15000 milliseconds

超时一般来自 Cucumber。

如果错误中出现以下关键词,则更可能是浏览器驱动或等待方法超时:

waitUntil
waitForDisplayed
element was not displayed
TimeoutError
condition timed out

此时只提高 Cucumber timeout,并不会延长 confirmation.isDisplayed() 内部的等待时间。例如,该方法内部可能设置了 15 秒超时:

async isDisplayed() {
  await confirmationElement.waitForDisplayed({
    timeout: 15 * 1000
  });

  return confirmationElement.isDisplayed();
}

需要修改实际等待操作的 timeout:

async isDisplayed() {
  await confirmationElement.waitForDisplayed({
    timeout: 30 * 1000
  });

  return confirmationElement.isDisplayed();
}

也可以让页面对象接收 timeout:

async isDisplayed(timeout = 30 * 1000) {
  await confirmationElement.waitForDisplayed({ timeout });
  return confirmationElement.isDisplayed();
}

然后在 step 中明确传入:

result = await confirmation.isDisplayed(30 * 1000);

具体使用哪种等待 API,取决于项目采用的是 WebdriverIO、Selenium、Playwright、Protractor 还是其他框架。不同框架的参数名称不能直接混用。

版本兼容问题

如果当前 Cucumber-JS 版本不支持下面这种重载形式:

Then(pattern, { timeout: 30000 }, implementation);

第二个参数可能不会按预期生效。这种情况下,应改用该版本提供的全局设置方式:

setDefaultTimeout(30 * 1000);

还要确认项目没有混用旧包名和新包名,例如同时存在:

require('cucumber');
require('@cucumber/cucumber');

setDefaultTimeout、Then 和实际执行测试的 CLI 应来自同一套 Cucumber 包。否则,超时设置可能应用到了另一份模块实例上。

注意事项

Cucumber timeout 和页面等待 timeout 是两层不同的限制:

  • Cucumber timeout 控制整个 step 最长可以执行多久。
  • 页面或元素等待 timeout 控制元素、页面状态或浏览器条件最长等待多久。

如果 payment 最长需要约 20 秒,通常应满足:

元素等待 timeout > payment 的合理最长处理时间
Cucumber step timeout > 元素等待 timeout

例如,可以将页面等待设为 30 秒,将 step timeout 设为 35 秒。不要只增加固定延时。等待 confirmation page 的明确状态或元素出现,通常更稳定。

备注:内容仅供参考。