自 Chrome 56 起,我們就已支援 Web Bluetooth,開發人員可以撰寫可直接與使用者藍牙裝置通訊的網頁應用程式。舉例來說,Espruino 網頁編輯器可將程式碼上傳至相容的藍牙裝置。您現在可以使用 Puppeteer 測試這些應用程式。
這篇網誌文章將詳細說明如何使用 Puppeteer 操作及測試支援藍牙的網路應用程式。其中的重點是 Puppeteer 可操作 Chrome 的藍牙裝置選擇器。
如果您不熟悉如何在 Chrome 中使用 Web Bluetooth,請觀看下方影片,瞭解 Espruino 網頁編輯器中的藍牙提示:
如要追蹤這篇網誌文章,您需要具備藍牙功能的網頁應用程式、可與 Puppeteer v21.4.0 以上版本通訊的藍牙裝置。
啟動瀏覽器
如同大多數 Puppeteer 指令碼,請先使用 Puppeteer.launch()
啟動瀏覽器。如要存取藍牙功能,您必須提供一些額外的引數:
- 停用無頭模式:這表示 Puppeteer 會開啟可見的 Chrome 瀏覽器視窗來執行測試。如果您偏好在沒有 UI 的情況下執行,請使用新版無頭模式。舊版無頭模式不支援顯示藍牙提示。
- 其他 Chromium 引數:為 Linux 環境傳遞 「enable Web 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()
前往要測試的網頁應用程式網址。
開啟藍牙裝置提示
使用 Puppeteer 開啟網路應用程式的網頁後,您可以連線至藍牙裝置來讀取資料。在下一個步驟中,我們假設您的網頁應用程式中有一個按鈕,可執行一些 JavaScript,包括呼叫 navigator.bluetooth.requestDevice()
。
使用 Page.locator().click()
按下該按鈕,並使用 Page.waitForDevicePrompt()
辨識藍牙裝置選擇器顯示的時間。您必須在點選按鈕前呼叫 waitForDevicePrompt()
,否則提示會先開啟,系統就無法偵測。
由於這兩種 Puppeteer 方法都傳回承諾,因此使用 Promise.all()
時,能以正確順序同時呼叫這些方法,既簡單又方便:
const [devicePrompt] = await Promise.all([
page.waitForDevicePrompt(),
page.locator("#start-test-button").click(),
]);
waitForDevicePrompt()
傳回的承諾會解析為 DeviceRequestPrompt
物件,您接下來會使用該物件選取要連線的藍牙裝置。
選取裝置
使用 DeviceRequestPrompt.waitForDevice()
和 DeviceRequestPrompt.select()
尋找並連線至正確的藍牙裝置。
每當 Chrome 找到含有裝置基本資訊的藍牙裝置時,DeviceRequestPrompt.waitForDevice()
就會呼叫提供的回呼。回呼第一次傳回 true 時,waitForDevice()
會解析為相符的 DeviceRequestPromptDevice
。將該裝置傳遞至 DeviceRequestPrompt.select()
,即可選取並連線至該藍牙裝置。
const bluetoothDevice = await devicePrompt.waitForDevice(
(d) => d.name == wantedDeviceName,
);
await devicePrompt.select(bluetoothDevice);
DeviceRequestPrompt.select()
解析後,Chrome 就會連線至裝置,網頁就能存取裝置。
從裝置讀取
此時,您的網路應用程式會連線至所選的藍牙裝置,並可讀取該裝置的資訊。如下所示:
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 與藍牙裝置通訊。
到目前為止,您已瞭解如何使用 Puppeteer 自動化使用支援藍牙的網路應用程式,方法是取代人為從藍牙裝置選擇器選單中選取裝置的步驟。雖然這種做法通常很實用,但您也可以直接為這類網頁應用程式撰寫端對端測試。
建立測試
從目前的程式碼到編寫完整測試,缺少的部分就是從網頁應用程式擷取資訊,並將其納入 Puppeteer 指令碼。完成後,您可以輕鬆使用測試程式庫 (例如 TAP 或 mocha),驗證系統是否讀取並回報正確的資料。
最簡單的做法是將資料寫入 DOM。JavaScript 有許多方法可用於這項作業,而且不需要額外的程式庫。回到假設的網頁應用程式,當應用程式從藍牙裝置讀取資料,或在欄位中列印文字資料時,可能會變更狀態指標的顏色。例如:
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 為支援藍牙的網路應用程式編寫測試的更複雜範例,請參閱這個存放區:https://github.com/WebBluetoothCG/manual-tests/。Web Bluetooth 社群群組會維護這套測試,所有測試都可以在瀏覽器或本機上執行。「唯讀特徵」測試最接近本網誌文章中使用的範例。
特別銘謝
感謝 Vincent Scheib 啟動這個專案,並對這篇文章提供寶貴的意見回饋。