Automação com Playwright em 2023. Typescript, Page Object e Fixtures

Jan 30 2023
Introdução Hoje, quero apresentar a você uma estrutura Node.js que está se tornando cada vez mais popular para automação.

Introdução

Hoje, quero apresentar a você uma estrutura Node.js que está se tornando cada vez mais popular para automação. Até o final de 2022, Playwright terá mais de 1 milhão de downloads semanais de acordo com o npm. Ainda pode estar perdendo para ferramentas como Cypress ou Selenium Webdriver em termos de downloads semanais (esses têm 4 e 2 milhões de downloads, respectivamente, até o final de 2022). Mas esse framework merece a atenção dos Engenheiros de Automação? Vamos descobrir!

Longa história curta

O Playwright é desenvolvido pela Microsoft e a equipe principal consiste em desenvolvedores que antes eram engenheiros do Google que trabalharam no Puppeteer. Acho que isso nos dá autoridade suficiente para confiar nessa ferramenta, já que o Puppeteer dominou o mercado por mais de uma década ao lado do driver Selenium. Muitos projetos da Microsoft são incríveis, como o VS Code, que é amplamente considerado o melhor editor de código gratuito do mercado. Mas vamos voltar ao nosso tópico de automação.

Por que devo usar o Playwright?

Você não deveria. Mas deixe-me convencê-lo a tentar. Os resultados do stateofjs.com em 2022 mostram um nível de satisfação de 95%. Vejamos as vantagens que o Playwright nos oferece.

  • Velocidade : o Playwright foi projetado para ser rápido e eficiente, o que pode torná-lo mais rápido do que outras ferramentas de automação de navegador, como o Selenium. Isso pode ajudá-lo a executar seus testes mais rapidamente, especialmente se você tiver um grande conjunto de testes.
  • Espera automática. O dramaturgo espera que os elementos sejam acionáveis ​​antes de executar as ações. Ele também tem um rico conjunto de eventos de introspecção. A combinação dos dois elimina a necessidade de tempos limite artificiais — a principal causa de testes inconsistentes.
  • Rastreamento e relatório padrão sólido. Configure a estratégia de repetição de teste, capture rastreamento de execução, vídeos e capturas de tela para eliminar flakes.
  • Execução simultânea O Playwright permite executar vários contextos de navegador ao mesmo tempo em um único processo, o que pode tornar seus testes ainda mais rápidos.
  • Codegen e Playwright Inspector ajudam você a gerar testes registrando suas ações. Você pode salvá-los em qualquer idioma.
  • Teste entre navegadores : o Playwright permite que você execute seus testes em vários navegadores, incluindo Chrome, Firefox e Safari. Embora possa não ser necessário executar testes em vários navegadores para testes E2E, é bom ter a opção disponível.

Estrutura da automação.

.
├── config
│   ├── global-setup.ts
│   └── playwright.config.ts
├── package-lock.json
├── package.json
└── src
    ├── data
    │   └── data.json
    ├── fixtures
    │   ├── AxeFixture.ts
    │   └── TodoFixture.ts
    ├── pages
    │   └── TodoPage.ts
    └── tests
        ├── a11y.spec.ts
        └── demo-pom-todo-app.spec.ts

  • contém o arquivo playwright.config.ts . Você pode verificar a aparência deste arquivo de configuração no repositório e verificar a documentação , pois há um grande número de opções disponíveis.
  • a função global-setup.ts é executada uma vez antes de todos os testes. Seu principal objetivo é fazer login no aplicativo da web e salvar todo o estado do navegador. Esse estado é armazenado no arquivo storageState.json, que é usado para injetar o estado no navegador antes de cada teste. Isso nos ajuda a evitar ter que fazer login no aplicativo toda vez antes de executar os testes. Claro, existem diferentes tipos de autorizações, mas principalmente lidamos com JWT, que é armazenado em armazenamento local ou cookies. Consulte a documentação para obter mais informações.

A abordagem que acredito funcionar melhor para automação é usar o padrão POM. Aqui está um exemplo simples de como implementar o padrão Page Object. Todos os elementos da página com os quais planejamos interagir são definidos dentro da classe como campos. Esses campos são inicializados dentro do construtor.

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

export class TodoDemoPage {
  readonly page: Page;
  readonly newTodoInput: Locator;
  readonly todoTitle: Locator;
  readonly todoCount: Locator

  constructor(page: Page) {
    this.page = page;
    this.newTodoInput = page.getByPlaceholder('What needs to be done?');
    this.todoTitle = page.getByTestId('todo-title');
    this.todoCount = page.getByTestId('todo-count');
  }

  async goto() {
    await this.page.goto('https://demo.playwright.dev/todomvc');
  }

