Cómo probar la conexión Bluetooth web con Puppeteer

François Beaufort
François Beaufort

Web Bluetooth es compatible desde Chrome 56 y permite a los desarrolladores escribir aplicaciones web que se comuniquen directamente con los Dispositivos Bluetooth Un ejemplo de ello es la capacidad del editor web de Espruino de subir código en dispositivos Bluetooth compatibles. Ahora es posible probar estas aplicaciones con Puppeteer.

En esta entrada de blog, se explica cómo usar Puppeteer para operar y probar una app web con Bluetooth habilitado. La parte clave de este proceso es la capacidad de Puppeteer de operar el selector de dispositivos Bluetooth de Chrome.

Si desconoces el uso de Web Bluetooth en Chrome, en el siguiente video se muestra el mensaje de Bluetooth en el editor web de Espruino:

.
El usuario selecciona un dispositivo Bluetooth Puck.js en el editor web de Espruino.

Para seguir esta entrada de blog, necesitarás una app web con Bluetooth habilitado, un dispositivo Bluetooth con el que se pueda comunicar y usar Puppeteer v21.4.0 o una versión posterior.

Inicia el navegador.

Al igual que con la mayoría de las secuencias de comandos de Puppeteer, comienza por iniciar el navegador con Puppeteer.launch(). Para acceder a las funciones de Bluetooth, debes proporcionar algunos argumentos adicionales:

import puppeteer from 'puppeteer';

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

Cuando se abre la primera página, generalmente se recomienda usar un contexto del navegador en modo Incógnito. Esto ayuda a evitar la filtración de permisos entre las pruebas que se ejecutan con tu secuencia de comandos (aunque hay algunos estados compartidos a nivel del SO que Puppeteer no puede evitar). Esto se demuestra en el siguiente código:

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

Luego, puedes navegar a la URL de la app web que estás probando con Page.goto().

Abrir el mensaje del dispositivo Bluetooth

Una vez que hayas usado Puppeteer para abrir la página de la app web con Puppeteer, podrás conectarte al dispositivo Bluetooth para leer los datos. En el siguiente paso, se supone que tienes un botón en tu app web que ejecuta JavaScript, incluida una llamada a navigator.bluetooth.requestDevice().

Usa Page.locator().click() para presionar ese botón y Page.waitForDevicePrompt() para reconocer cuándo aparece el selector de dispositivos Bluetooth. Debes llamar a waitForDevicePrompt() antes de hacer clic en el botón. De lo contrario, el mensaje ya se habrá abierto y no podrá detectarlo.

Como ambos métodos de Puppeteer muestran promesas, Promise.all() es una forma conveniente de llamarlos juntos en el orden correcto:

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

La promesa que muestra waitForDevicePrompt() se resuelve en un objeto DeviceRequestPrompt, que usarás a continuación para seleccionar el dispositivo Bluetooth al que deseas conectarte.

Seleccionar un dispositivo

Usa DeviceRequestPrompt.waitForDevice() y DeviceRequestPrompt.select() para encontrar el dispositivo Bluetooth correcto y conectarte a él.

DeviceRequestPrompt.waitForDevice() llama a la devolución de llamada proporcionada cada vez que Chrome encuentra un dispositivo Bluetooth con cierta información básica sobre el dispositivo. La primera vez que la devolución de llamada muestra el valor true, waitForDevice() se resuelve en el DeviceRequestPromptDevice coincidente. Pasa ese dispositivo a DeviceRequestPrompt.select() para seleccionarlo y conectarse a él.

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

Una vez que se resuelve DeviceRequestPrompt.select(), Chrome se conecta al dispositivo, y la página web puede acceder a él.

Cómo leer desde el dispositivo

En este punto, tu app web estará conectada al dispositivo Bluetooth elegido y podrá leer información desde él. El aspecto podría ser el siguiente:

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

Para obtener una explicación más detallada de esta secuencia de llamadas a la API, consulta Cómo comunicarse con dispositivos Bluetooth a través de JavaScript.

En este punto, ya sabes cómo usar Puppeteer para automatizar el uso de una aplicación web con Bluetooth habilitada reemplazando el paso humano de seleccionar un dispositivo desde el menú del selector de dispositivos Bluetooth. Si bien esto puede ser generalmente útil, es directamente aplicable a escribir una prueba de extremo a extremo para una aplicación web de este tipo.

Crea una prueba

Lo que falta de completar el código y escribir una prueba completa es obtener información de la app web y agregarla a la secuencia de comandos de Puppeteer. Una vez que tengas esto, es bastante sencillo usar una biblioteca de pruebas (como TAP o mocha) para verificar que se hayan leído e informado los datos correctos.

Una de las formas más fáciles de hacerlo es escribir datos en el DOM. JavaScript tiene muchas maneras de hacer esto sin bibliotecas adicionales. Si volvemos a la app web hipotética, es posible que cambie el color de un indicador de estado cuando lea datos del dispositivo Bluetooth o imprima datos literales en un campo. Por ejemplo:

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

En Puppeteer, Page.$eval() te ofrece una manera de extraer estos datos del DOM de la página y enviarlos a una secuencia de comandos de prueba. $eval() usa la misma lógica que document.querySelector() para encontrar un elemento y, luego, ejecuta la función de devolución de llamada proporcionada con ese elemento como argumento. Una vez que tengas esto como una variable, usa tu biblioteca de aserciones para probar si los datos son los esperados.

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

Recursos adicionales

Para ver ejemplos más complejos sobre cómo escribir pruebas de escritura para apps web con Bluetooth habilitado con Puppeteer, consulta este repositorio: https://github.com/WebBluetoothCG/manual-tests/. El grupo de la comunidad de Web Bluetooth mantiene este conjunto de pruebas, que se pueden ejecutar desde un navegador o de forma local. La característica de solo lectura" test es muy similar al ejemplo que se usa en esta entrada de blog.

Agradecimientos

Agradecemos a Vincent Scheib por iniciar este proyecto y proporcionar comentarios valiosos sobre esta publicación.