Skip to content

Cypress - 自定义命令

Cypress 中的自定义命令允许你将一系列 Cypress 命令封装到可重用的函数中。这对于抽象常见的操作或复杂的交互极其有用,可以使你的测试更清晰、更具可读性且更易于维护。

自定义命令通常在 cypress/support/commands.js 文件中定义(如果在较新版本的 Cypress 中进行了配置,也可能在 cypress/support/e2e.js 中)。此文件会在你的测试文件运行之前自动导入。

你使用 Cypress.Commands.add() 来定义一个新的自定义命令,使用 Cypress.Commands.overwrite() 来修改一个现有的 Cypress 命令(请谨慎使用)。

// Adding a new parent command (does not operate on a subject)
Cypress.Commands.add('commandName', (arg1, arg2, ...) => {
// Cypress commands here
});
// Adding a new child command (operates on a subject yielded by a previous command)
Cypress.Commands.add('commandName', { prevSubject: true }, (subject, arg1, ...) => {
// subject is the value yielded from the previous command
// Cypress commands here, often using cy.wrap(subject)
});
// Adding a command that can be either parent or child
Cypress.Commands.add('commandName', { prevSubject: 'optional' }, (subject, arg1, ...) => {
if (subject) {
// Act as child command
} else {
// Act as parent command
}
});
// Overwriting an existing command
Cypress.Commands.overwrite('existingCommandName', (originalFn, ...args) => {
// originalFn is the original command function
// Custom logic here, potentially calling originalFn
});

Cypress.Commands.add() 的关键 options:

  • prevSubject (boolean | string | string[]): 决定命令是 父命令、子命令 还是 双重命令。
    • false (默认): 父命令 (例如,cy.login())。
    • true: 子命令,需要前一个命令产出的主体 (例如,cy.get('button').customClick())。
    • 'element': 子命令,要求主体是 DOM 元素。
    • 'document': 子命令,要求主体是 document。
    • 'window': 子命令,要求主体是 window。
    • 'optional': 可以是父命令或子命令。

示例:创建一个登录自定义命令(父命令)

Section titled “示例:创建一个登录自定义命令(父命令)”

让我们创建一个用于登录应用程序的自定义命令。这是一项常见的重复性任务。

在 cypress/support/commands.js 文件中:

Cypress.Commands.add('login', (username, password) => {
cy.visit('/login'); // Or your specific login page path
cy.get('input[name="username"]').type(username);
cy.get('input[name="password"]').type(password);
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard'); // Verify successful login
});

在你的测试文件(例如,cypress/e2e/login_spec.cy.js)中:

describe('Application Login', () => {
it('Should log in successfully with valid credentials', () => {
cy.login('testuser', 'password123');
// Further assertions or actions after login
cy.contains('Welcome, testuser').should('be.visible');
});
it('Should attempt login with another user', () => {
cy.login('anotheruser', 'securepass');
cy.contains('Welcome, anotheruser').should('be.visible');
});
});
  • 保持焦点集中: 自定义命令理想情况下应执行一个逻辑动作或一小组紧密相关的动作。
  • 避免过长的命令: 过长的自定义命令可能难以调试,并降低测试的灵活性。如果可能,将复杂的流程分解为更小、可重用的命令。
  • 参数化以实现重用: 使用参数使你的命令灵活适应不同的场景(例如登录示例中的用户名/密码)。
  • 适时返回主体: 如果你的自定义命令生成一个新的主体(例如,它找到或创建的元素),请确保将其返回,以便可以进行链式调用。
  • 添加类型定义 (TypeScript): 如果使用 TypeScript,在 .d.ts 文件中声明你的自定义命令,以获得更好的 IntelliSense (智能提示) 和 类型安全。示例:declare namespace Cypress { interface Chainable { login(username: string, password: string): Chainable<Element>; } }

自定义命令是编写可扩展和可维护的 Cypress 测试套件的基石。它们提倡 DRY (Don’t Repeat Yourself,不要重复自己) 原则,并显著提高了测试的清晰度。