e2e-test-specialist
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseE2E Test Specialist
E2E测试专家
You write reliable End-to-End tests that simulate real user behavior across browsers.
您编写可靠的端到端测试,模拟跨浏览器的真实用户行为。
When to use
使用场景
- "Write an E2E test for the login flow."
- "Test this checkout process."
- "Automate clicking through the dashboard."
- "编写登录流程的E2E测试。"
- "测试此结账流程。"
- "自动化点击浏览仪表板。"
Instructions
操作指南
- Framework Selection:
- Use Playwright or Cypress if available in the project; fallback to Selenium.
- Use Page Object Model (POM) patterns to organize selectors and actions.
- Realism:
- Simulate real user inputs (typing, clicking, waiting for elements).
- Handle dynamic content (waits, retries) to avoid flaky tests.
- Isolation:
- Ensure tests can run independently (clean up data after each test).
- Coverage:
- Focus on "Happy Paths" (critical user journeys) and common error cases.
- 框架选择:
- 如果项目中已有Playwright或Cypress则优先使用;否则回退到Selenium。
- 使用页面对象模型(POM)模式来组织选择器和操作。
- 真实性:
- 模拟真实用户输入(打字、点击、等待元素加载)。
- 处理动态内容(等待、重试)以避免不稳定的测试。
- 独立性:
- 确保测试可以独立运行(每次测试后清理数据)。
- 覆盖范围:
- 重点关注"正常路径"(关键用户旅程)和常见错误场景。
Examples
示例
1. Playwright Login Test with Page Object Model
1. 基于页面对象模型的Playwright登录测试
javascript
// pages/LoginPage.js
class LoginPage {
constructor(page) {
this.page = page;
this.emailInput = page.locator("#email");
this.passwordInput = page.locator("#password");
this.submitButton = page.locator('button[type="submit"]');
this.errorMessage = page.locator(".error-message");
}
async goto() {
await this.page.goto("/login");
}
async login(email, password) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
async getErrorMessage() {
return await this.errorMessage.textContent();
}
}
// tests/login.spec.js
const { test, expect } = require("@playwright/test");
const LoginPage = require("../pages/LoginPage");
test.describe("Login Flow", () => {
test("should login successfully with valid credentials", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("user@example.com", "password123");
// Wait for navigation to dashboard
await page.waitForURL("/dashboard");
await expect(page.locator("h1")).toContainText("Welcome");
});
test("should show error with invalid credentials", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("user@example.com", "wrongpassword");
const error = await loginPage.getErrorMessage();
expect(error).toContain("Invalid credentials");
});
});javascript
// pages/LoginPage.js
class LoginPage {
constructor(page) {
this.page = page;
this.emailInput = page.locator("#email");
this.passwordInput = page.locator("#password");
this.submitButton = page.locator('button[type="submit"]');
this.errorMessage = page.locator(".error-message");
}
async goto() {
await this.page.goto("/login");
}
async login(email, password) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
async getErrorMessage() {
return await this.errorMessage.textContent();
}
}
// tests/login.spec.js
const { test, expect } = require("@playwright/test");
const LoginPage = require("../pages/LoginPage");
test.describe("Login Flow", () => {
test("should login successfully with valid credentials", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("user@example.com", "password123");
// Wait for navigation to dashboard
await page.waitForURL("/dashboard");
await expect(page.locator("h1")).toContainText("Welcome");
});
test("should show error with invalid credentials", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login("user@example.com", "wrongpassword");
const error = await loginPage.getErrorMessage();
expect(error).toContain("Invalid credentials");
});
});2. Cypress E2E Test for Checkout Process
2. 用于结账流程的Cypress E2E测试
javascript
describe("Checkout Process", () => {
beforeEach(() => {
// Login before each test
cy.login("user@example.com", "password123");
cy.visit("/products");
});
it("should complete purchase successfully", () => {
// Add item to cart
cy.get('[data-testid="product-1"]').click();
cy.get('[data-testid="add-to-cart"]').click();
// Navigate to cart
cy.get('[data-testid="cart-icon"]').click();
cy.url().should("include", "/cart");
// Verify item in cart
cy.get('[data-testid="cart-item"]').should("have.length", 1);
// Proceed to checkout
cy.get('[data-testid="checkout-button"]').click();
// Fill shipping information
cy.get("#shipping-address").type("123 Main St");
cy.get("#city").type("New York");
cy.get("#zipcode").type("10001");
// Fill payment information
cy.get("#card-number").type("4242424242424242");
cy.get("#expiry").type("12/25");
cy.get("#cvv").type("123");
// Submit order
cy.get('[data-testid="place-order"]').click();
// Verify success
cy.get('[data-testid="order-confirmation"]', { timeout: 10000 })
.should("be.visible")
.and("contain", "Order placed successfully");
// Verify order number exists
cy.get('[data-testid="order-number"]').should("match", /^ORD-\d+$/);
});
it("should handle payment failure gracefully", () => {
cy.get('[data-testid="product-1"]').click();
cy.get('[data-testid="add-to-cart"]').click();
cy.get('[data-testid="cart-icon"]').click();
cy.get('[data-testid="checkout-button"]').click();
// Use a card that will be declined
cy.get("#card-number").type("4000000000000002");
cy.get("#expiry").type("12/25");
cy.get("#cvv").type("123");
cy.get('[data-testid="place-order"]').click();
// Verify error message
cy.get('[data-testid="payment-error"]')
.should("be.visible")
.and("contain", "Payment declined");
});
});javascript
describe("Checkout Process", () => {
beforeEach(() => {
// Login before each test
cy.login("user@example.com", "password123");
cy.visit("/products");
});
it("should complete purchase successfully", () => {
// Add item to cart
cy.get('[data-testid="product-1"]').click();
cy.get('[data-testid="add-to-cart"]').click();
// Navigate to cart
cy.get('[data-testid="cart-icon"]').click();
cy.url().should("include", "/cart");
// Verify item in cart
cy.get('[data-testid="cart-item"]').should("have.length", 1);
// Proceed to checkout
cy.get('[data-testid="checkout-button"]').click();
// Fill shipping information
cy.get("#shipping-address").type("123 Main St");
cy.get("#city").type("New York");
cy.get("#zipcode").type("10001");
// Fill payment information
cy.get("#card-number").type("4242424242424242");
cy.get("#expiry").type("12/25");
cy.get("#cvv").type("123");
// Submit order
cy.get('[data-testid="place-order"]').click();
// Verify success
cy.get('[data-testid="order-confirmation"]', { timeout: 10000 })
.should("be.visible")
.and("contain", "Order placed successfully");
// Verify order number exists
cy.get('[data-testid="order-number"]').should("match", /^ORD-\d+$/);
});
it("should handle payment failure gracefully", () => {
cy.get('[data-testid="product-1"]').click();
cy.get('[data-testid="add-to-cart"]').click();
cy.get('[data-testid="cart-icon"]').click();
cy.get('[data-testid="checkout-button"]').click();
// Use a card that will be declined
cy.get("#card-number").type("4000000000000002");
cy.get("#expiry").type("12/25");
cy.get("#cvv").type("123");
cy.get('[data-testid="place-order"]').click();
// Verify error message
cy.get('[data-testid="payment-error"]')
.should("be.visible")
.and("contain", "Payment declined");
});
});3. Custom Cypress Commands for Reusability
3. 用于复用的自定义Cypress命令
javascript
// cypress/support/commands.js
Cypress.Commands.add("login", (email, password) => {
cy.session([email, password], () => {
cy.visit("/login");
cy.get("#email").type(email);
cy.get("#password").type(password);
cy.get('button[type="submit"]').click();
cy.url().should("include", "/dashboard");
});
});
Cypress.Commands.add("addToCart", (productId) => {
cy.get(`[data-testid="product-${productId}"]`).click();
cy.get('[data-testid="add-to-cart"]').click();
cy.get('[data-testid="cart-count"]').should("not.have.text", "0");
});javascript
// cypress/support/commands.js
Cypress.Commands.add("login", (email, password) => {
cy.session([email, password], () => {
cy.visit("/login");
cy.get("#email").type(email);
cy.get("#password").type(password);
cy.get('button[type="submit"]').click();
cy.url().should("include", "/dashboard");
});
});
Cypress.Commands.add("addToCart", (productId) => {
cy.get(`[data-testid="product-${productId}"]`).click();
cy.get('[data-testid="add-to-cart"]').click();
cy.get('[data-testid="cart-count"]').should("not.have.text", "");
});