O Selenium exige gerenciamento separado de drivers de navegador e waits explícitos em quase toda interação. O Cypress não roda cross-browser e coloca a execução paralela atrás de um plano pago. O Playwright resolve tudo isso de forma nativa: um único comando de instalação baixa Chromium, Firefox e WebKit. O auto-waiting significa que os elementos não precisam de chamadas manuais de sleep() antes das interações.
Por que Playwright e não outra coisa
Antes de instalar qualquer coisa, a versão curta: o Playwright é o que a maioria dos projetos novos escolhe em 2026, e com boas razões.
O Selenium foi o padrão por anos. Funciona, mas é lento de configurar, verboso de escrever e exige gerenciamento manual de drivers de navegador. O Cypress é mais fácil mas só suporta navegadores baseados em Chromium e tem paywall para execuções paralelas no CI.
O Playwright lida com apps web modernos nativamente. Ele faz auto-wait para os elementos estarem prontos antes de interagir com eles, então você não precisa de chamadas aleatórias de sleep() nos testes. Suporta Chromium, Firefox e WebKit. Tem um test runner integrado, gravação de vídeo de falhas e um gerador de código que escreve locators para você enquanto você clica na página.
Se você está começando do zero em 2026, o Playwright é a escolha certa.
Instalação
Você precisa do Node.js instalado primeiro. Verifique se você tem:
node --versionSe retornar um número de versão (v18 ou superior está bom), pode continuar. Se não, baixe a versão LTS em nodejs.org.
Agora crie uma nova pasta para o projeto e rode o instalador do Playwright:
mkdir my-first-tests
cd my-first-tests
npm init playwright@latestO instalador faz algumas perguntas. Para aprendizado, aceite os padrões:
- TypeScript ou JavaScript → TypeScript
- Pasta de testes → tests
- Workflow do GitHub Actions → no (adicione depois)
- Instalar navegadores do Playwright → yes
O download dos navegadores leva um ou dois minutos. Quando terminar, o projeto fica assim:
my-first-tests/
tests/
example.spec.ts
playwright.config.ts
package.jsonÉ isso. Sem arquivos de configuração para batalhar, sem gerenciadores de driver, sem test runner separado para instalar.
Rode o teste de exemplo
Antes de escrever qualquer coisa, rode o que veio com a instalação:
npx playwright testO Playwright roda os testes de exemplo em modo headless (sem janela de navegador visível) e imprime os resultados no terminal. Você verá algo como:
Running 2 tests using 2 workers
2 passed (3s)Para ver o que realmente aconteceu, abra o relatório HTML:
npx playwright show-reportIsso abre um navegador com um relatório detalhado de cada teste: quais passos rodaram, quanto tempo cada um levou e screenshots no final.
npx playwright test --headed para assistir o navegador abrir e executar o teste em tempo real. Útil quando você está começando e quer ver o que está acontecendo.Escreva seu primeiro teste
Delete o arquivo de teste de exemplo e crie um novo. Abra tests/login.spec.ts e escreva isso:
import { test, expect } from '@playwright/test';
test('user can log in', async ({ page }) => {
await page.goto('https://lab.becomeqa.com');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByLabel('Username').fill('admin@becomeqa.com');
await page.getByLabel('Password').fill('testpass123');
await page.getByRole('button', { name: 'Submit' }).click();
await expect(page.getByText('My Travel Items')).toBeVisible();
});Rode:
npx playwright test tests/login.spec.tsVocê deve ver 1 passed. Aqui está o que cada parte faz.
Entendendo o que você acabou de escrever
test('user can log in', async ({ page }) => {
test é a função que define um caso de teste. O primeiro argumento é o nome: escreva como uma frase descrevendo o que o usuário faz, não o que o código faz. async significa que a função é assíncrona, necessário porque toda ação de navegador leva tempo. { page } é a fixture de página do Playwright, que dá uma aba de navegador nova para trabalhar.
await page.goto('https://lab.becomeqa.com')
Abre a URL. await diz ao JavaScript para esperar essa ação terminar antes de ir para a próxima linha. Você vai usar await na frente de toda ação do Playwright.
page.getByRole('button', { name: 'Login' })
Esse é um locator. Ele encontra um elemento na página. getByRole encontra elementos pelo seu papel ARIA e nome acessível. Encontra um botão com o texto "Login". É o tipo de locator mais confiável porque está vinculado a como o elemento realmente funciona, não à sua classe CSS ou posição.
await page.getByLabel('Username').fill('admin@becomeqa.com')
Encontra o campo de input associado a um label "Username" e digita o email nele.
await expect(page.getByText('My Travel Items')).toBeVisible()
Essa é a assertion, a parte que realmente verifica algo. Confirma que o texto "My Travel Items" está visível na página após o login. Se o login falhar e esse texto não aparecer, o teste falha.
Locators: como encontrar elementos
Locators são como você diz ao Playwright com qual elemento interagir. São vários tipos, cada um com um caso de uso diferente.
getByRole é a escolha preferida. Usa papéis ARIA, que descrevem o significado semântico dos elementos:
page.getByRole('button', { name: 'Submit' }) // um botão com label Submit
page.getByRole('link', { name: 'Home' }) // um link com label Home
page.getByRole('textbox', { name: 'Search' }) // um input de texto com label SearchgetByLabel funciona para inputs de formulário que têm um label visível:
page.getByLabel('Email address')
page.getByLabel('Password')getByPlaceholder quando não há label mas há texto de placeholder:
page.getByPlaceholder('Enter your email')getByText encontra elementos pelo conteúdo de texto visível:
page.getByText('My Travel Items')
page.getByText('Sign out')getByTestId usa um atributo data-testid. Útil quando desenvolvedores os adicionam especificamente para testes:
page.getByTestId('submit-button')Evite locators baseados em classes CSS ou XPath. Eles quebram sempre que um desenvolvedor renomeia uma classe ou reestrutura o HTML. Locators baseados em papel sobrevivem a essas mudanças.
Actions: interagindo com a página
Com um locator em mãos, você pode realizar ações nele:
await locator.click() // clicar em um elemento
await locator.fill('algum texto') // limpar e digitar em um input
await locator.type('algum texto') // digitar caractere por caractere (para inputs que reagem a teclas)
await locator.check() // marcar um checkbox
await locator.selectOption('value') // selecionar de um dropdown
await locator.hover() // passar o mouse sobre um elemento
await locator.press('Enter') // pressionar uma tecla do tecladoUma coisa importante: você quase nunca precisa esperar pelos elementos manualmente. O Playwright espera automaticamente que um elemento esteja visível e habilitado antes de realizar uma ação. Isso se chama auto-waiting e é o que elimina a maioria da flakiness nos testes Playwright.
Assertions: verificando o resultado
Uma assertion é o que faz um teste realmente testar algo. Sem assertions, você está apenas clicando em uma página.
// Verificar visibilidade
await expect(page.getByText('Welcome')).toBeVisible();
await expect(page.getByRole('dialog')).toBeHidden();
// Verificar conteúdo de texto
await expect(page.getByRole('heading')).toHaveText('My Travel Items');
await expect(page.getByRole('heading')).toContainText('Travel');
// Verificar valores de input
await expect(page.getByLabel('Email')).toHaveValue('test@example.com');
// Verificar URL
await expect(page).toHaveURL('https://lab.becomeqa.com/dashboard');
// Verificar título da página
await expect(page).toHaveTitle('BecomeQA Lab');
// Verificar contagem de elementos
await expect(page.getByRole('row')).toHaveCount(5);As assertions do Playwright também fazem auto-wait. toBeVisible() não apenas verifica agora. Tenta novamente por até 5 segundos por padrão, esperando o elemento aparecer. Isso significa que você também não precisa de waits explícitos antes das assertions.
Um teste mais completo
Aqui está um segundo teste que continua após o login:
import { test, expect } from '@playwright/test';
test('user can log in', async ({ page }) => {
await page.goto('https://lab.becomeqa.com');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByLabel('Username').fill('admin@becomeqa.com');
await page.getByLabel('Password').fill('testpass123');
await page.getByRole('button', { name: 'Submit' }).click();
await expect(page.getByText('My Travel Items')).toBeVisible();
});
test('travel items table has data', async ({ page }) => {
// fazer login primeiro
await page.goto('https://lab.becomeqa.com');
await page.getByRole('button', { name: 'Login' }).click();
await page.getByLabel('Username').fill('admin@becomeqa.com');
await page.getByLabel('Password').fill('testpass123');
await page.getByRole('button', { name: 'Submit' }).click();
// verificar a tabela
await expect(page.getByRole('table')).toBeVisible();
const rows = page.getByRole('row');
await expect(rows).toHaveCount(6); // cabeçalho + 5 linhas de dados
});Rode os dois testes:
npx playwright test tests/login.spec.tsVocê vai notar que os passos de login estão duplicados entre os testes. Tudo bem por enquanto. Com mais testes, você vai mover o setup repetido para um bloco beforeEach ou uma fixture, mas esse é um tópico intermediário.
O arquivo playwright.config.ts
Abra playwright.config.ts. Os padrões funcionam bem, mas duas configurações valem conhecer:
export default defineConfig({
testDir: './tests',
timeout: 30000, // tempo máximo por teste em ms
retries: 0, // quantas vezes tentar novamente um teste que falhou
use: {
baseURL: 'https://lab.becomeqa.com', // adicione isso
trace: 'on-first-retry',
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
});Se você definir baseURL, pode escrever page.goto('/') em vez da URL completa nos testes. Adicione ao config e atualize os testes:
await page.goto('/'); // em vez de 'https://lab.becomeqa.com'Por padrão o Playwright roda os testes nos três navegadores (Chromium, Firefox, WebKit). Para rodar apenas no Chromium enquanto aprende:
npx playwright test --project=chromiumQuando um teste falha
Vamos quebrar nosso teste de propósito. Mude o texto esperado para algo que não existe:
await expect(page.getByText('This text does not exist')).toBeVisible();Rode e você verá:
1 failed
login.spec.ts:10:3 › user can log in ✗
Error: expect(locator).toBeVisible()
Locator: getByText('This text does not exist')
Expected: visible
Received: hidden
Timeout: 5000msO erro diz exatamente o que estava esperando e que nunca ficou visível. Agora verifique o trace:
npx playwright show-reportClique no teste que falhou. Você verá um detalhamento passo a passo com screenshots em cada ação. Esse é o trace viewer, uma das features mais úteis do Playwright para debugar falhas.
→ Veja também: Instalando Playwright: Guia de Configuração Passo a Passo (2026) | Locators do Playwright: getByRole, getByLabel, getByText, getByTestId Comparados | Assertions no Playwright: O Guia Completo | Playwright Trace Viewer: Depure Testes com Falha Como um ProfissionalCorrija o teste de volta para 'My Travel Items' antes de continuar.
FAQ
Preciso saber TypeScript antes de começar?Não. O TypeScript que você vai escrever para testes é mínimo, basicamente async/await e tipos básicos. O curso cobre exatamente o que você precisa conforme avança.
TypeScript é a melhor escolha mesmo que você seja novo nele. Ele pega erros antes de você rodar o teste. A sintaxe extra é pequena e os benefícios são imediatos.
Como encontro o locator certo para um elemento?Use a ferramenta codegen do Playwright: npx playwright codegen https://lab.becomeqa.com. Abre um navegador, grava seus cliques e gera o código do locator automaticamente. Use para explorar, depois limpe o que ele gerou.
Geralmente é um problema de timing ou um await faltando. Rode com --headed localmente para ver o que acontece, depois verifique se você esqueceu algum await.