Capa de post contendo um cone branco escrito 'caution' acima de um teclado de notebook

Introdução ao Laravel Dusks


guias tdd ecossistema

Laravel Dusk é uma poderosa ferramenta de automação de ações no browser e testes de API. Com o Dusk somos capazes de automatizar testes interagindo com páginas, formulários, links etc. Apesar de também ser possível realizar testes de API este não será o foco do post.

O Dusk roda, por padrão, sob o Google Chrome e uma versão standalone do ChromeDriver o que nos permite interagir com páginas estáticas ou que precisam executar javascript (SPA), além de possuir interfaces excelentes para trabalhar com asserções e manipulação do DOM. Apesar de utilizar o ChromeDriver por padrão, é possível utilizar qualquer outro driver compatível com Selenium e também outros navegadores.

Instalação e configuração

A instalação e configuração do Laravel Dusk tende a ser bem simples e tranquila, uma instalação padrão requer apenas uma instalação via composer e execução do comando artisan para configuração.

Vamos instalar a dependência de desenvolvimento do Laravel Dusk:

composer require --dev laravel/dusk

É importante não se esquecer da flag --dev para instalar o Dusk apenas como dependência de desenvolvimento. Não é recomendado instalar o Laravel Dusk em ambiente de produção pois há interferências no sistema de autenticação que podem gerar brechas de segurança.

Uma vez instalada a dependência precisamos executar o comando artisan para gerar a pasta tests/Browser e criar um arquivo de testes de exemplo:

php artisan dusk:install

Estamos prontos para começar!

Vale ressaltar que é possível utilizar uma instalação customizada e configurações mais complexas como alterar a versão do driver instalado e utilizar browsers diferentes bem como alterar as portas de comunicação etc. Caso haja interesse em conhecer mais algumas configurações consulte a documentação oficial.

Os exemplos utilizados neste post são baseados na aplicação criada no post sobre jetstream.

Escrevendo os primeiros testes

Para iniciarmos os testes vamos dar uma olhada no arquivo de exemplo que foi criado em tests/Browser/ExampleTest.php. Este arquivo contém um teste básico que irá acessar a rota / da aplicação e verificar se a palavra Laravel é encontrada na página acessada.

// tests/Browser/ExampleTest.php

public function testBasicExample()
{
    $this->browse(function (Browser $browser) {
        $browser->visit('/')
                ->assertSee('Laravel');
    });
}

Dentro do método de teste podemos observar que foi passado um callback para o método $this->browse, este método cria uma instância dos browsers necessários e executa o que estiver dentro do callback passado. Podemos observar também que como parâmetro do callback estamos utilizando uma instância da classe Laravel\Dusk\Browser e esta classe é a responsável pelas configurações e ações do teste no contexto do callback.

Para executar o Laravel Dusk e rodar a suíte de testes basta utilizar o comando artisan dusk:

php artisan dusk

O comando acima deve gerar um output como este:

PHPUnit 9.3.10 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:00.656, Memory: 20.00 MB

OK (1 test, 1 assertion)

Vamos criar uma suíte de testes que apesar de simples é bem funcional: garantir que o fluxo de registro esteja funcionando perfeitamente.

Para criar um novo arquivo de testes e começar a compor nossa suíte podemos tanto utilizar o comando artisan quanto criar uma classe manualmente. Neste exemplo vamos executar o comando dusk:make e criar um arquivo de testes para a rota de registro de usuários:

php artisan dusk:make RegisterTest

Caso tenha recebido o output Test created successfully. um novo arquivo de teste deve ter sido criado em tests/Browser.

Agora vamos escrever os primeiros casos de teste referente ao fluxo de registro de usuários.

Nesta aplicação as senhas precisam conter no mínimo 8 caracteres e vamos garantir com o teste abaixo que caso o usuário digite menos caracteres uma mensagem de validação deve ser exibida:

// tests/Browser/RegisterTest.php

public function testShouldSeePasswordValidationFail()
{
    $this->browse(function (Browser $browser) {
        $browser->visit('/register')
                ->type('name', 'José Filho')
                ->type('email', '[email protected]’)
                ->type('password', '123')
                ->type('password_confirmation', '123')
                ->press('@register')
                ->assertSee('A senha deve conter no mínimo 8 caracteres');
    });
}

Basicamente estamos dizendo ao navegador para acessar a página /register, preencher o formulário e apertar o botão Register, com os passos concluídos fazemos a nossa asserção: garantir que a mensagem A senha deve conter no mínimo 8 caracteres esteja presente na tela (utilizando assertSee).

Vamos executar nosso teste e verificar o output. Para executar apenas um arquivo de testes em específico, podemos passar o caminho do arquivo junto ao comando dusk:

php artisan dusk tests/Browser/RegisterTest.php

E o output deve ser algo parecido com o seguinte:

PHPUnit 9.3.10 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 00:02.278, Memory: 20.00 MB

OK (1 test, 1 assertion)

Ótimo! Conseguimos garantir que caso o usuário não preencha o formulário adicionando uma senha válida o mesmo não conseguirá concluir o cadastro e receberá uma mensagem de erro.

Agora vamos escrever um novo teste para garantir que o caminho feliz esteja funcionando perfeitamente, ou seja, um usuário consegue se cadastrar com dados válidos. Além disso, quando o usuário completar com sucesso seu cadastro ele será direcionado diretamente para o dashboard sem precisar realizar o login:

// tests/Browser/RegisterTest.php

public function testCompleteRegistration()
{
    $this->browse(function (Browser $browser) {
        $browser->visit('/register')
        ->type('name', 'José Filho')
        ->type('email', '[email protected]')
        ->type('password', '12345678')
        ->type('password_confirmation', '12345678')
        ->press('@register')
        ->assertPathIs('/dashboard');
    });
}

Ao executar novamente o arquivo de teste devemos ter um output indicando dois testes realizados e duas asserções passando:

PHPUnit 9.3.10 by Sebastian Bergmann and contributors.

..                                                                  2 / 2 (100%)

Time: 00:02.686, Memory: 20.00 MB

OK (2 tests, 2 assertions)

Apesar de serem testes bem simples, conseguimos garantir uma funcionalidade importante para muitos sistemas: o fluxo de registro de usuários.

Conhecendo melhor o Laravel Dusk

Até aqui vimos que é possível utilizar um navegador, interagir com a página preenchendo e enviando formulários e vimos algumas asserções. Mas vamos entender melhor os conceitos utilizados e conhecer melhor esta ferramenta.

Navegação

Para navegar entre as páginas do sistema o Dusk utiliza alguns métodos:

Para visitar uma página através da URI (conforme fizemos) podemos utilizar o método visit(‘/uri’):

$browser->visit('/register’);

Também é possível acessar rotas nomeadas utilizando o método visitRoute(‘name-route’):

$browser->visitRoute(‘register’);

É possível ainda utilizar métodos como back() e forward() para navegar para as páginas anteriores e posteriores:

$browser->back();
$browser->forward();

Caso seja necessário atualizar a página para testar algum comportamento, temos o método refresh() que nos auxilia com esta tarefa:

$browser->refresh();

Interagindo com formulários

Nos testes escritos anteriormente nós preenchemos um formulário e o enviamos. Os métodos do Laravel Dusk são bem claros neste sentido e vamos ver um pouco mais sobre eles.

Para preencher os campos nos formulários podemos utilizar o método type(). Este método recebe dois parâmetros sendo o primeiro o nome do input (definido no atributo “name”) e o segundo parâmetro o valor que é para ser inserido no input:

$browser->type(‘name’, ‘José Filho’);

O método type() por padrão irá limpar os campos antes de adicionar os valores esperados. Caso seja necessário manter o valor anterior podemos utilizar o método append():

$browser->append(‘description’, ‘continuação da descrição anterior);

E também é possível limpar um campo com o método clear() passando como parâmetro o nome do campo (atributo “name”):

$browser->clear(‘password’);

Como não poderia ser diferente, também é possível interagir com campos do tipo select utilizando o método (adivinha?) select(). Este método também recebe dois parâmetros e segue a mesma linha de nome e valor:

$browser->select(city, 'São Paulo’);

Interagir com radio button e checkbox também é bastante simples. No caso checkbox basta utilizar o método check() ou uncheck() passando como parâmetro o nome do input:

$browser->check('remember-me');
$browser->uncheck(remember-me');

E em radio buttons basta utilizar o método radio() passando o parâmetros nome do campo e valor desejado:

$browser->radio('gender', 'Feminino');

Durante os testes também utilizamos um método para interagir com botões para submeter o formulário de registro. Isso foi possível com o auxílio do método press() que recebe um único parâmetro: uma string representando um seletor css ou seletor dusk ou ainda o texto do botão:

// utilizando seletor dusk
$browser->press('@register'); 
// utilizando seletor css
$browser->press(‘#register’);
// utilizando texto do botão
$browser->press(‘Register’);

Clicar em link também pode ser uma tarefa fácil com Dusk! Podemos utilizar o método clickLink() passando o como parâmetro um seletor ou texto assim como para pressionar botões:

$browser->clickLink('Logout');

É possível também utilizar navegação pelo teclado, utilizar as teclas shift, tab etc. Por fim temos métodos para lidar com o mouse, drag and drop, hover e tudo mais! Você pode conferir os demais métodos na documentação oficial.

Seletores customizadas (seletores Dusk)

Utilizar seletores css e propriedades do html pode ser o suficiente para a maioria das tarefas, mas em alguns casos específicos o seletor necessário pode ou ficar muito grande, prejudicando a experiência no desenvolvimento, ou então ficar muito complexo. Para resolver este problema é possível utilizar seletores Dusk.

Seletores Dusk nada mais são que propriedades customizadas que podem ser adicionadas ao código a fim de facilitar a automação de testes. Utilizá-los é bem simples e para isso precisamos apenas adicionar a propriedade dusk o elemento html desejado e passar o valor que gostaríamos.

No teste de exemplo foi utilizado um seletor Dusk chamado register, para que fosse possível utilizá-lo foi necessário adicionar a propriedade no elemento html conforme exemplo:

<button class="ml-4" dusk="register">
    Registrar
</button>

Uma vez definido o seletor Dusk, podemos utilizá-lo no teste com o nome do mesmo precedido por um @:

$browser->press(‘@register’);

Asserções

Existe uma lista imensa de asserções disponíveis para tornar nossa suíte de teste ainda mais completa e semântica.

Nos exemplos de teste utilizamos a diretiva assertPathIs() que nos ajuda a verificar se estamos na URI esperada após alguma ação ser executada.

Para uma lista completa de asserções confira a documentação oficial

Conclusão

Hoje conhecemos mais um pedaço do ecossistema Laravel e mais uma maneira de garantir a qualidade em nossas aplicações. Estou preparando um post com casos de uso “do mundo real” utilizando o Laravel Dusk então mantenha-se conectado!

-- Up the Laravel's \o/

← Post Anterior
Próximo Post →