<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tarcisio C. Uchoa</title>
    <description>The latest articles on DEV Community by Tarcisio C. Uchoa (@tcava).</description>
    <link>https://dev.to/tcava</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F722422%2F9beced03-a74c-4245-8d6c-5d4295df73f0.jpg</url>
      <title>DEV Community: Tarcisio C. Uchoa</title>
      <link>https://dev.to/tcava</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tcava"/>
    <language>en</language>
    <item>
      <title>Organização de testes automatizados</title>
      <dc:creator>Tarcisio C. Uchoa</dc:creator>
      <pubDate>Mon, 10 Feb 2025 18:19:20 +0000</pubDate>
      <link>https://dev.to/tcava/organizacao-de-testes-automatizados-2d7h</link>
      <guid>https://dev.to/tcava/organizacao-de-testes-automatizados-2d7h</guid>
      <description>&lt;p&gt;Uma vez que você determinou que está no negócio dos testes automatizados no navegador, está com seu ambiente Playwright pronto para começar a escrever os testes, você vai geralmente executar uma combinação de três passos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Configurar os dados&lt;/li&gt;
&lt;li&gt;Executar um conjunto discreto de ações&lt;/li&gt;
&lt;li&gt;Avaliar os resultados&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;E você deverá manter esses passos os mais curtos possível; uma ou duas operações devem ser suficientes maioria das vezes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Arrange, Act and Assert (AAA) pattern
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://medium.com/@pjbgf/title-testing-code-ocd-and-the-aaa-pattern-df453975ab80" rel="noopener noreferrer"&gt;Paulo Gomes: Unit Testing and the Arrange, Act and Assert (AAA) Pattern&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O padrão &lt;em&gt;AAA (Arrange-Act-Assert)&lt;/em&gt; tornou-se quase um padrão em todo o setor. Ele sugere que você divida seu método de teste em três seções: organizar, agir e afirmar. Cada um deles é responsável apenas pela parte em que recebe o nome.&lt;/p&gt;

&lt;p&gt;Portanto, na seção de organização &lt;em&gt;(Arrange)&lt;/em&gt;, você só tem o código necessário para configurar esse teste específico. Aqui, os objetos seriam criados, a configuração dos mocks (se você estiver usando um) e as expectativas potencialmente definidas. Depois, há a Ação &lt;em&gt;(Act)&lt;/em&gt;, que deve ser a invocação do método que está sendo testado. E no &lt;em&gt;Assert&lt;/em&gt; você simplesmente verificaria se as expectativas foram atendidas.&lt;/p&gt;

&lt;p&gt;Seguir esse padrão torna o código bem estruturado e fácil de entender. Em linhas gerais, ficaria assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// arrange
const homePage = new HomePage(page, BASE_URL);

// act
await homePage.navigate();

// assert
await expect(homePage.title).toBeVisible();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Exemplo&lt;/p&gt;

&lt;p&gt;Larry criou um site que permite que os usuários comprem unicórnios personalizados. O fluxo geral ("caminho feliz") seria algo semelhante a isso:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Criar uma conta&lt;/li&gt;
&lt;li&gt;Configurar o unicórnio&lt;/li&gt;
&lt;li&gt;Adicionar ao carrinho de compras&lt;/li&gt;
&lt;li&gt;Verificar e pagar&lt;/li&gt;
&lt;li&gt;Dar feedback sobre o unicórnio&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Em vez de um roteiro de teste que envolva todas as etapas, separar em testes independentes e rápidos.&lt;/p&gt;

&lt;p&gt;Se precisarmos testar apenas o "configurar o unicórnio", vamos precisar da primeira etapa "criar uma conta", mas não estamos testando a criação de conta.&lt;/p&gt;

&lt;p&gt;Criar a conta (independente se vai usar uma conta existente ou criar uma nova ou criar uma conta de administrador...) deve fazer parte do "configurar os dados".&lt;/p&gt;

&lt;p&gt;A fase de configuração (arrange) pode ser incluída com apenas uma ou duas linhas de código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
Crie um usuário que tenha permissões somente leitura.
eles podem configurar um unicórnio, mas eles não têm
informações de pagamento configuradas,
nem têm privilégios administrativos
No momento em que o usuário é criado, seu endereço
de e-mail e senha são gerados aleatoriamente
você nem precisa conhecê-los.
*/ 
let user = await userFactory.createCommonUser ();
// Esse método foi criado em outro lugar

/*
Faça login como este usuário.
O login neste site leva você à sua página pessoal
"Minha conta", e então o objeto AccountPage
é retornado pelo método loginAs, permitindo que
você execute ações da AccountPage.
*/
let accountPage = await loginAs(user.email, user.password);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A userFactory pode ser estendida para criar usuários administrativos ou outros tipos, retornando dados necessários para uso, como login, nome, e-mail, senha...&lt;/p&gt;

&lt;p&gt;Estamos usando o padrão Page Object Model (POM) neste caso.&lt;/p&gt;

&lt;p&gt;A utilização desses métodos, fora do teste de "configurar unicórnio" não deve atrapalhar/distrair o teste em si.&lt;/p&gt;

&lt;p&gt;Os testes devem ser compostos de ações, realizadas do ponto de vista do usuário, dentro do contexto das páginas do site. Essas páginas são armazenadas como objetos com informações específicas sobre como a página é composta e como as ações são realizadas.&lt;/p&gt;

&lt;p&gt;O testador deve se preocupar com o objetivo do teste: que tipo de unicórnio? Rosa ou roxo? Com óculos escuros? Tatuagem?&lt;/p&gt;

&lt;p&gt;E o teste ainda não precisa pensar em botões, campos, menus, formulários. Escrever o código como o usuário tentando resolver o problema. Fase de ação (executa rum conjunto discreto de ações):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
O Unicórnio é um objeto de nível superior - ele possui atributos,
que são definidos aqui. Isso armazena apenas os valores;
não preenche formulários da web nem interage com o navegador
de qualquer forma.
*/
let sparkles = new Unicorn(
    "Sparkles",
    UnicornColors.PURPLE,
    UnicornAccessories.SUNGLASSES,
    UnicornAdornments.STAR_TATTOOS);

