ทดสอบเว็บบลูทูธด้วย Puppeteer

François Beaufort
François Beaufort

มีการรองรับเว็บบลูทูธมาตั้งแต่ Chrome 56 และช่วยให้นักพัฒนาซอฟต์แวร์เขียนเว็บแอปที่สื่อสารกับผู้ใช้ได้โดยตรง อุปกรณ์บลูทูธ ความสามารถของเครื่องมือแก้ไขเว็บของ Espruino ในการอัปโหลดโค้ดไปยังอุปกรณ์บลูทูธที่เข้ากันได้คือตัวอย่างหนึ่ง ตอนนี้คุณสามารถทดสอบแอปพลิเคชันเหล่านี้ได้ด้วย Puppeteer

บล็อกโพสต์นี้แนะนำวิธีใช้ Puppeteer ในการใช้งานและทดสอบเว็บแอปที่เปิดใช้บลูทูธ ส่วนสำคัญของการดำเนินการนี้คือความสามารถของ Puppeteer ในการใช้งานตัวเลือกอุปกรณ์บลูทูธของ Chrome

หากคุณไม่คุ้นเคยกับการใช้เว็บบลูทูธใน 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 ทั้ง 2 วิธีนี้จะให้คำสัญญา ดังนั้น Promise.all() จึงเป็นวิธีที่สะดวกในการเรียกใช้โดยวิธีดังกล่าวตามลำดับที่ถูกต้อง

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

สัญญาที่ waitForDevicePrompt() ส่งคืนมาจะเปลี่ยนเป็นออบเจ็กต์ DeviceRequestPrompt ซึ่งคุณจะใช้ข้างการเลือกอุปกรณ์บลูทูธที่ต้องการเชื่อมต่อ

เลือกอุปกรณ์

ใช้ DeviceRequestPrompt.waitForDevice() และ DeviceRequestPrompt.select() เพื่อค้นหาและเชื่อมต่อกับอุปกรณ์บลูทูธที่ถูกต้อง

DeviceRequestPrompt.waitForDevice() จะโทรหา Callback ที่ให้มาทุกครั้งที่ Chrome พบอุปกรณ์บลูทูธที่มีข้อมูลพื้นฐานเกี่ยวกับอุปกรณ์บางอย่าง ครั้งแรกที่ Callback แสดงเป็น "จริง" 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();

ดูคำแนะนำแบบเจาะลึกเกี่ยวกับลำดับการเรียก API นี้ได้ที่การสื่อสารกับอุปกรณ์บลูทูธผ่าน JavaScript

ตอนนี้ คุณรู้วิธีใช้ Puppeteer เพื่อทำให้เว็บแอปที่เปิดใช้บลูทูธใช้งานได้โดยอัตโนมัติด้วยการเลือกอุปกรณ์ด้วยตนเองจากเมนูตัวเลือกอุปกรณ์บลูทูธ แม้ว่าวิธีนี้อาจมีประโยชน์โดยทั่วไป แต่ก็ใช้ได้โดยตรงกับการเขียนการทดสอบจากต้นทางถึงปลายทางสำหรับเว็บแอปดังกล่าว

สร้างการทดสอบ

ส่วนที่ขาดไปจากการนำโค้ดจนถึงการเขียนทดสอบแบบเต็มคือการดึงข้อมูลจากเว็บแอปเข้าสู่สคริปต์ Puppeteer เมื่อได้มาแล้ว ก็เป็นเรื่องง่ายที่จะใช้ไลบรารีการทดสอบ (เช่น TAP หรือ mocha) เพื่อตรวจสอบว่ามีการอ่านและรายงานข้อมูลที่ถูกต้องแล้ว

วิธีที่ง่ายที่สุดวิธีหนึ่งคือการเขียนข้อมูลลงใน DOM JavaScript มีหลายวิธีในการดำเนินการโดยไม่ต้องใช้ไลบรารีเพิ่มเติม หากย้อนกลับไปที่เว็บแอปสมมติ ระบบอาจเปลี่ยนสีของสัญญาณบอกสถานะเมื่ออ่านข้อมูลจากอุปกรณ์บลูทูธหรือพิมพ์ข้อมูลตามตัวอักษรลงในช่อง เช่น

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

จาก Puppeteer Page.$eval() จะช่วยให้คุณดึงข้อมูลนี้ออกจาก DOM ของหน้าเว็บและนำไปใช้ในสคริปต์ทดสอบได้ $eval() ใช้ตรรกะเดียวกับ document.querySelector() เพื่อค้นหาองค์ประกอบ แล้วเรียกใช้ฟังก์ชัน Callback ที่มีให้โดยมีองค์ประกอบนั้นเป็นอาร์กิวเมนต์ เมื่อคุณมีตัวแปรนี้เป็นตัวแปรแล้ว ให้ใช้ไลบรารีการยืนยันของคุณเพื่อทดสอบว่าข้อมูลนั้นเป็นไปตามที่เราคาดหวังหรือไม่

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

แหล่งข้อมูลเพิ่มเติม

หากต้องการดูตัวอย่างที่ซับซ้อนมากขึ้นของการเขียนการทดสอบสำหรับเว็บแอปที่ใช้ Puppeteer ซึ่งใช้บลูทูธได้ โปรดดูที่เก็บนี้ https://github.com/WebBluetoothCG/manual-tests/ กลุ่มชุมชนเว็บบลูทูธจะดูแลรักษาชุดการทดสอบนี้ โดยชุดการทดสอบทั้งหมดสามารถเรียกใช้ได้จากเบราว์เซอร์หรือในเครื่อง องค์ประกอบ "คุณลักษณะแบบอ่านอย่างเดียว" test จะคล้ายกับตัวอย่างที่ใช้ในบล็อกโพสต์นี้มากที่สุด

บริการรับรองคำให้การ

ขอขอบคุณ Vincent Scheib ที่เริ่มต้นโปรเจ็กต์นี้และแสดงความคิดเห็นอันมีค่าเกี่ยวกับโพสต์นี้