Skip to content

Cypress - 变量

在 Cypress 中,管理来自命令的值、元素或结果需要理解其异步特性和命令队列。你不能简单地将 Cypress 命令的结果赋值给一个标准的 JavaScript 变量,例如 const el = cy.get('.my-element');,并期望 el 直接持有 DOM 元素以便在 Cypress 链外立即使用。

相反,Cypress 提供了诸如 .then()(闭包)和 .as()(aliases)之类的机制来处理产生的 subject(值或元素)。

使用 .then() 进行即时访问 (Closures)

Section titled “使用 .then() 进行即时访问 (Closures)”

当一个 Cypress 命令产生一个 subject(例如,cy.get() 产生一个 DOM 元素,cy.request() 产生一个响应)时,你可以使用 .then() 在回调函数中访问该 subject。在这个回调函数内部,你可以使用标准的 JavaScript 变量 (const, let) 在该回调的作用域内存储或操作产生的值。

it('Captures and compares text using .then()', () => {
cy.visit('/counter-app'); // Assume an app with a counter and increment button
cy.get('#counter-value').invoke('text').then((initialText) => {
// initialText is the text content of #counter-value
const initialCount = parseInt(initialText);
cy.log(`Initial count: ${initialCount}`); // Logs to Cypress Command Log
cy.get('#increment-button').click();
cy.get('#counter-value').invoke('text').then((newText) => {
const newCount = parseInt(newText);
cy.log(`New count: ${newCount}`);
// Assert that the new count is greater than the initial count
expect(newCount).to.be.gt(initialCount);
expect(newCount).to.eq(initialCount + 1);
});
});
});

在这个示例中,initialCount 和 newCount 是标准的 const 变量。它们只能在各自的 .then() 回调作用域内访问。这是由于 JavaScript 闭包的特性。

为了在不同的 Cypress 命令链或多个测试步骤中共享 subject(元素、路由响应、fixture 数据),Cypress 提供了 aliases(别名)。你可以使用 .as('aliasName') 创建一个 alias,然后使用 cy.get('@aliasName') 在稍后访问它。

Aliases 对于以下场景特别有用:

  • 存储 DOM 元素以便多次交互,而无需重新查询。
  • 存储网络请求响应进行断言。
  • 存储 fixture 数据。
describe('Aliasing Example', () => {
beforeEach(() => {
cy.visit('/form-page');
// Alias an input field
cy.get('input[name="email"]').as('emailInput');
cy.get('button[type="submit"]').as('submitButton');
});
it('Uses aliased elements for interaction', function() { // Use 'function' for 'this' with Cypress aliases
// Access the aliased element using cy.get('@aliasName')
cy.get('@emailInput').type('test@example.com');
cy.get('@submitButton').click();
// Or access via this.aliasName (if test is not an arrow function)
// this.emailInput.type('another@example.com'); // Note: this.emailInput is the jQuery element
});
it('Reuses aliased element for assertions', function() {
cy.get('@emailInput').type('invalid-email').blur();
cy.get('@emailInput').should('have.class', 'error'); // Example assertion
});
it('Stores and uses a value with an alias', () => {
cy.get('#some-value-display').invoke('text').as('initialValue');
// ... perform some action that changes the value ...
cy.get('#update-button').click();
cy.get('@initialValue').then((originalValue) => {
cy.get('#some-value-display').invoke('text').should((newValue) => {
expect(newValue).not.to.eq(originalValue);
});
});
});
});

访问 Aliases:

  • cy.get(‘@aliasName’): 这是最常用的方式。如果 alias 指向 DOM 元素,它会重新查询 DOM,确保你总是获得当前状态。
  • this.aliasName: 如果你的测试函数(it, beforeEach 等)是标准的 function() {}(而不是箭头函数 () => {}),Cypress 会自动将 alias 的 yielded subject 放在 this 上。对于 DOM 元素,this.aliasName 将是在 alias 时 yielded 的 jQuery 对象(它不会重新查询)。

在 .then() 回调函数内部使用 const 或 let 用于临时存储不需要广泛共享或在链中稍后由 Cypress 命令重新访问的已处理值。

当你需要执行以下操作时,使用 Cypress aliases (.as() 和 cy.get('@aliasName')):

  • 在不同的命令链中多次引用同一个或多个 DOM 元素。
  • 在测试步骤之间共享数据(如网络响应或 fixture 内容)。
  • 使 yielded subject 在 Mocha 的 this 上下文中可用。

假设你有一个按钮,点击后会更新页面上的计数器。你想验证计数器是否正确递增。

it('Correctly increments a counter', () => {
cy.visit('/my-interactive-page');
// Get the initial count and alias it
cy.get('#counter').invoke('text').then(parseInt).as('initialCount');
// Click the increment button
cy.get('#incrementBtn').click();
// Get the new count and compare with the aliased initial count
cy.get('#counter').invoke('text').then(parseInt).then((newCount) => {
cy.get('@initialCount').then((initialCount) => {
expect(newCount).to.eq(initialCount + 1);
});
});
});

这展示了如何同时使用 .then() 进行即时处理(如 parseInt)和使用 .as() 存储一个值(initialCount),以便在测试流程的稍后使用。

进一步阅读: