【问题标题】:Accessing aliases in Cypress with "this"使用“this”访问赛普拉斯中的别名
【发布时间】:2018-03-22 14:40:57
【问题描述】:

我正在尝试使用别名在我的 beforebeforeEach 挂钩之间共享值。如果我的值是字符串,它目前可以工作,但是当值是对象时,别名仅在第一个测试中定义,之后的每个测试 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
});

【问题讨论】:

  • 这听起来不对(@RichardMatsen 也没有回答)。您能否发布一个示例,其中 this.user 在后续测试中未定义?

标签: cypress


【解决方案1】:

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

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

请参阅文档 Variables and Aliasesget


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

Cypress.Cookies.preserveOnce(names...)

但是这个recipe for preserving fixtures 显示了一种通过在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
  })
})

【讨论】:

  • 谢谢!最后我选择了cy.get('@user')。但是,documentation 暗示 this.user 语法应该按照我尝试的方式工作。
  • 你说的很对,我记得看过那个文档页面。可能是.register() 命令导致的延迟(是自定义命令吗?)
  • 是的.register() 是一个自定义命令,它调用cy.request()。我只是觉得奇怪的是别名总是只在第一个测试的 beforeEach 中可用,第一个之后的任何测试都是未定义的。似乎赛普拉斯清除了测试之间的别名。
  • 我对其中一个测试做了一些试验,发现在第二次调用beforeEach() 时确实清除了别名。也许所有别名都被清除以确保一个测试的值不会渗透到另一个测试中。
  • @itcropper,问题依然存在。这些文档没有涵盖在 before() 中创建别名而不是在 beforeEach() 中创建别名的情况,因此这是一种有效的用法。
【解决方案2】:

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

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

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

如果您确实需要避免重复,则不应通过常规变量来完成,因为赛普拉斯的自定义可链接对象可能存在时序问题。这是anti-pattern they publish。最好的方法是:

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

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

【讨论】:

    【解决方案3】:

    替换

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

    cy.log(this.user);
    

    它应该按预期工作。

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

    对于像console.log() 这样的其他命令显然不是这样。该命令在准备测试时执行。

    这是explained in great detail in the cypress documentation

    但我觉得很难理解这一点。你必须习惯它。 一条经验法则:几乎测试中的每个命令都应该是 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 文档中的 Avoiding the use of this

    【讨论】:

    • 不,这是误导。 cy.log() 记录到赛普拉斯日志,而 console.log() 记录到开发工具。除此之外,它们都输出变量。
    • 我不认为它具有误导性,因为问题的关键在于命令链。但是我添加了一段解释如何使用 console.log 如果这是问题的全部内容
    • 试一试,你会发现这不是真的。
    猜你喜欢
    • 1970-01-01
    • 2020-08-15
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 2020-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多