PL
playwright-automation
Playwright for E2E/component/API tests and data automation. Use when: writing tests, automating data population, testing user flows, validating UI interactions, or seeding test data.
Install
mkdir -p .claude/skills/playwright-automation && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15935" && unzip -o skill.zip -d .claude/skills/playwright-automation && rm skill.zipInstalls to .claude/skills/playwright-automation
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Playwright for E2E/component/API tests and data automation. Use when: writing tests, automating data population, testing user flows, validating UI interactions, or seeding test data.182 chars · catalog description✓ has a “when” trigger
About this skill
Playwright Automation & Testing
Padrões completos para usar Playwright tanto para testes (E2E, Component, API) quanto para automação de dados e seed de teste.
Princípios
- E2E First: Teste fluxos reais do usuário
- Data Automation: Script para popular dados rapidamente
- Reutilização: Fixtures e helpers reutilizáveis
- Manutenibilidade: Page objects para evitar duplicação
- Performance: Testes paralelos quando possível
- Clareza: Testes legíveis e autodocumentados
Quando Usar Esta Skill
- E2E Tests: Testar fluxos completos (login → adicionar transação → visualizar)
- Component Tests: Testar componentes isolados
- API Tests: Testar endpoints backend
- Seed Data: Popular banco de dados com dados de teste
- Data Automation: Automatizar preenchimento de dados via UI
- Fixtures: Criar helpers para reutilizar em múltiplos testes
Procedimento Rápido
1. Setup Inicial
Instale Playwright:
npm install -D @playwright/test
npx playwright install
Estrutura de pastas:
tests/
├── e2e/ # E2E tests
│ ├── auth.spec.ts
│ ├── transactions.spec.ts
│ └── dashboard.spec.ts
├── api/ # API tests
│ └── transactions.api.spec.ts
├── fixtures/ # Fixtures compartilhadas
│ ├── auth.fixture.ts
│ ├── database.fixture.ts
│ └── pages.fixture.ts
├── helpers/ # Helpers reutilizáveis
│ ├── seed-data.ts
│ ├── auth-helper.ts
│ └── transaction-helper.ts
└── playwright.config.ts
2. Fixture Básica (Autenticação)
// tests/fixtures/auth.fixture.ts
import { test as base } from '@playwright/test';
type AuthFixtures = {
authenticatedPage: Page;
};
export const test = base.extend<AuthFixtures>({
authenticatedPage: async ({ page }, use) => {
// Login
await page.goto('http://localhost:8000/login/');
await page.fill('input[name="email"]', '[email protected]');
await page.fill('input[name="password"]', 'senha123');
await page.click('button:has-text("Entrar")');
// Esperar dashboard carregar
await page.waitForURL('**/dashboard/**');
await use(page);
// Cleanup
await page.close();
},
});
export { expect } from '@playwright/test';
3. E2E Test - Adicionar Transação
// tests/e2e/transactions.spec.ts
import { test, expect } from '../fixtures/auth.fixture';
test.describe('Adicionar Transação', () => {
test('deve adicionar uma saída com sucesso', async ({ authenticatedPage: page }) => {
// Arrange: Navegar até dashboard
await page.goto('http://localhost:8000/dashboard/');
// Act: Clicar em adicionar
await page.click('button:has-text("+ Adicionar")');
// Modal abre
await expect(page.locator('#modalTransacao')).toBeVisible();
// Preencher formulário
await page.click('button:has-text("Saída")');
await page.fill('input[name="valor"]', '85.50');
await page.selectOption('select[name="categoria"]', 'alimentacao');
await page.fill('input[name="data"]', '2024-03-25');
await page.fill('input[name="descricao"]', 'Supermercado');
// Salvar
await page.click('button:has-text("Salvar")');
// Assert: Verificar sucesso
await expect(page.locator('text=Transação salva com sucesso')).toBeVisible();
// Verificar se aparece na lista
await expect(page.locator('text=Supermercado')).toBeVisible();
// Verificar se saldo atualizou
const novoSaldo = await page.locator('text=R\\$ 2.365').first();
await expect(novoSaldo).toBeVisible();
});
});
4. Automação de Dados (Seed Script)
Use seed data helper:
// tests/helpers/seed-data.ts
import { Page, Browser } from '@playwright/test';
export class SeedDataHelper {
constructor(private page: Page) {}
async addTransaction(data: {
tipo: 'entrada' | 'saída';
valor: number;
categoria: string;
descricao?: string;
data?: string;
}) {
// Abrir modal
await this.page.click('button:has-text("+ Adicionar")');
await this.page.waitForSelector('#modalTransacao:not(.hidden)');
// Selecionar tipo
if (data.tipo === 'entrada') {
await this.page.click('button:has-text("Entrada")');
} else {
await this.page.click('button:has-text("Saída")');
}
// Preencher campos
await this.page.fill('input[name="valor"]', data.valor.toString());
await this.page.selectOption('select[name="categoria"]', data.categoria);
if (data.data) {
await this.page.fill('input[name="data"]', data.data);
}
if (data.descricao) {
await this.page.fill('input[name="descricao"]', data.descricao);
}
// Salvar
await this.page.click('button:has-text("Salvar")');
// Aguardar sucesso
await this.page.waitForSelector('text=Transação salva');
await this.page.waitForTimeout(500); // Aguardar animação
}
async populateTestData(count = 5) {
const categorias = ['alimentacao', 'transporte', 'lazer', 'saude'];
for (let i = 0; i < count; i++) {
const tipo = i % 2 === 0 ? 'saída' : 'entrada';
const valor = Math.floor(Math.random() * 1000) + 10;
const categoria = categorias[Math.floor(Math.random() * categorias.length)];
await this.addTransaction({
tipo,
valor,
categoria,
descricao: `Transação teste ${i + 1}`,
});
}
}
}
export async function seedDatabase(page: Page) {
const seedHelper = new SeedDataHelper(page);
await seedHelper.populateTestData(10);
}
5. API Test (Backend)
// tests/api/transactions.api.spec.ts
import { test, expect } from '@playwright/test';
test.describe('Transactions API', () => {
let token: string;
const baseURL = 'http://localhost:8000/api';
test.beforeAll(async () => {
// Login e obter token
const response = await fetch(`${baseURL}/auth/login/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: '[email protected]',
password: 'senha123',
}),
});
const data = await response.json();
token = data.token;
});
test('POST /transactions - criar transação', async () => {
const response = await fetch(`${baseURL}/transactions/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: JSON.stringify({
tipo: 'saída',
valor: 85.50,
categoria: 'alimentacao',
descricao: 'Supermercado',
data: '2024-03-25',
}),
});
expect(response.status).toBe(201);
const data = await response.json();
expect(data.id).toBeDefined();
expect(data.valor).toBe(85.50);
});
test('GET /transactions - listar transações', async () => {
const response = await fetch(`${baseURL}/transactions/`, {
headers: { 'Authorization': `Bearer ${token}` },
});
expect(response.status).toBe(200);
const data = await response.json();
expect(Array.isArray(data)).toBe(true);
});
});
6. Config do Playwright
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:8000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] },
},
],
webServer: {
command: 'python manage.py runserver',
url: 'http://localhost:8000',
reuseExistingServer: !process.env.CI,
},
});
7. Package.json Scripts
{
"scripts": {
"test": "playwright test",
"test:e2e": "playwright test tests/e2e",
"test:api": "playwright test tests/api",
"test:debug": "playwright test --debug",
"test:ui": "playwright test --ui",
"test:headed": "playwright test --headed",
"test:report": "playwright show-report",
"seed:data": "playwright test tests/helpers/seed-data.ts --headed"
}
}
Padrões Comuns
Page Object Pattern (Reutilizável)
// tests/pages/DashboardPage.ts
export class DashboardPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto('/dashboard/');
}
async getSaldo(): Promise<string> {
return this.page.locator('text=Saldo Atual')
.locator('..').locator('text="R\\$"').first().textContent();
}
async openAddTransactionModal() {
await this.page.click('button:has-text("+ Adicionar")');
await this.page.waitForSelector('#modalTransacao:not(.hidden)');
}
async fillTransactionForm(data: TransactionData) {
await this.page.fill('input[name="valor"]', data.valor.toString());
// ... outros campos
}
async submitTransaction() {
await this.page.click('button:has-text("Salvar")');
await this.page.waitForSelector('text=salva');
}
}
Usar Page Object
test('adicionar transação com page object', async ({ authenticatedPage: page }) => {
const dashboard = new DashboardPage(page);
a
---
*Content truncated.*