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 i dispositivi Bluetooth degli utenti. La possibilità dell'editor web di Espruino di caricare il codice su dispositivi Bluetooth compatibili è un esempio di questo tipo. Ora è possibile testare queste applicazioni con Puppeteer.

Questo post del blog illustra come utilizzare Puppeteer per gestire e testare un'app web con Bluetooth. L'aspetto fondamentale è 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 la richiesta Bluetooth nell'editor web Espruino:

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

Per seguire questo post del blog, devi avere un'app web con il Bluetooth abilitato, 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 aprendo 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"],
});

Quando apri la prima pagina, in genere è consigliabile utilizzare un contesto del browser in incognito. In questo modo, puoi evitare la fuga di autorizzazioni tra i test eseguiti con lo script (anche se esiste uno stato condiviso a livello di sistema operativo che non può essere impedito da Puppeteer). Il seguente codice lo dimostra:

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

Puoi quindi passare 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, puoi connetterti al dispositivo Bluetooth per leggere i dati. Questo passaggio presuppone che nella tua app web sia presente un pulsante che esegue del codice JavaScript, inclusa una chiamata a navigator.bluetooth.requestDevice().

Usa Page.locator().click() per premere il pulsante e Page.waitForDevicePrompt() per riconoscere quando viene visualizzato il selettore del dispositivo Bluetooth. Devi chiamare waitForDevicePrompt() prima di fare clic sul pulsante, altrimenti la richiesta si aprirà già e non potrà rilevarla.

Poiché entrambi i metodi Puppeteer restituiscono promesse, Promise.all() è un modo pratico 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 successivamente 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() si risolve in DeviceRequestPromptDevice corrispondente. Passa il dispositivo a DeviceRequestPrompt.select() per selezionarlo e connetterti al dispositivo Bluetooth.

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

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

Leggere dal dispositivo

A questo punto, la tua app web sarà connessa al dispositivo Bluetooth scelto e potrà leggerne le 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 Comunicazione con i dispositivi Bluetooth tramite JavaScript.

A questo punto, sai come utilizzare Puppeteer per automatizzare l'utilizzo di un'app web con Bluetooth sostituendo il passaggio umano di selezione di un dispositivo dal menu di scelta del dispositivo Bluetooth. Sebbene possa essere utile in generale, è direttamente applicabile alla scrittura di un test end-to-end per un'app web di questo tipo.

Creare un test

L'elemento mancante per passare dal codice finora scritto a un test completo è estrarre le informazioni dall'app web e inserirle nello script Puppeteer. Una volta ottenuti, è abbastanza semplice utilizzare una libreria di test (come TAP o mocha) per verificare che i dati corretti siano stati letti e registrati.

Uno dei modi più semplici per farlo è scrivere i dati nel DOM. JavaScript offre molti modi per farlo senza librerie aggiuntive. Tornando alla tua ipotetica app web, potrebbe cambiare il colore di un indicatore di stato quando legge i dati dal dispositivo Bluetooth o stampare i dati letterali in un campo. Ad esempio:

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

In Puppeteer, Page.$eval() ti offre un modo per 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 e poi esegue la funzione di callback fornita con l'elemento come argomento. Una volta che hai questa variabile, utilizza la libreria di asserzioni per verificare se i dati sono quelli previsti.

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

Risorse aggiuntive

Per vedere esempi più complessi di scrittura di test per app web compatibili con il Bluetooth con Puppeteer, consulta questo repository: https://github.com/WebBluetoothCG/manual-tests/. Il gruppo della community Web Bluetooth gestisce questa suite di test, che possono essere eseguiti da un browser o localmente. Il test "Caratteristica di sola lettura" è molto simile all'esempio utilizzato in questo post del blog.

Riconoscimenti

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