Tester le Bluetooth Web avec Puppeteer

François Beaufort
François Beaufort

Le Bluetooth Web est pris en charge depuis Chrome 56 et permet aux développeurs de créer des applications Web qui communiquent directement avec les appareils Bluetooth des utilisateurs. La capacité de l'éditeur Web d'Espruino à importer du code sur des appareils Bluetooth compatibles en est un exemple. Il est désormais possible de tester ces applications avec Puppeteer.

Cet article de blog explique comment utiliser Puppeteer pour faire fonctionner et tester une application Web compatible Bluetooth. L'élément clé de cette opération est la capacité de Puppeteer à faire fonctionner le sélecteur d'appareil Bluetooth de Chrome.

Si vous ne savez pas comment utiliser Web Bluetooth dans Chrome, la vidéo suivante montre l'invite Bluetooth dans l'éditeur Web d'Espruino:

L'utilisateur sélectionne un appareil Bluetooth Puck.js dans l'éditeur Web d'Espruino.

Pour suivre cet article de blog, vous devez disposer d'une application Web sur laquelle le Bluetooth est activé et d'un appareil Bluetooth avec lequel il peut communiquer. Vous devez également utiliser Puppeteer v21.4.0 (ou version ultérieure).

Lancer le navigateur

Comme avec la plupart des scripts Puppeteer, commencez par lancer le navigateur avec Puppeteer.launch(). Pour accéder aux fonctionnalités Bluetooth, vous devez fournir quelques arguments supplémentaires:

  • Désactiver le mode headless: Puppeteer ouvre une fenêtre visible dans le navigateur Chrome pour exécuter le test. Utilisez le nouveau mode headless si vous préférez l'exécuter sans UI. L'ancien mode headless n'est pas compatible avec l'affichage des invites Bluetooth.
  • Arguments supplémentaires dans Chromium: transmettez un argument"enable Web Bluetooth" pour les environnements Linux.
import puppeteer from 'puppeteer';

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

Pour ouvrir la première page, il est généralement recommandé d'utiliser le contexte de navigation privée. Cela permet d'éviter les fuites d'autorisations entre les tests exécutés avec votre script (bien que certains états partagés au niveau du système d'exploitation ne puissent pas être évités par Puppeteer). Le code suivant illustre cela:

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

Vous pouvez ensuite accéder à l'URL de l'application Web que vous testez avec Page.goto().

Ouvrir l'invite de l'appareil Bluetooth

Une fois que vous avez utilisé Puppeteer pour ouvrir la page de l'application Web avec Puppeteer, vous pouvez vous connecter à l'appareil Bluetooth pour lire les données. Pour cette étape, nous partons du principe que votre application Web comporte un bouton qui exécute du code JavaScript, y compris un appel à navigator.bluetooth.requestDevice().

Utilisez Page.locator().click() pour appuyer sur ce bouton, puis Page.waitForDevicePrompt() pour reconnaître quand le sélecteur d'appareil Bluetooth s'affiche. Vous devez appeler waitForDevicePrompt() avant de cliquer sur le bouton. Sinon, l'invite sera déjà ouverte et ne pourra pas la détecter.

Étant donné que ces deux méthodes Puppeteer renvoient des promesses, Promise.all() est un moyen pratique de les appeler dans le bon ordre ensemble:

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

La promesse renvoyée par waitForDevicePrompt() est associée à un objet DeviceRequestPrompt que vous utiliserez à côté pour sélectionner l'appareil Bluetooth auquel vous souhaitez vous connecter.

Sélectionner un appareil

Utilisez DeviceRequestPrompt.waitForDevice() et DeviceRequestPrompt.select() pour rechercher le bon appareil Bluetooth et vous y connecter.

DeviceRequestPrompt.waitForDevice() appelle le rappel fourni chaque fois que Chrome trouve un appareil Bluetooth contenant des informations de base sur celui-ci. La première fois que le rappel renvoie la valeur "true", waitForDevice() renvoie le DeviceRequestPromptDevice correspondant. Transmettez cet appareil à DeviceRequestPrompt.select() pour le sélectionner et vous y connecter.

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

Une fois l'erreur DeviceRequestPrompt.select() résolue, Chrome est connecté à l'appareil et la page Web peut y accéder.

Lire des données depuis l'appareil

À ce stade, votre application Web est connectée à l'appareil Bluetooth choisi et peut lire les informations qu'il contient. Cela peut se présenter comme suit:

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

Pour une présentation plus détaillée de cette séquence d'appels d'API, consultez la section Communiquer avec des appareils Bluetooth via JavaScript.

À ce stade, vous savez comment utiliser Puppeteer pour automatiser l'utilisation d'une application Web compatible Bluetooth en remplaçant l'étape humaine consistant à sélectionner un appareil dans le menu du sélecteur d'appareil Bluetooth. Bien que cela puisse être utile d'une manière générale, il est directement applicable à l'écriture d'un test de bout en bout pour une telle application Web.

Créer un test

Entre l'exécution du code et l'écriture d'un test complet, il manque des informations : extraire les informations de l'application Web et les intégrer à votre script Puppeteer. Une fois que c'est fait, il est assez simple d'utiliser une bibliothèque de test (comme TAP ou mocha) pour vérifier que les bonnes données ont été lues et signalées.

Pour ce faire, l'une des méthodes les plus simples consiste à écrire les données dans le DOM. JavaScript offre de nombreuses méthodes pour le faire sans bibliothèques supplémentaires. Pour en revenir à votre application Web fictive, il est possible qu'elle change la couleur d'un indicateur d'état lorsqu'elle lit des données de l'appareil Bluetooth ou imprime les données littérales dans un champ. Exemple :

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

Dans Puppeteer, Page.$eval() vous permet d'extraire ces données du DOM de la page et de les intégrer à un script de test. $eval() utilise la même logique que document.querySelector() pour rechercher un élément, puis exécute la fonction de rappel fournie avec cet élément comme argument. Une fois que vous disposez de cette valeur en tant que variable, utilisez votre bibliothèque d'assertions pour vérifier que les données correspondent à celles attendues.

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

Ressources supplémentaires

Pour voir des exemples plus complexes d'écriture de tests pour des applications Web compatibles Bluetooth avec Puppeteer, consultez ce dépôt: https://github.com/WebBluetoothCG/manual-tests/. Le Web Bluetooth Community Group gère cette suite de tests, qui peuvent tous être exécutés depuis un navigateur ou localement. Le test "Read-only Characteristic" est le plus proche de l'exemple utilisé dans cet article de blog.

Remerciements

Merci à Vincent Scheib d'avoir lancé ce projet et de nous avoir fait part de vos précieux commentaires concernant cet article.