Web Bluetooth mit Puppeteer testen

François Beaufort
François Beaufort

Web Bluetooth wird seit Chrome 56 unterstützt und ermöglicht Entwicklern, Web-Apps zu entwickeln, die direkt mit den Bluetooth-Geräte Ein Beispiel dafür ist die Fähigkeit des Espruino-Webeditors, Code auf kompatible Bluetooth-Geräte hochzuladen. Das Testen dieser Anwendungen ist jetzt mit Puppeteer möglich.

In diesem Blogbeitrag erfahren Sie, wie Sie mit Puppeteer eine Bluetooth-fähige Webanwendung bedienen und testen. Der Hauptteil davon ist die Fähigkeit von Puppeteer, die Bluetooth-Geräteauswahl von Chrome zu bedienen.

Wenn Sie mit der Verwendung von Web Bluetooth in Chrome nicht vertraut sind, sehen Sie im folgenden Video die Bluetooth-Eingabeaufforderung im Espruino-Webeditor:

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
Der Nutzer wählt im Espruino-Webeditor ein Puck.js-Bluetooth-Gerät aus.

Um diesem Blogpost zu folgen, benötigen Sie eine Bluetooth-fähige Webanwendung sowie ein Bluetooth-Gerät, mit dem die App kommunizieren kann. Außerdem benötigen Sie Puppeteer v21.4.0 oder höher.

Browser starten

Wie bei den meisten Puppeteer-Skripts starten Sie den Browser zuerst mit Puppeteer.launch(). Für den Zugriff auf Bluetooth-Funktionen müssen einige zusätzliche Argumente angegeben werden:

import puppeteer from 'puppeteer';

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

Beim Öffnen der ersten Seite wird generell empfohlen, einen Inkognito-Browserkontext zu verwenden. Dadurch werden Datenlecks zwischen den mit Ihrem Skript ausgeführten Tests vermieden (obwohl es einen gemeinsamen Status auf Betriebssystemebene gibt, der von Puppeteer nicht verhindert werden kann). Der folgende Code veranschaulicht dies:

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

Sie können dann die URL der Web-App aufrufen, die Sie mit Page.goto() testen.

Aufforderung für Bluetooth-Gerät öffnen

Sobald Sie Puppeteer verwendet haben, um die Seite der Webanwendung mit Puppeteer zu öffnen, können Sie eine Verbindung zum Bluetooth-Gerät herstellen, um Daten zu lesen. Dieser nächste Schritt setzt voraus, dass Ihre Webanwendung eine Schaltfläche enthält, auf der JavaScript ausgeführt wird, einschließlich eines Aufrufs von navigator.bluetooth.requestDevice().

Drücken Sie Page.locator().click(), um diese Taste zu drücken, und Page.waitForDevicePrompt(), um zu erkennen, wann die Bluetooth-Geräteauswahl angezeigt wird. Sie müssen waitForDevicePrompt() aufrufen, bevor Sie auf die Schaltfläche klicken. Andernfalls ist die Aufforderung bereits geöffnet und kann nicht erkannt werden.

Da beide Puppeteer-Methoden Promise zurückgeben, ist Promise.all() eine bequeme Möglichkeit, sie in der richtigen Reihenfolge zusammen aufzurufen:

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

Das von waitForDevicePrompt() zurückgegebene Versprechen wird in ein DeviceRequestPrompt-Objekt aufgelöst, das du neben der Auswahl des Bluetooth-Geräts verwendest, mit dem du eine Verbindung herstellen möchtest.

Gerät auswählen

Verwenden Sie DeviceRequestPrompt.waitForDevice() und DeviceRequestPrompt.select(), um das richtige Bluetooth-Gerät zu finden und eine Verbindung herzustellen.

DeviceRequestPrompt.waitForDevice() ruft den bereitgestellten Callback jedes Mal auf, wenn Chrome ein Bluetooth-Gerät mit einigen grundlegenden Informationen über das Gerät findet. Wenn der Callback zum ersten Mal „true“ zurückgibt, wird waitForDevice() in den übereinstimmenden DeviceRequestPromptDevice aufgelöst. Gib das Gerät an DeviceRequestPrompt.select() weiter, um es auszuwählen und eine Verbindung zu diesem Bluetooth-Gerät herzustellen.

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

Sobald DeviceRequestPrompt.select() aufgelöst wurde, ist Chrome mit dem Gerät verbunden und die Webseite kann darauf zugreifen.

Vom Gerät lesen

Jetzt ist Ihre Web-App mit dem ausgewählten Bluetooth-Gerät verbunden und kann auf diesem Gerät Informationen lesen. Dies könnte etwa so aussehen:

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();

Eine ausführlichere Anleitung für diese Abfolge von API-Aufrufen finden Sie unter Kommunikation mit Bluetooth-Geräten über JavaScript.

Jetzt wissen Sie, wie Sie Puppeteer verwenden können, um die Verwendung einer Bluetooth-fähigen Webanwendung zu automatisieren, indem der manuelle Schritt der Auswahl eines Geräts aus dem Bluetooth-Geräteauswahlmenü ersetzt wird. Dies kann zwar allgemein nützlich sein, eignet sich jedoch direkt für das Schreiben eines End-to-End-Tests für eine solche Webanwendung.

Test erstellen

Der fehlende Teil vom bisherigen Code zum Schreiben eines vollständigen Tests besteht darin, Informationen aus der Webanwendung in Ihr Puppeteer-Skript abzurufen. Anschließend können Sie ganz einfach mithilfe einer Testbibliothek wie TAP oder Mocha überprüfen, ob die korrekten Daten gelesen und gemeldet wurden.

Eine der einfachsten Möglichkeiten, dies zu tun, besteht darin, Daten in das DOM zu schreiben. JavaScript bietet hierfür zahlreiche Möglichkeiten ohne zusätzliche Bibliotheken. Wenn Sie zu Ihrer hypothetischen Web-App zurückkehren, ändert sich möglicherweise die Farbe einer Statusanzeige, wenn sie Daten vom Bluetooth-Gerät liest oder die Literaldaten in einem Feld ausgibt. Beispiel:

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

In Puppeteer können Sie diese Daten mit Page.$eval() aus dem DOM der Seite in ein Testskript abrufen. $eval() verwendet dieselbe Logik wie document.querySelector(), um ein Element zu finden, und führt dann die bereitgestellte Callback-Funktion mit diesem Element als Argument aus. Sobald Sie dies als Variable haben, verwenden Sie Ihre Assertion-Bibliothek, um zu testen, ob die Daten unseren Erwartungen entsprechen.

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

Zusätzliche Ressourcen

Komplexere Beispiele für das Schreiben von Tests für Bluetooth-fähige Webanwendungen mit Puppeteer finden Sie in diesem Repository: https://github.com/WebBluetoothCG/manual-tests/. Die Web Bluetooth Community Group verwaltet diese Testsuite, die alle über einen Browser oder lokal ausgeführt werden können. Die "Schreibgeschützte Eigenschaft" Test ist dem Beispiel in diesem Blogpost am ähnlichsten.

Danksagung

Vielen Dank an Vincent Scheib für den Start dieses Projekts und für wertvolles Feedback zu diesem Beitrag.