/*
Uma vez que já estamos "na" página da conta,
temos que usá-la para chegar ao lugar real onde
você configura os unicórnios. Chamar o método
"Add Unicorn" nos leva lá.
*/
let addUnicornPage = await accountPage.addUnicorn();

/*
Agora que estamos na AddUnicornPage, passaremos o objeto
"sparkles" para o método createUnicorn().
Este método pegará os atributos do Sparkles,
preencher o formulário e clicar em enviar.
*/
let unicornConfirmationPage = await addUnicornPage.createUnicorn(sparkles);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora com o unicórnio configurado, etapa 3 (assert): certificar-se de que funcionou:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
O método exists() de UnicornConfirmationPage
pegará o objeto Sparkles - uma especificação
dos atributos que você deseja ver e compará-los
com os campos na página
*/
await expect(unicornConfirmationPage(sparkles)).toBeVisible();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sem botões, localizadores, controles de navegador. Este método de modelagem mantém os testes imutáveis. Se a lógica por trás disso alterar (posição dos botões, uso de framework diferente), o teste continua válido.&lt;/p&gt;

&lt;p&gt;Os objetos de página é que precisarão de alterações nesses casos de redesenho do site, mas os testes permanecerão os mesmos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Page Object Model (POM)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://www.selenium.dev/pt-br/documentation/test_practices/encouraged/page_object_models/" rel="noopener noreferrer"&gt;Selenium: Page Object Models&lt;/a&gt;&lt;br&gt;
Ref: &lt;a href="https://danilow86.medium.com/pom-page-object-model-design-pattern-343f0c231bb9" rel="noopener noreferrer"&gt;Danilo José: POM (Page Object Model design pattern)&lt;/a&gt;&lt;br&gt;
Ref: &lt;a href="https://danilow86.medium.com/pom-page-object-model-design-pattern-343f0c231bb9" rel="noopener noreferrer"&gt;Playwright: Page Object Models&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;De acordo com o padrão Page Object Model, devemos manter nossos testes e localizadores de elementos separados, usando um conceito de código limpo para facilitar o entendimento e a manutenção.&lt;/p&gt;

&lt;p&gt;Em geral, os casos de teste são otimizados, pois podem usar métodos de objeto de página em classes POM. Isso significa que quaisquer mudanças na interface do usuário podem ser facilmente implementadas, atualizadas ou mantidas dentro dos objetos de página e classes.&lt;/p&gt;

&lt;p&gt;Outra característica importante é que há uma separação clara entre o código de teste e o código específico da página, como localizadores e layout, tornando o código muito mais fácil de manter. Em outras palavras, isso faz com que alterações de código sejam necessárias apenas nas classes de objeto de página quando houver uma alteração na interface do usuário, conforme mencionado anteriormente, reduzindo também a duplicação de código.&lt;/p&gt;

&lt;p&gt;Um objeto de página é uma classe orientada a objeto que serve como uma interface para uma página de teste de automação. Os testes usam os métodos dessa classe de objeto de página sempre que precisam interagir com a interface do usuário dessa página.&lt;/p&gt;

&lt;p&gt;Outra vantagem é que há um único repositório para os serviços de operações oferecidos pela página, em vez de ter esses serviços espalhados pelos testes (teste de login aponta para o cabeçalho da home, teste de logout aponta para o cabeçalho da home, teste de navegação aponta para o cabeçalho na home...). Quaisquer alterações necessárias devido a alterações na interface do usuário são feitas em um só lugar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementação (com Playwright)
&lt;/h3&gt;

&lt;p&gt;Vamos criar uma classe HomePage para encapsular elementos e operações comuns da homepage do projeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// page-objects/HomePage.ts

import { Page, Locator } from '@playwright/test';

export default class HomePage {
    readonly page: Page;
    readonly baseUrl: string;
    readonly mainContent: Locator;
    readonly cardContact: Locator;

    constructor(page: Page, baseUrl: string) {
        this.page = page;
        this.baseUrl = baseUrl;
        this.mainContent = page.locator('data-test=main-content');
        this.cardContact = page.locator('data-test=card-contact');
    }

