اختبار بلوتوث الويب باستخدام Puppeteer

François Beaufort
François Beaufort

أصبحت تقنية Web Bluetooth متاحة منذ إصدار 56 من Chrome، وهي تتيح للمطوّرين كتابة تطبيقات الويب التي تتواصل مباشرةً مع أجهزة المستخدمين التي تتضمّن بلوتوث. وإحدى الأمثلة على ذلك هي قدرة محرري الويب Espruino على تحميل الرموز البرمجية إلى أجهزة بلوتوث المتوافقة. أصبح اختبار هذه التطبيقات ممكنًا مع Puppeteer.

تشرح مشاركة المدونة هذه كيفية استخدام تطبيق Puppeteer لتشغيل واختبار تطبيق ويب متوافق مع تقنية البلوتوث. والجزء الأساسي في هذه العملية هو قدرة تطبيق Puppeteer على تشغيل أداة اختيار الأجهزة التي تتضمّن بلوتوث في Chrome.

إذا لم تكن معتادًا على استخدام بلوتوث الويب في Chrome، يعرض الفيديو التالي طلب البلوتوث في محرر الويب في Espruino:

يختار المستخدم جهاز Puck.js يتضمّن بلوتوث في محرِّر الويب Espruino.

لمتابعة مشاركة المدونة هذه، ستحتاج إلى تطبيق ويب مزوّد بتقنية البلوتوث، وجهاز بلوتوث يمكنه التواصل معه، كما يجب استخدام v21.4.0 من Puppeteer أو إصدار أحدث.

تشغيل المتصفح

كما هو الحال مع معظم نصوص Puppeteer البرمجية، ابدأ بتشغيل المتصفّح باستخدام Puppeteer.launch(). للوصول إلى ميزات البلوتوث، يجب تقديم بعض الوسائط الإضافية:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: false,
  args: ["--enable-features=WebBluetooth"],
});

عند فتح الصفحة الأولى، ننصحك عمومًا باستخدام سياق المتصفِّح المتخفي. يساعد ذلك في منع تسريب الأذونات بين الاختبارات التي يتم إجراؤها باستخدام النص البرمجي (على الرغم من وجود حالة مشتركة على مستوى نظام التشغيل لا يمكن منعها بواسطة Puppeteer). توضح التعليمة البرمجية التالية ذلك:

const browserContext = await browser.createIncognitoBrowserContext();
const page = await browserContext.newPage();

يمكنك بعد ذلك الانتقال إلى عنوان URL لتطبيق الويب الذي تختبره باستخدام Page.goto().

فتح رسالة الطلب للجهاز الذي يتضمّن بلوتوث

بعد استخدام Puppeteer لفتح صفحة تطبيق الويب باستخدام Puppeteer، يمكنك الاتصال بجهاز البلوتوث لقراءة البيانات. تفترض هذه الخطوة التالية أن لديك زرًا في تطبيق الويب يشغِّل جزءًا من JavaScript، بما في ذلك اتصال إلى navigator.bluetooth.requestDevice().

استخدِم Page.locator().click() للضغط على هذا الزر، وPage.waitForDevicePrompt() للتعرّف على وقت ظهور أداة اختيار الأجهزة التي تتضمّن بلوتوث. يجب الاتصال بالرقم waitForDevicePrompt() قبل النقر على الزر، وإلا فستكون رسالة الطلب مفتوحة بالفعل، ولن تتمكن الأداة من اكتشافها.

بما أنّ طريقتَي Puppeteer هاتين الطريقتين تعرضان الوعود، تشكّل Promise.all() طريقة سهلة للاتصال بها بالترتيب الصحيح معًا:

const [devicePrompt] = await Promise.all([
  page.waitForDevicePrompt(),
  page.locator("#start-test-button").click(),
]);

يتم تحويل الوعد الذي يعرضه waitForDevicePrompt() إلى عنصر DeviceRequestPrompt ستستخدمه بجانب الجهاز الذي يتضمّن بلوتوث والذي تريد الاتصال به.

اختيار جهاز

استخدِم DeviceRequestPrompt.waitForDevice() وDeviceRequestPrompt.select() للعثور على الجهاز الصحيح الذي يتضمّن بلوتوث وربطه به.

