Saltar al contenido principal

Servicio de Comparación de Imágenes (Pruebas de Regresión Visual)

@wdio/visual-service es un paquete de terceros, para más información por favor consulte GitHub | npm

Para documentación sobre pruebas visuales con WebdriverIO, por favor consulte la documentación. Este proyecto contiene todos los módulos relevantes para ejecutar pruebas visuales con WebdriverIO. Dentro del directorio ./packages encontrará:

  • @wdio/visual-testing: el servicio de WebdriverIO para integrar pruebas visuales
  • webdriver-image-comparison: Un módulo de comparación de imágenes que puede ser utilizado para diferentes frameworks de automatización de pruebas NodeJS que soporten el protocolo WebDriver

Ejecutor de Storybook (BETA)

Haga clic para obtener más documentación sobre el Ejecutor de Storybook BETA

El Ejecutor de Storybook aún está en BETA, la documentación se trasladará posteriormente a las páginas de documentación de WebdriverIO.

Este módulo ahora soporta Storybook con un nuevo Ejecutor Visual. Este ejecutor automáticamente escanea una instancia local/remota de storybook y creará capturas de pantalla de elementos de cada componente. Esto se puede hacer agregando

export const config: WebdriverIO.Config = {
// ...
services: ["visual"],
// ....
};

a sus services y ejecutando npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook a través de la línea de comandos. Utilizará Chrome en modo headless como navegador predeterminado.

[!NOTE]

  • La mayoría de las opciones de Pruebas Visuales también funcionarán para el Ejecutor de Storybook, consulte la documentación de WebdriverIO.
  • El Ejecutor de Storybook sobrescribirá todas sus capacidades y solo puede ejecutarse en los navegadores que admite, consulte --browsers.
  • El Ejecutor de Storybook no admite una configuración existente que utilice capacidades Multiremote y arrojará un error.
  • El Ejecutor de Storybook solo admite Web de Escritorio, no Web Móvil.

Opciones de Servicio del Ejecutor de Storybook

Las opciones de servicio se pueden proporcionar así

export const config: WebdriverIO.Config  = {
// ...
services: [
[
'visual',
{
// Algunas opciones predeterminadas
baselineFolder: join(process.cwd(), './__snapshots__/'),
debug: true,
// Las opciones de storybook, ver opciones de cli para la descripción
storybook: {
additionalSearchParams: new URLSearchParams({foo: 'bar', abc: 'def'}),
clip: false,
clipSelector: ''#some-id,
numShards: 4,
// `skipStories` puede ser una cadena ('example-button--secondary'),
// un array (['example-button--secondary', 'example-button--small'])
// o una regex que debe proporcionarse como cadena ("/.*button.*/gm")
skipStories: ['example-button--secondary', 'example-button--small'],
url: 'https://www.bbc.co.uk/iplayer/storybook/',
version: 6,
// Opcional - Permite sobrescribir la ruta de líneas base. Por defecto agrupará las líneas base por categoría y componente (p.ej. forms/input/baseline.png)
getStoriesBaselinePath: (category, component) => `path__${category}__${component}`,
},
},
],
],
// ....
}

Opciones CLI del Ejecutor de Storybook

--additionalSearchParams

  • Tipo: string
  • Obligatorio: No
  • Predeterminado: ''
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --additionalSearchParams="foo=bar&abc=def"

Agregará parámetros de búsqueda adicionales a la URL de Storybook. Consulte la documentación de URLSearchParams para más información. La cadena debe ser una cadena válida de URLSearchParams.

[!NOTE] Las comillas dobles son necesarias para evitar que el & se interprete como un separador de comandos. Por ejemplo, con --additionalSearchParams="foo=bar&abc=def" generará la siguiente URL de Storybook para pruebas de historias: http://storybook.url/iframe.html?id=story-id&foo=bar&abc=def.

--browsers

  • Tipo: string
  • Obligatorio: No
  • Predeterminado: chrome, puede seleccionar entre chrome|firefox|edge|safari
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --browsers=chrome,firefox,edge,safari
  • NOTA: Solo disponible a través de la CLI

