Tester le Bluetooth Web avec Puppeteer

François Beaufort
François Beaufort

Le Bluetooth Web est compatible avec Chrome 56 et permet aux développeurs d'écrire des applications Web qui communiquent directement avec les appareils Bluetooth des utilisateurs. L'éditeur Web Espruino permet d'importer du code sur des appareils Bluetooth compatibles. Il est désormais possible de tester ces applications avec Puppeteer.

Cet article de blog explique comment utiliser Puppeteer pour exploiter et tester une application Web compatible avec le Bluetooth. L'élément clé de cette approche est la capacité de Puppeteer à utiliser le sélecteur d'appareils Bluetooth de Chrome.

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

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

Pour suivre cet article de blog, vous aurez besoin d'une application Web compatible Bluetooth, d'un appareil Bluetooth avec lequel elle peut communiquer et d'une version de Puppeteer v21.4.0 ou ultérieure.

Lancer le navigateur

Comme pour 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 sans interface utilisateur: cela signifie que Puppeteer ouvrira une fenêtre de navigateur Chrome visible pour exécuter le test. Utilisez le nouveau mode headless si vous préférez l'exécuter sans interface utilisateur. L'ancien mode sans tête ne permet pas d'afficher d'invites Bluetooth.
  • Arguments supplémentaires à 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"],
});

Lorsque vous ouvrez la première page, il est généralement recommandé d'utiliser un contexte de navigation privée. Cela permet d'éviter les fuites d'autorisations entre les tests exécutés avec votre script (bien qu'il existe un état partagé au niveau de l'OS que Puppeteer ne peut pas empêcher). 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, vous pouvez vous connecter à l'appareil Bluetooth pour lire les données. Cette étape suppose 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 et Page.waitForDevicePrompt() pour détecter 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 ensemble dans le bon ordre:

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

La promesse renvoyée par waitForDevicePrompt() se résout en un objet DeviceRequestPrompt que vous utiliserez ensuite pour sélectionner l'appareil Bluetooth auquel vous souhaitez vous connecter.

Sélectionner un appareil

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

DeviceRequestPrompt.waitForDevice() appelle le rappel fourni chaque fois que Chrome détecte un appareil Bluetooth avec des informations de base sur l'appareil. La première fois que le rappel renvoie la valeur "true", waitForDevice() renvoie l'élément 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 DeviceRequestPrompt.select() résolu, Chrome est connecté à l'appareil et la page Web peut y accéder.

Lire depuis l'appareil

À ce stade, votre application Web est connectée à l'appareil Bluetooth choisi et peut en lire les informations. 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 Communication avec des appareils Bluetooth via JavaScript.

À ce stade, vous savez utiliser Puppeteer pour automatiser l'utilisation d'une application Web compatible avec le Bluetooth en remplaçant l'étape manuelle de sélection d'un appareil dans le menu de sélection des appareils Bluetooth. Bien que cela puisse être utile en général, cela s'applique directement à la rédaction d'un test de bout en bout pour une telle application Web.

Créer un test

La pièce manquante pour écrire un test complet à partir du code est d'extraire des informations de l'application Web et de les insérer dans votre script Puppeteer. Une fois cette opération effectuée, 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, le moyen le plus simple consiste à écrire des données dans le DOM. JavaScript propose de nombreuses façons de procéder 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 à partir 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 placer dans 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 en tant qu'argument. Une fois que vous avez défini cette valeur en tant que variable, utilisez votre bibliothèque d'assertions pour vérifier si les données correspondent à ce que nous attendons.

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 avec le Bluetooth avec Puppeteer, consultez ce dépôt: https://github.com/WebBluetoothCG/manual-tests/. Le groupe de la communauté Web Bluetooth gère cette suite de tests, qui peuvent tous être exécutés à partir d'un navigateur ou en local. Le test "Caractéristique en lecture seule" 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 ses précieux commentaires sur ce post.