Pelajari cara menyiapkan pengujian E2E untuk passkey di berbagai browser dengan Playwright, Nightwatch, Selenium, dan Puppeteer menggunakan WebAuthn virtual authenticator.
Anders
Created: June 17, 2025
Updated: June 24, 2025
Misi kami adalah menjadikan Internet tempat yang lebih aman, dan standar login baru, passkey, menyediakan solusi yang unggul untuk mencapainya. Itulah mengapa kami ingin membantu Anda memahami passkey dan karakteristiknya dengan lebih baik.
Passkey menjadi semakin diterima secara luas sebagai metode autentikasi, dengan mengandalkan Web Authentication (WebAuthn) sebagai standar dasarnya. Popularitasnya yang meningkat cukup baru, yang membuat dokumentasi dan sumber daya lainnya relatif langka. Hal ini, ditambah dengan sifat implementasi passkey yang kompleks, dapat menyulitkan developer untuk menemukan informasi yang relevan tentang perancangan, implementasi, dan terutama pengujian passkey untuk platform dan layanan mereka.
Panduan ini bertujuan untuk mengisi celah tersebut, dengan fokus pada aspek-aspek WebAuthn virtual authenticator yang tidak dibahas secara menyeluruh dalam dokumentasi resminya. Misalnya, kami membahas opsi konfigurasi untuk virtual authenticator yang tidak dapat dijelaskan dengan sendirinya dalam dokumentasi, serta solusi untuk kasus penggunaan tertentu yang tidak disediakan solusi yang mudah oleh virtual authenticator. Selain itu, panduan ini juga bermanfaat bagi developer yang hanya mencari contoh yang mudah diikuti untuk menggunakan virtual authenticator dalam kode pengujian.
Panduan kami menggunakan contoh dari Playwright untuk memberikan panduan sederhana untuk menguji implementasi passkey secara efektif di proyek Anda. Playwright adalah kerangka kerja pengujian end-to-end (E2E) yang menggunakan Chrome DevTools Protocol (CDP) sebagai protokol untuk automasi browser. Jika Anda secara khusus mencari contoh teknis pengujian passkey di Playwright, Anda dapat langsung melompat ke Bagian 5. Di sisi lain, jika Anda menggunakan kerangka kerja pengujian E2E lain seperti Puppeteer atau Selenium dan ingin menguji passkey pada kerangka kerja ini, implementasi kode pengujian akan identik atau sangat mirip dengan contoh yang diberikan dalam panduan ini, tergantung pada kerangka kerja mana yang Anda gunakan. Di bagian selanjutnya, kami memberikan latar belakang tentang berbagai kerangka kerja E2E dan seberapa relevan panduan ini untuk kerangka kerja tersebut.
Automasi browser, seperti namanya, adalah proses mengotomatiskan tindakan pengguna yang berulang di browser untuk tujuan scraping data web atau dalam kasus kami, menguji aplikasi web. WebDriver dan Chrome DevTools Protocol (CDP) adalah dua protokol automasi browser utama yang relevan untuk panduan ini, karena masing-masing menyediakan implementasi WebAuthn virtual authenticator.
WebDriver adalah antarmuka yang dikendalikan dari jarak jauh yang dapat dilihat sebagai perantara dalam komunikasi antara klien dan browser. Fokus protokol ini adalah untuk menyediakan antarmuka yang netral terhadap platform dan bahasa yang mendukung semua browser utama, termasuk yang tidak berbasis Chromium seperti Firefox dan Safari. Karena antarmuka WebDriver perlu mengelola koneksi dengan klien serta dengan browser, pendekatan ini mengorbankan kecepatan dan stabilitas dengan imbalan jangkauan dukungan browser yang lebih luas (yaitu, flakiness yang lebih tinggi). Klien WebDriver yang terkenal termasuk Selenium dan Nightwatch.
Diambil dari jankaritech
Chrome DevTools Protocol (CDP), di sisi lain, tidak memiliki perantara seperti antarmuka WebDriver antara klien dan browser. Selain itu, komunikasi antara klien dan browser terjadi melalui koneksi socket, berbeda dengan koneksi HTTP yang lebih lambat antara klien dan antarmuka WebDriver pada pendekatan sebelumnya. Poin-poin ini membuat CDP jauh lebih cepat dan tidak terlalu flaky dibandingkan WebDriver. Kelemahannya adalah protokol ini hanya didukung untuk browser berbasis Chromium seperti Chrome dan Edge. Playwright dan Puppeteer adalah contoh klien yang menggunakan CDP untuk berkomunikasi dengan browser.
Diambil dari jankaritech
Puppeteer, mirip dengan Playwright, adalah kerangka kerja E2E yang dibangun langsung di atas CDP. Ini berarti bahwa Puppeteer dan Playwright keduanya menggunakan implementasi WebAuthn virtual authenticator yang sama dan komunikasi API menggunakan WebAuthn virtual authenticator melalui koneksi socket juga identik.
Untuk mendemonstrasikannya, kami membandingkan kode pengujian di Playwright dan Puppeteer untuk memanggil metode getCredentials yang mengembalikan daftar semua kredensial yang terdaftar di virtual authenticator sejauh ini. Kami juga melampirkan event listener sederhana untuk event credentialAdded yang dipicu ketika kredensial passkey berhasil didaftarkan. Jangan terintimidasi oleh detail implementasinya, karena akan dijelaskan di bagian selanjutnya. Contoh-contoh ini hanya untuk menunjukkan seberapa mirip implementasi antara kedua kerangka kerja tersebut.
Ben Gould
Head of Engineering
I’ve built hundreds of integrations in my time, including quite a few with identity providers and I’ve never been so impressed with a developer experience as I have been with Corbado.
10,000+ devs trust Corbado & make the Internet safer with passkeys. Got questions? We've written 150+ blog posts on passkeys.
Join Passkeys CommunityPlaywright:
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:
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!'); });
Meskipun metode untuk menginisialisasi sesi CDP di awal kode pengujian sedikit berbeda, memanggil metode dan menangani event di API WebAuthn virtual authenticator CDP adalah identik. Ini berarti jika Anda ingin menggunakan WebAuthn virtual authenticator di Puppeteer, Anda dapat mengikuti panduan ini baris demi baris.
Selenium dan Nightwatch adalah kerangka kerja pengujian E2E yang mengandalkan WebDriver untuk automasi browser. Meskipun implementasi WebAuthn virtual authenticator untuk WebDriver terpisah dari implementasinya untuk CDP, spesifikasi API mereka serupa. Untuk hampir setiap metode di API WebAuthn virtual authenticator CDP, Anda dapat menemukan metode yang sesuai di API WebAuthn virtual authenticator WebDriver. Namun, satu hal yang perlu diperhatikan adalah meskipun dimungkinkan untuk melampirkan event listener saat passkey berhasil ditambahkan atau ditegaskan di API WebAuthn virtual authenticator CDP, hal ini tidak dimungkinkan di rekan WebDriver-nya.
Selenium:
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();
Terbukti bahwa sintaks untuk menyiapkan instance virtual authenticator dan melakukan panggilan API berbeda dari implementasi CDP yang sesuai. Namun, karena spesifikasi API dari kedua WebAuthn virtual authenticator sangat mirip, akan layak untuk mengikuti panduan ini untuk menulis implementasi yang sesuai pada kerangka kerja pengujian E2E berbasis WebDriver.
Cypress adalah kerangka kerja pengujian E2E yang tidak dibangun terutama di atas WebDriver atau CDP seperti kerangka kerja yang disebutkan di atas. Ia menggunakan JavaScript asli untuk berkomunikasi dengan browser. Namun, ia menyediakan akses tingkat rendah ke CDP, yang berarti dimungkinkan untuk mengirim perintah CDP mentah untuk memanfaatkan WebAuthn virtual authenticator CDP.
Karena sintaks untuk akses tingkat rendah ini membosankan dan sangat berbeda dari contoh di atas, kami tidak akan membahas detailnya dalam panduan ini. Namun, informasi lebih lanjut tentang cara memanggil perintah CDP di Cypress dijelaskan dalam panduan ini. Konsep gambaran besar untuk menggunakan WebAuthn virtual authenticator CDP yang disajikan dalam panduan ini masih relevan bagi mereka yang ingin menguji passkey di Cypress.
Ada banyak alasan mengapa pengujian implementasi passkey secara alami lebih menantang daripada tindakan pengguna lain yang lebih sederhana di lingkungan web. Kebutuhan untuk menangani interaksi pengguna dinamis yang terlibat dengan autentikasi biometrik, seperti pemindaian sidik jari atau pengenalan wajah, menambah lapisan kompleksitas yang mungkin tidak praktis untuk ditangani secara detail saat menulis pengujian. Karena keamanan secara alami menjadi perhatian utama dalam konteks autentikasi, juga perlu untuk memastikan bahwa autentikasi passkey terintegrasi dengan mulus di berbagai browser dan perangkat tanpa ada ruang untuk kerentanan keamanan.
Menyederhanakan kompleksitas penanganan interaksi pengguna dinamis yang terlibat dalam operasi passkey, serta menguji integrasinya ke berbagai browser dan perangkat, menjadi lebih mudah menggunakan WebAuthn virtual authenticator.
WebAuthn virtual authenticator adalah representasi perangkat lunak dari model authenticator yang ditentukan dalam standar WebAuthn. Ini meniru perilaku perangkat authenticator fisik, seperti kunci keamanan perangkat keras (misalnya YubiKey) atau pemindai biometrik (misalnya yang digunakan di Face ID, Touch ID, atau Windows Hello), tetapi beroperasi sepenuhnya dalam perangkat lunak (jadi tidak ada autentikasi fisik atau pemindaian biometrik yang terlibat).
Ada dua manfaat utama dari WebAuthn virtual authenticator.
Karena WebDriver dan CDP adalah alat automasi browser, jelas bahwa kasus penggunaan utama dari implementasi WebAuthn virtual authenticator dalam protokol ini adalah pengujian otomatis. Dengan memanfaatkan protokol ini, virtual authenticator memungkinkan pengujian fungsionalitas passkey yang sederhana namun komprehensif di lingkungan yang terkontrol seperti kerangka kerja pengujian E2E (misalnya Playwright, Cypress, Nightwatch).
WebAuthn virtual authenticator CDP juga dapat diakses melalui DevTools browser Chrome, dan dapat digunakan untuk pengujian manual atau hanya untuk tujuan demonstrasi. Dengan fitur ini Anda dapat mensimulasikan input passkey pada perangkat yang tidak mendukung passkey secara native. Sejalan dengan itu, juga dimungkinkan untuk mensimulasikan lingkungan yang tidak didukung passkey pada perangkat yang mendukung passkey.
Tangkapan layar di atas menunjukkan contoh penggunaan virtual authenticator di Chrome untuk tujuan pengujian manual atau demonstrasi. Anda dapat melihat bahwa berbagai opsi konfigurasi untuk virtual authenticator dimungkinkan, dan penambahan serta penghapusan kredensial juga dapat dilacak. Rujuk ke panduan ini dari Google untuk informasi lebih lanjut tentang penggunaan virtual authenticator di browser Anda, termasuk opsi konfigurasi dan nilai yang direkomendasikan untuk masing-masing.
Meskipun WebAuthn virtual authenticator adalah solusi yang elegan untuk menguji implementasi passkey, ada beberapa kekurangan yang perlu diperhatikan.
Sebagai solusi yang murni berbasis perangkat lunak, WebAuthn virtual authenticator tidak dapat mereplikasi karakteristik perangkat keras yang unik dan fitur keamanan dari authenticator fisik. Perbedaan antara menggunakan berbagai platform authenticator (yang terpasang di perangkat, seperti pemindai biometrik di smartphone) dan berbagai cross-platform authenticator (yang merupakan perangkat eksternal, seperti kunci keamanan perangkat keras) tidak dapat disimulasikan menggunakan WebAuthn virtual authenticator. Meskipun penyederhanaan black-box dari kompleksitas yang terlibat dengan berbagai jenis platform dan cross-platform authenticator adalah salah satu keuntungan menggunakan WebAuthn virtual authenticator, jika Anda ingin mensimulasikan dan menguji nuansa dari berbagai jenis authenticator, solusi lain harus dieksplorasi.
Mengingat adopsi WebAuthn yang relatif baru dan kebaruan teknologi passkey, ekosistem di sekitar virtual authenticator masih dalam tahap pematangan. Hal ini mengakibatkan kelangkaan dokumentasi yang komprehensif dan tantangan teknis yang belum terselesaikan, terutama dalam konteks mengintegrasikan virtual authenticator dengan kerangka kerja pengujian otomatis. Panduan ini bertujuan untuk mengatasi masalah ini dengan memberikan wawasan komprehensif tentang pengujian passkey di lingkungan pengujian otomatis, sambil juga berfokus pada mengatasi ketidaknyamanan yang masih ada dalam menggunakan alat-alat ini dan menyajikan solusi untuk masalah-masalah ini.
Setelah instalasi Playwright dan dependensinya berhasil, Anda dapat langsung mulai menulis pengujian pertama Anda dengan membuat file dengan nama yang diakhiri dengan .spec.ts atau .test.ts dengan konten berikut:
import { test, expect } from "@playwright/test"; test("my first test", async ({ page }) => { await page.goto("https://passkeys.eu"); // start simulating user actions });
Untuk menggunakan WebAuthn virtual authenticator di Playwright, cukup dengan memulai sesi CDP dan melampirkan virtual authenticator di awal kasus pengujian, sebagai berikut:
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 ... });
Opsi untuk mengonfigurasi WebAuthn virtual authenticator:
Di bagian ini, kita akan menjelajahi penggunaan metode dan event WebAuthn virtual authenticator dalam konteks kasus penggunaan umum dan khusus.
Ini mungkin tugas yang paling penting namun membingungkan saat menggunakan WebAuthn virtual authenticator dalam kode pengujian, karena tidak ada metode bawaan yang eksplisit untuk memicu input passkey. Solusinya terletak pada opsi konfigurasi WebAuthn virtual authenticator yaitu, isUserVerified dan automaticPresenceSimulation. Dengan opsi ini kita dapat mensimulasikan interaksi pengguna ini melalui dua pendekatan berbeda yang dijelaskan di bawah ini.
Kasus 1: Mensimulasikan input passkey yang berhasil
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!'); ... });
Mensimulasikan input passkey yang berhasil biasanya tidak memerlukan baris tambahan dalam kode pengujian. Baris terakhir (await expect...) menunggu halaman berubah (dipicu oleh input passkey yang berhasil secara implisit).
Kasus 2: Mensimulasikan input passkey yang dibatalkan (yang tidak memicu perubahan pada UI)
Menguji input passkey yang gagal atau dibatalkan lebih rumit karena mungkin tidak menyebabkan perubahan yang dapat diamati pada UI. Dengan kata lain, menunggu halaman berubah seperti pada contoh sebelumnya tidak cukup untuk memastikan bahwa input passkey telah selesai diproses. Memeriksa bahwa halaman tidak berubah setelah input passkey implisit tidak ada artinya, karena pemeriksaan hampir pasti akan terjadi sebelum input passkey selesai diproses. Meskipun virtual authenticator menyediakan cara untuk menunggu input passkey yang berhasil diproses dengan mendengarkan emisi event (seperti yang akan dibahas dalam pendekatan 2), saat ini tidak ada cara bawaan untuk mendeteksi input passkey yang gagal atau dibatalkan. Solusinya adalah dengan menambahkan timeout keras untuk menunggu operasi passkey selesai sebelum memeriksa bahwa UI memang tetap sama.
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 ... });
Dalam kedua kasus, keterbacaan kode pengujian dibatasi oleh sifat implisit dari operasi passkey. Seperti yang disebutkan sebelumnya, akan mudah juga untuk mengabaikan kapan Conditional UI mungkin diminta, dalam hal ini operasi passkey akan selesai secara otomatis tanpa sepengetahuan penguji.
Memicu input passkey secara manual dengan mengubah nilai opsi automaticPresenceSimulation menyelesaikan masalah yang dihadapi pada pendekatan sebelumnya, yaitu dalam hal keterbacaan kode pengujian.
Kasus 1: Mensimulasikan input passkey yang berhasil
Cuplikan kode berikut mensimulasikan input passkey yang berhasil:
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, }); }
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() ); ... });
Fungsi pembantu (helper function) mungkin cukup mengintimidasi saat Anda melihatnya untuk pertama kali. Akan membantu untuk memahami bahwa semua kompleksitas teknis dalam mensimulasikan operasi passkey diabstraksikan ke dalam fungsi pembantu. Ini berarti bahwa ketika digunakan di dalam kode pengujian, itu membuat kode menjadi sederhana dan jelas, seperti yang dapat dilihat pada cuplikan kode kedua di atas.
Dibandingkan dengan pendekatan implisit di Bagian 6.1.1, pendekatan eksplisit ini juga meningkatkan keterbacaan kode. Ini akan sangat membantu ketika Conditional UI diminta, karena pendekatan eksplisit ini mencegah penyelesaian operasi passkey yang tidak disengaja dan implisit tanpa sepengetahuan developer.
Sekarang mari kita pahami setiap bagian dari fungsi pembantu.
Pertama, kita mendefinisikan promise operationCompleted yang menunggu event WebAuthn.credentialAdded atau event WebAuthn.credentialAsserted, yang, seperti namanya, dipancarkan ketika kredensial passkey berhasil didaftarkan atau diverifikasi. Promise ini akan digunakan nanti.
Selanjutnya, opsi isUserVerified diatur ke true, sehingga operasi passkey berikutnya oleh WebAuthn virtual authenticator akan berhasil. automaticPresenceSimulation juga diatur ke true, sehingga WebAuthn virtual authenticator akan merespons prompt passkey berikutnya dari halaman web.
Menunggu promise operationTrigger diperlukan untuk menghindari race condition. Race condition terjadi ketika halaman web meminta passkey sebelum automaticPresenceSimulation diatur ke true. Untuk mencegah ini, tindakan pengguna yang memicu prompt passkey harus dilakukan setelah automaticPresenceSimulation diatur ke true. Dalam contoh di atas, pengguna mengklik tombol bernama Create account with passkeys untuk memicu prompt passkey.
Setelah tindakan pengguna selesai, kita harus menunggu operasi passkey yang berhasil selesai. Ini dilakukan dengan menunggu promise yang kita definisikan di awal fungsi pembantu. Penyelesaian operasi passkey yang berhasil ditandai dengan pancaran event WebAuthn.credentialAdded atau WebAuthn.credentialAsserted. Dalam contoh di atas, karena pengguna mendaftarkan passkey, event WebAuthn.credentialAdded akan dipancarkan.
Akhirnya, opsi automaticPresenceSimulation diatur kembali ke false, untuk mencegah operasi passkey yang tidak disengaja terjadi nanti dalam kode pengujian.
Kasus 2: Mensimulasikan input passkey yang dibatalkan
Untuk input passkey yang dibatalkan, kita harus membuat sedikit modifikasi pada implementasi untuk kasus sebelumnya. Dalam kasus input passkey yang berhasil, ada event, yaitu WebAuthn.credentialAdded dan WebAuthn.credentialAsserted, yang dipancarkan setelah penyelesaian operasi. Namun, WebAuthn virtual authenticator tidak menyediakan event apa pun untuk input passkey yang dibatalkan atau gagal. Jadi, kita harus menggunakan cara alternatif untuk memeriksa penyelesaian operasi passkey yang dibatalkan atau gagal.
Cuplikan kode berikut mensimulasikan input passkey yang gagal:
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, }); }
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 ... });
Dalam fungsi pembantu, event listener diganti dengan parameter promise postOperationCheck yang menunggu perubahan UI yang diharapkan terjadi sebelum automaticPresenceSimulation dapat diatur kembali ke false.
Dalam kode pengujian, satu-satunya perbedaan adalah bahwa fungsi pembantu harus dipanggil dengan promise tambahan yang memeriksa perubahan UI yang dimaksud. Dalam contoh di atas, kami memeriksa bahwa aplikasi web telah berhasil menavigasi ke halaman di mana header memiliki teks Something went wrong....
Seperti yang dibahas di Bagian 6.1.1, membatalkan input passkey mungkin tidak menyebabkan perubahan yang dapat diamati pada UI. Seperti contoh yang diberikan di bagian itu, kita harus menambahkan penantian keras (hard wait) sebelum memeriksa bahwa UI memang tetap sama dalam kasus seperti itu:
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'); } ); ... });
Kenyamanan menggunakan WebAuthn virtual authenticator ditingkatkan oleh kemampuannya untuk berperilaku seperti authenticator nyata dalam hal pembuatan atau penghapusan passkey oleh aplikasi web. Sebuah pengujian hanya perlu melakukan tindakan pengguna untuk mensimulasikan pembuatan atau penghapusan passkey pada aplikasi web, dan WebAuthn virtual authenticator secara otomatis memodifikasi informasi kredensial yang disimpannya tanpa pekerjaan tambahan dari sisi kode pengujian.
Berikut adalah contoh kode pengujian yang memeriksa bahwa aplikasi web mendaftarkan passkey baru ke authenticator dengan benar:
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); ... });
Menggabungkan cuplikan kode ini dengan cuplikan kode dari Bagian 6.1, kita dapat menguji alur pendaftaran di halaman web demo kami. Video berikut adalah visualisasi pengujian dalam mode UI Playwright:
Memverifikasi kredensial passkey dengan WebAuthn virtual authenticator bekerja mirip dengan membuat passkey, di mana virtual authenticator secara otomatis melacak jumlah verifikasi yang dilakukan menggunakan kredensial tertentu.
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); ... });
Video berikut mendemonstrasikan pengujian untuk alur login di halaman web demo kami:
Menghapus passkey dari aplikasi web, di sisi lain, seharusnya tidak mengubah informasi apa pun di dalam WebAuthn virtual authenticator. Aplikasi web seharusnya hanya dapat menghapus kredensial yang disimpan di servernya sendiri. Hanya pengguna itu sendiri yang seharusnya dapat secara sadar dan manual menghapus kredensial passkey dari WebAuthn virtual authenticator.
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); ... });
Video berikut mendemonstrasikan pengujian untuk penghapusan kredensial passkey di halaman web demo kami:
Cara paling intuitif untuk mensimulasikan autentikasi lintas perangkat dari perangkat kedua (yang belum memiliki passkey terdaftar) adalah dengan hanya menambahkan instance baru dari WebAuthn virtual authenticator melalui perintah CDP, seperti ini:
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 .. });
Untuk menghindari kompleksitas mengelola ID dari beberapa virtual authenticator, juga dimungkinkan untuk mensimulasikan perangkat baru dengan hanya menghapus kredensial dari satu authenticator, dan menambahkannya kembali saat dibutuhkan:
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 ... });
Pendekatan ini terutama dapat menyederhanakan implementasi dalam kasus di mana perangkat baru perlu disimulasikan, tetapi perangkat lama tidak perlu digunakan lagi. Dalam hal ini, Anda hanya perlu membersihkan kredensial dari virtual authenticator dan membuang kredensialnya sama sekali:
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 ... });
Menjelajahi alternatif untuk WebAuthn virtual authenticator dapat menawarkan fleksibilitas dalam cara proses autentikasi passkey / WebAuthn diuji dalam proyek.
Mengembangkan layanan atau endpoint mock dapat secara efektif mensimulasikan perilaku autentikasi, menyederhanakan pengujian dengan mengabstraksi seluk-beluk mekanisme autentikasi yang sebenarnya. Pendekatan ini sangat bermanfaat ketika layanan autentikasi eksternal digunakan, memungkinkan fokus tetap pada integrasi dan fungsionalitas komponen sistem tanpa harus mendalami spesifik autentikasi.
Untuk pemeriksaan menyeluruh fungsionalitas autentikasi, menggunakan authenticator nyata untuk pengujian integrasi memberikan wawasan terperinci tentang interaksi dengan kunci keamanan perangkat keras (misalnya YubiKeys) atau perangkat biometrik (misalnya yang digunakan di Face ID, Touch ID, atau Windows Hello). Meskipun biasanya dilakukan secara manual karena sifat kompleks mengintegrasikan perangkat dunia nyata ke dalam pengujian otomatis, dimungkinkan untuk mengembangkan skrip automasi kustom. Skrip ini dapat menjembatani authenticator nyata dengan kerangka kerja pengujian end-to-end, menawarkan perkiraan yang lebih dekat dengan skenario pengguna nyata dan meningkatkan keandalan proses autentikasi di lingkungan langsung.
Setelah mendemonstrasikan berbagai opsi dan menampilkan cuplikan kode spesifik untuk pengujian E2E passkey / WebAuthn dengan Playwright, kami juga ingin memberikan beberapa rekomendasi yang lebih umum untuk developer yang baru mengenal topik ini.
Sebelum terjun ke pengujian passkey atau mekanisme autentikasi lainnya, penting untuk menilai kerangka kerja pengujian E2E yang tersedia dan memilih opsi yang paling sesuai dengan kebutuhan proyek Anda. Pertimbangkan trade-off antara kecepatan dan stabilitas yang ditawarkan oleh kerangka kerja berbasis CDP seperti Playwright dan Puppeteer, dan kompatibilitas lintas-browser yang disediakan oleh kerangka kerja berbasis WebDriver seperti Selenium dan Nightwatch. Meskipun kerangka kerja berbasis CDP menawarkan automasi browser yang lebih cepat dan lebih stabil, mereka terbatas pada browser berbasis Chromium. Sebaliknya, kerangka kerja berbasis WebDriver menyediakan kompatibilitas lintas-browser yang lebih luas, termasuk dukungan untuk browser non-Chromium seperti Firefox dan Safari, meskipun dengan kinerja yang berpotensi lebih lambat dan kurang stabil. Memahami trade-off ini akan membantu Anda membuat keputusan yang tepat dan memilih kerangka kerja yang paling sesuai dengan kebutuhan proyek Anda.
Meskipun WebAuthn virtual authenticator menyederhanakan proses pengujian implementasi passkey, sangat penting bagi developer untuk memiliki pemahaman yang kuat tentang konsep dasar di balik standar WebAuthn dan passkey. Biasakan diri Anda dengan berbagai konfigurasi yang tersedia untuk WebAuthn virtual authenticator, seperti protocol, transport, hasResidentKey, hasUserVerification, dan isUserVerified. Memahami konfigurasi ini akan memungkinkan Anda untuk menyempurnakan virtual authenticator untuk mensimulasikan berbagai skenario autentikasi secara akurat. Selain itu, selami seluk-beluk autentikasi passkey, termasuk integrasinya dengan berbagai browser dan perangkat, serta pertimbangan keamanan yang potensial. Pengetahuan dasar ini akan memberdayakan Anda untuk merancang strategi pengujian yang komprehensif dan efektif untuk autentikasi passkey di aplikasi web Anda.
Panduan ini membahas penggunaan WebAuthn virtual authenticator CDP dengan Playwright, menyoroti konsep-konsep lanjutan dan mengatasi masalah yang tidak tercakup dalam dokumentasi resmi. Kami juga menjelajahi alternatif untuk CDP dalam Playwright dan kerangka kerja pengujian E2E lainnya. Meskipun implementasinya bervariasi, spesifikasi WebAuthn virtual authenticator yang terstandarisasi memastikan relevansi panduan ini di berbagai protokol automasi web dan kerangka kerja pengujian end-to-end. Untuk mempelajari lebih dalam tentang berbagai konsep mengenai passkey, rujuk ke glosarium kami tentang terminologi relevan yang mungkin membantu Anda menyempurnakan WebAuthn virtual authenticator berdasarkan kebutuhan Anda.
Enjoyed this read?
🤝 Join our Passkeys Community
Share passkeys implementation tips and get support to free the world from passwords.
🚀 Subscribe to Substack
Get the latest news, strategies, and insights about passkeys sent straight to your inbox.
Related Articles
Table of Contents