Utilizará los navegadores proporcionados para tomar capturas de pantalla de componentes

[!NOTE] Asegúrese de tener instalados en su máquina local los navegadores en los que desea ejecutar

--clip

  • Tipo: boolean
  • Obligatorio: No
  • Predeterminado: true
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --clip=false

Cuando está desactivado creará una captura de pantalla de la vista completa. Cuando está activado creará capturas de pantalla de elementos basadas en el --clipSelector que reducirá la cantidad de espacio en blanco alrededor de la captura de pantalla del componente y reducirá el tamaño de la captura.

--clipSelector

  • Tipo: string
  • Obligatorio: No
  • Predeterminado: #storybook-root > :first-child para Storybook V7 y #root > :first-child:not(script):not(style) para Storybook V6, ver también --version
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --clipSelector="#some-id"

Este es el selector que se utilizará:

  • para seleccionar el elemento del que se tomará la captura de pantalla
  • para el elemento que debe esperar a ser visible antes de tomar una captura de pantalla

--devices

  • Tipo: string
  • Obligatorio: No
  • Predeterminado: Puede seleccionar de los deviceDescriptors.ts
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --devices="iPhone 14 Pro Max","Pixel 3 XL"
  • NOTA: Solo disponible a través de la CLI

Utilizará los dispositivos proporcionados que coincidan con los deviceDescriptors.ts para tomar capturas de pantalla de componentes

[!NOTE]

  • Si falta una configuración de dispositivo, no dude en enviar una solicitud de función
  • Esto solo funcionará con Chrome:
    • si proporciona --devices, todas las instancias de Chrome se ejecutarán en modo de emulación móvil
    • si también proporciona otros navegadores además de Chrome, como --devices --browsers=firefox,safari,edge, agregará automáticamente Chrome en modo de emulación móvil
  • El Ejecutor de Storybook creará por defecto capturas de elementos, si desea ver la captura completa de Emulación Móvil, proporcione --clip=false a través de la línea de comandos
  • El nombre del archivo se verá, por ejemplo, como __snapshots__/example/button/desktop_chrome/example-button--large-local-chrome-iPhone-14-Pro-Max-430x932-dpr-3.png
  • SRC: Probar un sitio web móvil en un escritorio usando emulación móvil puede ser útil, pero los probadores deben saber que hay muchas diferencias sutiles como:
    • GPU completamente diferente, lo que puede llevar a grandes cambios de rendimiento;
    • la interfaz de usuario móvil no se emula (en particular, la barra de URL oculta afecta la altura de la página);
    • el popup de desambiguación (donde selecciona uno de varios objetivos táctiles) no es compatible;
    • muchas API de hardware (por ejemplo, el evento orientationchange) no están disponibles.

--headless

  • Tipo: boolean
  • Obligatorio: No
  • Predeterminado: true
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --headless=false
  • NOTA: Solo disponible a través de la CLI

Ejecutará las pruebas de forma predeterminada en modo headless (cuando el navegador lo admita) o se puede desactivar

--numShards

  • Tipo: number
  • Obligatorio: No
  • Predeterminado: true
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --numShards=10

Este será el número de instancias paralelas que se utilizarán para ejecutar las historias. Esto estará limitado por el maxInstances en su archivo wdio.conf.

[!IMPORTANT] Cuando se ejecuta en modo headless, no aumente el número a más de 20 para evitar inestabilidad debido a restricciones de recursos

--skipStories

  • Tipo: string|regex
  • Obligatorio: No
  • Predeterminado: null
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --skipStories="/.*button.*/gm"

Esto puede ser:

  • una cadena (example-button--secondary,example-button--small)
  • o una expresión regular ("/.*button.*/gm")

para omitir ciertas historias. Use el id de la historia que se puede encontrar en la URL de la historia. Por ejemplo, el id en esta URL http://localhost:6006/?path=/story/example-page--logged-out es example-page--logged-out

--url

  • Tipo: string
  • Obligatorio: No
  • Predeterminado: http://127.0.0.1:6006
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --url="https://example.com"

La URL donde está alojada su instancia de Storybook.

