JavaScript蓝牙降级核心是执行前检测navigator.bluetooth是否存在且requestDevice可用,通过工厂模式分离逻辑并用mock覆盖测试,CI中禁用WebBluetooth特性验证降级路径。

JavaScript 中处理蓝牙设备未支持 API 的降级分支,核心在于主动检测、合理回退、并确保测试能覆盖所有路径——尤其是 navigator.bluetooth 不存在或不可用的场景。
明确降级触发条件
降级不是“API 调用失败才触发”,而是要在执行前就判断环境是否具备基础能力。关键检查点包括:
-
'bluetooth' in navigator—— 检查全局对象是否暴露bluetooth属性(最基础的 UA 支持) -
typeof navigator.bluetooth?.requestDevice === 'function'—— 确认核心方法存在且可调用(避免部分实验性环境仅挂载空对象) - 在非安全上下文(如 HTTP 页面)中,
navigator.bluetooth可能为undefined或抛出SecurityError,需单独捕获
结构化降级逻辑,分离可测分支
避免把降级逻辑揉进业务函数内部。推荐用工厂或策略模式提前分流:
const BluetoothService = (() => {
if (!('bluetooth' in navigator) || !navigator.bluetooth?.requestDevice) {
return { isEnabled: false, requestDevice: () => Promise.reject(new Error('Bluetooth API not available')) };
}
return {
isEnabled: true,
requestDevice: (options) => navigator.bluetooth.requestDevice(options)
};
})();
这样测试时只需 mock navigator.bluetooth 为 undefined 或 {},就能 100% 进入降级分支,无需真实设备或权限弹窗。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
单元测试覆盖降级路径的关键技巧
使用 Jest 或 Vitest 时,重点模拟浏览器环境缺失状态:
- 在测试前删除属性:
delete (window.navigator as any).bluetooth - 或临时覆盖:
Object.defineProperty(navigator, 'bluetooth', { value: undefined, configurable: true }) - 运行被测函数后,断言是否返回预期的 fallback 值(如空数组、
null、提示消息)、是否调用了替代方案(如 localStorage 提示、二维码配对入口) - 对异步降级逻辑(如尝试后退到 Web Serial),用
jest.useFakeTimers()控制超时分支
真实环境验证不能只靠桌面 Chrome
不同平台降级表现差异大:
- iOS Safari:始终不支持 Web Bluetooth,
navigator.bluetooth永远undefined - Android WebView(旧版):可能有
bluetooth对象但方法不可用,需 try/catchrequestDevice - Windows 桌面 Edge/Chrome:需开启「Experimental Web Platform features」才能启用,否则视为不支持
CI 中建议用 Puppeteer 启动禁用蓝牙的 Chromium:chromium.launch({ args: ['--disable-features=WebBluetooth'] }),直接触发降级路径。

















