Viết E2E tests bền vững: Page Object Model để tập trung selectors, semantic locators (getByRole) thay CSS classes, trace-on-first-retry để debug CI failures, base fixtures để tránh duplicate login.
- E2E tests hay bị brittle (break khi UI thay đổi).
- Chiến lược viết maintainable tests: Page Object Model (POM):
class LoginPage { async login(email, pw) { await this.page.fill('[data-testid=email]', email); await this.page.fill('[data-testid=password]', pw); await this.page.click('[data-testid=submit]'); } }— encapsulate selectors và actions, một chỗ thay đổi khi UI thay đổi. Semantic locators:page.getByRole('button', { name: 'Submit' })vàpage.getByLabel('Email')bền hơnpage.locator('.btn-submit')— ít bị ảnh hưởng bởi CSS class changes. data-testid attributes: đặtdata-testidtrên key elements trong production code — explicit contract giữa dev và test. Avoid hardcoded waits: thaypage.waitForTimeout(2000)bằngpage.waitForSelector('[data-testid=result]')hoặcexpect(locator).toBeVisible()— Playwright auto-retry. Base test fixtures:test.extend({ authenticatedPage })pre-login trước mỗi test — không repeat login logic. Tracing on failure:trace: 'on-first-retry'trong playwright.config.ts — chỉ record trace khi fail, xem trace.zip trong Playwright Trace Viewer để debug CI failures không cần reproduce locally.
Pitfall: quá nhiều assertions trong một test — nếu một assertion fail, không biết context; nhóm related assertions theo user journey.