--version

  • Tipo: number
  • Obligatorio: No
  • Predeterminado: 7
  • Ejemplo: npx wdio tests/configs/wdio.local.desktop.storybook.conf.ts --storybook --version=6

Esta es la versión de Storybook, el valor predeterminado es 7. Esto es necesario para saber si se debe usar el clipSelector de la V6.

Pruebas de Interacción con Storybook

Las Pruebas de Interacción con Storybook le permiten interactuar con su componente creando scripts personalizados con comandos WDIO para establecer un componente en un estado determinado. Por ejemplo, vea el siguiente fragmento de código:

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`
);
});
});

Se ejecutan dos pruebas en dos componentes diferentes. Cada prueba primero establece un estado y luego toma una captura de pantalla. También notará que se ha introducido un nuevo comando personalizado, que se puede encontrar aquí.

El archivo de especificación anterior se puede guardar en una carpeta y agregarse a la línea de comandos con el siguiente comando:

pnpm run test.local.desktop.storybook.localhost -- --spec='tests/specs/storybook-interaction/*.ts'

El ejecutor de Storybook primero escaneará automáticamente su instancia de Storybook y luego agregará sus pruebas a las historias que deben compararse. Si no desea que los componentes que utiliza para las pruebas de interacción se comparen dos veces, puede agregar un filtro para eliminar las historias "predeterminadas" del escaneo proporcionando el filtro --skipStories. Esto se vería así:

pnpm run test.local.desktop.storybook.localhost -- --skipStories="/example-page.*/gm" --spec='tests/specs/storybook-interaction/*.ts'

Nuevo Comando Personalizado

Se agregará un nuevo comando personalizado llamado browser.waitForStorybookComponentToBeLoaded({ id: 'componentId' }) al objeto browser/driver que cargará automáticamente el componente y esperará a que termine, por lo que no necesita usar el método browser.url('url.com'). Se puede usar así

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`
);
});
});

Las opciones son:

additionalSearchParams

  • Tipo: URLSearchParams
  • Obligatorio: No
  • Predeterminado: new URLSearchParams()
  • Ejemplo:
await browser.waitForStorybookComponentToBeLoaded({
additionalSearchParams: new URLSearchParams({ foo: "bar", abc: "def" }),
id: "componentId",
});

Esto agregará parámetros de búsqueda adicionales a la URL de Storybook, en el ejemplo anterior la URL será http://storybook.url/iframe.html?id=story-id&foo=bar&abc=def. Consulte la documentación de URLSearchParams para más información.

clipSelector

  • Tipo: string
  • Obligatorio: No
  • Predeterminado: #storybook-root > :first-child para Storybook V7 y #root > :first-child:not(script):not(style) para Storybook V6
  • Ejemplo:
await browser.waitForStorybookComponentToBeLoaded({
clipSelector: "#your-selector",
id: "componentId",
});

Este es el selector que se utilizará:

  • para seleccionar el elemento del que se tomará la captura de pantalla
  • para el elemento que debe esperar a ser visible antes de tomar una captura de pantalla

id

  • Tipo: string
  • Obligatorio:
  • Ejemplo:
await browser.waitForStorybookComponentToBeLoaded({ '#your-selector', id: 'componentId' })

Use el id de la historia que se puede encontrar en la URL de la historia. Por ejemplo, el id en esta URL http://localhost:6006/?path=/story/example-page--logged-out es example-page--logged-out

timeout

  • Tipo: number
  • Obligatorio: No
  • Predeterminado: 1100 milisegundos
  • Ejemplo:
await browser.waitForStorybookComponentToBeLoaded({
id: "componentId",
timeout: 20000,
});

El tiempo máximo de espera para que un componente sea visible después de cargarse en la página

url

  • Tipo: string
  • Obligatorio: No
  • Predeterminado: http://127.0.0.1:6006
  • Ejemplo:
await browser.waitForStorybookComponentToBeLoaded({
id: "componentId",
url: "https://your.url",
});

La URL donde está alojada su instancia de Storybook.

Contribuciones

Actualización de paquetes

Puede actualizar los paquetes con una herramienta CLI simple. Asegúrese de haber instalado todas las dependencias, luego puede ejecutar