  async addTodo(data: string) {
    await this.newTodoInput.fill(data)
    await this.newTodoInput.press("Enter")
  }

  async addDefaultTodos(todosItems: string[]) {
    for (const todo of todosItems) {
      await this.addTodo(todo)
    }
  }
...
}

  • nomenclatura — certifique-se de que os campos e métodos tenham nomes apropriados.
  • o método faz apenas uma coisa de acordo com o nome e faz bem.
  • executar a asserção de resultados específicos na página.
  • seco - não se repita.

Antes de irmos para o teste real e como usar o POM, quero apresentar os acessórios. É um recurso mais avançado que, na minha opinião, é mais flexível do que apenas usar métodos usuais de ciclo de vida, como antes/depois. Essencialmente, eles são usados ​​para estabelecer o ambiente para cada teste, dando ao teste tudo o que ele precisa.

Mas chega de palavras, vamos ver o código.

import { test as base } from '@playwright/test';
import { TodoDemoPage } from '../pages/TodoPage';

type MyFixtures = {
  todoDemoPage: TodoDemoPage;
  noneExistingPage: any
};

export const todoDemoPage = async({page}, use) => {
  const todoDemoPage = new TodoDemoPage(page);
  // Set up the fixture.
  await todoDemoPage.goto();
  // Use the fixture value in the test.
  await use(todoDemoPage);
}

// we can create as many fixtures as we want, but I prefer to store them in separate files
export const noneExistingPage = async({page}, use) => {
  // Let's imagine we have another fixter-page set up here
}

export const test = base.extend<MyFixtures>({todoDemoPage, noneExistingPage});

Não consigo descrever melhor as vantagens do que a documentação , mas há algumas que gostaria de citar aqui. Espero que você aprecie os acessórios à medida que o número de suas páginas e casos de teste aumenta.

As luminárias encapsulam a configuração e a desmontagem no mesmo local, facilitando a escrita.

Os acessórios são reutilizáveis ​​entre os arquivos de teste — você pode defini-los uma vez e usá-los em todos os seus testes. É assim que funciona o acessório embutido do Playwright page.

Os equipamentos são sob demanda - você pode definir quantos equipamentos quiser, e o Playwright Test configurará apenas os necessários para o seu teste e nada mais.

As luminárias podem ser compostas — elas podem depender umas das outras para fornecer comportamentos complexos.

fonte:https://playwright.dev/docs/test-fixtures

testes

Então, a parte mais difícil já passou e agora podemos nos divertir escrevendo testes usando nossos fixtures, que encapsulam toda a lógica de configuração, permitindo que nos concentremos na construção de nossos testes de automação.

import { test } from '../fixtures/TodoFixture'

const TODO_ITEMS = [
    'buy some cheese',
    'buy bottle of wine, or two',
    'celebrate'
];

// our test is imported from fixtures folder
// so we can have access to tododDempPage and noneExistingPage objects
// in callback function trhough destructuring and we can use it for our needs
test.describe('New Todo', () => {
  test('should allow me to add todo items', async ({ todoDemoPage }) => {
    await todoDemoPage.addTodo(TODO_ITEMS[0])
    await todoDemoPage.checkInputIsEmpty();
    await todoDemoPage.addTodo(TODO_ITEMS[1])
    await todoDemoPage.checkAddedTodos([TODO_ITEMS[0], TODO_ITEMS[1]])
    await todoDemoPage.checkNumberOfTodosInLocalStorage(2);
  });

  test('should clear text input field when an item is added', async ({ todoDemoPage }) => {
    await todoDemoPage.addTodo(TODO_ITEMS[0])
    await todoDemoPage.checkInputIsEmpty();
    await todoDemoPage.checkNumberOfTodosInLocalStorage(1);
  });


  test('should append new items to the bottom of the list', async ({ todoDemoPage }) => {
    await todoDemoPage.addDefaultTodos(TODO_ITEMS);
    await todoDemoPage.checkDefaultAddedTodods(TODO_ITEMS);
    await todoDemoPage.checkAddedTodos(TODO_ITEMS)
    await todoDemoPage.checkNumberOfTodosInLocalStorage(3);
  });
});

CI/CD

Uma vez que nossos testes foram desenvolvidos e temos uma prova de conceito para nosso p, é importante configurar nosso pipeline de integração contínua e implantação contínua (CI/CD). A abordagem específica para fazer isso varia dependendo do projeto específico. Recomenda-se ler a documentação para configurar corretamente o pipeline de CI/CD.

Resumo

Espero que você tenha achado as informações úteis em sua jornada rumo à automação. Aproveite a codificação e espere que você tenha projetos livres de bugs!

Github com o iniciador do dramaturgo :https://github.com/eugeniuszG/playwright-starter