---
url: 'https://www.corbado.com/es/blog/passkeys-e2e-playwright-pruebas-webauthn-autenticador-virtual'
title: 'Pruebas E2E de Passkeys con Playwright mediante el Autenticador Virtual WebAuthn'
description: 'Aprende a configurar pruebas E2E para passkeys en diferentes navegadores con Playwright, Nightwatch, Selenium y Puppeteer utilizando el autenticador virtual WebAuthn.'
lang: 'es'
author: 'Anders'
date: '2025-06-17T16:16:22.610Z'
lastModified: '2026-03-25T10:03:10.999Z'
keywords: 'pruebas e2e, prueba de extremo a extremo, prueba end-to-end'
category: 'Passkeys Implementation'
---

# Pruebas E2E de Passkeys con Playwright mediante el Autenticador Virtual WebAuthn

> **Nuestra misión es hacer de Internet un lugar más seguro**, y el nuevo estándar de
> login, las passkeys, proporciona una solución superior para lograrlo. Por eso queremos
> ayudarte a comprender mejor las passkeys y sus características.

## 1. Introducción: Pruebas E2E de Passkeys

Las passkeys son cada vez más aceptadas como método de [autenticación](https://www.corbado.com/es/glossary/jwks),
basándose en la [Autenticación](https://www.corbado.com/es/glossary/jwks) Web (WebAuthn) como su estándar
subyacente. Su aumento de popularidad es bastante reciente, lo que hace que la
documentación y otros recursos sean relativamente escasos. Esto, junto con la naturaleza
compleja de la implementación de passkeys, puede dificultar que los desarrolladores
encuentren información relevante sobre el diseño, la implementación y, especialmente, las
pruebas de passkeys para sus plataformas y servicios.

Esta guía tiene como objetivo llenar ese vacío, centrándose en aspectos del autenticador
virtual WebAuthn que no se tratan a fondo en su documentación oficial. Por ejemplo,
discutimos opciones de configuración para el autenticador virtual que no son
autoexplicativas en la documentación, así como soluciones para ciertos casos de uso para
los que el autenticador virtual no proporciona una solución conveniente. Además, esta guía
también es útil para los desarrolladores que simplemente buscan ejemplos fáciles de seguir
para usar el autenticador virtual en el código de prueba.

Nuestra guía utiliza ejemplos de
[Playwright](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) para
proporcionar un recorrido sencillo para probar eficazmente la implementación de passkeys
en tu proyecto.
[Playwright](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) es un
marco de pruebas de extremo a extremo (E2E) que utiliza el Protocolo de Herramientas para
Desarrolladores de Chrome (CDP) como protocolo para la automatización de navegadores. Si
buscas específicamente ejemplos técnicos de pruebas de passkeys en
[Playwright](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator), puedes
saltar a la Sección 5. Por otro lado, si estás utilizando otros marcos de pruebas E2E como
[Puppeteer](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) o
[Selenium](https://www.corbado.com/blog/selenium-passkeys-testing-nodejs) y buscas probar passkeys en estos
marcos, las implementaciones del código de prueba serán idénticas o muy similares a los
ejemplos proporcionados en esta guía, dependiendo del marco que estés utilizando. En la
siguiente sección, proporcionamos un contexto sobre los diferentes marcos E2E y cuán
relevante será esta guía para estos marcos.

## 2. Contexto: Automatización de Navegadores y Frameworks de Pruebas E2E

### 2.1. ¿Qué es la automatización de navegadores?

La automatización de navegadores, como su nombre indica, es el proceso de automatizar
acciones repetitivas del usuario en el navegador con el fin de extraer datos de la web o,
en nuestro caso, probar aplicaciones web. WebDriver y el Protocolo de Herramientas para
Desarrolladores de Chrome (CDP) son dos de los principales protocolos de automatización de
navegadores relevantes para esta guía, ya que cada uno proporciona una implementación del
autenticador virtual WebAuthn.

### 2.2. ¿Qué es WebDriver?

WebDriver es una interfaz de control remoto que puede verse como un intermediario en la
comunicación entre el cliente y el navegador. El enfoque de este protocolo es proporcionar
una interfaz neutral en cuanto a plataforma e idioma que admita todos los principales
navegadores, incluidos los que no están basados en Chromium, como Firefox y Safari. Como
la interfaz de WebDriver necesita gestionar una conexión tanto con el cliente como con el
navegador, este enfoque sacrifica velocidad y estabilidad a cambio de un mayor soporte de
navegadores (es decir, mayor inestabilidad o _flakiness_). Clientes notables de WebDriver
incluyen [Selenium](https://www.corbado.com/blog/selenium-passkeys-testing-nodejs) y
[Nightwatch](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator).

![Cliente WebDriver de Playwright para Passkeys](https://www.corbado.com/website-assets/66090bb89296b283f07f69eb_passkeys_playwright_webdriver_client_1efc6dec0e.jpg)

Tomado de jankaritech

### 2.3. ¿Qué es el Protocolo de Herramientas para Desarrolladores de Chrome (CDP)?

El Protocolo de Herramientas para Desarrolladores de Chrome (CDP), por otro lado, no tiene
un intermediario como la interfaz de WebDriver entre el cliente y el navegador. Además, la
comunicación entre el cliente y el navegador se realiza a través de una conexión de
socket, en contraste con la conexión HTTP más lenta entre el cliente y la interfaz de
WebDriver en el enfoque anterior. Estos puntos hacen que el CDP sea mucho más rápido y
menos propenso a fallos (_flaky_) que WebDriver. La desventaja es que este protocolo solo
es compatible con navegadores basados en Chromium como Chrome y Edge. Playwright y
[Puppeteer](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) son
ejemplos de clientes que utilizan CDP para comunicarse con los navegadores.

![Cliente CDP de Playwright para Passkeys](https://www.corbado.com/website-assets/66090be6820f38fba3e156f3_passkeys_playwright_cdp_client_44e000d341.jpg)

Tomado de jankaritech

### 2.4. Puppeteer y Playwright como frameworks de pruebas E2E basados en CDP

[Puppeteer](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator), al
igual que Playwright, es un marco de pruebas E2E construido directamente sobre el CDP.
Esto significa que tanto Puppeteer como Playwright utilizan la misma implementación del
autenticador virtual WebAuthn y que la comunicación de la API utilizando el autenticador
virtual WebAuthn a través de la conexión de socket también es idéntica.

Para demostrarlo, comparamos el código de prueba tanto en Playwright como en Puppeteer
para llamar al método getCredentials, que devuelve una lista de todas las credenciales
registradas en el autenticador virtual hasta el momento. También adjuntamos un simple
detector de eventos para el evento credentialAdded, que se activa cuando una credencial de
passkey se registra con éxito. No te dejes intimidar por los detalles de la
implementación, ya que se explicarán en las secciones posteriores. Estos ejemplos son
simplemente para demostrar cuán similares son las implementaciones entre los dos marcos.

**Playwright:**

```js
const client = await page.context().newCDPSession(page);
await client.send('WebAuthn.enable');
const authenticatorId = const result = await client.send('WebAuthn.addVirtualAuthenticator', { options });

...

// get all credentials registered in the virtual authenticator
const result = await client.send('WebAuthn.getCredentials', { authenticatorId });
console.log(result.credentials);

// add a listener to the credentialAdded event to output a log to the console whenever a passkey credential is registered
client.on('WebAuthn.credentialAdded', () => {
  console.log('Credential Added!');
});
```

**Puppeteer:**

```js
const client = await page.target().createCDPSession();
await client.send('WebAuthn.enable');
const authenticatorId = const result = await client.send('WebAuthn.addVirtualAuthenticator', { options });

...

// get all credentials registered in the virtual authenticator
const result = await client.send('WebAuthn.getCredentials', { authenticatorId });
console.log(result.credentials);

// add a listener to the credentialAdded event to output a log to the console whenever a passkey credential is registered
client.on('WebAuthn.credentialAdded', () => {
  console.log('Credential Added!');
});
```

Aunque los métodos para inicializar la sesión de CDP al principio de los códigos de prueba
eran ligeramente diferentes, la llamada a métodos y el manejo de eventos en la API del
autenticador virtual WebAuthn de CDP son idénticos. Esto significa que si buscas utilizar
el autenticador virtual WebAuthn en Puppeteer, puedes seguir esta guía línea por línea.

### 2.5. Selenium y Nightwatch como frameworks de pruebas E2E basados en WebDriver

[Selenium](https://www.corbado.com/blog/selenium-passkeys-testing-nodejs) y
[Nightwatch](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) son
marcos de pruebas E2E que dependen de WebDriver para la automatización de navegadores.
Aunque la implementación del autenticador virtual WebAuthn para WebDriver es independiente
de su implementación para CDP, sus especificaciones de API son similares. Para casi todos
los métodos en la API del autenticador virtual WebAuthn de CDP, puedes encontrar un método
correspondiente en la API del autenticador virtual WebAuthn de WebDriver. Sin embargo, una
cosa a tener en cuenta es que, si bien era posible adjuntar detectores de eventos para
cuando una passkey se agrega o se afirma con éxito en la API del autenticador virtual
WebAuthn de CDP, esto no es posible en su contraparte de WebDriver.

**Selenium:**

```js
const driver = await new Builder().forBrowser('chrome').build();
const options = new VirtualAuthenticatorOptions();
await driver.addVirtualAuthenticator(options);

...

// get all credentials registered in the virtual authenticator
const credentials = await driver.getCredentials();
```

Es evidente que la sintaxis para configurar la instancia del autenticador virtual y
realizar llamadas a la API es diferente de la implementación de CDP correspondiente. Sin
embargo, dado que las especificaciones de la API de los dos autenticadores virtuales
WebAuthn son muy similares, sería viable seguir esta guía para escribir una implementación
correspondiente en un marco de pruebas E2E basado en WebDriver.

### 2.6. Cypress como framework de pruebas E2E con scripting nativo

[Cypress](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) es un
marco de pruebas E2E que no se basa principalmente en WebDriver o CDP como los marcos
mencionados anteriormente. Utiliza JavaScript nativo para comunicarse con el navegador.
Sin embargo, proporciona acceso de bajo nivel al CDP, lo que significa que es posible
enviar comandos CDP sin procesar para utilizar el autenticador virtual WebAuthn del CDP.

Debido a que la sintaxis para este acceso de bajo nivel es tediosa y muy diferente de los
ejemplos anteriores, no entraremos en detalles en esta guía. Sin embargo, se explica más
información sobre cómo llamar a los comandos de CDP en
[Cypress](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) en esta
guía. Los conceptos generales para usar el autenticador virtual WebAuthn de CDP
presentados en esta guía siguen siendo relevantes para aquellos que buscan probar passkeys
en [Cypress](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator).

## 3. ¿Qué hace que las pruebas E2E de passkeys con Playwright sean un problema?

Hay muchas razones por las que probar la implementación de passkeys es naturalmente más
desafiante que otras acciones de usuario más simples en un entorno web. La necesidad de
manejar interacciones dinámicas del usuario involucradas en la
[autenticación biométrica](https://www.corbado.com/es/blog/mastercard-passkeys), como el escaneo de huellas
dactilares o el reconocimiento facial, agrega una capa de complejidad que podría no ser
práctica de abordar en detalle al escribir pruebas. Como la
[seguridad](https://www.corbado.com/es/blog/como-eliminar-contrasenas-por-completo) es naturalmente una
preocupación importante en el contexto de la [autenticación](https://www.corbado.com/es/glossary/jwks), también
es necesario garantizar que la autenticación con passkeys se integre sin problemas en
varios navegadores y dispositivos sin dejar lugar a vulnerabilidades de
[seguridad](https://www.corbado.com/es/blog/como-eliminar-contrasenas-por-completo).

## 4. El autenticador virtual WebAuthn hace posibles las pruebas E2E de passkeys

Simplificar la complejidad de manejar las interacciones dinámicas del usuario involucradas
en las operaciones de passkeys, así como probar su integración en diferentes navegadores y
dispositivos, se facilita con el uso del autenticador virtual WebAuthn.

### 4.1. ¿Qué es el autenticador virtual WebAuthn?

El autenticador virtual WebAuthn es una representación de software del modelo de
autenticador especificado en el estándar WebAuthn. Emula el comportamiento de un
dispositivo autenticador físico, como una
[llave de seguridad](https://www.corbado.com/es/blog/mejores-llaves-seguridad-hardware-fido2) de hardware (p.
ej., [YubiKey](https://www.corbado.com/glossary/yubikey)) o un escáner biométrico (p. ej., utilizado en
[Face ID](https://www.corbado.com/faq/is-face-id-passkey), Touch ID o [Windows Hello](https://www.corbado.com/glossary/windows-hello)),
pero opera completamente dentro del software (por lo que no hay autenticación física ni
escaneo de datos biométricos involucrados).

### 4.2. ¿Cuáles son los beneficios del autenticador virtual WebAuthn?

Hay dos beneficios principales del autenticador virtual WebAuthn.

#### 4.2.1. Pruebas automatizadas con el autenticador virtual Webauthn

Como WebDriver y CDP son herramientas de automatización de navegadores, es evidente que el
caso de uso principal de la implementación del autenticador virtual WebAuthn en estos
protocolos son las pruebas automatizadas. Aprovechando estos protocolos, el autenticador
virtual permite pruebas simples pero exhaustivas de las funcionalidades de las passkeys en
entornos controlados, como los marcos de pruebas E2E (p. ej., Playwright, Cypress,
[Nightwatch](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator)).

#### 4.2.2. Pruebas manuales y demostración con el autenticador virtual WebAuthn

El autenticador virtual WebAuthn del CDP también es accesible a través de las Herramientas
para Desarrolladores (DevTools) del navegador Chrome, y puede usarse para pruebas manuales
o simplemente con fines de demostración. Con esta función, puedes simular la entrada de
una passkey en un dispositivo que no admite passkeys de forma nativa. De manera
correspondiente, también es posible simular un entorno sin soporte para passkeys en un
dispositivo que sí las admite.

![Autenticador virtual WebAuthn de Playwright para Passkeys](https://www.corbado.com/website-assets/66090c090678d8241d6e9f67_passkeys_playwright_virtual_webauthn_authenticator_3d1fa5c566.jpg)

La captura de pantalla anterior muestra un ejemplo del uso del autenticador virtual en
Chrome para pruebas manuales o fines de demostración. Puedes ver que son posibles
diferentes opciones de configuración para el autenticador virtual, y también se puede
hacer un seguimiento de la adición y eliminación de credenciales. Consulta esta guía de
Google para obtener más información sobre el uso del autenticador virtual en tu navegador,
incluidas las opciones de configuración y los valores recomendados para cada una.

### 4.3. ¿Cuáles son las desventajas del autenticador virtual WebAuthn?

Si bien el autenticador virtual WebAuthn es una solución elegante para probar
implementaciones de passkeys, hay algunas desventajas que vale la pena señalar.

#### 4.3.1. Incapacidad para simular funcionalidades específicas del hardware

Al ser una solución puramente basada en software, el autenticador virtual WebAuthn no
puede replicar las características de hardware y las funciones de
[seguridad](https://www.corbado.com/es/blog/como-eliminar-contrasenas-por-completo) únicas de los autenticadores
físicos. La distinción entre el uso de varios autenticadores de plataforma (que están
integrados en un dispositivo, como un escáner biométrico en un teléfono inteligente) y
varios autenticadores multiplataforma (que son dispositivos externos, como las
[llaves de seguridad de hardware](https://www.corbado.com/es/blog/mejores-llaves-seguridad-hardware-fido2)) no se
puede simular utilizando el autenticador virtual WebAuthn. Si bien la simplificación de
caja negra de las complejidades involucradas con varios tipos de autenticadores de
plataforma y multiplataforma es una de las ventajas de usar el autenticador virtual
WebAuthn, si buscas simular y probar los matices de los diferentes tipos de
autenticadores, se deben explorar otras soluciones.

#### 4.3.2. Documentación escasa y problemas técnicos no resueltos

Dada la adopción relativamente reciente de WebAuthn y la novedad de la tecnología de
passkeys, el ecosistema que rodea a los autenticadores virtuales aún está madurando. Esto
resulta en una escasez de documentación completa y desafíos técnicos no resueltos,
particularmente en el contexto de la integración de autenticadores virtuales con marcos de
pruebas automatizadas. Esta guía tiene como objetivo abordar este problema proporcionando
información completa sobre las pruebas de passkeys en un entorno de pruebas automatizado,
al tiempo que se centra en abordar los inconvenientes aún presentes en el uso de estas
herramientas y presentar soluciones para estos problemas.

## 5. Cómo configurar el autenticador virtual WebAuthn en Playwright

Después de una instalación exitosa de Playwright y sus dependencias, puedes comenzar de
inmediato a escribir tu primera prueba creando un archivo con un nombre que termine en
.spec.ts o .test.ts con el siguiente contenido:

```js
import { test, expect } from "@playwright/test";

test("my first test", async ({ page }) => {
    await page.goto("https://passkeys.eu");

    // start simulating user actions
});
```

Para usar el autenticador virtual WebAuthn en Playwright, es suficiente con iniciar una
sesión de CDP y adjuntar un autenticador virtual al principio de un caso de prueba, de la
siguiente manera:

```js
test('signup with passkey', async ({ page }) => {
  // Initialize a CDP session for the current page
  const client = await page.context().newCDPSession(page);

  // Enable WebAuthn environment in this session
  await client.send('WebAuthn.enable');

  // Attach a virtual authenticator with specific options
  const result = await client.send('WebAuthn.addVirtualAuthenticator', {
    options: {
      protocol: 'ctap2',
      transport: 'internal',
      hasResidentKey: true,
      hasUserVerification: true,
      isUserVerified: true,
      automaticPresenceSimulation: false,
    },
  });
  const authenticatorId = result.authenticatorId;

  // Further test steps to simulate user interactions and assertions
...
});
```

Opciones para configurar el autenticador virtual WebAuthn:

- **protocol:** Esta opción especifica el protocolo que habla el autenticador virtual. Los
  valores posibles son "ctap2" y "u2f".
- **transport:** Esta opción especifica el tipo de autenticador que simula el autenticador
  virtual. Los valores posibles son "usb", "nfc", "ble" e "internal". Si se establece en
  "internal", simula un autenticador de plataforma, mientras que otros valores simulan
  autenticadores multiplataforma.
- **hasResidentKey:** Establecerlo en `true` admite
  [Resident Key](https://www.corbado.com/blog/webauthn-resident-key-discoverable-credentials-passkeys) (es decir,
  credencial detectable del lado del cliente).
- **hasUserVerification:** Establecerlo en `true` admite la
  [verificación](https://www.corbado.com/es/blog/verificacion-de-identidad-digital) de usuario. Se recomienda
  establecer esto como `true` ya que permite la simulación de entradas de passkey exitosas
  y fallidas.
- **isUserVerified:** Establecerlo en `true` emula un escenario de autenticación exitoso,
  mientras que `false` imita un fallo de autenticación, como cuando un usuario cancela la
  entrada de la passkey. Ten en cuenta que esta configuración solo es efectiva cuando
  `hasUserVerification` está establecido en `true`.
- **automaticPresenceSimulation:** Cuando se establece en `true`, la entrada de la passkey
  ocurre de forma automática e inmediata ante cualquier solicitud de autenticación. Por el
  contrario, establecerlo en `false` requiere la iniciación manual de la simulación de
  autenticación con passkey en el código de prueba. Se recomienda optar por la simulación
  manual (`false`) por dos razones:
    - **Aumentar la legibilidad del código de prueba:** La simulación automática puede
      oscurecer la comprensión del flujo de la prueba, ya que los intentos de
      autenticación se simulan sin activadores explícitos en el código de prueba.
    - **Evitar comportamientos no deseados:** La simulación automática significa que la
      entrada de la passkey se activará incluso si el probador no es consciente de que se
      solicitó la passkey. Esto es especialmente un problema para la UI condicional, que
      sería más fácil de pasar por alto para el probador.

## 6. Casos de uso del autenticador virtual WebAuthn

En esta sección, exploramos el uso de los métodos y eventos del autenticador virtual
WebAuthn en el contexto de casos de uso tanto comunes como marginales.

### 6.1. Cómo simular un intento de entrada de passkey en Playwright

Esta podría ser la tarea más importante pero confusa al usar el autenticador virtual
WebAuthn en un código de prueba, ya que no hay un método incorporado explícito para
activar una entrada de passkey. La solución radica en las opciones de configuración del
autenticador virtual WebAuthn, a saber, isUserVerified y automaticPresenceSimulation. Con
estas opciones podemos simular esta interacción del usuario a través de dos enfoques
diferentes que se describen a continuación.

#### 6.1.1. Enfoque 1: Simulación automática con automaticPresenceSimulation establecido en true

**Caso 1: Simulación de una entrada de passkey exitosa**

```js
test('signup with passkey', async ({ page }) => {
...

  await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in');
  await page.getByRole('button', { name: 'Login' }).click();
  // successful passkey input is automatically simulated (isUserVerified=true)
  await expect(page.getByRole('heading', { level: 1 })).toHaveText('Welcome!');

...
});
```

Simular una entrada de passkey exitosa generalmente no requiere líneas adicionales en el
código de prueba. La línea final (await expect...) espera a que la página cambie
(desencadenada por la entrada de passkey exitosa implícita).

**Caso 2: Simulación de una entrada de passkey cancelada (que no provoca cambios en la
interfaz de usuario)**

Probar una entrada de passkey fallida o cancelada es más complicado, ya que puede no
conducir a ningún cambio observable en la interfaz de usuario. En otras palabras, esperar
a que la página cambie como en el ejemplo anterior no es adecuado para garantizar que la
entrada de la passkey haya completado el procesamiento. Comprobar que la página no ha
cambiado después de la entrada implícita de la passkey no tiene sentido, ya que la
comprobación casi con seguridad ocurrirá antes de que la entrada de la passkey haya
completado el procesamiento. Si bien el autenticador virtual proporciona una forma de
esperar a que se procese una entrada de passkey exitosa escuchando la emisión de eventos
(como se discutirá en el enfoque 2), actualmente no hay una forma incorporada de detectar
una entrada de passkey fallida o cancelada. Una solución sería simplemente agregar un
tiempo de espera fijo para esperar a que se complete la operación de la passkey antes de
verificar que la interfaz de usuario realmente se mantuvo igual.

```js
test('signup with passkey', async ({ page }) => {
  // Simulate a set of user actions to trigger a passkey prompt
...

  await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in');

  // Simulate passkey input when prompted in the test
  await inputPasskey(async () => {
    await page.waitForTimeout(300);
    await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in');
  });

  // Further test steps
...
});
```

En cualquier caso, la legibilidad del código de prueba está limitada por la naturaleza
implícita de la operación de la passkey. Como se mencionó anteriormente, también sería
fácil pasar por alto cuándo se podría solicitar una UI condicional, en cuyo caso la
operación de la passkey se completaría automáticamente sin el conocimiento del probador.

#### 6.1.2. Enfoque 2: Simulación manual con automaticPresenceSimulation establecido en false

Activar manualmente una entrada de passkey cambiando el valor de la opción
automaticPresenceSimulation resuelve los problemas encontrados en el enfoque anterior,
especialmente en términos de legibilidad del código de prueba.

**Caso 1: Simulación de una entrada de passkey exitosa**

Los siguientes fragmentos de código simulan una entrada de passkey exitosa:

```js
async simulateSuccessfulPasskeyInput(operationTrigger: () => Promise<void>) {
  // initialize event listeners to wait for a successful passkey input event
  const operationCompleted = new Promise<void>(resolve => {
    client.on('WebAuthn.credentialAdded', () => resolve());
    client.on('WebAuthn.credentialAsserted', () => resolve());
  });

  // set isUserVerified option to true
  // (so that subsequent passkey operations will be successful)
  await client.send('WebAuthn.setUserVerified', {
    authenticatorId: authenticatorId,
    isUserVerified: true,
  });

  // set automaticPresenceSimulation option to true
  // (so that the virtual authenticator will respond to the next passkey prompt)
  await client.send('WebAuthn.setAutomaticPresenceSimulation', {
    authenticatorId: authenticatorId,
            enabled: true,
  });

  // perform a user action that triggers passkey prompt
  await operationTrigger();

  // wait to receive the event that the passkey was successfully registered or verified
  await operationCompleted;

  // set automaticPresenceSimulation option back to false
  await client.send('WebAuthn.setAutomaticPresenceSimulation', {
    authenticatorId,
            enabled: false,
  });
}
```

```js
test('signup with passkey', async ({ page }) => {
...

  // Simulate passkey input with a promise that triggers a passkey prompt as the argument
  await simulateSuccessfulPasskeyInput(() =>
          page.getByRole('button', { name: 'Create account with passkeys' }).click()
  );

...
});
```

La función de ayuda puede ser bastante intimidante la primera vez que la ves. Ayuda a
entender que todas las complejidades técnicas de simular una operación de passkey se
abstraen en la función de ayuda. Esto significa que cuando se usa dentro del código de
prueba, hace que el código sea simple y claro, como se puede ver en el segundo fragmento
de código anterior.

En comparación con el enfoque implícito de la Sección 6.1.1, este enfoque explícito
también aumenta la legibilidad del código. Esto sería especialmente útil para cuando se
solicita una UI condicional, ya que este enfoque explícito evita la finalización implícita
y no intencionada de la operación de la passkey sin que el desarrollador se dé cuenta.

Ahora entendamos cada parte de la función de ayuda.

Primero, definimos la promesa `operationCompleted` que espera el evento
`WebAuthn.credentialAdded` o el evento `WebAuthn.credentialAsserted`, que, como su nombre
indica, se emite cuando una credencial de passkey se registra o verifica, respectivamente.
Esta promesa se usará más adelante.

A continuación, la opción `isUserVerified` se establece en `true`, para que la operación
de passkey posterior por parte del autenticador virtual WebAuthn sea exitosa. La
`automaticPresenceSimulation` también se establece en `true`, para que el autenticador
virtual WebAuthn responda a la siguiente solicitud de passkey de la página web.

La espera de la promesa `operationTrigger` es necesaria para evitar una condición de
carrera. La condición de carrera ocurre cuando la página web solicita la passkey antes de
que `automaticPresenceSimulation` se establezca en `true`. Para evitar esto, la acción del
usuario que desencadena la solicitud de passkey debe realizarse después de que
`automaticPresenceSimulation` se haya establecido en `true`. En el ejemplo anterior, el
usuario hace clic en el botón llamado `Create account with passkeys` para activar la
solicitud de passkey.

Una vez completada la acción del usuario, debemos esperar a que se complete la operación
de passkey exitosa. Esto se hace esperando la promesa que definimos al principio de la
función de ayuda. La finalización de la operación de passkey exitosa está marcada por la
emisión del evento `WebAuthn.credentialAdded` o `WebAuthn.credentialAsserted`. En el
ejemplo anterior, como el usuario está registrando una passkey, se emitiría el evento
`WebAuthn.credentialAdded`.

Finalmente, la opción `automaticPresenceSimulation` se vuelve a establecer en `false`,
para evitar que ocurran operaciones de passkey no intencionadas más adelante en el código
de prueba.

**Caso 2: Simulación de una entrada de passkey cancelada**

Para una entrada de passkey cancelada, debemos hacer una ligera modificación a la
implementación del caso anterior. En el caso de una entrada de passkey exitosa, hay
eventos, a saber, `WebAuthn.credentialAdded` y `WebAuthn.credentialAsserted`, que se
emiten al finalizar la operación. Sin embargo, el autenticador virtual WebAuthn no
proporciona ningún evento para una entrada de passkey cancelada o fallida. Por lo tanto,
debemos usar una forma alternativa de verificar la finalización de una operación de
passkey cancelada o fallida.

Los siguientes fragmentos de código simulan una entrada de passkey fallida:

```js
async simulateFailedPasskeyInput(operationTrigger: () => Promise<void>, postOperationCheck: () => Promise<void>) {
  // set isUserVerified option to false
  // (so that subsequent passkey operations will fail)
  await client.send('WebAuthn.setUserVerified', {
    authenticatorId: authenticatorId,
    isUserVerified: false,
  });

  // set automaticPresenceSimulation option to true
  // (so that the virtual authenticator will respond to the next passkey prompt)
  await client.send('WebAuthn.setAutomaticPresenceSimulation', {
    authenticatorId: authenticatorId,
            enabled: true,
  });

  // perform a user action that triggers passkey prompt
  await operationTrigger();

  // wait for an expected UI change that indicates the passkey operation has completed
  await postOperationCheck();

  // set automaticPresenceSimulation option back to false
  await client.send('WebAuthn.setAutomaticPresenceSimulation', {
    authenticatorId,
            enabled: false,
  });
}
```

```js

test('signup with passkey', async ({ page }) => {
  // Simulate a set of user actions to trigger a passkey prompt
...

  await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in');

  // Simulate passkey input when prompted in the test
  await inputPasskey(async () => {
    await page.waitForTimeout(300);
    await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in');
  });

  // Further test steps
...
});
```

En la función de ayuda, los detectores de eventos se reemplazan con un parámetro de
promesa `postOperationCheck` que espera que ocurra un cambio esperado en la interfaz de
usuario antes de que `automaticPresenceSimulation` pueda volver a establecerse en `false`.

En el código de prueba, la única diferencia es que la función de ayuda debe llamarse con
una promesa adicional que verifica el cambio de interfaz de usuario deseado. En el ejemplo
anterior, verificamos que la aplicación web haya navegado con éxito a una página en la que
el encabezado tiene el texto `Something went wrong...`.

Como se discutió en la Sección 6.1.1, cancelar una entrada de passkey puede no conducir a
ningún cambio observable en la interfaz de usuario. Al igual que en el ejemplo
proporcionado en esa sección, debemos agregar una espera fija antes de verificar que la
interfaz de usuario realmente ha permanecido igual en tales casos:

```js
test('signup with passkey', async ({ page }) => {
...

  await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in');

  // Simulate passkey input with a promise that triggers a passkey prompt as the argument
  await simulateFailedPasskeyInput(
          () => page.getByRole('button', { name: 'Create account with passkeys' }).click(),
          async () => {
            await page.waitForTimeout(300);
            await expect(page.getByRole('heading', { level: 1 })).toHaveText('Please log in');
          }
  );

...
});
```

### 6.2. Cómo probar la creación de passkeys

La conveniencia de usar un autenticador virtual WebAuthn se ve reforzada por su capacidad
para comportarse como un autenticador real en caso de creación o eliminación de passkeys
por parte de la aplicación web. Una prueba simplemente necesita realizar acciones de
usuario para simular la creación o eliminación de una passkey en la aplicación web, y el
autenticador virtual WebAuthn modifica automáticamente la información de sus credenciales
guardadas sin ningún trabajo adicional por parte del código de prueba.

Aquí está el ejemplo de código de prueba que verifica que la aplicación web registra una
nueva passkey en el autenticador correctamente:

```js
test('signup with passkey', async ({ page }) => {
...

  // Confirm there are currently no registered credentials
  const result1 = await client.send('WebAuthn.getCredentials', { authenticatorId });
  expect(result1.credentials).toHaveLength(0);

  // Perform user actions to simulate creation of a passkey credential (e.g. user registration with passkey input)
...

  // Confirm the passkey was successfully registered
  const result2 = await client.send('WebAuthn.getCredentials', { authenticatorId });
  expect(result2.credentials).toHaveLength(1);

...
});
```

Combinando este fragmento de código con los fragmentos de código de la Sección 6.1,
podemos probar el flujo de registro en nuestra página de demostración. El siguiente video
es una visualización de la prueba en el modo de interfaz de usuario de Playwright:

[Watch on YouTube](https://www.youtube.com/watch?v=HqqRgds2T94)

### 6.3. Cómo probar la verificación de passkeys

Verificar una credencial de passkey con el autenticador virtual WebAuthn funciona de
manera similar a la creación de una passkey, en el sentido de que el autenticador virtual
realiza un seguimiento automático del número de verificaciones realizadas con una
credencial en particular.

```js
test('login with passkey', async ({ page }) => {
...

  // Confirm there is only one credential, and save its signCount
  const result1 = await client.send('WebAuthn.getCredentials', { authenticatorId });
  expect(result1.credentials).toHaveLength(1);
  const signCount1 = result1.credentials[0].signCount;

  // Perform user actions to simulate verification of a passkey credential (e.g. login with passkey input)
...

  // Confirm the credential's new signCount is greater than the previous signCount
  const result2 = await client.send('WebAuthn.getCredentials', { authenticatorId });
  expect(result2.credentials).toHaveLength(1);
  expect(result2.credentials[0].signCount).toBeGreaterThan(signCount1);

...
});
```

El siguiente video demuestra una prueba para el flujo de inicio de sesión en nuestra
página de demostración:

[Watch on YouTube](https://www.youtube.com/watch?v=f3Vj0Dd562A)

### 6.4. Cómo probar la eliminación de passkeys

Eliminar una passkey de una aplicación web, por otro lado, no debería modificar ninguna
información dentro del autenticador virtual WebAuthn. La aplicación web solo debería poder
eliminar las credenciales guardadas en su propio servidor. Solo el propio usuario debería
poder eliminar consciente y manualmente una credencial de passkey del autenticador virtual
WebAuthn.

```js
test('delete a registered passkey credential', async ({ page }) => {
...

  // Confirm there is currently one registered credential
  const result1 = await client.send('WebAuthn.getCredentials', { authenticatorId });
  expect(result1.credentials).toHaveLength(1);

  // Perform user actions to simulate deletion of a passkey credential
...

  // Deleting a passkey credential from a website should not remove the credential from the authenticator
  const result2 = await client.send('WebAuthn.getCredentials', { authenticatorId });
  expect(result2.credentials).toHaveLength(1);

...
});
```

El siguiente video demuestra una prueba para la eliminación de una credencial de passkey
en nuestra página de demostración:

[Watch on YouTube](https://www.youtube.com/watch?v=QG5_wPMY9q8)

### 6.5. Cómo simular la autenticación entre dispositivos

La forma más intuitiva de simular una autenticación entre dispositivos desde un segundo
dispositivo (que aún no tiene una passkey registrada) es simplemente agregar una nueva
instancia del autenticador virtual WebAuthn a través del comando CDP, de la siguiente
manera:

```js
test('signup with passkey', async ({ page }) => {
...

  // add a virtual authenticator for the first device
  const authenticatorId1 = await client.send('WebAuthn.addVirtualAuthenticator', { options });

  // perform test actions of the first device
...

  // add a virtual authenticator for the second device
  const authenticatorId2 = await client.send('WebAuthn.addVirtualAuthenticator', { options });

  // perform test actions of the second device
..
});
```

Para evitar la complejidad de gestionar los ID de múltiples autenticadores virtuales,
también es posible simular un nuevo dispositivo simplemente eliminando las credenciales de
un único autenticador y volviéndolas a agregar cuando sea necesario:

```js

test('signup with passkey', async ({ page }) => {
...

  const result = await client.send('WebAuthn.getCredentials', { authenticatorId });
  const credential = result.credentials[0]; // assuming only one registered passkey
  const credentialId = credential.credentialId;
  await client.send('WebAuthn.removeCredential', { authenticatorId, credentialId });

  // Perform test actions of the second device which doesn't have a registered passkey
...

  // Call if it's necessary to simulate the first device which has a registered passkey
  await client.send('WebAuthn.addCredential', { credential });

  // Perform test actions of the first device
...
});
```

Este enfoque puede simplificar especialmente la implementación en el caso de que se
necesite simular un nuevo dispositivo, pero el dispositivo antiguo ya no necesite ser
utilizado. En este caso, simplemente necesitas borrar las credenciales del autenticador
virtual y descartarlas por completo:

```js
test('signup with passkey', async ({ page }) => {
...

  const result = await client.send('WebAuthn.getCredentials', { authenticatorId });
  const credential = result.credentials[0]; // assuming only one registered passkey
  const credentialId = credential.credentialId;
  await client.send('WebAuthn.clearCredentials', { authenticatorId });

  // Perform test actions of the second device which doesn't have a registered passkey
...
});
```

## 7. Alternativas al autenticador virtual WebAuthn

Explorar alternativas al autenticador virtual WebAuthn puede ofrecer flexibilidad en la
forma en que se prueban los procesos de autenticación de passkeys / WebAuthn dentro de los
proyectos.

### 7.1. Pruebas con servicios simulados (mock)

Desarrollar servicios o puntos finales simulados (mock) puede simular eficazmente el
comportamiento de la autenticación, simplificando las pruebas al abstraer las
complejidades del mecanismo de autenticación real. Este enfoque es particularmente
beneficioso cuando se utilizan servicios de autenticación externos, permitiendo que el
enfoque permanezca en la integración y funcionalidad de los componentes del sistema sin
profundizar en los detalles de la autenticación.

### 7.2. Pruebas de integración con autenticadores reales

Para un examen exhaustivo de las funcionalidades de autenticación, emplear autenticadores
reales para las pruebas de integración proporciona una visión detallada de la interacción
con [llaves de seguridad de hardware](https://www.corbado.com/es/blog/mejores-llaves-seguridad-hardware-fido2)
(p. ej., YubiKeys) o dispositivos biométricos (p. ej., utilizados en
[Face ID](https://www.corbado.com/faq/is-face-id-passkey), Touch ID o [Windows Hello](https://www.corbado.com/glossary/windows-hello)).
Aunque generalmente se realiza de forma manual debido a la naturaleza compleja de integrar
dispositivos del mundo real en pruebas automatizadas, es factible desarrollar scripts de
automatización personalizados. Estos scripts pueden conectar autenticadores reales con
marcos de pruebas de extremo a extremo, ofreciendo una aproximación más cercana a los
escenarios de usuario reales y mejorando la fiabilidad del proceso de autenticación en
entornos de producción.

## 8. Recomendaciones para desarrolladores

Después de demostrar las diferentes opciones y mostrar fragmentos de código específicos
para las pruebas E2E de passkeys / WebAuthn con Playwright, adicionalmente queremos
proporcionar algunas recomendaciones más generales para los desarrolladores nuevos en el
tema.

### 8.1. Estudia el panorama de los frameworks de pruebas E2E

Antes de sumergirse en las pruebas de passkeys o cualquier otro mecanismo de
autenticación, es esencial evaluar los marcos de pruebas E2E disponibles y elegir la
opción más apropiada según los requisitos de tu proyecto. Considera el equilibrio entre la
velocidad y la estabilidad que ofrecen los marcos basados en CDP como Playwright y
Puppeteer, y la compatibilidad entre navegadores que proporcionan los marcos basados en
WebDriver como Selenium y Nightwatch. Si bien los marcos basados en CDP ofrecen una
automatización de navegadores más rápida y estable, están limitados a navegadores basados
en Chromium. En contraste, los marcos basados en WebDriver proporcionan una compatibilidad
entre navegadores más amplia, incluido el soporte para navegadores no basados en Chromium
como Firefox y Safari, aunque con un rendimiento potencialmente más lento y menos estable.
Comprender estas compensaciones te ayudará a tomar una decisión informada y a seleccionar
el marco que mejor se adapte a las necesidades de tu proyecto.

### 8.2. Comprende los conceptos subyacentes detrás de WebAuthn y las passkeys

Si bien el autenticador virtual WebAuthn simplifica el proceso de prueba de las
implementaciones de passkeys, es crucial que los desarrolladores tengan una sólida
comprensión de los conceptos subyacentes detrás del estándar WebAuthn y las passkeys.
Familiarízate con las diferentes configuraciones disponibles para el autenticador virtual
WebAuthn, como protocolo, transporte, hasResidentKey, hasUserVerification e
isUserVerified. Comprender estas configuraciones te permitirá ajustar el autenticador
virtual para simular diversos escenarios de autenticación con precisión. Además,
profundiza en las complejidades de la autenticación con passkeys, incluida su integración
con diferentes navegadores y dispositivos, así como las posibles consideraciones de
seguridad. Este conocimiento fundamental te capacitará para diseñar estrategias de prueba
completas y efectivas para la autenticación con passkeys en tus aplicaciones web.

## 9. Resumen

Esta guía profundizó en el uso del autenticador virtual WebAuthn de CDP con Playwright,
destacando conceptos avanzados y abordando problemas no cubiertos en la documentación
oficial. También exploramos alternativas a CDP dentro de Playwright y otros marcos de
pruebas E2E. A pesar de las diferentes implementaciones, las especificaciones
estandarizadas del autenticador virtual WebAuthn aseguran la relevancia de esta guía en
diferentes protocolos de automatización web y marcos de pruebas de extremo a extremo. Para
aprender más en profundidad sobre diferentes conceptos relacionados con las passkeys,
consulta nuestro glosario de terminologías relevantes que podrían ayudarte a ajustar el
autenticador virtual WebAuthn según tus necesidades.