يتصل DeviceRequestPrompt.waitForDevice() بمعاودة الاتصال المقدَّمة في كل مرة يعثر فيها Chrome على جهاز يتضمّن بلوتوث يتضمن بعض المعلومات الأساسية عن الجهاز. في المرة الأولى التي تكون فيها معاودة الاتصال صحيحة، يتم تحويل waitForDevice() إلى DeviceRequestPromptDevice المطابق. مرِّر هذا الجهاز إلى "DeviceRequestPrompt.select()" لاختيار الجهاز الذي يتضمّن بلوتوث وربطه به.

const bluetoothDevice = await devicePrompt.waitForDevice(
  (d) => d.name == wantedDeviceName,
);
await devicePrompt.select(bluetoothDevice);

بعد حل DeviceRequestPrompt.select()، يتم توصيل Chrome بالجهاز، وتتمكن صفحة الويب من الوصول إليه.

القراءة من الجهاز

في هذه المرحلة، سيتم ربط تطبيق الويب بالجهاز الذي تم اختياره يتضمّن بلوتوث، وسيكون بإمكانه قراءة المعلومات منه. قد يبدو هذا كما يلي:

const serviceId = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";

const device = await navigator.bluetooth.requestDevice({
  filters: [{ services: [serviceId] }],
});
const gattServer = await device.gatt.connect();
const service = await gattServer.getPrimaryService(serviceId);
const characteristic = await service.getCharacteristic(
  "0b30afd0-193e-11eb-adc1-0242ac120002",
);
const dataView = await characteristic.readValue();

للحصول على جولة تفصيلية أكثر تفصيلاً لهذا التسلسل من طلبات البيانات من واجهة برمجة التطبيقات، يُرجى الاطّلاع على التواصل مع الأجهزة التي تتضمّن بلوتوث عبر JavaScript.

في هذه المرحلة، ستعرف كيفية استخدام Puppeteer لأتمتة استخدام تطبيق ويب ممكن به البلوتوث من خلال استبدال الخطوة البشرية المتمثلة في اختيار جهاز من قائمة أداة اختيار الأجهزة التي تعمل بالبلوتوث. على الرغم من أنّ هذا الإجراء قد يكون مفيدًا بشكل عام، إلّا أنّه ينطبق مباشرةً على كتابة اختبار شامل لتطبيق الويب هذا.

إنشاء اختبار

الجزء المفقود من أخذ الرمز حتى الآن إلى كتابة اختبار كامل هو الحصول على المعلومات من تطبيق الويب وإلى نص Puppeteer البرمجي. بعد حصولك على ذلك، يكون من السهل إلى حدّ ما استخدام مكتبة اختبار (مثل TAP أو mocha) للتأكّد من قراءة البيانات الصحيحة وإعداد تقارير عنها.

وتتمثل إحدى أسهل الطرق لإجراء ذلك في كتابة البيانات في نموذج العناصر في المستند (DOM). وهناك العديد من الطرق في JavaScript لإجراء ذلك بدون مكتبات إضافية. بالعودة إلى تطبيق الويب الافتراضي، قد يغيِّر لون مؤشر الحالة عند قراءة البيانات من الجهاز الذي يتضمّن بلوتوث أو طباعة البيانات الحرفية في أحد الحقول. مثال:

const dataDisplayElement = document.querySelector('#data-display');
dataDisplayElement.innerText = dataView.getUint8();

من Puppeteer، توفر لك Page.$eval() طريقة لسحب هذه البيانات من نموذج العناصر في المستند (DOM) للصفحة وتحويلها إلى نص برمجي تجريبي. تستخدم $eval() نفس المنطق مثل document.querySelector() للعثور على عنصر ثم تشغِّل دالة رد الاتصال المقدمة مع ذلك العنصر كوسيطة. بمجرد الحصول على هذا كمتغير، استخدم مكتبة التأكيد لاختبار ما إذا كانت البيانات هي ما نتوقعه.

const dataText = await page.$eval('#data-display', (el) => el.innerText);
equal(17, dataText);

مراجع إضافية

للاطّلاع على أمثلة أكثر تعقيدًا لكتابة اختبارات تطبيقات الويب التي تفعِّل البلوتوث باستخدام Puppeteer، يُرجى الاطّلاع على هذا المستودع: https://github.com/WebBluetoothCG/manual-tests/. تحتفظ مجموعة منتدى البلوتوث على الويب بهذه الحزمة من الاختبارات، والتي يمكن تشغيلها جميعًا من متصفّح أو على الجهاز. يشبه اختبار"الخاصية للقراءة فقط" المثال المستخدَم في مشاركة المدونة هذه.

خدمات الإقرار

شكرًا لفنسنت شيب لبدء هذا المشروع وتقديم ملاحظات قيّمة على هذه المشاركة.