使用 "this" 访问 Cypress 中的别名
Accessing aliases in Cypress with "this"
我正在尝试使用别名在我的 before
和 beforeEach
挂钩之间共享值。如果我的值是一个字符串,它目前可以工作,但是当该值是一个对象时,别名只在第一个测试中定义,之后的每个测试 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
});
别名在每个测试中都是未定义,除了第一个,因为别名在之后被清除] 每次测试。
通过 cy.get('@user')
语法访问别名变量。一些命令本质上是异步的,因此使用包装器访问变量可确保在使用之前解析它。
参见文档 Variables and Aliases and get。
似乎没有办法明确保留别名,就像 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
})
})
TL;DR:如果你想在每个测试中使用一个别名 user
对象,你必须在 beforeEach
挂钩而不是 before
挂钩中定义它。
赛普拉斯在测试之间执行大量清理,这包括清除所有别名。根据 Variables and Aliases 的共享上下文部分:“每次测试后都会自动清除别名和属性。”因此,您看到的结果(您的别名在第一次测试后被清除,随后未定义)是预期的行为。
我无法确定 register
在原始 post 中做了什么,但您的意图似乎是节省在 beforeEach
中重复执行 API 调用的开销钩。将您想要的所有内容都放在 beforeEach
挂钩中并忽略开销绝对是最简单的(另外,没有 UI 交互的纯 API 调用不会产生太多损失)。
如果您真的需要避免重复,这不应该通过常规变量来完成,因为赛普拉斯的自定义链可能存在时序问题。这是一个anti-pattern they publish。最好的方法是:
- 创建一个 fixture file 静态用户数据,您将使用它来进行测试。 (删除 uuidv4。)
- 对于需要您的用户数据的测试集,使用夹具数据在
before
挂钩中调用 register
。这将在被测系统中创建数据。
- 使用
beforeEach
挂钩加载夹具数据并为每个测试设置别名。现在,无需 API 调用即可访问您需要的静态数据,并且由于 before
挂钩,它可以保证正确地存在于系统中。
- 运行 您使用别名进行的测试。
- 清理
after
钩子中的数据(因为您的用户不再有随机电子邮件,您需要添加此步骤)。
如果您需要对整个测试套件执行上述操作,请将 before
和 after
挂钩放在 support file 中,使它们成为全局的。
替换
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
。请参阅赛普拉斯文档中的 Avoiding the use of this。
我正在尝试使用别名在我的 before
和 beforeEach
挂钩之间共享值。如果我的值是一个字符串,它目前可以工作,但是当该值是一个对象时,别名只在第一个测试中定义,之后的每个测试 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
});
别名在每个测试中都是未定义,除了第一个,因为别名在之后被清除] 每次测试。
通过 cy.get('@user')
语法访问别名变量。一些命令本质上是异步的,因此使用包装器访问变量可确保在使用之前解析它。
参见文档 Variables and Aliases and get。
似乎没有办法明确保留别名,就像 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
})
})
TL;DR:如果你想在每个测试中使用一个别名 user
对象,你必须在 beforeEach
挂钩而不是 before
挂钩中定义它。
赛普拉斯在测试之间执行大量清理,这包括清除所有别名。根据 Variables and Aliases 的共享上下文部分:“每次测试后都会自动清除别名和属性。”因此,您看到的结果(您的别名在第一次测试后被清除,随后未定义)是预期的行为。
我无法确定 register
在原始 post 中做了什么,但您的意图似乎是节省在 beforeEach
中重复执行 API 调用的开销钩。将您想要的所有内容都放在 beforeEach
挂钩中并忽略开销绝对是最简单的(另外,没有 UI 交互的纯 API 调用不会产生太多损失)。
如果您真的需要避免重复,这不应该通过常规变量来完成,因为赛普拉斯的自定义链可能存在时序问题。这是一个anti-pattern they publish。最好的方法是:
- 创建一个 fixture file 静态用户数据,您将使用它来进行测试。 (删除 uuidv4。)
- 对于需要您的用户数据的测试集,使用夹具数据在
before
挂钩中调用register
。这将在被测系统中创建数据。 - 使用
beforeEach
挂钩加载夹具数据并为每个测试设置别名。现在,无需 API 调用即可访问您需要的静态数据,并且由于before
挂钩,它可以保证正确地存在于系统中。 - 运行 您使用别名进行的测试。
- 清理
after
钩子中的数据(因为您的用户不再有随机电子邮件,您需要添加此步骤)。
如果您需要对整个测试套件执行上述操作,请将 before
和 after
挂钩放在 support file 中,使它们成为全局的。
替换
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
。请参阅赛普拉斯文档中的 Avoiding the use of this。