Puppeteer でウェブ Bluetooth をテストする

François Beaufort
François Beaufort

ウェブ Bluetooth は Chrome 56 以降でサポートされており、デベロッパーはユーザーのユーザーと直接通信するウェブアプリを記述できます。Bluetooth デバイス互換性のある Bluetooth デバイスにコードをアップロードする Espruino ウェブエディタはその一例です。これらのアプリケーションを Puppeteer でテストできるようになりました。

このブログ投稿では、Puppeteer を使用して Bluetooth 対応ウェブアプリを操作、テストする方法について説明します。その重要な部分は、Chrome の Bluetooth デバイス選択ツールを操作できる Puppeteer の機能です。

Chrome でのウェブ Bluetooth の使い方に慣れていない方のために、次の動画では、Espruino ウェブエディタでの Bluetooth のプロンプトについて説明しています。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">をご覧ください。
ユーザーが Espruino ウェブエディタで Puck.js Bluetooth デバイスを選択します。

このブログ投稿の手順を進めるには、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 では防止できない OS レベルの共有状態があります)。次のコードでこれを示します。

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

次に、Page.goto() を使用して、テストするウェブアプリの URL に移動します。

Bluetooth デバイスのメッセージを開く

Puppeteer を使用して Puppeteer でウェブアプリのページを開いたら、Bluetooth デバイスに接続してデータを読み取ることができます。次のステップでは、ウェブアプリに navigator.bluetooth.requestDevice() の呼び出しを含む JavaScript を実行するボタンがあることを前提としています。

Page.locator().click() を使用してそのボタンを押します。Page.waitForDevicePrompt() を使用して Bluetooth デバイス選択ツールが表示されるタイミングを認識できます。ボタンをクリックする前に waitForDevicePrompt() を呼び出す必要があります。そうしないと、プロンプトがすでに開いていて検出できません。

Puppeteer のメソッドはどちらも Promise を返すため、Promise.all() を使用すると、両方のメソッドを正しい順序でまとめて呼び出すことができます。

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

waitForDevicePrompt() から返される Promise は DeviceRequestPrompt オブジェクトに解決されます。このオブジェクトは、接続する Bluetooth デバイスを選択するために次に使用します。

デバイスを選択する

DeviceRequestPrompt.waitForDevice()DeviceRequestPrompt.select() を使用して、適切な Bluetooth デバイスを見つけて接続します。

DeviceRequestPrompt.waitForDevice() は、デバイスに関する基本情報を持つ Bluetooth デバイスを Chrome が検出するたびに、指定されたコールバックを呼び出します。コールバックが初めて true を返すと、waitForDevice() は一致した DeviceRequestPromptDevice に解決されます。Bluetooth デバイスを選択して接続するには、そのデバイスを DeviceRequestPrompt.select() に渡してください。

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 呼び出しについて詳しくは、JavaScript 経由で Bluetooth デバイスと通信するをご覧ください。

これで、Puppeteer を使用して、人手による Bluetooth デバイス選択ツールのメニューからデバイスを選択する手順を置き換えることで、Bluetooth 対応のウェブアプリを自動的に使用する方法を学びました。これは一般的に有用ですが、このようなウェブアプリのエンドツーエンド テストの作成に直接適用できます。

テストの作成

ここまでで、コードの記述から完全なテストの作成まで、ウェブアプリから Puppeteer スクリプトに情報を取得する必要があります。これを取得したら、テスト ライブラリ(TAPmocha など)を使用して、正しいデータが読み取られて報告されたことを簡単に確認できます。

これを行うための最も簡単な方法の 1 つは、データを 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);

参考情報

Puppeteer を使用して Bluetooth 対応ウェブアプリのテストを作成する複雑な例については、https://github.com/WebBluetoothCG/manual-tests/ のリポジトリをご覧ください。Web Bluetooth Community Group ではこの一連のテストを管理しており、すべてのテストをブラウザからローカルに実行できます。「読み取り専用の特性」test は、このブログ投稿で使用した例と非常によく似ています。

謝辞

このプロジェクトを開始し、この投稿に貴重なフィードバックを提供してくれた Vincent Scheib に感謝します。