---
url: 'https://www.corbado.com/pt/blog/passkeys-teste-e2e-playwright-webauthn-autenticador-virtual'
title: 'Teste E2E de Passkeys com Playwright via Autenticador Virtual WebAuthn'
description: 'Aprenda a configurar testes E2E para passkeys em diferentes navegadores com Playwright, Nightwatch, Selenium e Puppeteer usando o autenticador virtual WebAuthn.'
lang: 'pt'
author: 'Anders'
date: '2025-06-17T16:17:03.737Z'
lastModified: '2026-03-25T10:03:38.982Z'
keywords: 'teste e2e, teste de ponta a ponta'
category: 'Passkeys Implementation'
---

# Teste E2E de Passkeys com Playwright via Autenticador Virtual WebAuthn

> **Nossa missão é tornar a Internet um lugar mais seguro**, e o novo padrão de login
> passkeys oferece uma solução superior para alcançar isso. É por isso que queremos
> ajudá-lo a entender melhor as passkeys e suas características.

## 1. Introdução: Teste E2E de Passkeys

As passkeys estão se tornando cada vez mais aceitas como método de
[autenticação](https://www.corbado.com/pt/blog/passkeys-revolut), baseando-se no Web Authentication (WebAuthn)
como seu padrão subjacente. Seu aumento de popularidade é bastante recente, o que torna a
documentação e outros recursos relativamente escassos. Isso, juntamente com a natureza
complexa da implementação de passkeys, pode tornar desafiador para os desenvolvedores
encontrar informações relevantes sobre o design, a implementação e, especialmente, o teste
de passkeys para suas plataformas e serviços.

Este guia [visa](https://www.corbado.com/blog/visa-passkeys) preencher essa lacuna, focando em aspectos do
autenticador virtual WebAuthn que não são abordados em detalhes em sua
[documentação oficial](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn/).
Por exemplo, discutimos opções de configuração para o autenticador virtual que não são
autoexplicativas na documentação, bem como soluções alternativas para certos casos de uso
para os quais o autenticador virtual não oferece uma solução conveniente. Além disso, este
guia também é útil para desenvolvedores que estão simplesmente procurando exemplos fáceis
de seguir para usar o autenticador virtual em código de teste.

Nosso guia usa exemplos do
[Playwright](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) para
fornecer um passo a passo simples para testar eficazmente a implementação de passkeys em
seu projeto.
[Playwright](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) é um
framework de teste de ponta a ponta (E2E) que usa o Chrome DevTools Protocol (CDP) como
protocolo para automação de navegador. Se você está procurando especificamente por
exemplos técnicos de teste de passkeys no
[Playwright](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator), pode
pular para a Seção 5. Por outro lado, se você está usando outros frameworks de teste E2E
como [Puppeteer](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) ou
[Selenium](https://www.corbado.com/blog/selenium-passkeys-testing-nodejs) e deseja testar passkeys nesses
frameworks, as implementações do código de teste serão idênticas ou muito semelhantes aos
exemplos fornecidos neste guia, dependendo do framework que você está usando. Na próxima
seção, fornecemos um contexto sobre os diferentes frameworks E2E e quão relevante este
guia será para eles.

## 2. Contexto: Automação de Navegador e Frameworks de Teste E2E

### 2.1. O que é Automação de Navegador?

Automação de navegador, como o nome sugere, é o processo de automatizar ações repetitivas
do usuário no navegador para fins de extração de dados da web ou, em nosso caso, para
testar aplicações web. WebDriver e Chrome DevTools Protocol (CDP) são dois dos principais
protocolos de automação de navegador relevantes para este guia, pois cada um deles fornece
uma implementação do autenticador virtual WebAuthn.

### 2.2. O que é o WebDriver?

[WebDriver ](https://w3c.github.io/webdriver/)é uma interface controlada remotamente que
pode ser vista como um intermediário na comunicação entre o cliente e o navegador. O foco
deste protocolo é fornecer uma interface neutra em termos de plataforma e linguagem que
suporte todos os principais navegadores, incluindo aqueles que não são baseados em
Chromium, como Firefox e Safari. Como a interface do WebDriver precisa gerenciar uma
conexão com o cliente e com o navegador, essa abordagem sacrifica velocidade e
estabilidade em troca de um suporte mais amplo a navegadores (ou seja, maior
instabilidade). Clientes notáveis do WebDriver incluem
[Selenium](https://www.corbado.com/blog/selenium-passkeys-testing-nodejs) e
[Nightwatch](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator).

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

Retirado de
[jankaritech](https://dev.to/jankaritech/different-approaches-protocols-to-automate-the-browser-39f1)

### 2.3. O que é o Chrome DevTools Protocol (CDP)?

O Chrome DevTools Protocol (CDP), por outro lado, não possui um intermediário como a
interface do WebDriver entre o cliente e o navegador. Além disso, a comunicação entre o
cliente e o navegador ocorre por meio de uma conexão de soquete, em contraste com a
conexão HTTP mais lenta entre o cliente e a interface do WebDriver na abordagem anterior.
Esses pontos tornam o CDP muito mais rápido e menos instável que o WebDriver. A
desvantagem é que este protocolo é suportado apenas por navegadores baseados em Chromium,
como Chrome e Edge. Playwright e
[Puppeteer](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) são
exemplos de clientes que usam o CDP para se comunicar com os navegadores.

![Passkeys PlayWright CDP Client](https://www.corbado.com/website-assets/66090be6820f38fba3e156f3_passkeys_playwright_cdp_client_44e000d341.jpg)

Retirado de
[jankaritech](https://dev.to/jankaritech/different-approaches-protocols-to-automate-the-browser-39f1)

### 2.4. Puppeteer e Playwright como Frameworks de Teste E2E baseados em CDP

[Puppeteer](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator), assim
como o Playwright, é um framework E2E construído diretamente sobre o CDP. Isso significa
que tanto o Puppeteer quanto o Playwright usam a mesma implementação do autenticador
virtual WebAuthn e que a comunicação da API usando o autenticador virtual WebAuthn através
da conexão de soquete também é idêntica.

Para demonstrar, comparamos o código de teste tanto no Playwright quanto no Puppeteer para
chamar o método getCredentials, que retorna uma lista de todas as credenciais registradas
no autenticador virtual até o momento. Também anexamos um ouvinte de eventos (event
listener) simples para o evento credentialAdded, que é acionado quando uma credencial de
passkey é registrada com sucesso. Não se intimide com os detalhes da implementação, pois
eles serão explicados nas seções posteriores. Estes exemplos servem simplesmente para
demonstrar como as implementações são semelhantes entre os dois frameworks.

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

Embora os métodos para inicializar a sessão CDP no início dos códigos de teste sejam
ligeiramente diferentes, chamar métodos e lidar com eventos na
[API do autenticador virtual WebAuthn do CDP](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn/)
é idêntico. Isso significa que, se você pretende usar o autenticador virtual WebAuthn no
Puppeteer, pode seguir este guia linha por linha.

### 2.5. Selenium e Nightwatch como Frameworks de Teste E2E baseados em WebDriver

[Selenium](https://www.corbado.com/blog/selenium-passkeys-testing-nodejs) e
[Nightwatch](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) são
frameworks de teste E2E que dependem do WebDriver para automação de navegador. Embora a
implementação do autenticador virtual WebAuthn para WebDriver seja separada de sua
implementação para CDP, suas especificações de API são semelhantes. Para quase todos os
métodos na
[API do autenticador virtual WebAuthn do CDP](https://chromedevtools.github.io/devtools-protocol/tot/WebAuthn/),
você pode encontrar um método correspondente na
[API do autenticador virtual WebAuthn do WebDriver](https://www.w3.org/TR/webauthn-2/#sctn-automation-virtual-authenticators).
No entanto, uma coisa a notar é que, embora seja possível anexar ouvintes de eventos para
quando uma passkey é adicionada ou confirmada com sucesso na API do autenticador virtual
WebAuthn do CDP, isso não é possível na contraparte do 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();
```

É evidente que a sintaxe para configurar a instância do autenticador virtual e fazer
chamadas de API é diferente da implementação CDP correspondente. No entanto, como as
especificações da API dos dois autenticadores virtuais WebAuthn são muito semelhantes,
seria viável seguir este guia para escrever uma implementação correspondente em um
framework de teste E2E baseado em WebDriver.

### 2.6. Cypress como Framework de Teste E2E com Scripting Nativo

[Cypress](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) é um
framework de teste E2E que não é construído primariamente sobre WebDriver ou CDP como os
frameworks mencionados acima. Ele usa JavaScript nativo para se comunicar com o navegador.
No entanto, ele fornece acesso de baixo nível ao CDP, o que significa que é possível
enviar comandos CDP brutos para utilizar o autenticador virtual WebAuthn do CDP.

Como a sintaxe para este acesso de baixo nível é tediosa e muito diferente dos exemplos
acima, não entraremos em detalhes neste guia. No entanto, mais informações sobre como
chamar comandos CDP no
[Cypress](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator) são
explicadas neste [guia](https://glebbahmutov.com/blog/cypress-automation/). Os conceitos
gerais para usar o autenticador virtual WebAuthn do CDP apresentados neste guia ainda são
relevantes para aqueles que buscam testar passkeys no
[Cypress](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator).

## 3. O que Torna o Teste E2E de Passkeys com Playwright um Problema?

Existem muitas razões pelas quais testar a implementação de passkeys é naturalmente mais
desafiador do que outras ações de usuário mais simples em um ambiente web. A necessidade
de lidar com interações dinâmicas do usuário envolvidas na
[autenticação](https://www.corbado.com/pt/blog/passkeys-revolut) biométrica, como leitura de impressão digital ou
reconhecimento facial, adiciona uma camada de complexidade que pode não ser prática de
abordar em detalhes ao escrever testes. Como a segurança é naturalmente uma grande
preocupação no contexto da [autenticação](https://www.corbado.com/pt/blog/passkeys-revolut), também é necessário
garantir que a autenticação com passkey seja integrada de forma transparente em vários
navegadores e dispositivos, sem espaço para vulnerabilidades de segurança.

## 4. O Autenticador Virtual WebAuthn Torna o Teste E2E de Passkeys Possível

Simplificar a complexidade de lidar com interações dinâmicas do usuário envolvidas nas
operações de passkey, bem como testar sua integração em diferentes navegadores e
dispositivos, torna-se mais fácil com o uso do autenticador virtual WebAuthn.

### 4.1. O que é o Autenticador Virtual WebAuthn?

O autenticador virtual WebAuthn é uma representação de software do modelo de autenticador
especificado no padrão WebAuthn. Ele emula o comportamento de um dispositivo autenticador
físico, como uma
[chave de segurança](https://www.corbado.com/pt/blog/melhores-fido2-chaves-de-seguranca-hardware) de hardware
(por exemplo, [YubiKey](https://www.corbado.com/glossary/yubikey)) ou um scanner biométrico (por exemplo, usado
no [Face ID](https://www.corbado.com/faq/is-face-id-passkey), Touch ID ou
[Windows Hello](https://www.corbado.com/glossary/windows-hello)), mas opera inteiramente em software (portanto,
nenhuma autenticação física ou leitura de
[biometria](https://www.corbado.com/pt/blog/biometria-confirmacao-pagador) está envolvida).

### 4.2. Quais são os Benefícios do Autenticador Virtual WebAuthn?

Existem dois benefícios principais para o autenticador virtual WebAuthn.

#### 4.2.1. Teste Automatizado com o Autenticador Virtual WebAuthn

Como o WebDriver e o CDP são ferramentas de automação de navegador, é evidente que o
principal caso de uso da implementação do autenticador virtual WebAuthn nesses protocolos
é o teste automatizado. Aproveitando esses protocolos, o autenticador virtual permite
testes simples, mas abrangentes, das funcionalidades de passkey em ambientes controlados,
como frameworks de teste E2E (por exemplo, Playwright, Cypress,
[Nightwatch](https://www.corbado.com/blog/passkeys-e2e-playwright-testing-webauthn-virtual-authenticator)).

#### 4.2.2. Teste Manual e Demonstração com o Autenticador Virtual WebAuthn

O autenticador virtual WebAuthn do CDP também é acessível através das Ferramentas de
Desenvolvedor (DevTools) do navegador Chrome, e pode ser usado para testes manuais ou
simplesmente para fins de demonstração. Com este recurso, você pode simular a entrada de
passkey em um dispositivo que não suporta passkeys nativamente. Da mesma forma, também é
possível simular um ambiente sem suporte a passkeys em um dispositivo que as suporta.

![Passkeys Playwright Virtual WebAuthn Authenticator](https://www.corbado.com/website-assets/66090c090678d8241d6e9f67_passkeys_playwright_virtual_webauthn_authenticator_3d1fa5c566.jpg)

A captura de tela acima mostra um exemplo de uso do autenticador virtual no Chrome para
testes manuais ou fins de demonstração. Você pode ver que diferentes opções de
configuração para o autenticador virtual são possíveis, e a adição e exclusão de
credenciais também podem ser rastreadas. Consulte este
[guia ](https://docs.corbado.com/other/google-chrome-virtual-authenticator)do Google para
obter mais informações sobre como usar o autenticador virtual em seu navegador, incluindo
as opções de configuração e os valores recomendados para cada uma.

### 4.3. Quais são as Desvantagens do Autenticador Virtual WebAuthn?

Embora o autenticador virtual WebAuthn seja uma solução elegante para testar
implementações de passkey, existem algumas desvantagens que valem a pena notar.

#### 4.3.1. Incapacidade de Simular Funcionalidades Específicas de Hardware

Sendo uma solução puramente baseada em software, o autenticador virtual WebAuthn não pode
replicar as características de hardware e os recursos de segurança únicos dos
autenticadores físicos. A distinção entre o uso de vários autenticadores de plataforma
(que são integrados a um dispositivo, como um scanner biométrico em um smartphone) e
vários autenticadores de plataforma cruzada (que são dispositivos externos, como chaves de
segurança de hardware) não pode ser simulada usando o autenticador virtual WebAuthn.
Embora a simplificação em caixa-preta das complexidades envolvidas com vários tipos de
autenticadores de plataforma e de plataforma cruzada seja uma das vantagens de usar o
autenticador virtual WebAuthn, se você busca simular e testar as nuances dos diferentes
tipos de autenticadores, outras soluções devem ser exploradas.

#### 4.3.2. Documentação Escassa e Problemas Técnicos não Resolvidos

Dada a adoção relativamente recente do WebAuthn e a novidade da tecnologia de passkeys, o
ecossistema em torno dos autenticadores virtuais ainda está amadurecendo. Isso resulta em
uma escassez de documentação abrangente e desafios técnicos não resolvidos,
particularmente no contexto da integração de autenticadores virtuais com frameworks de
teste automatizado. Este guia [visa](https://www.corbado.com/blog/visa-passkeys) abordar esse problema,
fornecendo insights abrangentes sobre o teste de passkeys em um ambiente de teste
automatizado, ao mesmo tempo em que se concentra em abordar os inconvenientes ainda
presentes no uso dessas ferramentas e apresentar soluções alternativas para esses
problemas.

## 5. Como Configurar o Autenticador Virtual WebAuthn no Playwright

Após uma [instalação](https://playwright.dev/docs/intro) bem-sucedida do Playwright e suas
dependências, você pode começar imediatamente a escrever seu primeiro teste criando um
arquivo com um nome que termine em .spec.ts ou .test.ts com o seguinte conteúdo:

```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 o autenticador virtual WebAuthn no Playwright, basta iniciar uma sessão CDP e
anexar um autenticador virtual no início de um caso de teste, da seguinte forma:

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

Opções para configurar o autenticador virtual WebAuthn:

- **protocol:** Esta opção especifica o protocolo que o autenticador virtual utiliza. Os
  valores possíveis são "[ctap2](https://www.corbado.com/pt/glossary/ctap)" e "u2f"
- **transport:** Esta opção especifica o tipo de autenticador que o autenticador virtual
  simula. Os valores possíveis são "usb", "nfc", "ble" e "internal". Se definido como
  "internal", ele simula um autenticador de plataforma, enquanto outros valores simulam
  autenticadores de plataforma cruzada.
- **hasResidentKey:** Definir como `true` suporta
  [Chave Residente](https://www.corbado.com/pt/blog/webauthn-resident-key-discoverable-credentials-passkeys) (ou
  seja,
  [credencial detectável](https://www.corbado.com/pt/blog/webauthn-resident-key-discoverable-credentials-passkeys)
  do lado do cliente).
- **hasUserVerification:** Definir como `true` suporta a Verificação do Usuário. É
  recomendado definir como `true`, pois permite a simulação de entrada de passkey
  bem-sucedida e com falha.
- **isUserVerified:** Definir como `true` emula um cenário de autenticação bem-sucedido,
  enquanto `false` imita uma falha de autenticação, como quando um usuário cancela a
  entrada da passkey. Note que esta configuração só é eficaz quando `hasUserVerification`
  está definido como `true`.
- **automaticPresenceSimulation:** Quando definido como `true`, a entrada da passkey
  ocorre automática e imediatamente após qualquer solicitação de autenticação. Por outro
  lado, definir como `false` requer a iniciação manual da simulação de autenticação com
  passkey no código de teste. Optar pela simulação manual (`false`) é recomendado por duas
  razões:
    - **Aumentar a legibilidade do código de teste:** A simulação automática pode
      obscurecer o entendimento do fluxo de teste, pois as tentativas de autenticação são
      simuladas sem gatilhos explícitos no código de teste.
    - **Evitar comportamento não intencional:** A simulação automática significa que a
      entrada da passkey será acionada mesmo que o testador não esteja ciente de que a
      passkey foi solicitada. Isso é especialmente um problema para a UI Condicional, que
      seria mais fácil para o testador ignorar.

## 6. Casos de Uso do Autenticador Virtual WebAuthn

Nesta seção, exploramos o uso dos métodos e eventos do autenticador virtual WebAuthn no
contexto de casos de uso comuns e mais específicos.

### 6.1. Como Simular uma Tentativa de Entrada de Passkey no Playwright

Esta pode ser a tarefa mais importante e, ao mesmo tempo, confusa ao usar o autenticador
virtual WebAuthn em um código de teste, pois não há um método integrado explícito para
acionar uma entrada de passkey. A solução está nas opções de configuração do autenticador
virtual WebAuthn, especificamente, `isUserVerified` e `automaticPresenceSimulation`. Com
essas opções, podemos simular essa interação do usuário por meio de duas abordagens
diferentes descritas abaixo.

#### 6.1.1. Abordagem 1: Simulação automática com `automaticPresenceSimulation` definido como `true`

**Caso 1: Simulando uma entrada de passkey bem-sucedida**

```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 uma entrada de passkey bem-sucedida geralmente não requer linhas adicionais no
código de teste. A linha final (`await expect...`) espera que a página mude (acionada pela
entrada implícita e bem-sucedida da passkey).

**Caso 2: Simulando uma entrada de passkey cancelada (que não aciona mudanças na UI)**

Testar uma entrada de passkey com falha ou cancelada é mais complicado, pois pode não
levar a nenhuma mudança observável na UI. Em outras palavras, esperar que a página mude
como no exemplo anterior não é adequado para garantir que a entrada da passkey tenha
concluído o processamento. Verificar que a página não mudou após a entrada implícita da
passkey não tem sentido, pois a verificação quase certamente acontecerá antes que a
entrada da passkey tenha concluído o processamento. Embora o autenticador virtual forneça
uma maneira de esperar que uma entrada de passkey bem-sucedida seja processada ouvindo a
emissão de eventos (como será discutido na abordagem 2), atualmente não há uma maneira
integrada de detectar uma entrada de passkey com falha ou cancelada. Uma solução
alternativa seria simplesmente adicionar um tempo de espera fixo (hard timeout) para
aguardar a conclusão da operação da passkey antes de verificar se a UI de fato permaneceu
a mesma.

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

Em ambos os casos, a legibilidade do código de teste é limitada pela natureza implícita da
operação da passkey. Como mencionado anteriormente, também seria fácil ignorar quando uma
UI Condicional pode ser solicitada, caso em que a operação da passkey seria concluída
automaticamente sem o conhecimento do testador.

#### 6.1.2. Abordagem 2: Simulação Manual com `automaticPresenceSimulation` definido como `false`

Acionar manualmente uma entrada de passkey, alterando o valor da opção
`automaticPresenceSimulation`, resolve os problemas encontrados na abordagem anterior,
especialmente em termos de legibilidade do código de teste.

**Caso 1: Simulando uma entrada de passkey bem-sucedida**

Os trechos de código a seguir simulam uma entrada de passkey bem-sucedida:

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

...
});
```

A função auxiliar (helper function) pode ser bastante intimidadora à primeira vista. Ajuda
a entender que todas as complexidades técnicas de simular uma operação de passkey são
abstraídas na função auxiliar. Isso significa que, quando usada dentro do código de teste,
ela torna o código simples e claro, como pode ser visto no segundo trecho de código acima.

Comparada à abordagem implícita na Seção 6.1.1, esta abordagem explícita também aumenta a
legibilidade do código. Isso seria especialmente útil para quando uma UI Condicional é
solicitada, pois esta abordagem explícita impede a conclusão implícita e não intencional
da operação de passkey sem o conhecimento do desenvolvedor.

Agora, vamos entender cada parte da função auxiliar.

Primeiro, definimos a `promise` `operationCompleted`, que aguarda pelo evento
`WebAuthn.credentialAdded` ou pelo evento `WebAuthn.credentialAsserted`, que são, como os
nomes sugerem, emitidos quando uma credencial de passkey é registrada ou verificada,
respectivamente. Esta `promise` será usada mais tarde.

Em seguida, a opção `isUserVerified` é definida como `true`, para que a operação de
passkey subsequente pelo autenticador virtual WebAuthn seja bem-sucedida. A
`automaticPresenceSimulation` também é definida como `true`, para que o autenticador
virtual WebAuthn responda à próxima solicitação de passkey da página da web.

A espera (await) da `promise` `operationTrigger` é necessária para evitar uma condição de
corrida (race condition). A condição de corrida acontece quando a página da web solicita a
passkey antes que `automaticPresenceSimulation` seja definido como `true`. Para evitar
isso, a ação do usuário que aciona a solicitação de passkey deve ser executada depois que
`automaticPresenceSimulation` for definido como `true`. No exemplo acima, o usuário clica
no botão chamado `Create account with passkeys` para acionar a solicitação de passkey.

Após a conclusão da ação do usuário, devemos esperar que a operação de passkey
bem-sucedida seja concluída. Isso é feito aguardando a `promise` que definimos no início
da função auxiliar. A conclusão da operação de passkey bem-sucedida é marcada pela emissão
do evento `WebAuthn.credentialAdded` ou `WebAuthn.credentialAsserted`. No exemplo acima,
como o usuário está registrando uma passkey, o evento `WebAuthn.credentialAdded` seria
emitido.

Finalmente, a opção `automaticPresenceSimulation` é definida de volta para `false`, para
evitar que operações de passkey não intencionais ocorram mais tarde no código de teste.

**Caso 2: Simulando uma entrada de passkey cancelada**

Para uma entrada de passkey cancelada, devemos fazer uma pequena modificação na
implementação do caso anterior. No caso de uma entrada de passkey bem-sucedida, existem
eventos, nomeadamente `WebAuthn.credentialAdded` e `WebAuthn.credentialAsserted`, que são
emitidos após a conclusão da operação. No entanto, o autenticador virtual WebAuthn não
fornece nenhum evento para uma entrada de passkey cancelada ou com falha. Portanto,
devemos usar uma maneira alternativa para verificar a conclusão de uma operação de passkey
cancelada ou com falha.

Os trechos de código a seguir simulam uma entrada de passkey com falha:

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

Na função auxiliar, os ouvintes de eventos são substituídos por um parâmetro de `promise`
`postOperationCheck`, que aguarda a ocorrência de uma mudança esperada na UI antes que
`automaticPresenceSimulation` possa ser definido de volta para `false`.

No código de teste, a única diferença é que a função auxiliar deve ser chamada com uma
`promise` adicional que verifica a mudança pretendida na UI. No exemplo acima, verificamos
se a aplicação web navegou com sucesso para uma página em que o cabeçalho tem o texto
`Something went wrong...`.

Como foi discutido na Seção 6.1.1, cancelar uma entrada de passkey pode não levar a
nenhuma mudança observável na UI. Assim como no exemplo fornecido naquela seção, devemos
adicionar uma espera fixa (hard wait) antes de verificar se a UI de fato permaneceu a
mesma em tais 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. Como Testar a Criação de Passkey

A conveniência de usar um autenticador virtual WebAuthn é aprimorada por sua capacidade de
se comportar como um autenticador real no caso de
[criação de passkey](https://www.corbado.com/pt/blog/melhores-praticas-criacao-passkeys) ou exclusão pela
aplicação web. Um teste simplesmente precisa executar ações do usuário para simular a
criação ou exclusão de uma passkey na aplicação web, e o autenticador virtual WebAuthn
modifica automaticamente suas informações de credencial salvas sem nenhum trabalho
adicional do lado do código de teste.

Aqui está o exemplo de código de teste que verifica se a aplicação web registra uma nova
passkey no autenticador corretamente:

```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 trecho de código com os trechos da Seção 6.1, podemos testar o fluxo de
inscrição em nossa [página de demonstração](https://passkeys.eu/). O vídeo a seguir é uma
visualização do teste no modo de UI do Playwright:

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

### 6.3. Como Testar a Verificação de Passkey

Verificar uma credencial de passkey com o autenticador virtual WebAuthn funciona de forma
semelhante à criação de uma passkey, pois o autenticador virtual rastreia automaticamente
o número de verificações realizadas usando uma credencial específica.

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

...
});
```

O vídeo a seguir demonstra um teste para o fluxo de login em nossa página de demonstração:

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

### 6.4. Como Testar a Exclusão de Passkey

Excluir uma passkey de uma aplicação web, por outro lado, não deve modificar nenhuma
informação dentro do autenticador virtual WebAuthn. A aplicação web só deve ser capaz de
excluir credenciais salvas em seu próprio servidor. Apenas o próprio usuário deve ser
capaz de excluir consciente e manualmente uma credencial de passkey do 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);

...
});
```

O vídeo a seguir demonstra um teste para a exclusão de uma credencial de passkey em nossa
página de demonstração:

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

### 6.5. Como Simular Autenticação entre Dispositivos

A maneira mais intuitiva de simular uma autenticação entre dispositivos a partir de um
segundo dispositivo (que ainda não possui uma passkey registrada) é simplesmente adicionar
uma nova instância do autenticador virtual WebAuthn através do comando CDP, assim:

```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 a complexidade de gerenciar os IDs de múltiplos autenticadores virtuais,
também é possível simular um novo dispositivo simplesmente excluindo as credenciais de um
único autenticador e adicionando-as de volta quando necessário:

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

Essa abordagem pode simplificar especialmente a implementação no caso em que um novo
dispositivo precisa ser simulado, mas o dispositivo antigo não precisa mais ser usado.
Nesse caso, você simplesmente precisa limpar as credenciais do autenticador virtual e
descartá-las completamente:

```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 ao Autenticador Virtual WebAuthn

Explorar alternativas ao autenticador virtual WebAuthn pode oferecer flexibilidade na
forma como os processos de autenticação com passkey / WebAuthn são testados dentro dos
projetos.

### 7.1. Teste com Serviços de Simulação (Mock)

Desenvolver serviços ou endpoints de simulação (mock) pode simular eficazmente o
comportamento de autenticação, simplificando os testes ao abstrair as complexidades do
mecanismo de autenticação real. Essa abordagem é particularmente benéfica quando serviços
de autenticação externos estão em uso, permitindo que o foco permaneça na integração e
funcionalidade dos componentes do sistema sem aprofundar nos detalhes da autenticação.

### 7.2. Teste de Integração com Autenticadores Reais

Para um exame completo das funcionalidades de autenticação, o uso de autenticadores reais
para testes de integração fornece uma visão detalhada da interação com chaves de segurança
de hardware (por exemplo, YubiKeys) ou dispositivos biométricos (por exemplo, usados no
[Face ID](https://www.corbado.com/faq/is-face-id-passkey), Touch ID ou [Windows Hello](https://www.corbado.com/glossary/windows-hello)).
Embora normalmente conduzido manualmente devido à natureza complexa da integração de
dispositivos do mundo real em testes automatizados, é viável desenvolver scripts de
automação personalizados. Esses scripts podem conectar autenticadores reais com frameworks
de teste de ponta a ponta, oferecendo uma aproximação mais próxima dos cenários de usuário
reais e aumentando a confiabilidade do processo de autenticação em ambientes de produção.

## 8. Recomendações para Desenvolvedores

Após demonstrar as diferentes opções e apresentar trechos de código específicos para
testes E2E de passkeys / WebAuthn com Playwright, queremos também fornecer algumas
recomendações mais gerais para desenvolvedores novos no assunto.

### 8.1. Estude o Cenário de Frameworks de Teste E2E

Antes de mergulhar nos testes de passkeys ou de qualquer outro mecanismo de autenticação,
é essencial avaliar os frameworks de teste E2E disponíveis e escolher a opção mais
apropriada de acordo com os requisitos do seu projeto. Considere o equilíbrio entre a
velocidade e a estabilidade oferecidas por frameworks baseados em CDP, como Playwright e
Puppeteer, e a compatibilidade entre navegadores fornecida por frameworks baseados em
WebDriver, como Selenium e Nightwatch. Embora os frameworks baseados em CDP ofereçam
automação de navegador mais rápida e estável, eles são limitados a navegadores baseados em
Chromium. Em contraste, os frameworks baseados em WebDriver fornecem uma compatibilidade
mais ampla entre navegadores, incluindo suporte para navegadores não-Chromium como Firefox
e Safari, embora com um desempenho potencialmente mais lento e menos estável. Entender
esses equilíbrios ajudará você a tomar uma decisão informada e a selecionar o framework
que melhor se adapta às necessidades do seu projeto.

### 8.2. Entenda os Conceitos Subjacentes ao WebAuthn e às Passkeys

Embora o autenticador virtual WebAuthn simplifique o processo de teste de implementações
de passkey, é crucial que os desenvolvedores tenham um sólido entendimento dos conceitos
subjacentes ao padrão WebAuthn e às passkeys. Familiarize-se com as diferentes
configurações disponíveis para o autenticador virtual WebAuthn, como `protocol`,
`transport`, `hasResidentKey`, `hasUserVerification` e `isUserVerified`. Entender essas
configurações permitirá que você ajuste o autenticador virtual para simular vários
cenários de autenticação com precisão. Além disso, aprofunde-se nas complexidades da
autenticação com passkey, incluindo sua integração com diferentes navegadores e
dispositivos, bem como possíveis considerações de segurança. Esse conhecimento fundamental
o capacitará a projetar estratégias de teste abrangentes e eficazes para a autenticação
com passkey em suas aplicações web.

## 9. Resumo

Este guia aprofundou o uso do autenticador virtual WebAuthn do CDP com o Playwright,
destacando conceitos avançados e abordando questões não cobertas na documentação oficial.
Também exploramos alternativas ao CDP dentro do Playwright e de outros frameworks de teste
E2E. Apesar das implementações variadas, as especificações padronizadas do autenticador
virtual WebAuthn garantem a relevância deste guia em diferentes protocolos de automação
web e frameworks de teste de ponta a ponta. Para aprender mais a fundo sobre diferentes
conceitos relacionados a passkeys, consulte nosso [glossário ](#)de terminologias
relevantes que podem ajudá-lo a ajustar o autenticador virtual WebAuthn com base em suas
necessidades.
