fix: retry macOS robot hotspot scans

This commit is contained in:
2026-08-17 20:43:24 +08:00
parent 7e8d9e3811
commit 55e61b7d8f
3 changed files with 201 additions and 8 deletions

View File

@@ -1,7 +1,7 @@
import { describe, expect, it, vi } from 'vitest';
import type { RobotHotspotAdapter, RobotHotspotAdapterCandidate } from '@electron/robot-hotspot/adapter';
import { RobotHotspotError, createRobotHotspotModule } from '@electron/robot-hotspot';
import { MacosWorkerController, requestMacosWorker } from '@electron/robot-hotspot/macos';
import { MacosWorkerController, requestMacosWorker, scanMacosCandidatesWithRetry } from '@electron/robot-hotspot/macos';
import type { MacosWorkerLike } from '@electron/robot-hotspot/macos';
function candidate(ssid: string, signalPercent: number, overrides: Partial<RobotHotspotAdapterCandidate> = {}): RobotHotspotAdapterCandidate {
@@ -22,6 +22,62 @@ async function expectCode(promise: Promise<unknown>, code: string): Promise<void
}
describe('Robot hotspot module', () => {
it('retries once when the first macOS scan hides every SSID and returns the recovered open hotspot', () => {
const readNetworks = vi.fn()
.mockReturnValueOnce([
{ ssid: null, rssi: -80, open: true },
{ ssid: '', rssi: -60, open: true },
])
.mockReturnValueOnce([
{ ssid: 'Xiaozhi-7A2B', rssi: -58, open: true },
{ ssid: 'Private-Network', rssi: -42, open: false },
]);
const waitBeforeRetry = vi.fn();
expect(scanMacosCandidatesWithRetry(readNetworks, 'Xiaozhi-7A2B', waitBeforeRetry)).toEqual([
{ ssid: 'Xiaozhi-7A2B', signalPercent: 84, connected: true, open: true },
]);
expect(readNetworks).toHaveBeenCalledTimes(2);
expect(waitBeforeRetry).toHaveBeenCalledOnce();
});
it('reports permission denied when both macOS scans find networks but expose no SSIDs', () => {
const readNetworks = vi.fn()
.mockReturnValueOnce([{ ssid: null, rssi: -70, open: true }])
.mockReturnValueOnce([{ ssid: '', rssi: -65, open: true }]);
expect(() => scanMacosCandidatesWithRetry(readNetworks, null, vi.fn())).toThrowError(
expect.objectContaining({ reason: 'permission_denied' }),
);
expect(readNetworks).toHaveBeenCalledTimes(2);
});
it('bounds an empty macOS scan retry and keeps an empty result empty', () => {
const readNetworks = vi.fn().mockReturnValue([]);
const waitBeforeRetry = vi.fn();
expect(scanMacosCandidatesWithRetry(readNetworks, null, waitBeforeRetry)).toEqual([]);
expect(readNetworks).toHaveBeenCalledTimes(2);
expect(waitBeforeRetry).toHaveBeenCalledOnce();
});
it('does not retry a readable macOS scan and filters secured networks while clamping RSSI', () => {
const readNetworks = vi.fn().mockReturnValue([
{ ssid: 'Xiaozhi-weak', rssi: -120, open: true },
{ ssid: 'Xiaozhi-strong', rssi: -20, open: true },
{ ssid: 'Xiaozhi-secured', rssi: -50, open: false },
{ ssid: null, rssi: -40, open: true },
]);
const waitBeforeRetry = vi.fn();
expect(scanMacosCandidatesWithRetry(readNetworks, 'Xiaozhi-strong', waitBeforeRetry)).toEqual([
{ ssid: 'Xiaozhi-weak', signalPercent: 0, connected: false, open: true },
{ ssid: 'Xiaozhi-strong', signalPercent: 100, connected: true, open: true },
]);
expect(readNetworks).toHaveBeenCalledOnce();
expect(waitBeforeRetry).not.toHaveBeenCalled();
});
it('terminates a hanging macOS native worker when the request is aborted', async () => {
const worker = {
postMessage: vi.fn(),