Тестирование веб-Bluetooth с помощью Puppeteer

Франсуа Бофор
François Beaufort

Веб-Bluetooth поддерживается начиная с Chrome 56 и позволяет разработчикам создавать веб-приложения, которые напрямую взаимодействуют с устройствами Bluetooth пользователей. Одним из таких примеров является возможность веб-редактора Espruino загружать код на совместимые устройства Bluetooth. Тестирование этих приложений теперь возможно с помощью Puppeteer .

В этом сообщении блога рассказывается, как использовать Puppeteer для работы и тестирования веб-приложения с поддержкой Bluetooth. Ключевой частью этого является способность Puppeteer управлять устройством выбора Bluetooth-устройства Chrome.

Если вы не знакомы с использованием Web Bluetooth в Chrome, в следующем видео показано приглашение Bluetooth в веб-редакторе Espruino:

Пользователь выбирает Bluetooth-устройство Puck.js в веб-редакторе Espruino.

Чтобы следить за этим сообщением в блоге, вам понадобится веб-приложение с поддержкой Bluetooth, устройство Bluetooth, с которым оно может обмениваться данными, и использовать Puppeteer v21.4.0 или более позднюю версию.

Запустите браузер

Как и в большинстве сценариев Puppeteer, начните с запуска браузера с помощью Puppeteer.launch() . Чтобы получить доступ к функциям Bluetooth, вам необходимо предоставить несколько дополнительных аргументов:

import puppeteer from 'puppeteer';

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

При открытии первой страницы обычно рекомендуется использовать контекст браузера в режиме инкогнито . Это помогает предотвратить утечку разрешений между тестами, выполняемыми с помощью вашего скрипта (хотя существует некоторое общее состояние на уровне ОС, которое Puppeteer не может предотвратить). Следующий код демонстрирует это:

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

Затем вы можете перейти к URL-адресу тестируемого веб-приложения с помощью Page.goto() .

Откройте приглашение устройства Bluetooth

После того, как вы использовали Puppeteer для открытия страницы веб-приложения с помощью Puppeteer, вы можете подключиться к устройству Bluetooth для чтения данных. На следующем шаге предполагается, что в вашем веб-приложении есть кнопка, которая запускает некоторый JavaScript, включая вызов navigator.bluetooth.requestDevice() .

Используйте Page.locator().click() чтобы нажать эту кнопку, и Page.waitForDevicePrompt() , чтобы распознать появление средства выбора устройства Bluetooth. Вы должны вызвать waitForDevicePrompt() перед нажатием кнопки, иначе приглашение уже откроется, и оно не сможет его обнаружить.

Поскольку оба метода Puppeteer возвращают обещания, Promise.all() — удобный способ вызвать их вместе в правильном порядке:

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

Обещание, возвращаемое функцией waitForDevicePrompt() преобразуется в объект DeviceRequestPrompt , который вы будете использовать далее для выбора устройства Bluetooth, к которому хотите подключиться.

Выберите устройство

Используйте DeviceRequestPrompt.waitForDevice() и DeviceRequestPrompt.select() чтобы найти и подключиться к правильному устройству Bluetooth.

DeviceRequestPrompt.waitForDevice() вызывает предоставленный обратный вызов каждый раз, когда Chrome находит устройство Bluetooth с некоторой базовой информацией об устройстве . Когда обратный вызов в первый раз возвращает true, waitForDevice() разрешает соответствующий DeviceRequestPromptDevice . Передайте это устройство в DeviceRequestPrompt.select() чтобы выбрать и подключиться к этому устройству Bluetooth.

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

После разрешения DeviceRequestPrompt.select() Chrome подключается к устройству, и веб-страница получает к нему доступ.

Чтение с устройства

На этом этапе ваше веб-приложение будет подключено к выбранному устройству Bluetooth и сможет считывать с него информацию. Это может выглядеть так:

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

Более подробное описание этой последовательности вызовов API см. в разделе Связь с устройствами Bluetooth через JavaScript .

К этому моменту вы знаете, как использовать Puppeteer для автоматизации использования веб-приложения с поддержкой Bluetooth, заменив человеческий шаг по выбору устройства из меню выбора устройства Bluetooth. Хотя в целом это может быть полезно, это напрямую применимо к написанию сквозного теста для такого веб-приложения.

Создать тест

Недостающим звеном от написания кода до написания полноценного теста является получение информации из веб-приложения в ваш скрипт Puppeteer. Если у вас это есть, довольно просто использовать библиотеку тестирования (например, TAP или mocha ), чтобы убедиться, что правильные данные были прочитаны и отправлены в отчет.

Один из самых простых способов сделать это — записать данные в DOM. В JavaScript есть множество способов сделать это без дополнительных библиотек. Возвращаясь к вашему гипотетическому веб-приложению, оно может изменить цвет индикатора состояния, когда считывает данные с устройства Bluetooth или печатает буквальные данные в поле. Например:

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

В Puppeteer Page.$eval() дает вам возможность извлечь эти данные из DOM страницы в тестовый скрипт. $eval() использует ту же логику, что и document.querySelector() чтобы найти элемент, а затем запускает предоставленную функцию обратного вызова с этим элементом в качестве аргумента. Получив это как переменную, используйте свою библиотеку утверждений, чтобы проверить, соответствуют ли данные нашим ожиданиям.

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

Дополнительные ресурсы

Чтобы увидеть более сложные примеры написания тестов для веб-приложений с поддержкой Bluetooth с помощью Puppeteer, посетите этот репозиторий: https://github.com/WebBluetoothCG/manual-tests/ . Группа сообщества Web Bluetooth поддерживает этот набор тестов, каждый из которых можно запускать из браузера или локально. Тест «Характеристика только для чтения» наиболее похож на пример, использованный в этой записи блога.

Благодарности

Спасибо Винсенту Шейбу за начало этого проекта и ценный отзыв по этому посту.