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. 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 Bluetooth. La parte fondamentale di questo processo è 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 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 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"],
});

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 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, 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().

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

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

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 hai questa variabile, utilizza la libreria di asserzioni per verificare se i dati corrispondono a quanto previsto.

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 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.