有条件地跳过赛普拉斯的测试

Skipping a test in Cypress conditionally

我想知道我是否能够在我的测试套件中有条件地跳过测试 it() 并处理它的异步性质。

我在 Cypress 文档中阅读了有关条件测试的内容 https://docs.cypress.io/guides/core-concepts/conditional-testing.html and also mochajs documentation about it https://mochajs.org/

我的目的是检查网站上是否显示错误,如果显示错误则跳过测试。否则继续断言。

我试图在 Cypress 中测试的来自 mochajs 的代码片段是:

it('should only test in the correct environment', function() {
  if (/* check test environment */) {
    // make assertions
  } else {
    this.skip();
  }
});

所以我在赛普拉斯得到的是:

it('shows the list', function() {
    if (queryFailed()) {
      this.skip();
    } else {
      cy.get('.list')
        .should('be.visible')
    }

请注意,我将 it() 中的箭头函数更改为 function() 以便我可以使用 this.

queryFailed()是一个检查查询是否成功的函数。

function queryFailed() {
  cy.get('.spin')
    .then($container => {
      const htmlLoaded = $container[0].innerHTML;

      if (htmlLoaded.indexOf('List') !== -1) {
        return false;
      }

      if (htmlLoaded.indexOf('error') !== -1) {
        return true;
      }

      cy.wait(1000);
      queryFailed();
    });
}

简而言之,如果我等待的 div 元素的内容有 "error" 那么我知道查询失败所以我 return 为真,否则我 return 错误。

我在调试后的测试中看到的是,即使条件运行良好,JS 的异步特性与 if 同时执行 else 语句中的代码.所以最后的输出就好像根本没有条件一样,因为一切都经过了测试。

有没有更好的方法来处理 JS 的这种异步特性?

感谢您的详细描述! 我为您的第一个问题提供了解决方案

I'm trying to find out if I'm able to conditionally skip a test it() in my test suite and deal with its async nature as well.

使用环境变量,我向你报告我的解决方案(实际在我的管道中使用)。

if (!Cypress.env("SKIP_E2E_TESTS")) {
  it(...);
}

在我的 package.json 文件中,我有一个如下所示的脚本

"test": "CYPRESS_SKIP_E2E_TESTS=true npm-run-all --parallel --silent test:unit test:cypress",

我的目标和你的一样,我想在某些情况下禁用一些测试(在我的例子中是 CI 管道)。

因此,将整个测试置于一个条件中,而不是进行条件测试。

如果您需要更多帮助,请告诉我

我想你快到了,但是你需要异步回调模式而不是同步 if () {...} else {...} 模式。

it('shows the list', function() {

  const whenFailed = function() {
    this.skip()
  }

  const whenSucceeded = function() {
    cy.get('.list').should('be.visible')
  }

  queryFailed(whenFailed, whenSucceeded);
}

function queryFailed(whenFailed, whenSucceeded) {
  cy.get('.spin')
    .then($container => {
      const htmlLoaded = $container[0].innerHTML;

      if (htmlLoaded.indexOf('List') !== -1) {
        whenSucceeded();
        return;
      }

      if (htmlLoaded.indexOf('error') !== -1) {
        whenFailed();
        return;
      }

      cy.wait(1000);
      queryFailed(whenFailed, whenSucceeded);
    });
}

但是,我注意到对 queryFailed() 的递归调用,看起来您正在手动重试旋转容器的内容。

Cypress 内置了重试功能,因此您所要做的就是确定您的结果可能需要的最长时间(比如 20 秒),它会在所需内容到达或失败时立即结束命令如果在 20 秒内没有发生,则完全测试。

此外,您应该控制微调器正在等待的任何内容的 success/failure(例如,通过 XHR 获取列表)。因此,您应该将测试分成两部分 - 一个用于成功,一个用于失败。

context('when the list loading succeeds' function() {

  it('shows the list', function() {
    // Mock XHR success here
    cy.contains('.spin', 'List', { timeout: 20000 });
    cy.get('.list').should('be.visible');
  })

  it('does not show an error message', function() {
    ...
  })

})

context('when the list loading fails' function() {

  it('does not show the list', function() {
    // Mock XHR failure here
    cy.contains('.spin', 'error', { timeout: 20000 });
    cy.get('.list').should('not.be.visible');
  })

  it('shows an error message', function() {
    ...
  })

})

这有点粗糙,因为我不知道确切的 HTML 预期,或者微调器在等待什么,但你可以看到这个模式更整洁,并以受控方式测试所有路径.

我使用的是 @NoriSte 答案的改编版本,它仍然注册了测试,但已跳过:

const maybeDescribe = Cypress.env('SOME_ENV_VAR') ? describe : describe.skip

maybeDescribe('Test suite', function() { /* ... */ })

然后类似地,在 CI,我想跳过测试:

export CYPRESS_SOME_ENV_VAR=
$(npm bin)/cypress run

我的 source-controlled cypress.json 定义了 SOME_ENV_VAR 所以当我在本地 运行 时,不会跳过测试。

Cypress 现在还提供了一个库 @cypress/skip-test,它可以通过

提供更多控件
  • cy.skipOn
  • cy.onlyOn
  • isOn
  • 布尔标志
  • 有头/无头环境
  • 环境

披露:我与赛普拉斯无关。

例如,Cypress Real World App, a payment application to demonstrate real-world usage of Cypress testing methods, patterns, and workflows 包含一些用于 CI 中有条件 运行 测试的工作流程和用于移动视口的更改工作流程。

此外,从 Cypress v4.8.0 开始,某些 Test Configurations 可能适用于套件或个人测试。

例如:

it('Show warning outside Chrome', {  browser: '!chrome' }, () => {
  cy.get('.browser-warning')
   .should('contain', 'For optimal viewing, use Chrome browser')
})