12

我正在尝试使用别名在 mybeforebeforeEachhooks 之间共享值。如果我的值是字符串,它目前可以工作,但是当值是对象时,别名仅在第一个测试中定义,之后的每个测试在我的钩子中this.user都未定义。beforeEach如何在测试之间共享作为对象的值?

这是我的代码:

before(function() {
  const email = `test+${uuidv4()}@example.com`;
  cy
    .register(email)
    .its("body.data.user")
    .as("user");
});

beforeEach(function() {
  console.log("this.user", this.user); // This is undefined in every test except the first
});
4

3 回答 3

6

除了第一个测试之外,别名在每个测试中都未定义,因为在每次测试都清除了别名。

别名变量通过cy.get('@user')语法访问。某些命令本质上是异步的,因此使用包装器访问变量可确保在使用之前对其进行解析。

请参阅文档变量和别名获取.


似乎没有办法显式保留别名,就像cookie一样

Cypress.Cookies.preserveOnce(names...)

但是这个保存固定装置的方法显示了一种通过在beforeEach()

let city
let country

before(() => {
  // load fixtures just once, need to store in
  // closure variables because Mocha context is cleared
  // before each test
  cy.fixture('city').then((c) => {
    city = c
  })

  cy.fixture('country').then((c) => {
    country = c
  })
})

beforeEach(() => {
  // we can put data back into the empty Mocha context before each test
  // by the time this callback executes, "before" hook has finished
  cy.wrap(city).as('city')
  cy.wrap(country).as('country')
})

如果你想访问一个全局user值,你可以尝试类似

let user;

before(function() {
  const email = `test+${uuidv4()}@example.com`;
  cy
    .register(email)
    .its("body.data.user")
    .then(result => user = result);
});

beforeEach(function() {
  console.log("global user", user); 
  cy.wrap(user).as('user');              // set as alias
});

it('first', () => {
  cy.get('@user').then(val => {
    console.log('first', val)            // user alias is valid
  })
})

it('second', () => {
  cy.get('@user').then(val => {
    console.log('second', val)           // user alias is valid
  })
})
于 2018-03-22T20:19:41.243 回答
0

TL;DR:如果您希望user在每个测试中都可以使用别名对象,则必须在beforeEach钩子而不是before钩子中定义它。

赛普拉斯在测试之间执行了大量清理工作,其中包括清除所有别名。根据变量和别名的共享上下文部分:“每次测试后都会自动清理别名和属性。” 因此,您看到的结果(您的别名在第一次测试后被清除,随后未定义)是预期的行为。

我无法确定register原始帖子中的内容,但您的意图似乎是节省在beforeEach挂钩中重复执行 API 调用的开销。将你想要的一切都放在beforeEach钩子中并忽略开销绝对是最简单的(此外,没有 UI 交互的纯 API 调用不会产生太大的损失)。

如果您确实需要避免重复,则不应通过常规变量来完成,因为 Cypress 的自定义可链接对象存在潜在的时序问题。这是他们发布的反模式。最好的方法是:

  • 创建一个包含静态用户数据的夹具文件,您将使用该文件进行测试。(删除 uuidv4。)
  • 对于需要您的用户数据的测试集,请使用夹具数据调用register挂钩before。这将在被测系统中创建数据。
  • 使用beforeEach钩子加载夹具数据并为每个测试设置别名。现在,您需要的静态数据无需 API 调用即可访问,并且由于beforehook,它可以保证正确地存在于系统中。
  • 使用别名运行测试。
  • 清理after钩子中的数据(由于您的用户不再有随机电子邮件,因此您需要添加此步骤)。

如果您需要对整个测试套件执行上述操作,请将您的beforeafter钩子放在支持文件中以使其全局化。

于 2020-12-23T19:58:47.380 回答
0

代替

console.log("global user", this.user); 

cy.log(this.user);

它应该按预期工作。

原因是 cypress 命令的异步特性。将其视为一个两步过程:所有 cypress 命令在运行时都没有按照您的想法执行。他们只是建立了一个命令链。该链稍后作为测试执行。

对于其他命令(例如console.log(). 该命令在准备测试时执行。

赛普拉斯文档中对此进行了详细说明

但我觉得很难理解这一点。你必须习惯它。一条经验法则:几乎测试中的每个命令都应该是 cypress 命令。

所以只需使用cy.log而不是console.log

如果你必须使用 console.log 你可以这样做:

cy.visit("/).then(() => console.log(this.user))

这种方式console.log是链式的。或者,如果您没有要链接的主题,请构建您自己的自定义命令,如下所示:

Cypress.Commands.add("console", (message) => console.log(message))
cy.console(this.user)

在 cypress 中使用的另一个错误this是使用箭头函数。如果这样做,您将无法访问this您所期望的。请参阅在 cypress 文档中避免使用 this 。

于 2021-02-17T08:27:41.053 回答