Serviço de Comparação de Imagens (Testes de Regressão Visual)
@wdio/visual-service é um pacote de terceiros, para mais informações, consulte GitHub | npm
Para documentação sobre testes visuais com WebdriverIO, consulte a documentação. Este projeto contém todos os módulos relevantes para executar testes visuais com WebdriverIO. Dentro do diretório ./packages
você encontrará:
@wdio/visual-testing
: o serviço WebdriverIO para integração de testes visuaiswebdriver-image-comparison
: Um módulo de comparação de imagens que pode ser usado para diferentes frameworks de automação de testes NodeJS que suportam o protocolo WebDriver
Storybook Runner (BETA)
Clique para descobrir mais documentação sobre o Storybook Runner BETA
Storybook Runner ainda está em BETA, a documentação será posteriormente movida para as páginas de documentação do WebdriverIO.
Este módulo agora suporta Storybook com um novo Visual Runner. Este executor verifica automaticamente uma instância local/remota do storybook e criará capturas de tela de elementos de cada componente. Isso pode ser feito adicionando
export const config: WebdriverIO.Config = {
// ...
services: ["visual"],
// ....
};
aos seus services
e executando npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook
através da linha de comando.
Ele usará o Chrome no modo headless como navegador padrão.
[!NOTE]
- A maioria das opções de Teste Visual também funcionará para o Storybook Runner, consulte a documentação do WebdriverIO.
- O Storybook Runner substituirá todas as suas capacidades e só pode ser executado nos navegadores que ele suporta, veja
--browsers
.- O Storybook Runner não suporta uma configuração existente que usa capacidades Multiremote e lançará um erro.
- O Storybook Runner suporta apenas Desktop Web, não Mobile Web.
Opções de Serviço do Storybook Runner
As opções de serviço podem ser fornecidas assim
export const config: WebdriverIO.Config = {
// ...
services: [
[
'visual',
{
// Algumas opções padrão
baselineFolder: join(process.cwd(), './__snapshots__/'),
debug: true,
// As opções do storybook, veja as opções cli para a descrição
storybook: {
additionalSearchParams: new URLSearchParams({foo: 'bar', abc: 'def'}),
clip: false,
clipSelector: ''#some-id,
numShards: 4,
// `skipStories` pode ser uma string ('example-button--secondary'),
// um array (['example-button--secondary', 'example-button--small'])
// ou uma regex que precisa ser fornecida como string ("/.*button.*/gm")
skipStories: ['example-button--secondary', 'example-button--small'],
url: 'https://www.bbc.co.uk/iplayer/storybook/',
version: 6,
// Opcional - Permite substituir o caminho de linhas de base. Por padrão, agrupará as linhas de base por categoria e componente (por exemplo, forms/input/baseline.png)
getStoriesBaselinePath: (category, component) => `path__${category}__${component}`,
},
},
],
],
// ....
}
Opções de CLI do Storybook Runner
--additionalSearchParams
- Tipo:
string
- Obrigatório: Não
- Padrão: ''
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --additionalSearchParams="foo=bar&abc=def"
Adicionará parâmetros de pesquisa adicionais à URL do Storybook. Consulte a documentação URLSearchParams para mais informações. A string deve ser uma string URLSearchParams válida.
[!NOTE] As aspas duplas são necessárias para evitar que o
&
seja interpretado como um separador de comando. Por exemplo, com--additionalSearchParams="foo=bar&abc=def"
gerará a seguinte URL do Storybook para testes de histórias:http://storybook.url/iframe.html?id=story-id&foo=bar&abc=def
.
--browsers
- Tipo:
string
- Obrigatório: Não
- Padrão:
chrome
, você pode selecionar entrechrome|firefox|edge|safari
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --browsers=chrome,firefox,edge,safari
- NOTA: Disponível apenas através da CLI
Usará os navegadores fornecidos para tirar capturas de tela dos componentes
[!NOTE] Certifique-se de ter os navegadores que deseja executar instalados em sua máquina local
--clip
- Tipo:
boolean
- Obrigatório: Não
- Padrão:
true
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --clip=false
Quando desativado, criará uma captura de tela da viewport. Quando ativado, criará capturas de tela de elementos com base no --clipSelector
, o que reduzirá a quantidade de espaço em branco ao redor da captura de tela do componente e reduzirá o tamanho da captura de tela.
--clipSelector
- Tipo:
string
- Obrigatório: Não
- Padrão:
#storybook-root > :first-child
para Storybook V7 e#root > :first-child:not(script):not(style)
para Storybook V6, veja também--version
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --clipSelector="#some-id"
Este é o seletor que será usado:
- para selecionar o elemento para tirar a captura de tela
- para o elemento esperar ficar visível antes de uma captura de tela ser tirada
--devices
- Tipo:
string
- Obrigatório: Não
- Padrão: Você pode selecionar a partir de
deviceDescriptors.ts
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --devices="iPhone 14 Pro Max","Pixel 3 XL"
- NOTA: Disponível apenas através da CLI
Ele usará os dispositivos fornecidos que correspondem ao deviceDescriptors.ts
para tirar capturas de tela dos componentes
[!NOTE]
- Se você sentir falta de uma configuração de dispositivo, sinta-se à vontade para enviar uma Solicitação de recurso
- Isso só funcionará com Chrome:
- se você fornecer
--devices
, todas as instâncias do Chrome serão executadas no modo de Emulação Móvel- se você também fornecer outros navegadores além do Chrome, como
--devices --browsers=firefox,safari,edge
, ele adicionará automaticamente Chrome no modo de emulação móvel- O Storybook Runner criará por padrão capturas de elementos; se voc ê quiser ver a captura de tela completa da Emulação Móvel, forneça
--clip=false
pela linha de comando- O nome do arquivo ficará, por exemplo, como
__snapshots__/example/button/desktop_chrome/example-button--large-local-chrome-iPhone-14-Pro-Max-430x932-dpr-3.png
- SRC: Testar um site móvel em um desktop usando emulação móvel pode ser útil, mas os testadores devem estar cientes de que existem muitas diferenças sutis, como:
- GPU totalmente diferente, o que pode levar a grandes mudanças de desempenho;
- a interface do usuário móvel não é emulada (em particular, a barra de URL oculta afeta a altura da página);
- o popup de desambiguação (onde você seleciona um dos poucos alvos de toque) não é suportado;
- muitas APIs de hardware (por exemplo, evento orientationchange) não estão disponíveis.
--headless
- Tipo:
boolean
- Obrigatório: Não
- Padrão:
true
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --headless=false
- NOTA: Disponível apenas através da CLI
Isso executará os testes por padrão no modo headless (quando o navegador o suportar) ou pode ser desativado
--numShards
- Tipo:
number
- Obrigatório: Não
- Padrão:
true
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --numShards=10
Este será o número de instâncias paralelas que serão usadas para executar as histórias. Isso será limitado pelo maxInstances
no seu arquivo wdio.conf
.
[!IMPORTANT] Ao executar no modo
headless
, não aumente o número para mais de 20 para evitar instabilidade devido a restrições de recursos
--skipStories
- Tipo:
string|regex
- Obrigatório: Não
- Padrão: null
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --skipStories="/.*button.*/gm"
Isso pode ser:
- uma string (
example-button--secondary,example-button--small
) - ou uma regex (
"/.*button.*/gm"
)
para pular certas histórias. Use o id
da história que pode ser encontrado na URL da história. Por exemplo, o id
nesta URL http://localhost:6006/?path=/story/example-page--logged-out
é example-page--logged-out
--url
- Tipo:
string
- Obrigatório: Não
- Padrão:
http://127.0.0.1:6006
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --url="https://example.com"
A URL onde sua instância do Storybook está hospedada.
--version
- Tipo:
number
- Obrigatório: Não
- Padrão: 7
- Exemplo:
npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --version=6
Esta é a versão do Storybook, o padrão é 7
. Isso é necessário para saber se o clipSelector
V6 precisa ser usado.
Testes de Interação do Storybook
Os Testes de Interação do Storybook permitem que você interaja com seu componente criando scripts personalizados com comandos WDIO para colocar um componente em um determinado estado. Por exemplo, veja o trecho de código abaixo:
import { browser, expect } from "@wdio/globals";
describe("Storybook Interaction", () => {
it("should create screenshots for the logged in state when it logs out", async () => {
const componentId = "example-page--logged-in";
await browser.waitForStorybookComponentToBeLoaded({ id: componentId });
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-in-state`
);
await $("button=Log out").click();
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-out-state`
);
});
it("should create screenshots for the logged out state when it logs in", async () => {
const componentId = "example-page--logged-out";
await browser.waitForStorybookComponentToBeLoaded({ id: componentId });
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-out-state`
);
await $("button=Log in").click();
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-in-state`
);
});
});
Dois testes em dois componentes diferentes são executados. Cada teste primeiro define um estado e depois tira uma captura de tela. Você também notará que um novo comando personalizado foi introduzido, que pode ser encontrado aqui.
O arquivo de especificação acima pode ser salvo em uma pasta e adicionado à linha de comando com o seguinte comando:
pnpm run test.local.desktop.storybook.localhost -- --spec='tests/specs/storybook-interaction/*.ts'
O Storybook runner primeiro verificará automaticamente sua instância do Storybook e depois adicionará seus testes às histórias que precisam ser comparadas. Se você não quiser que os componentes que você usa para testes de interação sejam comparados duas vezes, você pode adicionar um filtro para remover as histórias "padrão" da verificação fornecendo o filtro --skipStories
. Isso ficaria assim:
pnpm run test.local.desktop.storybook.localhost -- --skipStories="/example-page.*/gm" --spec='tests/specs/storybook-interaction/*.ts'
Novo Comando Personalizado
Um novo comando personalizado chamado browser.waitForStorybookComponentToBeLoaded({ id: 'componentId' })
será adicionado ao objeto browser/driver
que carregará automaticamente o componente e esperará que ele seja concluído, para que você não precise usar o método browser.url('url.com')
. Pode ser usado assim
import { browser, expect } from "@wdio/globals";
describe("Storybook Interaction", () => {
it("should create screenshots for the logged in state when it logs out", async () => {
const componentId = "example-page--logged-in";
await browser.waitForStorybookComponentToBeLoaded({ id: componentId });
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-in-state`
);
await $("button=Log out").click();
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-out-state`
);
});
it("should create screenshots for the logged out state when it logs in", async () => {
const componentId = "example-page--logged-out";
await browser.waitForStorybookComponentToBeLoaded({ id: componentId });
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-out-state`
);
await $("button=Log in").click();
await expect($("header")).toMatchElementSnapshot(
`${componentId}-logged-in-state`
);
});
});
As opções são:
additionalSearchParams
- Tipo:
URLSearchParams
- Obrigatório: Não
- Padrão:
new URLSearchParams()
- Exemplo:
await browser.waitForStorybookComponentToBeLoaded({
additionalSearchParams: new URLSearchParams({ foo: "bar", abc: "def" }),
id: "componentId",
});
Isso adicionará parâmetros de pesquisa adicionais à URL do Storybook, no exemplo acima a URL será http://storybook.url/iframe.html?id=story-id&foo=bar&abc=def
.
Consulte a documentação URLSearchParams para mais informações.
clipSelector
- Tipo:
string
- Obrigatório: Não
- Padrão:
#storybook-root > :first-child
para Storybook V7 e#root > :first-child:not(script):not(style)
para Storybook V6 - Exemplo:
await browser.waitForStorybookComponentToBeLoaded({
clipSelector: "#your-selector",
id: "componentId",
});
Este é o seletor que será usado:
- para selecionar o elemento para tirar a captura de tela
- para o elemento esperar ficar visível antes de uma captura de tela ser tirada
id
- Tipo:
string
- Obrigatório: sim
- Exemplo:
await browser.waitForStorybookComponentToBeLoaded({ '#your-selector', id: 'componentId' })
Use o id
da história que pode ser encontrado na URL da história. Por exemplo, o id
nesta URL http://localhost:6006/?path=/story/example-page--logged-out
é example-page--logged-out
timeout
- Tipo:
number
- Obrigatório: Não
- Padrão: 1100 milissegundos
- Exemplo:
await browser.waitForStorybookComponentToBeLoaded({
id: "componentId",
timeout: 20000,
});
O tempo máximo que queremos esperar para que um componente fique visível após o carregamento na página
url
- Tipo:
string
- Obrigatório: Não
- Padrão:
http://127.0.0.1:6006
- Exemplo:
await browser.waitForStorybookComponentToBeLoaded({
id: "componentId",
url: "https://your.url",
});
A URL onde sua instância do Storybook está hospedada.
Contribuindo
Atualizando os pacotes
Você pode atualizar os pacotes com uma ferramenta simples de CLI. Certifique-se de ter instalado todas as dependências, então você pode executar
pnpm update.packages
Isso acionará uma CLI que fará as seguintes perguntas
==========================
🤖 Package update Wizard 🧙
==========================
? Which version target would you like to update to? (Minor|Latest)
? Do you want to update the package.json files? (Y/n)
? Do you want to remove all "node_modules" and reinstall dependencies? (Y/n)
? Would you like reinstall the dependencies? (Y/n)
Isso resultará nos seguintes logs
Abra para ver um exemplo dos logs
==========================
🤖 Package update Wizard 🧙
==========================
? Which version target would you like to update to? Minor
? Do you want to update the package.json files? yes
Updating root 'package.json' for minor updates...
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/package.json
[====================] 38/38 100%
@typescript-eslint/eslint-plugin ^8.7.0 → ^8.8.0
@typescript-eslint/parser ^8.7.0 → ^8.8.0
@typescript-eslint/utils ^8.7.0 → ^8.8.0
@vitest/coverage-v8 ^2.1.1 → ^2.1.2
vitest ^2.1.1 → ^2.1.2
Run pnpm install to install new versions.
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing/packages/ocr-service...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/packages/ocr-service/package.json
[====================] 11/11 100%
All dependencies match the minor package versions :)
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing/packages/visual-reporter...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/packages/visual-reporter/package.json
[====================] 11/11 100%
eslint-config-next 14.2.13 → 14.2.14
next 14.2.13 → 14.2.14
Run pnpm install to install new versions.
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing/packages/visual-service...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/packages/visual-service/package.json
[====================] 5/5 100%
All dependencies match the minor package versions :)
Updating packages for minor updates in /Users/wswebcreation/Git/wdio/visual-testing/packages/webdriver-image-comparison...
Using pnpm
Upgrading /Users/wswebcreation/Git/wdio/visual-testing/packages/webdriver-image-comparison/package.json
[====================] 8/8 100%
All dependencies match the minor package versions :)
? Do you want to remove all "node_modules" and reinstall dependencies? yes
Removing root dependencies in /Users/wswebcreation/Git/wdio/visual-testing...
Removing dependencies in ocr-service...
Removing dependencies in visual-reporter...
Removing dependencies in visual-service...
Removing dependencies in webdriver-image-comparison...
? Would you like reinstall the dependencies? yes
Installing dependencies in /Users/wswebcreation/Git/wdio/visual-testing...
> @wdio/visual-testing-monorepo@ pnpm.install.workaround /Users/wswebcreation/Git/wdio/visual-testing
> pnpm install --shamefully-hoist
Scope: all 5 workspace projects
Lockfile is up to date, resolution step is skipped
Packages: +1274
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 1274, reused 1265, downloaded 0, added 1274, done
dependencies:
- @wdio/ocr-service 2.0.0 <- packages/ocr-service
- @wdio/visual-service 6.0.0 <- packages/visual-service
devDependencies:
- @changesets/cli 2.27.8
- @inquirer/prompts 5.5.0
- @tsconfig/node20 20.1.4
- @types/eslint 9.6.1
- @types/jsdom 21.1.7
- @types/node 20.16.4
- @types/react 18.3.5
- @types/react-dom 18.3.0
- @types/xml2js 0.4.14
- @typescript-eslint/eslint-plugin 8.8.0
- @typescript-eslint/parser 8.8.0
- @typescript-eslint/utils 8.8.0
- @vitest/coverage-v8 2.1.2
- @wdio/appium-service 9.1.2
- @wdio/cli 9.1.2
- @wdio/globals 9.1.2
- @wdio/local-runner 9.1.2
- @wdio/mocha-framework 9.1.2
- @wdio/sauce-service 9.1.2
- @wdio/shared-store-service 9.1.2
- @wdio/spec-reporter 9.1.2
- @wdio/types 9.1.2
- eslint 9.11.1
- eslint-plugin-import 2.30.0
- eslint-plugin-unicorn 55.0.0
- eslint-plugin-wdio 9.0.8
- husky 9.1.6
- jsdom 25.0.1
- pnpm-run-all2 6.2.3
- release-it 17.6.0
- rimraf 6.0.1
- saucelabs 8.0.0
- ts-node 10.9.2
- typescript 5.6.2
- vitest 2.1.2
- webdriverio 9.1.2
. prepare$ husky
└─ Done in 204ms
Done in 9.5s
All packages updated!
Perguntas
Por favor, junte-se ao nosso servidor Discord se você tiver dúvidas ou problemas ao contribuir para este projeto. Encontre-nos contribuidores no canal 🙏-contributing
.
Problemas
Se você tiver dúvidas, bugs ou solicitações de recursos, por favor, registre um problema. Antes de enviar um problema, pesquise o arquivo de problemas para ajudar a reduzir duplicações e leia o FAQ.
Se você não conseguir encontrar lá, pode enviar um problema onde pode submeter:
- 🐛Relatório de bug: Crie um relatório para nos ajudar a melhorar
- 📖Documentação: Sugira melhorias ou relate documentação ausente/pouco clara.
- 💡Solicitação de recurso: Sugira uma ideia para este módulo.
- 💬Pergunta: Faça perguntas.
Fluxo de Trabalho de Desenvolvimento
Para criar um PR para este projeto e começar a contribuir, siga este guia passo a passo:
-
Faça um fork do projeto.
-
Clone o projeto em algum lugar no seu computador
$ git clone https://github.com/webdriverio/visual-testing.git
-
Vá para o diretório e configure o projeto
$ cd visual-testing
$ corepack enable
$ pnpm pnpm.install.workaround -
Execute o modo de observação que transpilará automaticamente o código
$ pnpm watch
para construir o projeto, execute:
$ pnpm build
-
Garanta que suas alterações não quebrem nenhum teste, execute:
$ pnpm test
Este projeto usa changesets para criar automaticamente changelogs e releases.
Testes
Vários testes precisam ser executados para poder testar o módulo. Ao adicionar um PR, todos os testes devem pelo menos passar nos testes locais. Cada PR é automaticamente testado no Sauce Labs, veja nosso pipeline de GitHub Actions. Antes de aprovar um PR, os principais contribuidores testarão o PR em emuladores/simuladores / dispositivos reais.
Testes Locais
Primeiro, uma linha de base local precisa ser criada. Isso pode ser feito com:
// Com o protocolo webdriver
$ pnpm run test.local.init
Este comando criará uma pasta chamada localBaseline
que conterá todas as imagens de linha de base.
Em seguida, execute:
// Com o protocolo webdriver
pnpm run test.local.desktop
Isso executará todos os testes em uma máquina local no Chrome.
Testes Locais do Storybook Runner (Beta)
Primeiro, uma linha de base local precisa ser criada. Isso pode ser feito com:
pnpm run test.local.desktop.storybook
Isso executará testes do Storybook com Chrome no modo headless contra um repo Demo Storybook localizado em https://govuk-react.github.io/govuk-react/.
Para executar os testes com mais navegadores, você pode executar
pnpm run test.local.desktop.storybook -- --browsers=chrome,firefox,edge,safari
[!NOTE] Certifique-se de ter os navegadores que deseja executar instalados em sua máquina local
Testes de CI com Sauce Labs (não necessários para um PR)
O comando abaixo é usado para testar a construção no GitHub Actions, ele só pode ser usado lá e não para desenvolvimento local.
$ pnpm run test.saucelabs
Ele testará contra muitas configurações que podem ser encontradas aqui. Todos os PRs são automaticamente verificados no Sauce Labs.
Lançamento
Para lançar uma versão de qualquer um dos pacotes listados acima, faça o seguinte:
- acione o pipeline de lançamento
- um PR de lançamento é gerado, peça que seja revisado e aprovado por outro membro do WebdriverIO
- mescle o PR
- acione o pipeline de lançamento novamente
- uma nova versão deve ser lançada 🎉
Créditos
@wdio/visual-testing
usa uma licença de código aberto da LambdaTest e Sauce Labs.