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

François Beaufort
François Beaufort

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

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

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

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

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

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

كما هو الحال مع معظم النصوص البرمجية من 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 على جهاز يتضمّن بلوتوث يحتوي على بعض المعلومات الأساسية عن الجهاز. في المرة الأولى التي يعود فيها معاودة الاتصال إلى القيمة true، تتم مطابقة 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/. تحتفظ مجموعة منتدى Web Bluetooth بهذه المجموعة من الاختبارات، والتي يمكن تشغيلها كلّها من متصفّح أو على الجهاز. "خاصية القراءة فقط" الاختبار إلى حد كبير مع المثال المستخدم في مشاركة المدونة هذه.

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

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