pnpm update.packages

Esto activará una CLI que le hará las siguientes preguntas

==========================
🤖 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)

Esto resultará en los siguientes registros

Abrir para ver un ejemplo de los registros
==========================
🤖 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!

Preguntas

Por favor, únase a nuestro servidor de Discord si tiene alguna pregunta o problemas para contribuir a este proyecto. Encuentre a los colaboradores en el canal 🙏-contributing.

Problemas

Si tiene preguntas, errores o solicitudes de funciones, por favor abra un issue. Antes de enviar un issue, busque en el archivo de issues para ayudar a reducir duplicados y lea las FAQ.

Si no puede encontrarlo allí, puede enviar un issue donde puede presentar:

  • 🐛Informe de error: Cree un informe para ayudarnos a mejorar
  • 📖Documentación: Sugiera mejoras o informe sobre documentación faltante/poco clara.
  • 💡Solicitud de función: Sugiera una idea para este módulo.
  • 💬Pregunta: Haga preguntas.

Flujo de Trabajo de Desarrollo

Para crear un PR para este proyecto y comenzar a contribuir, siga esta guía paso a paso:

  • Haga un fork del proyecto.

  • Clone el proyecto en algún lugar de su computadora

    $ git clone https://github.com/webdriverio/visual-testing.git
  • Vaya al directorio y configure el proyecto

    $ cd visual-testing
    $ corepack enable
    $ pnpm pnpm.install.workaround
  • Ejecute el modo de observación que transpilará automáticamente el código

    $ pnpm watch

    para construir el proyecto, ejecute:

    $ pnpm build
  • Asegúrese de que sus cambios no rompan ninguna prueba, ejecute:

    $ pnpm test

Este proyecto utiliza changesets para crear automáticamente registros de cambios y lanzamientos.

Pruebas

Se deben ejecutar varias pruebas para poder probar el módulo. Al agregar un PR, todas las pruebas deben al menos pasar las pruebas locales. Cada PR se prueba automáticamente contra Sauce Labs, vea nuestro pipeline de GitHub Actions. Antes de aprobar un PR, los colaboradores principales probarán el PR contra emuladores/simuladores / dispositivos reales.

Pruebas Locales

Primero, se debe crear una línea base local. Esto se puede hacer con:

// Con el protocolo webdriver
$ pnpm run test.local.init

Este comando creará una carpeta llamada localBaseline que contendrá todas las imágenes de línea base.

Luego ejecute:

// Con el protocolo webdriver
pnpm run test.local.desktop

Esto ejecutará todas las pruebas en una máquina local en Chrome.

Pruebas Locales del Ejecutor de Storybook (Beta)

Primero, se debe crear una línea base local. Esto se puede hacer con:

pnpm run test.local.desktop.storybook

Esto ejecutará pruebas de Storybook con Chrome en modo headless contra un repositorio Demo de Storybook ubicado en https://govuk-react.github.io/govuk-react/.

Para ejecutar las pruebas con más navegadores, puede ejecutar

pnpm run test.local.desktop.storybook -- --browsers=chrome,firefox,edge,safari

[!NOTE] Asegúrese de tener instalados en su máquina local los navegadores en los que desea ejecutar

Pruebas CI con Sauce Labs (no necesarias para un PR)

El comando a continuación se utiliza para probar la compilación en GitHub Actions, solo se puede usar allí y no para desarrollo local.

$ pnpm run test.saucelabs

Probará contra muchas configuraciones que se pueden encontrar aquí. Todos los PR se comprueban automáticamente contra Sauce Labs.

Lanzamientos

Para lanzar una versión de cualquiera de los paquetes mencionados anteriormente, haga lo siguiente:

  • active el pipeline de lanzamiento
  • se genera un PR de lanzamiento, haga que sea revisado y aprobado por otro miembro de WebdriverIO
  • fusione el PR
  • active el pipeline de lanzamiento nuevamente
  • ¡debería lanzarse una nueva versión 🎉

Créditos

@wdio/visual-testing utiliza una licencia de código abierto de LambdaTest y Sauce Labs.

Welcome! How can I help?

WebdriverIO AI Copilot