Testa il Bluetooth web con Puppeteer

François Beaufort
François Beaufort

Il Bluetooth web è supportato da Chrome 56 e consente agli sviluppatori di scrivere app web che comunicano direttamente con Dispositivi Bluetooth. Un esempio è la capacità dell'editor web Espruino di caricare codice su dispositivi Bluetooth compatibili. Ora è possibile testare queste applicazioni con Puppeteer.

Questo blog post spiega come utilizzare Puppeteer per far funzionare e testare un'app web con Bluetooth abilitato. Il principale è la capacità di Puppeteer di utilizzare il selettore di dispositivi Bluetooth di Chrome.

Se non hai dimestichezza con l'utilizzo di Web Bluetooth in Chrome, il seguente video mostra il prompt Bluetooth nell'editor web di Espruino:

L'utente seleziona un dispositivo Bluetooth Puck.js nell'editor web di Espruino.

Per seguire questo post del blog devi avere un'app web abilitata per il Bluetooth, un dispositivo Bluetooth con cui può comunicare e utilizzare Puppeteer v21.4.0 o versioni successive.

Avvia il browser.

Come per la maggior parte degli script Puppeteer, inizia avviando il browser con Puppeteer.launch(). Per accedere alle funzionalità Bluetooth, devi fornire alcuni argomenti aggiuntivi:

import puppeteer from 'puppeteer';

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

In genere, quando apri la prima pagina, consigliamo di utilizzare un contesto di navigazione in incognito nel browser. Ciò consente di evitare fughe di autorizzazioni tra i test eseguiti con lo script (anche se è presente uno stato condiviso a livello di sistema operativo che non può essere impedito da Puppeteer). Il seguente codice dimostra che:

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

Puoi quindi andare all'URL dell'app web che stai testando con Page.goto().

Apri la richiesta del dispositivo Bluetooth

Dopo aver utilizzato Puppeteer per aprire la pagina dell'app web con Puppeteer, puoi connetterti al dispositivo Bluetooth per leggere i dati. Questo passaggio successivo presuppone che nella tua app web sia presente un pulsante che esegue JavaScript, inclusa una chiamata a navigator.bluetooth.requestDevice().

Utilizza Page.locator().click() per premere il pulsante e Page.waitForDevicePrompt() per riconoscere quando viene visualizzato il selettore di dispositivi Bluetooth. Devi chiamare waitForDevicePrompt() prima di fare clic sul pulsante, altrimenti la richiesta si sarà già aperta e non sarà in grado di rilevarla.

Poiché entrambi questi metodi dei Puppeteer restituiscono promesse, Promise.all() è un modo conveniente per chiamarli insieme nell'ordine corretto:

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

La promessa restituita da waitForDevicePrompt() si risolve in un oggetto DeviceRequestPrompt che utilizzerai accanto per selezionare il dispositivo Bluetooth a cui vuoi connetterti.

Seleziona un dispositivo

Usa DeviceRequestPrompt.waitForDevice() e DeviceRequestPrompt.select() per trovare e connetterti al dispositivo Bluetooth corretto.

DeviceRequestPrompt.waitForDevice() chiama il callback fornito ogni volta che Chrome trova un dispositivo Bluetooth con alcune informazioni di base sul dispositivo. La prima volta che il callback restituisce true, waitForDevice() viene risolto nel DeviceRequestPromptDevice corrispondente. Passa il dispositivo a DeviceRequestPrompt.select() per selezionarlo e connetterlo a quel dispositivo.

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

Una volta risolto il problema DeviceRequestPrompt.select(), Chrome si connette al dispositivo e la pagina web può accedervi.

Lettura dal dispositivo

A questo punto, la tua applicazione web verrà connessa al dispositivo Bluetooth scelto e potrà leggere le relative informazioni. Potrebbe avere il seguente aspetto:

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

Per una procedura dettagliata più approfondita di questa sequenza di chiamate API, consulta l'articolo Comunicazione con dispositivi Bluetooth tramite JavaScript.

A questo punto, sai come utilizzare Puppeteer per automatizzare l'uso di un'app web abilitata per il Bluetooth sostituendo il passaggio umano nella selezione di un dispositivo dal menu del selettore dei dispositivi Bluetooth. Sebbene questo metodo possa essere generalmente utile, è direttamente applicabile alla scrittura di un test end-to-end per un'app web di questo tipo.

Creare un test

Il pezzo mancante dalla scrittura del codice fino a ora per scrivere un test completo è recuperare le informazioni dall'app web e inserirle nello script Puppeteer. Una volta ottenuto questo risultato, è abbastanza semplice utilizzare una libreria di test (come TAP o mocha) per verificare che i dati corretti siano stati letti e segnalati.

Uno dei modi più semplici per eseguire questa operazione è scrivere dati nel DOM. JavaScript ha molti modi per farlo senza altre librerie. Tornando all'app web ipotetica, il colore di un indicatore di stato potrebbe cambiare quando legge i dati dal dispositivo Bluetooth o stampa i dati letterali in un campo. Ad esempio:

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

Da Puppeteer, Page.$eval() consente di estrarre questi dati dal DOM della pagina e inserirli in uno script di test. $eval() utilizza la stessa logica di document.querySelector() per trovare un elemento, quindi esegue la funzione di callback fornita con quell'elemento come argomento. Una volta che questa è una variabile, utilizza la tua libreria di asserzioni per verificare se i dati sono quelli che ci aspettiamo.

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

Risorse aggiuntive

Per esempi più complessi di scrittura di test per app web con Bluetooth abilitato con Puppeteer, consulta questo repository: https://github.com/WebBluetoothCG/manual-tests/. Il Web Bluetooth Community Group gestisce questa suite di test, tutti eseguibili da un browser o in locale. La "Caratteristica di sola lettura" test è più simile all'esempio utilizzato in questo post del blog.

Riconoscimenti

Grazie a Vincent Scheib per aver avviato il progetto e fornito un prezioso feedback su questo post.