تعلم كيفية إعداد اختبار E2E لمفاتيح المرور عبر المتصفحات باستخدام Playwright وNightwatch وSelenium وPuppeteer والمصادق الافتراضي WebAuthn.
Anders
Created: June 17, 2025
Updated: June 20, 2025
مهمتنا هي جعل الإنترنت مكانًا أكثر أمانًا، ويوفر معيار login الجديد "مفاتيح المرور" حلاً فائقًا لتحقيق ذلك. لهذا السبب نريد مساعدتك على فهم مفاتيح المرور وخصائصها بشكل أفضل.
تكتسب مفاتيح المرور قبولاً واسعًا كوسيلة للمصادقة، معتمدة على معيار المصادقة عبر الويب (WebAuthn) كأساس لها. إن ازدياد شعبيتها حديث نسبيًا، مما يجعل التوثيق والموارد الأخرى نادرة إلى حد ما. هذا الأمر، بالإضافة إلى الطبيعة المعقدة لتطبيق مفاتيح المرور، يمكن أن يجعل من الصعب على المطورين العثور على معلومات ذات صلة بتصميم وتنفيذ، وخاصة اختبار، مفاتيح المرور لمنصاتهم وخدماتهم.
يهدف هذا الدليل إلى سد هذه الفجوة، مع التركيز على جوانب المصادق الافتراضي WebAuthn التي لم يتم تغطيتها بشكل شامل في توثيقه الرسمي. على سبيل المثال، نناقش خيارات التكوين للمصادق الافتراضي التي ليست بديهية في التوثيق، بالإضافة إلى حلول بديلة لبعض حالات الاستخدام التي لا يوفر لها المصادق الافتراضي حلاً مناسبًا. بخلاف ذلك، يعد هذا الدليل مفيدًا أيضًا للمطورين الذين يبحثون ببساطة عن أمثلة سهلة المتابعة لاستخدام المصادق الافتراضي في كود الاختبار.
يستخدم دليلنا أمثلة من Playwright لتقديم شرح بسيط لاختبار تطبيق مفاتيح المرور في مشروعك بفعالية. Playwright هو إطار عمل للاختبار الشامل (E2E) يستخدم بروتوكول أدوات مطوري Chrome (CDP) كبروتوكول لأتمتة المتصفح. إذا كنت تبحث تحديدًا عن أمثلة تقنية لاختبار مفاتيح المرور في Playwright، يمكنك الانتقال مباشرة إلى القسم 5. من ناحية أخرى، إذا كنت تستخدم أطر عمل اختبار E2E أخرى مثل Puppeteer أو Selenium وتتطلع إلى اختبار مفاتيح المرور على هذه الأطر، فإن تطبيقات كود الاختبار ستكون متطابقة أو مشابهة جدًا للأمثلة المقدمة في هذا الدليل، اعتمادًا على إطار العمل الذي تستخدمه. في القسم التالي، نقدم خلفية عن أطر عمل E2E المختلفة ومدى صلة هذا الدليل بهذه الأطر.
Recent Articles
📖
مفاتيح المرور في التطبيقات الأصلية: التنفيذ الأصلي مقابل التنفيذ عبر WebView
👤
استكشاف أخطاء مفاتيح المرور وإصلاحها: حلول لمشكلات وأخطاء مفاتيح المرور
👤
كيفية تمكين مفاتيح المرور على نظام ويندوز
⚙️
اختبار مفاتيح المرور الشامل (E2E) باستخدام Playwright عبر المصادق الافتراضي WebAuthn
⚙️
دليل تعليمي حول مفاتيح المرور: كيفية تطبيقها في تطبيقات الويب
أتمتة المتصفح، كما يوحي الاسم، هي عملية أتمتة الإجراءات المتكررة للمستخدم على المتصفح لأغراض استخلاص البيانات من الويب أو، في حالتنا، اختبار تطبيقات الويب. يعد WebDriver وبروتوكول أدوات مطوري Chrome (CDP) من بروتوكولات أتمتة المتصفح الرئيسية ذات الصلة بهذا الدليل، حيث يوفر كل منهما تطبيقًا للمصادق الافتراضي WebAuthn.
WebDriver هي واجهة يتم التحكم فيها عن بعد يمكن اعتبارها وسيطًا في الاتصال بين العميل والمتصفح. يركز هذا البروتوكول على توفير واجهة محايدة للمنصة واللغة تدعم جميع المتصفحات الرئيسية، بما في ذلك تلك التي لا تعتمد على Chromium مثل Firefox و Safari. نظرًا لأن واجهة WebDriver تحتاج إلى إدارة اتصال مع العميل وكذلك مع المتصفح، فإن هذا النهج يضحي بالسرعة والاستقرار مقابل نطاق أوسع من دعم المتصفحات (أي تقشر أعلى). من بين عملاء WebDriver البارزين Selenium و Nightwatch.
مأخوذ من jankaritech
من ناحية أخرى، لا يحتوي بروتوكول أدوات مطوري Chrome (CDP) على وسيط مثل واجهة WebDriver بين العميل والمتصفح. بالإضافة إلى ذلك، يتم الاتصال بين العميل والمتصفح عبر اتصال socket، على عكس اتصال HTTP الأبطأ بين العميل وواجهة WebDriver في النهج السابق. هذه النقاط تجعل CDP أسرع بكثير وأقل تقشرًا من WebDriver. الجانب السلبي هو أن هذا البروتوكول مدعوم فقط للمتصفحات القائمة على Chromium مثل Chrome و Edge. Playwright و Puppeteer هما مثالان للعملاء الذين يستخدمون CDP للتواصل مع المتصفحات.
مأخوذ من jankaritech
Puppeteer، على غرار Playwright، هو إطار عمل E2E مبني مباشرة على CDP. هذا يعني أن Puppeteer و Playwright يستخدمان نفس تطبيق المصادق الافتراضي WebAuthn وأن اتصال API باستخدام المصادق الافتراضي WebAuthn عبر اتصال socket متطابق أيضًا.
للتوضيح، نقارن كود الاختبار في كل من Playwright و Puppeteer لاستدعاء طريقة getCredentials التي تُرجع قائمة بجميع بيانات الاعتماد المسجلة في المصادق الافتراضي حتى الآن. نرفق أيضًا مستمع أحداث بسيط لحدث credentialAdded الذي يتم تشغيله عند تسجيل بيانات اعتماد مفتاح المرور بنجاح. لا تدع تفاصيل التنفيذ تخيفك، حيث سيتم شرحها في الأقسام اللاحقة. هذه الأمثلة هي ببساطة لإظهار مدى تشابه التطبيقات بين إطاري العمل.
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!'); });
بينما كانت طرق تهيئة جلسة CDP في بداية أكواد الاختبار مختلفة قليلاً، فإن استدعاء الطرق ومعالجة الأحداث في واجهة برمجة تطبيقات المصادق الافتراضي WebAuthn لـ CDP متطابقة. هذا يعني أنه إذا كنت تتطلع إلى استخدام المصادق الافتراضي WebAuthn في Puppeteer، فيمكنك اتباع هذا الدليل سطراً بسطر.
Selenium و Nightwatch هما إطارا عمل لاختبار E2E يعتمدان على WebDriver لأتمتة المتصفح. في حين أن تطبيق المصادق الافتراضي WebAuthn لـ WebDriver منفصل عن تطبيقه لـ CDP، فإن مواصفات واجهة برمجة التطبيقات الخاصة بهما متشابهة. لكل طريقة تقريبًا في واجهة برمجة تطبيقات المصادق الافتراضي WebAuthn لـ CDP، يمكنك العثور على طريقة مقابلة في واجهة برمجة تطبيقات المصادق الافتراضي WebAuthn لـ WebDriver. ومع ذلك، تجدر الإشارة إلى أنه بينما كان من الممكن إرفاق مستمعي الأحداث عند إضافة مفتاح مرور أو تأكيده بنجاح في واجهة برمجة تطبيقات المصادق الافتراضي WebAuthn لـ CDP، فإن هذا غير ممكن في نظيره WebDriver.
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();
من الواضح أن بناء جملة إعداد مثيل المصادق الافتراضي وإجراء استدعاءات API يختلف عن تطبيق CDP المقابل. ومع ذلك، نظرًا لأن مواصفات API لمصادقي WebAuthn الافتراضيين متشابهة جدًا، فسيكون من الممكن اتباع هذا الدليل لكتابة تطبيق مقابل على إطار عمل اختبار E2E قائم على WebDriver.
Cypress هو إطار عمل اختبار E2E لا يعتمد بشكل أساسي على WebDriver أو CDP مثل الأطر المذكورة أعلاه. يستخدم JavaScript الأصلي للتواصل مع المتصفح. ومع ذلك، فإنه يوفر وصولاً منخفض المستوى إلى CDP، مما يعني أنه من الممكن إرسال أوامر CDP أولية لاستخدام المصادق الافتراضي WebAuthn الخاص بـ CDP.
نظرًا لأن بناء الجملة لهذا الوصول منخفض المستوى ممل ومختلف تمامًا عن الأمثلة المذكورة أعلاه، فلن ندخل في التفاصيل في هذا الدليل. ومع ذلك، يتم شرح مزيد من المعلومات حول كيفية استدعاء أوامر CDP في Cypress في هذا الدليل. لا تزال المفاهيم العامة لاستخدام المصادق الافتراضي WebAuthn لـ CDP المقدمة في هذا الدليل ذات صلة لأولئك الذين يسعون إلى اختبار مفاتيح المرور على Cypress.
هناك العديد من الأسباب التي تجعل اختبار تطبيق مفاتيح المرور أكثر صعوبة بشكل طبيعي من إجراءات المستخدم الأخرى الأبسط في بيئة الويب. تضيف الحاجة إلى التعامل مع تفاعلات المستخدم الديناميكية المتضمنة في المصادقة البيومترية، مثل مسح بصمات الأصابع أو التعرف على الوجه، طبقة من التعقيد قد لا يكون من العملي معالجتها بالتفصيل أثناء كتابة الاختبارات. نظرًا لأن الأمان يمثل بطبيعة الحال مصدر قلق كبير في سياق المصادقة، فمن الضروري أيضًا التأكد من أن مصادقة مفتاح المرور مدمجة بسلاسة عبر مختلف المتصفحات والأجهزة دون ترك مجال للثغرات الأمنية.
يتم تسهيل تبسيط تعقيد التعامل مع تفاعلات المستخدم الديناميكية المتضمنة في عمليات مفاتيح المرور، بالإضافة إلى اختبار تكاملها في متصفحات وأجهزة مختلفة، باستخدام المصادق الافتراضي WebAuthn.
المصادق الافتراضي WebAuthn هو تمثيل برمجي لنموذج المصادق المحدد في معيار WebAuthn. إنه يحاكي سلوك جهاز مصادقة مادي، مثل مفتاح أمان مادي (على سبيل المثال YubiKey) أو ماسح ضوئي بيومتري (على سبيل المثال المستخدم في Face ID أو Touch ID أو Windows Hello)، ولكنه يعمل بالكامل داخل البرنامج (لذلك لا يوجد مصادقة مادية أو مسح للبيانات البيومترية).
هناك فائدتان رئيسيتان للمصادق الافتراضي WebAuthn.
نظرًا لأن WebDriver و CDP هما أدوات لأتمتة المتصفح، فمن الواضح أن حالة الاستخدام الأساسية لتطبيق المصادق الافتراضي WebAuthn في هذه البروتوكولات هي الاختبار الآلي. بالاستفادة من هذه البروتوكولات، يتيح المصادق الافتراضي اختبارًا بسيطًا وشاملاً لوظائف مفاتيح المرور في بيئات خاضعة للرقابة مثل أطر عمل اختبار E2E (على سبيل المثال Playwright، Cypress، Nightwatch).
يمكن أيضًا الوصول إلى المصادق الافتراضي WebAuthn الخاص بـ CDP عبر أدوات مطوري متصفح Chrome، ويمكن استخدامه للاختبار اليدوي أو ببساطة لأغراض العرض التوضيحي. باستخدام هذه الميزة، يمكنك محاكاة إدخال مفتاح المرور على جهاز لا يدعم مفاتيح المرور أصلاً. بالمقابل، من الممكن أيضًا محاكاة بيئة غير مدعومة لمفاتيح المرور على جهاز يدعم مفاتيح المرور.
تُظهر لقطة الشاشة أعلاه مثالاً على استخدام المصادق الافتراضي في Chrome لأغراض الاختبار اليدوي أو العرض التوضيحي. يمكنك أن ترى أن خيارات التكوين المختلفة للمصادق الافتراضي ممكنة، ويمكن أيضًا تتبع إضافة وحذف بيانات الاعتماد. ارجع إلى هذا الدليل من Google لمزيد من المعلومات حول استخدام المصادق الافتراضي في متصفحك، بما في ذلك خيارات التكوين والقيم الموصى بها لكل منها.
بينما يعد المصادق الافتراضي WebAuthn حلاً أنيقًا لاختبار تطبيقات مفاتيح المرور، هناك بعض العيوب التي تستحق الذكر.
كونه حلاً برمجيًا بحتًا، لا يمكن للمصادق الافتراضي WebAuthn تكرار خصائص الأجهزة الفريدة وميزات الأمان للمصادقات المادية. لا يمكن محاكاة التمييز بين استخدام مصادقات المنصة المختلفة (المدمجة في جهاز، مثل الماسح الضوئي البيومتري على هاتف ذكي) ومصادقات عبر المنصات المختلفة (وهي أجهزة خارجية، مثل مفاتيح الأمان المادية) باستخدام المصادق الافتراضي WebAuthn. في حين أن تبسيط الصندوق الأسود للتعقيدات المتعلقة بأنواع مختلفة من مصادقات المنصة وعبر المنصات هو أحد مزايا استخدام المصادق الافتراضي WebAuthn، إذا كنت تسعى إلى محاكاة واختبار الفروق الدقيقة للأنواع المختلفة من المصادقات، فيجب استكشاف حلول أخرى.
نظرًا للاعتماد الحديث نسبيًا لـ WebAuthn وحداثة تقنية مفاتيح المرور، لا يزال النظام البيئي المحيط بالمصادقات الافتراضية في طور النضج. ينتج عن هذا ندرة في التوثيق الشامل والتحديات التقنية التي لم يتم حلها، لا سيما في سياق دمج المصادقات الافتراضية مع أطر الاختبار الآلي. يهدف هذا الدليل إلى معالجة هذه المشكلة من خلال توفير رؤى شاملة حول اختبار مفاتيح المرور في بيئة اختبار آلية، مع التركيز أيضًا على معالجة الإزعاجات التي لا تزال موجودة في استخدام هذه الأدوات وتقديم حلول بديلة لهذه المشاكل.
بعد التثبيت الناجح لـ Playwright وتوابعه، يمكنك البدء فورًا في كتابة اختبارك الأول عن طريق إنشاء ملف باسم ينتهي إما بـ .spec.ts أو .test.ts بالمحتوى التالي:
import { test, expect } from "@playwright/test"; test("my first test", async ({ page }) => { await page.goto("https://passkeys.eu"); // start simulating user actions });
لاستخدام المصادق الافتراضي WebAuthn في Playwright، يكفي ببساطة بدء جلسة CDP وإرفاق مصادق افتراضي في بداية حالة الاختبار، على النحو التالي:
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 ... });
خيارات تكوين المصادق الافتراضي WebAuthn:
في هذا القسم، نستكشف استخدام طرق وأحداث المصادق الافتراضي WebAuthn في سياق حالات الاستخدام الشائعة والهامشية.
قد تكون هذه هي المهمة الأكثر أهمية وإرباكًا عند استخدام المصادق الافتراضي WebAuthn في كود الاختبار، حيث لا توجد طريقة مدمجة صريحة لتشغيل إدخال مفتاح المرور. يكمن الحل في خيارات تكوين المصادق الافتراضي WebAuthn، وهي isUserVerified و automaticPresenceSimulation. باستخدام هذه الخيارات، يمكننا محاكاة تفاعل المستخدم هذا عبر نهجين مختلفين موضحين أدناه.
الحالة 1: محاكاة إدخال مفتاح مرور ناجح
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!'); ... });
عادةً لا تتطلب محاكاة إدخال مفتاح مرور ناجح أي أسطر إضافية في كود الاختبار. السطر الأخير (await expect...) ينتظر تغيير الصفحة (الذي يتم تشغيله بواسطة إدخال مفتاح المرور الناجح الضمني).
الحالة 2: محاكاة إدخال مفتاح مرور ملغى (لا يؤدي إلى تغييرات في واجهة المستخدم)
يعد اختبار إدخال مفتاح مرور فاشل أو ملغى أكثر تعقيدًا لأنه قد لا يؤدي إلى أي تغييرات ملحوظة في واجهة المستخدم. بعبارة أخرى، انتظار تغيير الصفحة كما في المثال السابق ليس كافيًا لضمان اكتمال معالجة إدخال مفتاح المرور. التحقق من أن الصفحة لم تتغير بعد إدخال مفتاح المرور الضمني لا معنى له، حيث سيحدث التحقق بالتأكيد تقريبًا قبل اكتمال معالجة إدخال مفتاح المرور. بينما يوفر المصادق الافتراضي طريقة لانتظار معالجة إدخال مفتاح مرور ناجح عن طريق الاستماع إلى انبعاث الأحداث (كما سيناقش في النهج 2)، لا توجد حاليًا طريقة مدمجة لاكتشاف إدخال مفتاح مرور فاشل أو ملغى. الحل البديل هو ببساطة إضافة مهلة زمنية ثابتة لانتظار اكتمال عملية مفتاح المرور قبل التحقق من أن واجهة المستخدم بقيت كما هي بالفعل.
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 ... });
في كلتا الحالتين، تكون قابلية قراءة كود الاختبار محدودة بسبب ضمنية عملية مفتاح المرور. كما ذكرنا سابقًا، سيكون من السهل أيضًا التغاضي عن وقت المطالبة بواجهة المستخدم الشرطية (Conditional UI)، وفي هذه الحالة ستكتمل عملية مفتاح المرور تلقائيًا دون علم المختبرين.
يؤدي تشغيل إدخال مفتاح المرور يدويًا عن طريق تبديل قيمة خيار automaticPresenceSimulation إلى حل المشكلات التي تمت مواجهتها في النهج السابق، وتحديداً من حيث قابلية قراءة كود الاختبار.
الحالة 1: محاكاة إدخال مفتاح مرور ناجح
مقتطفات الكود التالية تحاكي إدخال مفتاح مرور ناجح:
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() ); ... });
قد تكون الدالة المساعدة مخيفة جدًا عند النظر إليها لأول مرة. من المفيد أن نفهم أن جميع التعقيدات التقنية لمحاكاة عملية مفتاح المرور مجردة في الدالة المساعدة. هذا يعني أنه عند استخدامها داخل كود الاختبار، فإنها تجعل الكود بسيطًا وواضحًا، كما يمكن رؤيته في مقتطف الكود الثاني أعلاه.
مقارنة بالنهج الضمني في القسم 6.1.1، يزيد هذا النهج الصريح من قابلية قراءة الكود أيضًا. سيكون هذا مفيدًا بشكل خاص عند المطالبة بواجهة المستخدم الشرطية (Conditional UI)، حيث يمنع هذا النهج الصريح إكمال عملية مفتاح المرور الضمنية غير المقصودة دون وعي المطورين.
الآن دعنا نفهم كل جزء من الدالة المساعدة.
أولاً، نحدد الوعد operationCompleted الذي ينتظر إما حدث WebAuthn.credentialAdded أو حدث WebAuthn.credentialAsserted، والذي، كما يوحي الاسم، ينبعث عند تسجيل أو التحقق من بيانات اعتماد مفتاح المرور، على التوالي. سيتم استخدام هذا الوعد لاحقًا.
بعد ذلك، يتم تعيين خيار isUserVerified على true، بحيث تكون عملية مفتاح المرور اللاحقة بواسطة المصادق الافتراضي WebAuthn ناجحة. يتم أيضًا تعيين automaticPresenceSimulation على true، بحيث يستجيب المصادق الافتراضي WebAuthn لمطالبة مفتاح المرور التالية من صفحة الويب.
إن انتظار وعد operationTrigger ضروري لتجنب حالة السباق. تحدث حالة السباق عندما تطالب صفحة الويب بمفتاح المرور قبل تعيين automaticPresenceSimulation على true. لمنع ذلك، يجب تنفيذ إجراء المستخدم الذي يؤدي إلى تشغيل مطالبة مفتاح المرور بعد تعيين automaticPresenceSimulation على true. في المثال أعلاه، ينقر المستخدم على الزر المسمى Create account with passkeys لتشغيل مطالبة مفتاح المرور.
بعد اكتمال إجراء المستخدم، يجب أن ننتظر اكتمال عملية مفتاح المرور الناجحة. يتم ذلك عن طريق انتظار الوعد الذي حددناه في بداية الدالة المساعدة. يتم تمييز اكتمال عملية مفتاح المرور الناجحة بانبعاث حدث WebAuthn.credentialAdded أو WebAuthn.credentialAsserted. في المثال أعلاه، نظرًا لأن المستخدم يقوم بتسجيل مفتاح مرور، سيتم انبعاث حدث WebAuthn.credentialAdded.
أخيرًا، يتم تعيين خيار automaticPresenceSimulation مرة أخرى على false، لمنع حدوث عمليات مفتاح مرور غير مقصودة لاحقًا في كود الاختبار.
الحالة 2: محاكاة إدخال مفتاح مرور ملغى
بالنسبة لإدخال مفتاح مرور ملغى، يجب أن نجري تعديلاً طفيفًا على التنفيذ للحالة السابقة. في حالة إدخال مفتاح مرور ناجح، هناك أحداث، وهي WebAuthn.credentialAdded و WebAuthn.credentialAsserted، والتي تنبعث عند اكتمال العملية. ومع ذلك، لا يوفر المصادق الافتراضي WebAuthn أي حدث لإدخال مفتاح مرور ملغى أو فاشل. وبالتالي، يجب أن نستخدم طريقة بديلة للتحقق من اكتمال عملية مفتاح مرور ملغاة أو فاشلة.
مقتطفات الكود التالية تحاكي إدخال مفتاح مرور فاشل:
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 ... });
في الدالة المساعدة، يتم استبدال مستمعي الأحداث بمعلمة وعد postOperationCheck التي تنتظر حدوث تغيير متوقع في واجهة المستخدم قبل أن يمكن تعيين automaticPresenceSimulation مرة أخرى على false.
في كود الاختبار، الفرق الوحيد هو أنه يجب استدعاء الدالة المساعدة بوعد إضافي يتحقق من تغيير واجهة المستخدم المقصود. في المثال أعلاه، نتحقق من أن تطبيق الويب قد انتقل بنجاح إلى صفحة يحتوي فيها العنوان على النص Something went wrong....
كما نوقش في القسم 6.1.1، قد لا يؤدي إلغاء إدخال مفتاح المرور إلى أي تغيير ملحوظ في واجهة المستخدم. مثل المثال المقدم في ذلك القسم، يجب أن نضيف انتظارًا ثابتًا قبل التحقق من أن واجهة المستخدم قد بقيت بالفعل كما هي في مثل هذه الحالات:
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'); } ); ... });
تتعزز راحة استخدام المصادق الافتراضي WebAuthn بقدرته على التصرف مثل مصادق حقيقي في حالة إنشاء أو حذف مفتاح مرور بواسطة تطبيق الويب. يحتاج الاختبار ببساطة إلى أداء إجراءات المستخدم لمحاكاة إنشاء أو حذف مفتاح مرور على تطبيق الويب، ويقوم المصادق الافتراضي WebAuthn تلقائيًا بتعديل معلومات بيانات الاعتماد المحفوظة لديه دون أي عمل إضافي من جانب كود الاختبار.
إليك مثال على كود الاختبار الذي يتحقق من أن تطبيق الويب يسجل مفتاح مرور جديدًا إلى المصادق بشكل صحيح:
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); ... });
بدمج مقتطف الكود هذا مع مقتطفات الكود من القسم 6.1، يمكننا اختبار تدفق التسجيل على صفحة الويب التجريبية الخاصة بنا. الفيديو التالي هو تصور للاختبار في وضع واجهة المستخدم لـ Playwright:
يعمل التحقق من بيانات اعتماد مفتاح المرور باستخدام المصادق الافتراضي WebAuthn بشكل مشابه لإنشاء مفتاح مرور، حيث يتتبع المصادق الافتراضي تلقائيًا عدد عمليات التحقق التي تم إجراؤها باستخدام بيانات اعتماد معينة.
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); ... });
يوضح الفيديو التالي اختبارًا لتدفق login على صفحة الويب التجريبية الخاصة بنا:
من ناحية أخرى، لا ينبغي أن يؤدي حذف مفتاح مرور من تطبيق ويب إلى تعديل أي معلومات داخل المصادق الافتراضي WebAuthn. يجب أن يكون تطبيق الويب قادرًا فقط على حذف بيانات الاعتماد المحفوظة في خادمه الخاص. يجب أن يكون المستخدم نفسه فقط قادرًا على حذف بيانات اعتماد مفتاح المرور بوعي ويدويًا من المصادق الافتراضي WebAuthn.
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); ... });
يوضح الفيديو التالي اختبارًا لحذف بيانات اعتماد مفتاح مرور على صفحة الويب التجريبية الخاصة بنا:
الطريقة الأكثر بديهية لمحاكاة المصادقة عبر الأجهزة من جهاز ثانٍ (لا يحتوي بعد على مفتاح مرور مسجل) هي ببساطة إضافة مثيل جديد من المصادق الافتراضي WebAuthn عبر أمر CDP، على هذا النحو:
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 .. });
لتجنب تعقيد إدارة معرفات المصادقات الافتراضية المتعددة، من الممكن أيضًا محاكاة جهاز جديد ببساطة عن طريق حذف بيانات الاعتماد من مصادق واحد، وإضافتها مرة أخرى عند الحاجة:
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 ... });
يمكن لهذا النهج أن يبسط التنفيذ بشكل خاص في الحالة التي يلزم فيها محاكاة جهاز جديد، ولكن لم تعد هناك حاجة لاستخدام الجهاز القديم. في هذه الحالة، تحتاج ببساطة إلى مسح بيانات الاعتماد من المصادق الافتراضي وتجاهل بيانات الاعتماد الخاصة به تمامًا:
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 ... });
يمكن أن يوفر استكشاف بدائل للمصادق الافتراضي WebAuthn مرونة في كيفية اختبار عمليات مصادقة مفاتيح المرور / WebAuthn داخل المشاريع.
يمكن أن يؤدي تطوير خدمات أو نقاط نهاية وهمية إلى محاكاة سلوك المصادقة بفعالية، مما يبسط الاختبارات عن طريق تجريد تعقيدات آلية المصادقة الفعلية. هذا النهج مفيد بشكل خاص عند استخدام خدمات مصادقة خارجية، مما يتيح الحفاظ على التركيز على تكامل ووظائف مكونات النظام دون الخوض في تفاصيل المصادقة.
لإجراء فحص شامل لوظائف المصادقة، يوفر استخدام المصادقات الحقيقية للاختبار التكاملي نظرة مفصلة على التفاعل مع مفاتيح الأمان المادية (على سبيل المثال YubiKeys) أو الأجهزة البيومترية (على سبيل المثال المستخدمة في Face ID أو Touch ID أو Windows Hello). على الرغم من أنه يتم إجراؤه يدويًا عادةً بسبب الطبيعة المعقدة لدمج الأجهزة الواقعية في الاختبارات الآلية، فمن الممكن تطوير نصوص أتمتة مخصصة. يمكن لهذه النصوص ربط المصادقات الحقيقية بأطر عمل الاختبار الشامل، مما يوفر تقريبًا أقرب إلى سيناريوهات المستخدم الحقيقية ويعزز موثوقية عملية المصادقة في البيئات الحية.
بعد عرض الخيارات المختلفة وعرض مقتطفات كود محددة لاختبار E2E لمفاتيح المرور / WebAuthn باستخدام Playwright، نريد بالإضافة إلى ذلك تقديم بعض التوصيات العامة للمطورين الجدد في هذا الموضوع.
قبل الغوص في اختبار مفاتيح المرور أو أي آليات مصادقة أخرى، من الضروري تقييم أطر عمل اختبار E2E المتاحة واختيار الخيار الأنسب وفقًا لمتطلبات مشروعك. ضع في اعتبارك المقايضة بين السرعة والاستقرار التي توفرها أطر العمل القائمة على CDP مثل Playwright و Puppeteer، والتوافق عبر المتصفحات الذي توفره أطر العمل القائمة على WebDriver مثل Selenium و Nightwatch. بينما توفر أطر العمل القائمة على CDP أتمتة متصفح أسرع وأكثر استقرارًا، إلا أنها تقتصر على المتصفحات القائمة على Chromium. في المقابل، توفر أطر العمل القائمة على WebDriver توافقًا أوسع عبر المتصفحات، بما في ذلك دعم المتصفحات غير القائمة على Chromium مثل Firefox و Safari، وإن كان ذلك بأداء أبطأ وأقل استقرارًا. سيساعدك فهم هذه المقايضات على اتخاذ قرار مستنير واختيار إطار العمل الذي يناسب احتياجات مشروعك على أفضل وجه.
بينما يبسط المصادق الافتراضي WebAuthn عملية اختبار تطبيقات مفاتيح المرور، من الأهمية بمكان أن يكون لدى المطورين فهم قوي للمفاهيم الأساسية وراء معيار WebAuthn ومفاتيح المرور. تعرف على التكوينات المختلفة المتاحة للمصادق الافتراضي WebAuthn، مثل protocol و transport و hasResidentKey و hasUserVerification و isUserVerified. سيمكنك فهم هذه التكوينات من ضبط المصادق الافتراضي لمحاكاة سيناريوهات المصادقة المختلفة بدقة. بالإضافة إلى ذلك، تعمق في تعقيدات مصادقة مفتاح المرور، بما في ذلك تكاملها مع المتصفحات والأجهزة المختلفة، بالإضافة إلى اعتبارات الأمان المحتملة. ستمكنك هذه المعرفة التأسيسية من تصميم استراتيجيات اختبار شاملة وفعالة لمصادقة مفتاح المرور في تطبيقات الويب الخاصة بك.
تعمق هذا الدليل في استخدام المصادق الافتراضي WebAuthn لـ CDP مع Playwright، مسلطًا الضوء على المفاهيم المتقدمة ومعالجة المشكلات التي لم يتم تناولها في التوثيق الرسمي. استكشفنا أيضًا بدائل لـ CDP داخل Playwright وأطر عمل اختبار E2E الأخرى. على الرغم من التطبيقات المتباينة، تضمن مواصفات المصادق الافتراضي WebAuthn الموحدة أهمية هذا الدليل عبر بروتوكولات أتمتة الويب المختلفة وأطر عمل الاختبار الشامل. لمعرفة المزيد بعمق حول المفاهيم المختلفة المتعلقة بمفاتيح المرور، ارجع إلى مسرد المصطلحات ذات الصلة لدينا والذي قد يساعدك على ضبط المصادق الافتراضي WebAuthn بناءً على احتياجاتك.
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