Dusk: browser testing automatizado no Laravel
1. Introdução ao Laravel Dusk e seu Propósito
Laravel Dusk é uma ferramenta de teste de browser expressiva e fácil de usar, desenvolvida especificamente para o ecossistema Laravel. Enquanto testes unitários verificam métodos individuais e testes de integração validam interações entre componentes, o Dusk permite simular ações reais de usuários em um navegador completo.
Diferente do PHPUnit Headless, que executa testes sem interface gráfica e sem suporte a JavaScript, o Dusk opera sobre um navegador real (Chrome) controlado via ChromeDriver ou Selenium. Isso significa que ele consegue testar componentes Vue.js, React, Livewire e qualquer interação JavaScript que sua aplicação execute.
A grande vantagem do Dusk sobre ferramentas como Selenium puro é sua integração nativa com o Laravel. Você não precisa configurar WebDriver manualmente nem gerenciar sessões complexas — o framework já oferece helpers prontos para autenticação, manipulação de cookies e interação com elementos DOM.
2. Instalação e Configuração Inicial
Para instalar o Dusk, utilize o Composer:
composer require --dev laravel/dusk
Em seguida, registre o service provider e instale os arquivos base:
php artisan dusk:install
Este comando cria o diretório tests/Browser/ e baixa a versão compatível do ChromeDriver:
php artisan dusk:chrome-driver
Para ambientes de teste, crie arquivos .env.dusk.local ou .env.dusk.testing com variáveis específicas:
APP_URL=http://localhost:8000
DB_DATABASE=testing_dusk
Você pode escolher entre executar com ChromeDriver (padrão) ou Selenium. Para modo headless (útil em servidores CI), configure no arquivo tests/DuskTestCase.php:
protected function driver()
{
$options = (new ChromeOptions)->addArguments([
'--disable-gpu',
'--headless',
'--window-size=1920,1080',
]);
return RemoteWebDriver::create(
'http://localhost:9515', DesiredCapabilities::chrome()->setCapability(
ChromeOptions::CAPABILITY, $options
)
);
}
3. Estrutura e Criação de Testes com Dusk
Os testes ficam organizados em tests/Browser/. Uma classe básica estende DuskTestCase:
<?php
namespace Tests\Browser;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
class LoginTest extends DuskTestCase
{
public function test_usuario_pode_fazer_login()
{
$this->browse(function (Browser $browser) {
$browser->visit('/login')
->type('email', 'usuario@exemplo.com')
->type('password', 'senha123')
->click('button[type="submit"]')
->assertPathIs('/dashboard')
->assertSee('Bem-vindo');
});
}
}
Métodos fundamentais incluem:
visit()— navega para uma URLtype()— preenche campos de formulárioclick()— clica em elementosassertSee()— verifica texto visível na páginawith()— foca em um elemento específico (ex.:$browser->with('.modal')->assertSee('Confirmar'))elsewhere()— interage com elementos fora do escopo atual
4. Interações Avançadas com o Navegador
Para upload de arquivos:
$browser->attach('foto', __DIR__.'/files/teste.jpg')
->press('Enviar')
->assertSee('Upload realizado');
Trabalhando com JavaScript:
$browser->script('document.getElementById("meu-botao").click()');
$browser->waitFor('.carregando', 5) // espera até 5 segundos
->waitUntil('document.readyState === "complete"')
->pause(1000); // pausa de 1 segundo
Navegação entre páginas:
$browser->clickLink('Próxima página')
->back()
->forward()
->refresh();
Para debug, capture screenshots e logs:
$browser->screenshot('falha-login')
->storeConsoleLog('console-errors');
5. Page Objects e Componentes Reutilizáveis
Page Objects organizam seletores e ações de páginas específicas. Crie uma classe em tests/Browser/Pages/:
<?php
namespace Tests\Browser\Pages;
use Laravel\Dusk\Browser;
use Laravel\Dusk\Page;
class LoginPage extends Page
{
public function url()
{
return '/login';
}
public function assert(Browser $browser)
{
$browser->assertSee('Entrar');
}
public function elements()
{
return [
'@email' => 'input[name="email"]',
'@senha' => 'input[name="password"]',
'@botao' => 'button[type="submit"]',
];
}
public function fazerLogin(Browser $browser, $email, $senha)
{
$browser->type('@email', $email)
->type('@senha', $senha)
->click('@botao');
}
}
Componentes são ideais para blocos de UI repetitivos, como modais:
<?php
namespace Tests\Browser\Components;
use Laravel\Dusk\Component;
class Modal extends Component
{
public function selector()
{
return '.modal';
}
public function assert(Browser $browser)
{
$browser->assertVisible('@fechar');
}
public function elements()
{
return [
'@fechar' => '.modal-close',
'@titulo' => '.modal-title',
];
}
}
6. Testes de Autenticação e Sessão
Para simular login, utilize loginAs():
public function test_usuario_autenticado()
{
$usuario = User::factory()->create();
$this->browse(function (Browser $browser) use ($usuario) {
$browser->loginAs($usuario)
->visit('/dashboard')
->assertSee($usuario->name);
});
}
Testando fluxos de registro:
$browser->visit('/register')
->type('name', 'João Silva')
->type('email', 'joao@exemplo.com')
->type('password', 'senha123')
->type('password_confirmation', 'senha123')
->click('button[type="submit"]')
->assertAuthenticated();
Manipulação de cookies:
$browser->cookie('meu_cookie', 'valor')
->withCookie('outro_cookie', 'outro_valor')
->visit('/cookies');
7. Estratégias para Dados de Teste e Ambiente
Use DatabaseMigrations para garantir um estado limpo:
use Illuminate\Foundation\Testing\DatabaseMigrations;
class ProdutoTest extends DuskTestCase
{
use DatabaseMigrations;
public function test_criacao_produto()
{
$categoria = Categoria::factory()->create();
$this->browse(function (Browser $browser) use ($categoria) {
$browser->visit('/produtos/criar')
->type('nome', 'Produto Teste')
->select('categoria_id', $categoria->id)
->press('Salvar')
->assertSee('Produto criado com sucesso');
});
}
}
Para paralelismo, configure bancos separados no .env.dusk.testing:
DB_DATABASE=testing_dusk_{process_id}
Evite efeitos colaterais usando afterClass para limpeza:
protected static function afterClass()
{
parent::afterClass();
// limpar arquivos temporários
}
8. Integração Contínua e Boas Práticas
No GitHub Actions, configure o workflow:
- name: Run Dusk Tests
run: |
php artisan serve --env=dusk.testing &
php artisan dusk --parallel
Para execução headless, garanta que o ChromeDriver esteja instalado e configure as opções headless no DuskTestCase.
Dicas de performance:
- Use
--parallelpara executar testes em paralelo - Fragmente suites grandes em grupos menores
- Ajuste timeouts com
$browser->waitFor('.elemento', 10)
Tratamento de falhas:
public function test_com_retry()
{
$this->browse(function (Browser $browser) {
$browser->waitForText('Sucesso', 10)
->retry(3, function ($browser) {
$browser->click('.confirmar');
});
});
}
Referências
- Documentação Oficial do Laravel Dusk — Guia completo com todos os métodos, configurações e exemplos oficiais
- Laravel Dusk: Testes de Browser no Laravel — Seção detalhada sobre instalação, configuração e primeiros passos
- Testes com Laravel Dusk: Guia Prático — Tutorial passo a passo com exemplos reais de formulários e autenticação
- Laravel Dusk no CI/CD com GitHub Actions — Artigo técnico sobre configuração de Dusk em pipelines de integração contínua
- Page Objects no Laravel Dusk — Explicação detalhada sobre o padrão Page Objects e componentes reutilizáveis
- Laravel Dusk: Testes Paralelos e Performance — Dicas avançadas de paralelização e otimização de testes