    async navigate(): Promise&amp;lt;void&amp;gt;{
        const url = await this.page.url();
        if (url != this.baseUrl) {
            await this.page.goto(this.baseUrl);
        }    
        await this.page.waitForLoadState('networkidle');
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora importamos a classe HomePage no nosso teste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// HomePageExample.spec.ts

import { expect, test} from '@playwright/test';
import { HomePage } from './page-objects/HomePage';

test('Home Page should be successfully loaded', async ({page}) =&amp;gt; {
    cont BASE_URL = 'https://meuprojeto.com.br';
    const homePage = new HomePage(page, BASE_URL);

    // using HomePage class method to navigate
    await homePage.navigate();

    const pageTitle = await page.title();
    await expect(pageTitle).toBe('Meu Projeto');
    await expect(page.url()).toBe(BASE_URL);

    // using HomePage class locators
    await expect(homePage.mainContent).toBeVisible();
    await expect(homePage.cardContact).toBeVisible();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se outros testes precisarem usar elementos da Homepage, eles podem chamar a classe HomePage e usar seus métodos e localizadores.&lt;/p&gt;

&lt;p&gt;Se a interface do usuário for alterada, o testador só precisa alterar os localizadores na classe auxiliar e não em várias linhas em vários testes diferentes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regras para objetos de página
&lt;/h3&gt;

&lt;p&gt;Os próprios objetos de página nunca devem fazer asserções, verificações ou afirmações. Isso é parte do teste e deve estar no código de teste. O objeto de página conterá a representação da página, os serviços que a página fornece por meio de métodos. Nenhum código que está sendo testado deve estar dentro do objeto de página.&lt;/p&gt;

&lt;p&gt;Evitar coisas como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await homePage.verifySearchIsVisible();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...deixando a asserção com o método verifySearchIsVisible() do objeto de página homePage.&lt;/p&gt;

&lt;p&gt;Idealmente a homePage pode retornar o Search input e o teste faz a asserção se ele está visível:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await expect(homePage.searchInput).toBeVisible();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se a entrada de pesquisa for alterada, o testador precisará alterar apenas a classe que manipula a entrada e não todos os testes que usam essa classe.&lt;/p&gt;

&lt;p&gt;Há uma única verificação que pode e deve ser feita dentro do Objeto de Página: &lt;strong&gt;verificar se a página, e possivelmente elementos críticos da página, foram carregados corretamente&lt;/strong&gt;. Esta verificação deve ser fei enquanto instanciar o objeto de página.&lt;/p&gt;

&lt;p&gt;Um objeto de página não precisa necessariamente representar todas as partes da própria página. Os mesmos princípios de objeto de página devem ser usados para "objetos de componente de página", que representam partes da página que podem ser incluídas em objetos de página ou testes.&lt;/p&gt;

&lt;p&gt;Um objeto de página pode incluir vários objetos de componente, e cada objeto de componente de página tem seus próprios métodos para utilizar a funcionalidade a que serve, como uma barra de navegação, uma caixa de pesquisa, um cabeçalho ou rodapé (aninhando objetos de componente dentro de outros objetos de componente para mais páginas complexas ou a objetos que são usados em todo o site), melhorando a manutenção e reduzindo a duplicação de código.&lt;/p&gt;




&lt;h2&gt;
  
  
  Série de artigos sobre E2E:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/teste-e2e-end-to-end-3cfg"&gt;Teste E2E (end-to-end)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/melhores-praticas-para-criacao-e-automacao-de-testes-e2e-51g5"&gt;Melhores práticas para criação e automação de testes E2E&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/testes-de-ui-resilientes-a-mudancas-4g0p"&gt;Testes de UI resilientes a mudanças&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/playwright-dicas-e-boas-praticas-2j9f"&gt;Playwright: dicas e boas práticas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/organizacao-de-testes-automatizados-2d7h"&gt;Organização de testes automatizados&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>e2e</category>
      <category>playwright</category>
      <category>pom</category>
      <category>aaa</category>
    </item>
    <item>
      <title>Playwright: dicas e boas práticas</title>
      <dc:creator>Tarcisio C. Uchoa</dc:creator>
      <pubDate>Mon, 10 Feb 2025 18:10:16 +0000</pubDate>
      <link>https://dev.to/tcava/playwright-dicas-e-boas-praticas-2j9f</link>
      <guid>https://dev.to/tcava/playwright-dicas-e-boas-praticas-2j9f</guid>
      <description>&lt;h2&gt;
  
  
  Priorizar atributos que o usuário interage (user-facing)
&lt;/h2&gt;

&lt;p&gt;Um usuário não sabe o que são ids ou classes e não procuram esses itens na hora de interagir com a página.&lt;/p&gt;

&lt;p&gt;O teste deve imitar o comportamento do usuário e o teste ficará mais robusto, uma vez que a interação do usuário pouco mudará, em reação a ids, classes e outros detalhes de implementação.&lt;/p&gt;

&lt;p&gt;Quanto mais o teste se assemelhar à forma como o software é utilizado, mais confiante será.&lt;/p&gt;

&lt;p&gt;Localizar um elemento pelo texto, conforme um usuário faria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.locator('text=Login');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;em vez de localizar um elemento pelo ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.locator('#login-button');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Utilizar localizadores em vez de seletores
&lt;/h2&gt;

&lt;p&gt;O uso de localizadores previne imprevisibilidades ou quebras imprevistas quando a página muda. Essas quebras podem não ser percebidas e o teste falhar, se foram utilizados seletores.&lt;/p&gt;

&lt;p&gt;Usar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.locator('text=Login').click();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;em vez de:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.click('text=Login');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Os localizadores ajudarão a mitigar imprevisibilidades, devido a seu nível de restrição.&lt;/p&gt;

&lt;p&gt;Se muitos elementos iguais surgirem na página, o uso de localizadores fará com que o teste "reclame" disso. O teste falhará e exibirá uma mensagem melhor sobre a falha, em vez de simplesmente falhar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilizar Page Object Model (POM)
&lt;/h2&gt;

&lt;p&gt;Page Object Model (POM) é um design pattern que ajuda a evitar duplicação de código, melhora a manutenibilidade e simplifica interações entre páginas e múltiplos testes.&lt;/p&gt;

&lt;p&gt;Não que seja necessário utilizar para tudo. Utilizar quando fizer sentido abstrair um trecho de código, se o teste se beneficiará dele.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Duplicação é mais barato do que uma abstração errada.&lt;br&gt;
— Sandi Metz&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Mais detalhes sobre o Page Object Model no próximo artigo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Utilizar aspas duplas para encontrar elementos específicos
&lt;/h2&gt;

&lt;p&gt;Se está encontrando múltiplos elementos com a mesma string, tente utilizar aspas duplas para habilitar "case sensivity".&lt;/p&gt;

&lt;p&gt;Por exemplo: &lt;code&gt;await page.locator('text=Checkout')&lt;/code&gt; pode retornar um botão com o texto "Checkout" e um título com o texto "Check out this new shoe".&lt;/p&gt;

&lt;p&gt;Utilize aspas duplas para retornar somente o botão com o código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.locator('text="Checkout"')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://playwright.dev/docs/other-locators#legacy-text-locator" rel="noopener noreferrer"&gt;Playwright: text locator&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Evite seletores amarrados à implementação
&lt;/h2&gt;

&lt;p&gt;XPATH e CSS podem ser amarrados à estrutura ou implementação e podem facilmente serem alterados, então melhor evitar coisas como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await locator (`#tsf &amp;gt; div:nth-child(2) &amp;gt;
div.A8SBwf &amp;gt; div.RNNXgb &amp;gt; div &amp;gt; div.a4bIc &amp;gt; input`).click();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Série de artigos sobre E2E:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/teste-e2e-end-to-end-3cfg"&gt;Teste E2E (end-to-end)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/melhores-praticas-para-criacao-e-automacao-de-testes-e2e-51g5"&gt;Melhores práticas para criação e automação de testes E2E&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/testes-de-ui-resilientes-a-mudancas-4g0p"&gt;Testes de UI resilientes a mudanças&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/playwright-dicas-e-boas-praticas-2j9f"&gt;Playwright: dicas e boas práticas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/organizacao-de-testes-automatizados-2d7h"&gt;Organização de testes automatizados&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>e2e</category>
      <category>testing</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Testes de UI resilientes a mudanças</title>
      <dc:creator>Tarcisio C. Uchoa</dc:creator>
      <pubDate>Mon, 10 Feb 2025 18:05:12 +0000</pubDate>
      <link>https://dev.to/tcava/testes-de-ui-resilientes-a-mudancas-4g0p</link>
      <guid>https://dev.to/tcava/testes-de-ui-resilientes-a-mudancas-4g0p</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change" rel="noopener noreferrer"&gt;Kent C. Dodds: Making your UI tests resilient to change&lt;/a&gt;&lt;br&gt;
Ref: &lt;a href="https://nocode.autify.com/blog/why-id-should-not-be-used" rel="noopener noreferrer"&gt;Autify Blog: Why you shouldn’t use ids in E2E testing&lt;/a&gt;&lt;br&gt;
Ref: &lt;a href="https://docs.cypress.io/app/core-concepts/best-practices#Selecting-Elements" rel="noopener noreferrer"&gt;Cypress: Selecting Elements&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Evitar buscar elementos pela tag genérica  ou por classes, que estão sujeitas a alterações.&lt;/p&gt;

&lt;p&gt;O ideal é fazer o teste o mais próximo possível de como o usuário faria.&lt;/p&gt;

&lt;p&gt;O usuário não vai abrir o Dev Tools e procurar o elemento com o ID ou nome username-field, ele vai procurar o campo de usuário.&lt;/p&gt;

&lt;p&gt;O cenário de teste mais próximo do que o usuário faria é:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Digitar o nome de usuário no campo com a label "Nome de usuário"&lt;/li&gt;
&lt;li&gt;Digitar a senha no campo com a label "Senha"&lt;/li&gt;
&lt;li&gt;Clicar no botão que tem o texto "Entrar"&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mas nem sempre é possível seguir os passos do usuário dessa forma, sem falar que se basear no texto também está sujeito a alterações (o campo "nome de usuário" pode mudar para "Usuário").&lt;/p&gt;

&lt;p&gt;Buscar pelo ID ou class é interessante, mas se um sistema que utiliza Bootstrap (&lt;code&gt;.btn-primary&lt;/code&gt;) passa a utilizar Styled Components, ou Material UI, ou Tailwind... é preciso refazer todos os testes para adaptar às novas classes.&lt;/p&gt;

&lt;p&gt;Se reutilizarmos nomes de classes por conta de estilo, ou alterarmos nomes de casses ou até mesmo a estrutura de componentes (uma &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; ou &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; a mais ou a menos), a cada alteração, o teste precisa ser reescrito, indicando um teste fraco e falho.&lt;/p&gt;

&lt;p&gt;O problema principal é que a relação entre o código e o teste está muito implícita. É necessário superar essa dificuldade tornando a relação mais explícita.&lt;/p&gt;

&lt;p&gt;Então a forma ideal é &lt;strong&gt;criar um data-attribute como data-test para identificar os elementos que devem ser testados&lt;/strong&gt;, garantindo que o data-attribute não será utilizado para nenhum outro propósito.&lt;/p&gt;

&lt;p&gt;Adicionando "metadata" aos elementos que serão explicitamente testados. Tornando a relação entre o código e o teste mais explícita e o desenvolvedor pode alterar ids, classes e estruturas sem dificuldade, desde que mantendo a indicação do teste explícita com o data-attribute .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;button
    type="submit"
    name="submit"
    id="form1234-submt"
    class="btn btn-primary"
    data-test="login-btn-submit"&amp;gt; ✅
    Enviar
&amp;lt;/button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mais código para escrever?
&lt;/h2&gt;

&lt;p&gt;Embora seja a prática ideal, os desenvolvedores têm que se preocupar agora, além dos Ids , também com os data-test para manter a compatibilidade entre o código e o teste, evitando repeti-los ou removê-los ou alterá-los em refatorações de código ou criação de novos.&lt;/p&gt;

&lt;p&gt;Uma possibilidade para diminuir riscos e ainda manter a referência é identificar componentes maiores com o data-attribute , em vez de identificar todos os componentes individualmente.&lt;/p&gt;

&lt;p&gt;Talvez escrever:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="modal" tabindex="-1" role="dialog" 👉🏻data-test="modal"👈🏻&amp;gt;
  &amp;lt;div class="modal-dialog" role="document"&amp;gt;
    &amp;lt;div class="modal-content"&amp;gt;
      &amp;lt;div class="modal-header"&amp;gt;        
        &amp;lt;h5 class="modal-title"&amp;gt;Confirm&amp;lt;/h5&amp;gt;
          &amp;lt;button
            type="button"
            class="close"
            data-dismiss="modal"
            aria-label="Close"&amp;gt;
          &amp;lt;span aria-hidden="true"&amp;gt;&amp;amp;times;&amp;lt;/span&amp;gt;        
        &amp;lt;/button&amp;gt;      
      &amp;lt;/div&amp;gt;      
      &amp;lt;div class="modal-body"&amp;gt;
        &amp;lt;p&amp;gt;Really submit?&amp;lt;/p&amp;gt;     
      &amp;lt;/div&amp;gt;
      &amp;lt;div class="modal-footer"&amp;gt;        
        &amp;lt;button
          type="button"
          class="btn btn-primary"&amp;gt;
          Submit
        &amp;lt;/button&amp;gt;
        &amp;lt;button
          type="button"
          class="btn btn-secondary"
          data-dismiss="modal"&amp;gt;
            Cancel
        &amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;   
    &amp;lt;/div&amp;gt; 
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em vez de :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="modal" tabindex="-1" role="dialog" 👉🏻data-test="modal"👈🏻&amp;gt;
    &amp;lt;div class="modal-dialog" role="document"&amp;gt;
        &amp;lt;div class="modal-content"&amp;gt;
            &amp;lt;div class="modal-header"&amp;gt;        
                &amp;lt;h5 class="modal-title" 👉🏻data-test="modal-title"👈🏻&amp;gt;Confirm&amp;lt;/h5&amp;gt;
                &amp;lt;button
                    type="button"
                    class="close"
                    data-dismiss="modal"
                    aria-label="Close"
                   👉🏻data-test="modal-close"👈🏻&amp;gt;
                    &amp;lt;span aria-hidden="true"&amp;gt;&amp;amp;times;&amp;lt;/span&amp;gt;        
                &amp;lt;/button&amp;gt;      
            &amp;lt;/div&amp;gt;      
            &amp;lt;div class="modal-body" 👉🏻data-test="modal-body"👈🏻&amp;gt;
                &amp;lt;p&amp;gt;Really submit?&amp;lt;/p&amp;gt;     
            &amp;lt;/div&amp;gt;
            &amp;lt;div class="modal-footer"&amp;gt;        
                 &amp;lt;button
                     type="button"
                     class="btn btn-primary"
                    👉🏻data-test="modal-btn-submit"👈🏻&amp;gt;
                     Submit&amp;lt;/button&amp;gt;        
                 &amp;lt;button
                     type="button"
                     class="btn btn-secondary"
                     data-dismiss="modal"
                    👉🏻data-test="modal-btn-cancel"👈🏻&amp;gt;Cancel&amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;   
        &amp;lt;/div&amp;gt; 
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assim é possível se basear no componente maior para localizar os itens internos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.page.locator('data-test=modal &amp;gt;&amp;gt; button:has-text("Submit")')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O código acima busca somente o botão com o texto "Submit" que está dentro do elemento com o data-test=modal , ignorando outros botões, possivelmente com o mesmo texto.&lt;/p&gt;

&lt;p&gt;Dependendo do formato e tamanho do projeto, isso pode ser útil.&lt;/p&gt;

&lt;h2&gt;
  
  
  Suja o código?
&lt;/h2&gt;

&lt;p&gt;Se houver alguma preocupação com o fato de colocar em produção data-attributes que indiquem os testes (não é um grande problema, mas...), é possível remover esses atributos de produção com plugins como o babel-plugin-react-remove-properties.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boas práticas do Cypress
&lt;/h2&gt;

&lt;p&gt;Utilização de atributos data-* provém melhor contexto aos seletores, isolando das alterações de CSS e JavaScript.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evitar localizar elementos por tags , classes e Ids , altamente sujeitos a mudanças.&lt;/li&gt;
&lt;li&gt;É interessante localizar objetos pelo texto, se o conteúdo do texto fizer parte do cenário de teste, evitar se for um objeto que o texto pode ser alterado e não faça sentido para o teste.&lt;/li&gt;
&lt;li&gt;Utilizar data-attributes facilita a identificação dos elementos exclusiva para testes, isolando de alterações de HTML, JS e CSS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quando utilizar a localização por texto?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await page.locator('text=Log in').click();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o conteúdo (texto) do elemento alterar, você quer que o teste falhe?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Se SIM: localizar o elemento por texto&lt;/li&gt;
&lt;li&gt;Se NÃO: localizar o elemento por data-attribute&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Possível conclusão
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;O que deve ser imutável em uma aplicação não são suas casses ou Ids, mas o comportamento.&lt;/li&gt;
&lt;li&gt;Quando o comportamento é alterado, o teste E2E deve detectar isso.&lt;/li&gt;
&lt;li&gt;Testes E2E não devem travar o desenvolvimento além do comportamento.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considerando isso, semelhante ao indicado nas boas práticas do Cypress, é interessante utilizar a localização por texto (quando necessário) e um pouco mais de &lt;code&gt;data-attribute&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Localizar elementos por texto, quando necessário&lt;/li&gt;
&lt;li&gt;Usar &lt;code&gt;data-attributes&lt;/code&gt;, preferencialmente para identificar componentes UI e não todos os elementos individualmente.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vantagens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Não emprega Ids e classes internas, garantindo a manutenibilidade do código.&lt;/li&gt;
&lt;li&gt;Comparado ao uso massivo de &lt;code&gt;data-attributes&lt;/code&gt;, diminui o custo de desenvolvimento e manutenção de código.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Série de artigos sobre E2E:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/teste-e2e-end-to-end-3cfg"&gt;Teste E2E (end-to-end)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/melhores-praticas-para-criacao-e-automacao-de-testes-e2e-51g5"&gt;Melhores práticas para criação e automação de testes E2E&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/testes-de-ui-resilientes-a-mudancas-4g0p"&gt;Testes de UI resilientes a mudanças&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/playwright-dicas-e-boas-praticas-2j9f"&gt;Playwright: dicas e boas práticas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/organizacao-de-testes-automatizados-2d7h"&gt;Organização de testes automatizados&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>e2e</category>
      <category>testing</category>
      <category>playwright</category>
      <category>cypress</category>
    </item>
    <item>
      <title>Melhores práticas para criação e automação de testes E2E</title>
      <dc:creator>Tarcisio C. Uchoa</dc:creator>
      <pubDate>Mon, 10 Feb 2025 17:55:36 +0000</pubDate>
      <link>https://dev.to/tcava/melhores-praticas-para-criacao-e-automacao-de-testes-e2e-51g5</link>
      <guid>https://dev.to/tcava/melhores-praticas-para-criacao-e-automacao-de-testes-e2e-51g5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://www.datadoghq.com/blog/test-creation-best-practices/" rel="noopener noreferrer"&gt;Best practices for creating end-to-end tests&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Os testes E2E são críticos para monitorar fluxos de trabalho chaves de uma aplicação — como criar uma conta ou adicionar itens num carrinho de compras — e garantir que os usuários não encontrem funcionalidades quebradas.&lt;/p&gt;

&lt;p&gt;É importante criar um plano de testes que provêm uma cobertura apropriada e fácil de adotar e manter a longo prazo.&lt;/p&gt;

&lt;p&gt;As melhores práticas para criação de testes E2E incluem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Definir a cobertura de testes&lt;/li&gt;
&lt;li&gt;Criar testes eficientes e significativos&lt;/li&gt;
&lt;li&gt;Desenhar suítes de teste coerentes e fáceis de navegar&lt;/li&gt;
&lt;li&gt;Criar notificações que permitam que o time responda aos problemas rapidamente&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Definir a cobertura de testes
&lt;/h2&gt;

&lt;p&gt;Antes de começar a criar os testes, é importante considerar os fluxos da aplicação que devem ser testados. Nem todos os fluxos da aplicação cabem nos testes E2E.&lt;/p&gt;

&lt;p&gt;Não deixar os testes muito grandes, complexos e de difícil manutenção.&lt;/p&gt;

&lt;p&gt;A cobertura de testes deve ser representativa para os usuários e como eles usam a aplicação.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Identificar e priorizar os fluxos de trabalho mais utilizados da aplicação&lt;/strong&gt;. Assim, colocando no escopo das suítes de teste o que traz mais valor para o negócio.&lt;/p&gt;

&lt;p&gt;Essa abordagem ajudará a alcançar melhor balanço entre cobertura de testes e manutenibilidade.&lt;/p&gt;

&lt;p&gt;Fluxos-chave de uma aplicação podem incluir:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Criar ou entrar numa conta.&lt;/li&gt;
&lt;li&gt;Agendar um voo.&lt;/li&gt;
&lt;li&gt;Adicionar itens num carrinho de compras.&lt;/li&gt;
&lt;li&gt;Ver a lista de empregados de uma companhia.&lt;/li&gt;
&lt;li&gt;Fazer um depósito na conta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interessante descobrir quais os principais fluxos utilizados na aplicação. Ferramentas como RUM (Real User Monitoring) da Datadog, ou mesmo acompanhar o Google Analytics. Ver quais as URLs mais visitadas, quais os fluxos mais utilizados.&lt;/p&gt;

&lt;p&gt;Além de testar os fluxos mais populares, é importante &lt;strong&gt;criar testes para os fluxos não tão utilizados&lt;/strong&gt;, mas ainda assim críticos (como recuperar a senha ou editar o perfil). Criar testes para esses fluxos permite identificar problemas de funcionalidade antes que os clientes reclamem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criar testes eficientes e significativos para fluxos chave
&lt;/h2&gt;

&lt;p&gt;Sem um bom plano de testes de como abordar um fluxo de trabalho específico, os testes podem se tornar complexos, com um número grande de passos, dependências e asserções desnecessárias, aumentando as falhas e tempo de execução, tornando mais difícil de resolver e responder aos problemas rapidamente.&lt;/p&gt;

&lt;p&gt;Boas práticas para suítes de testes mais eficientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quebrar fluxos de trabalho em testes menores&lt;/li&gt;
&lt;li&gt;Criar asserções significativas para verificar o comportamento esperado&lt;/li&gt;
&lt;li&gt;Criar testes que se adaptem a fatores fora do nosso controle&lt;/li&gt;
&lt;li&gt;Manter o estado da aplicação para que testes possam ser executados mais de uma vez sem alterar o resultado&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quebrar fluxos de trabalho em testes menores
&lt;/h3&gt;

&lt;p&gt;É importante criar testes que não dupliquem passos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separar fluxos de teste em testes menores e mais focados&lt;/strong&gt; ajuda a manter o escopo, reduz pontos de manutenção e facilita encontrar erros e falhas.&lt;/p&gt;

&lt;p&gt;Por exemplo: um teste que verifica a funcionalidade de carrinho de compras, não precisa incluir os passos de criar uma conta. Se o teste falhar, você não vai querer perder tempo tentando descobrir onde ocorreu a falha: no carrinho ou na hora de criar a conta.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separar testes menores que podem ser reutilizados.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Utilizar a prática &lt;em&gt;DRY (don’t repeat yourself)&lt;/em&gt; e &lt;em&gt;Page Object Models (POM)&lt;/em&gt;, onde organizamos os itens e ações de uma página ou componente em um arquivo separado, que serão chamados nos testes definitivos.&lt;/p&gt;

&lt;p&gt;Criar componentes de teste, da mesma forma que separamos componentes em front-end. Em caso de falhas, basta localizar e reparar apenas aquele componente e não uma suíte inteira de testes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Criar asserções significativas para verificar o comportamento esperado
&lt;/h3&gt;

&lt;p&gt;Construir suítes de testes eficientes é garantir que os testes verifiquem comportamentos importantes da aplicação.&lt;/p&gt;

&lt;p&gt;As asserções do teste são passos que descrevem o fluxo lógico de uma ação na aplicação. Elas adicionam valor aos testes imitando o que os usuários esperam ver quando eles interagem com a aplicação.&lt;/p&gt;

&lt;p&gt;Exemplo: uma asserção pode confirmar que o usuário é redirecionado para a página inicial e vê uma mensagem de boas-vindas após fazer o login.&lt;/p&gt;

&lt;p&gt;Asserções comumente usadas em testes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Um elemento tem (ou não tem) determinado conteúdo.&lt;/li&gt;
&lt;li&gt;Um elemento ou texto está presente (ou não) em uma página.&lt;/li&gt;
&lt;li&gt;Uma URL contém um determinado texto, número ou expressão regular.&lt;/li&gt;
&lt;li&gt;Um arquivo foi baixado.&lt;/li&gt;
&lt;li&gt;Um e-mail foi enviado e inclui determinado texto.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;É importante incluir apenas asserções que imitam o que o usuário espera que aconteça num fluxo de trabalho.&lt;/p&gt;

&lt;p&gt;Um teste da funcionalidade de compra, por exemplo, apenas precisa incluir asserções que são relevantes à compra, como verificar a confirmação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Criar testes que se adaptem a fatores fora do nosso controle
&lt;/h3&gt;

&lt;p&gt;Teste geralmente falham se a aplicação demorar para carregar. O tempo de carregamento pode ser afetado por fatores como uma inesperada falha na rede ou uma onda incomum de tráfego que pode sobrecarregar o servidor.&lt;/p&gt;

&lt;p&gt;Inconsistências de demora no carregamento podem levar a falsos positivos, e adicionar tempos de espera manualmente no teste (hard coding) pode deixar os testes menos confiáveis.&lt;/p&gt;

&lt;p&gt;Uma melhor prática de garantir que os testes se adaptem a flutuações de tempo é desenhá-los para &lt;strong&gt;esperar automaticamente&lt;/strong&gt; até que uma página esteja pronta para interagir antes de executar (ou refazer) um passo de teste.&lt;/p&gt;

&lt;p&gt;Isso não apenas elimina a necessidade de adicionar esperas no código, como também permite focar em falhas legítimas no ambiente de produção.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//exemplo no Playwright: aguardando o estado "network idle" antes de testar

async navigate(): Promise&amp;lt;void&amp;gt; {
    const url = await this.page.url();
    if (url != this.baseUrl) {
        await this.page.goto(this.baseUrl);
    }
    await this.page.waitForLoadState('networkidle');
}

await frame.click('button');  // o clique aciona a execução
await frame.waitForLoadState();  // espera pelo estado de "carregado"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://playwright.dev/docs/api/class-frame#frame-wait-for-load-state" rel="noopener noreferrer"&gt;Playwright: waitForLoadState&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O Playwright realiza uma série de verificações de ação nos elementos antes de executar ações para garantir que essas ações se comportem conforme o esperado. Ele espera automaticamente que todas as verificações relevantes sejam aprovadas e só então executa a ação solicitada. Se as verificações necessárias não passarem dentro do &lt;code&gt;timeout&lt;/code&gt; fornecido, a ação falhará com o &lt;code&gt;TimeoutError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Por exemplo, para &lt;code&gt;page.click()&lt;/code&gt;, o Playwright garantirá que:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;o elemento está presente no DOM&lt;/li&gt;
&lt;li&gt;o elemento está visível&lt;/li&gt;
&lt;li&gt;o elemento está estável, não está sendo animado ou terminou a animação&lt;/li&gt;
&lt;li&gt;o elemento pode receber um evento/ação, não está ofuscado por outros elementos&lt;/li&gt;
&lt;li&gt;o elemento está habilitado&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://playwright.dev/docs/actionability" rel="noopener noreferrer"&gt;Playwright: Auto-waiting&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Manter o estado da aplicação para que testes possam ser executados mais de uma vez sem alterar o resultado
&lt;/h3&gt;

&lt;p&gt;Testes dependem de dados limpos para recriar os passos para cada execução. É importante ter configurações dedicadas aos testes (credenciais de login, ambientes, cookies) que são usadas somente nos testes.&lt;/p&gt;

&lt;p&gt;É importante criar testes que possam ser executados sem serem afetados pelos seus próprios resultados, os testes devem deixar o estado da aplicação e ambiente de teste sem alteração antes e depois da execução.&lt;/p&gt;

&lt;p&gt;Um teste que foca em adicionar múltiplos itens em um carrinho de compras, por exemplo, deve possuir um mecanismo que exclua os itens do carrinho depois.&lt;/p&gt;

&lt;p&gt;É interessante ter um recurso que consiga apagar do banco de dados as transações executadas pelos testes.&lt;/p&gt;

&lt;p&gt;Também é possível ter subtestes que limpem a execução dos testes após cada execução (&lt;code&gt;afterAll&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test.beforeAll(async ({ browser }) =&amp;gt; {
    page = await browser.newPage();
    homePage = new HomePage(page, BASE_URL);
    await homePage.navigate();
});

test('do tests', async () =&amp;gt; {
    // faz os testes
});

test.afterAll(async () =&amp;gt; {
    await homePage.clean(); // volta ao estado original
    await page.close();
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Desenhar suítes de teste coerentes e fáceis de navegar
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configurar testes por ambiente
&lt;/h3&gt;

&lt;p&gt;Cada ambiente que é utilizado para testar as funcionalidades durante o desenvolvimento podem requerer configurações diferentes para rodar os testes.&lt;/p&gt;

&lt;p&gt;Por exemplo: testes em ambiente de desenvolvimento talvez só precisem executar em um dispositivo, enquanto testes em pré-produção requerem vários diferentes tipos de dispositivos.&lt;/p&gt;

&lt;p&gt;O ideal é separar os testes por ambiente para garantir que serão executados somente o necessário para cada ambiente.&lt;/p&gt;

&lt;p&gt;Outra dica é identificar nos títulos dos testes o ambiente/dispositivo testado, facilitando a identificação e/ou correção quando um teste falhar.&lt;/p&gt;

&lt;p&gt;Importante configurar variáveis de ambiente quando colocar os testes em integração contínua (CI).&lt;/p&gt;

&lt;h3&gt;
  
  
  Organizar testes por localidade, dispositivos e mais
&lt;/h3&gt;

&lt;p&gt;Encontrar maneiras de organizar e categorizar os testes é um outro aspecto chave para desenvolver suítes de testes coerentes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desenhando uma boa estrutura organizacional&lt;/strong&gt; permite gerenciar facilmente as suítes de teste enquanto eles aumentam.&lt;/p&gt;

&lt;p&gt;Uma forma de adicionar estrutura aos testes é incorporar metadados ou etiquetas como tipo de teste, ambiente e dispositivo. Etiquetas (tags) provém melhor contexto sobre o que está sendo testado, facilitando encontrar quais fluxos de trabalho estão quebrando.&lt;/p&gt;

&lt;p&gt;Apenas adicionando o ambiente no título do teste ajuda identificar onde o teste está executando. Tags também permite categorizar os testes com atributos chave no momento de criar os testes.&lt;/p&gt;

&lt;p&gt;Adicionar metadados e tags aos testes é especialmente útil se você gerenciar uma suíte muito grande de testes e precisa revisar apenas uma parte deles. Por exemplo, pode usar uma tag “team” para buscar e executar testes de um time que desenvolveu uma funcionalidade ou a tag “site” para encontrar os testes associados a um site específico.&lt;/p&gt;

&lt;p&gt;Interessante utilizar tags nos testes (o Playwright permite) para identificar e executar facilmente apenas os testes prioritários (smoke tests), ou talvez testes relacionados a uma sprint ou funcionalidade.&lt;/p&gt;

&lt;p&gt;Escrevendo tags no Playwright:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { test, expect } from '@playwright/test';

test('Test login page @fast', async ({ page }) =&amp;gt; {
    // ...
});

test('Test full report @slow', async ({ page }) =&amp;gt; {
    // ...
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você poderá então rodar apenas os testes com uma determinada a tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx playwright test --grep @fast
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou se quiser o contrário, pular os testes com uma determinada tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx playwright test --grep-invert @slow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Ref: &lt;a href="https://playwright.dev/docs/test-annotations#tag-tests" rel="noopener noreferrer"&gt;Playwright: Tag tests&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Criar notificações que permitam que o time responda aos problemas rapidamente
&lt;/h2&gt;

&lt;p&gt;Independentemente de como você estrutura os testes ou onde os executa, é importante que o time esteja apto para acessar rapidamente as falhas dos testes, assim como saberem quando a suíte de testes finalizou a execução com sucesso.&lt;/p&gt;

&lt;p&gt;Se você está executando testes de um serviço crítico em produção, os desenvolvedores deverão saber o estado e resultado dos testes assim que possível. Se todos os testes passaram, eles poderão seguir adiante com o desenvolvimento. Se há falhas, eles precisam ser notificados imediatamente para resolver os problemas rapidamente.&lt;/p&gt;

&lt;p&gt;Relatórios de teste geralmente são difíceis de analisar, especialmente se você adiciona mais testes à suíte. Se executar os testes em diferentes dispositivos, você precisará ver vários diferentes relatórios para encontrar falhas em cada dispositivo. Perdendo mais tempos navegando no resultado dos testes do que em encontrar e consertar o problema.&lt;/p&gt;

&lt;p&gt;O ideal seria &lt;strong&gt;construir notificações que automaticamente consolidem&lt;/strong&gt; e encaminhem os resultados para os times apropriados, provendo o contexto necessário sobre o que foi testado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interessante configurar que o teste (CI) notifique por e-mail ou envie para grupos no Teams&lt;/strong&gt;, por exemplo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Série de artigos sobre E2E:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/teste-e2e-end-to-end-3cfg"&gt;Teste E2E (end-to-end)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/melhores-praticas-para-criacao-e-automacao-de-testes-e2e-51g5"&gt;Melhores práticas para criação e automação de testes E2E&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/testes-de-ui-resilientes-a-mudancas-4g0p"&gt;Testes de UI resilientes a mudanças&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/playwright-dicas-e-boas-praticas-2j9f"&gt;Playwright: dicas e boas práticas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/organizacao-de-testes-automatizados-2d7h"&gt;Organização de testes automatizados&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>e2e</category>
      <category>testing</category>
      <category>automation</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Teste E2E (end-to-end)</title>
      <dc:creator>Tarcisio C. Uchoa</dc:creator>
      <pubDate>Mon, 10 Feb 2025 17:41:04 +0000</pubDate>
      <link>https://dev.to/tcava/teste-e2e-end-to-end-3cfg</link>
      <guid>https://dev.to/tcava/teste-e2e-end-to-end-3cfg</guid>
      <description>&lt;p&gt;O teste end-to-end é uma metodologia utilizada para testar se o fluxo de um aplicativo está sendo executado conforme o projeto do início ao fim. O objetivo da realização de testes end-to-end é identificar dependências do sistema e garantir que a informação certa seja passada entre vários componentes e sistemas.&lt;/p&gt;

&lt;p&gt;Resumindo, o teste end-to-end é um forma de realizar testes nas quais visam provar o sistema de uma forma mais completa simulando o ambiente real.&lt;/p&gt;

&lt;p&gt;Os testes E2E são críticos para monitorar fluxos de trabalho chaves de uma aplicação — como criar uma conta ou adicionar itens num carrinho de compras — e garantir que os usuários não encontrem funcionalidades quebradas.&lt;/p&gt;

&lt;p&gt;É importante criar um plano de testes que provêm uma cobertura apropriada e fácil de adotar e manter a longo prazo. Veja nosso documento de Melhores práticas para criar testes E2E.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automação de teste E2E com Playwright
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;https://playwright.dev/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Vantagens dos Testes Automatizados no Front-End
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Testes de ponta a ponta, simulando todas as possíveis interações do usuário, sem dependência de interações manuais.&lt;/li&gt;
&lt;li&gt;Garantir qualidade após mudanças.&lt;/li&gt;
&lt;li&gt;Diminuição do tempo de testes antes de lançar uma nova versão.&lt;/li&gt;
&lt;li&gt;A cada nova funcionalidade lançada e testada manualmente, os testes automatizados garantem que nada que já funciona foi alterado.&lt;/li&gt;
&lt;li&gt;Revalidar todo o sistema a cada atualização do código.&lt;/li&gt;
&lt;li&gt;Ajuda a manter uma documentação viva.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Vantagens do Playwright
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Executa nos principais navegadores: Chrome, Firefox, Webkit (Safari) e Edge.&lt;/li&gt;
&lt;li&gt;Simula dispositivos (Android, iOS) e resoluções.&lt;/li&gt;
&lt;li&gt;Auto-wait: com ele é possível tornar a escrita de testes mais simples, permitindo que o desenvolvedor se preocupe somente com as interações com o navegador, deixando o trabalho de aguardar os elementos totalmente com o framework.&lt;/li&gt;
&lt;li&gt;Recorder/CodeGen: o Playwright permite que o desenvolvedor execute as ações de um teste manualmente e essas ações são gravadas em forma de código, facilitando a criação dos testes. A ferramenta também possui um buscador de seletores (semelhante ao “inspecionar elemento” do DevTools) que permite validar os seletores escritos pelo desenvolvedor ou buscar novos seletores para escrever o teste.&lt;/li&gt;
&lt;li&gt;Possui mais ferramentas e tem melhor desempenho que outros frameworks de teste E2E.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Série de artigos sobre E2E:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/teste-e2e-end-to-end-3cfg"&gt;Teste E2E (end-to-end)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/melhores-praticas-para-criacao-e-automacao-de-testes-e2e-51g5"&gt;Melhores práticas para criação e automação de testes E2E&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/testes-de-ui-resilientes-a-mudancas-4g0p"&gt;Testes de UI resilientes a mudanças&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/playwright-dicas-e-boas-praticas-2j9f"&gt;Playwright: dicas e boas práticas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tcava/organizacao-de-testes-automatizados-2d7h"&gt;Organização de testes automatizados&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>e2e</category>
      <category>playwright</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
