Testar o Web Bluetooth com o Puppeteer

François Beaufort
François Beaufort

O Bluetooth Web tem suporte desde o Chrome 56 e permite que os desenvolvedores criem apps da Web que se comunicam diretamente com os usuários Dispositivos Bluetooth. A capacidade do editor da Web Espruino de fazer upload de código para dispositivos Bluetooth compatíveis é um exemplo disso. Testar esses aplicativos agora é possível com o Puppeteer.

Esta postagem de blog mostra como usar o Puppeteer para operar e testar um aplicativo da Web habilitado para Bluetooth. A parte principal disso é a capacidade do Puppeteer de operar o seletor de dispositivos Bluetooth do Chrome.

Se você não sabe usar o Web Bluetooth no Chrome, o vídeo a seguir mostra a solicitação de Bluetooth no editor da Web Espruino:

O usuário seleciona um dispositivo Bluetooth Puck.js no editor da Web do Espruino.

Para acompanhar esta postagem do blog, você precisará de um app da Web com Bluetooth, um dispositivo Bluetooth com o qual ele possa se comunicar e estar usando o Puppeteer v21.4.0 ou posterior.

Inicie o navegador

Como na maioria dos scripts do Puppeteer, inicie o navegador com Puppeteer.launch(). Para acessar os recursos do Bluetooth, você precisa fornecer alguns argumentos extras:

import puppeteer from 'puppeteer';

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

Ao abrir a primeira página, geralmente é recomendável usar um contexto de navegador anônimo. Isso ajuda a evitar o vazamento de permissões entre os testes executados com seu script (embora haja alguns estados compartilhados no nível do SO que não podem ser impedidos pelo Puppeteer). O código a seguir demonstra isso:

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

Em seguida, acesse o URL do app da Web que você está testando com Page.goto().

Abrir a solicitação do dispositivo Bluetooth

Depois de usar o Puppeteer para abrir a página do app da Web com ele, será possível se conectar ao dispositivo Bluetooth para ler dados. Esta próxima etapa pressupõe que você tenha um botão em seu app da Web que execute algum código JavaScript, incluindo uma chamada para navigator.bluetooth.requestDevice().

Use Page.locator().click() para pressionar esse botão e Page.waitForDevicePrompt() para reconhecer quando o seletor de dispositivos Bluetooth aparece. Você precisa chamar waitForDevicePrompt() antes de clicar no botão. Caso contrário, a solicitação já será aberta e ele não conseguirá detectá-lo.

Como os dois métodos do Puppeteer retornam promessas, o Promise.all() é uma maneira conveniente de chamá-los juntos na ordem correta:

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

A promessa retornada por waitForDevicePrompt() é resolvida em um objeto DeviceRequestPrompt, que você vai usar em seguida para selecionar o dispositivo Bluetooth a que quer se conectar.

Selecionar um dispositivo

Use DeviceRequestPrompt.waitForDevice() e DeviceRequestPrompt.select() para encontrar e se conectar ao dispositivo Bluetooth correto.

DeviceRequestPrompt.waitForDevice() chama o callback fornecido sempre que o Chrome encontra um dispositivo Bluetooth com algumas informações básicas sobre ele. Na primeira vez que o callback retornar "true", waitForDevice() será resolvido como o DeviceRequestPromptDevice correspondente. Transmita esse dispositivo ao DeviceRequestPrompt.select() para que ele possa ser selecionado e conectado a ele.

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

Quando o DeviceRequestPrompt.select() for resolvido, o Chrome será conectado ao dispositivo e a página da Web poderá acessá-lo.

Ler no dispositivo

Neste ponto, seu app da Web estará conectado ao dispositivo Bluetooth escolhido e poderá ler informações dele. O resultado será algo como o seguinte:

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 um tutorial mais detalhado dessa sequência de chamadas de API, consulte Comunicação com dispositivos Bluetooth por JavaScript.

A esta altura, você já sabe como usar o Puppeteer para automatizar o uso de um aplicativo da web habilitado para Bluetooth, substituindo a etapa humana de selecionar um dispositivo no menu seletor de dispositivos Bluetooth. Embora isso possa ser útil de modo geral, é diretamente aplicável à criação de um teste completo para esse aplicativo da Web.

Criar um teste

A parte que faltava de levar o código até agora até escrever um teste completo é conseguir informações do aplicativo da Web para o script Puppeteer. Com isso, é bem simples usar uma biblioteca de testes (como TAP ou mocha) para verificar se os dados corretos foram lidos e informados.

Uma das maneiras mais fáceis de fazer isso é gravar dados no DOM. O JavaScript tem muitas maneiras de fazer isso sem bibliotecas adicionais. Voltando ao seu app da Web hipotético, ele pode mudar a cor de um indicador de status ao ler dados do dispositivo Bluetooth ou imprimir os dados literais em um campo. Exemplo:

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

No Puppeteer, o Page.$eval() (link em inglês) oferece uma maneira de extrair esses dados do DOM da página e colocá-los em um script de teste. $eval() usa a mesma lógica de document.querySelector() para encontrar um elemento e executa a função de callback fornecida com esse elemento como argumento. Depois de definir isso como uma variável, use sua biblioteca de declarações para testar se os dados são o que esperamos.

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

Outros recursos

Para ver exemplos mais complexos de criação de testes para apps da Web com Bluetooth ativado com o Puppeteer, consulte este repositório: https://github.com/WebBluetoothCG/manual-tests/. O Grupo da comunidade do Web Bluetooth mantém esse conjunto de testes, que podem ser executados em um navegador ou localmente. A "característica somente leitura" test é o mais semelhante ao exemplo usado nesta postagem do blog.

Agradecimentos

Agradecemos a Vincent Scheib por iniciar este projeto e fornecer feedback valioso nesta publicação.