Page Object Model
Domine suítes E2E frágeis escondendo seletores e fluxos atrás de uma API pequena.
Praticante
- e2e
- maintainability
- design
Problema
Os testes E2E estão cheios de seletores soltos e interações passo a passo. Uma única mudança na interface obriga a editar dezenas de testes, e a intenção fica enterrada sob a mecânica.
Solução
Envolva cada página (ou componente relevante) numa classe que expõe métodos que revelam a intenção, como login(user) e addToCart(item), e mantém os seletores privados. Os testes passam a ler como histórias de usuário, e a rotatividade de seletores fica contida num lugar só.
Mantenha os page objects enxutos: eles modelam a interação, não as asserções. Deixe que o teste decida o que verificar, para o objeto continuar reutilizável.
Trechos de código
export class LoginPage {
constructor(private readonly page: Page) {}
// Os seletores são privados; a intenção é pública.
private readonly email = () => this.page.getByLabel('Email');
private readonly password = () => this.page.getByLabel('Password');
private readonly submit = () => this.page.getByRole('button', { name: 'Sign in' });
async goto() {
await this.page.goto('/login');
}
async login(email: string, pass: string) {
await this.email().fill(email);
await this.password().fill(pass);
await this.submit().click();
}
}test('user can sign in', async ({ page }) => {
const login = new LoginPage(page);
await login.goto();
await login.login('user@example.com', 'secret');
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
});Armadilhas
- Pôr asserções dentro do page object: isso amarra o modelo a um único teste e prejudica o reuso.
- Objetos-deus: uma classe gigante para o app inteiro. Divida por página ou componente.
- Deixar os seletores vazarem de volta para os testes: depois que escapam, a abstração deixa de compensar.