@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
242 lines • 12.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
/**
* @jest-environment jsdom
*/
const react_1 = require("@testing-library/react");
const devices_1 = require("@ledgerhq/devices");
const useBleDevicesScanning_1 = require("./useBleDevicesScanning");
jest.useFakeTimers();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const nanoXServiceUuid = (0, devices_1.getDeviceModel)(devices_1.DeviceModelId.nanoX).bluetoothSpec[0].serviceUuid;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const staxServiceUuid = (0, devices_1.getDeviceModel)(devices_1.DeviceModelId.stax).bluetoothSpec[0].serviceUuid;
// Fake devices info we would get from the bluetooth transport listen
const aTransportBleDevice = (overrideProps) => {
return {
id: "aBleNanoId",
name: "aBleNano",
localName: null,
rssi: 50,
mtu: 50,
serviceUUIDs: [nanoXServiceUuid],
...overrideProps,
};
};
const mockBleTransportListenUnsubscribe = jest.fn();
// HOF creating a mocked Transport listen method to be given to useBleDevicesScanning
const setupMockBleTransportListen = (mockEmitValuesByObserver) => (observer) => {
mockEmitValuesByObserver(observer);
return {
unsubscribe: mockBleTransportListenUnsubscribe,
};
};
describe("useBleDevicesScanning", () => {
afterEach(() => {
jest.clearAllTimers();
mockBleTransportListenUnsubscribe.mockClear();
});
describe("When several unique devices are found by the scanner", () => {
const deviceIdA = "ID_A";
const deviceIdB = "ID_B";
const deviceIdC = "ID_C";
const mockEmitValuesByObserver = (observer) => {
observer.next({
type: "add",
descriptor: aTransportBleDevice({ id: deviceIdA }),
});
setTimeout(() => {
observer.next({
type: "add",
descriptor: aTransportBleDevice({
id: deviceIdB,
serviceUUIDs: [staxServiceUuid],
}),
});
}, 1000);
setTimeout(() => {
observer.next({
type: "add",
descriptor: aTransportBleDevice({ id: deviceIdC }),
});
}, 2000);
};
describe("and when no filters are applied to the scanning", () => {
it("should update the list of scanned devices for each new scanned device", async () => {
const { result } = (0, react_1.renderHook)(() => (0, useBleDevicesScanning_1.useBleDevicesScanning)({
bleTransportListen: setupMockBleTransportListen(mockEmitValuesByObserver),
}));
expect(result.current.scannedDevices).toHaveLength(1);
expect(result.current.scannedDevices[0].deviceId).toBe(deviceIdA);
// The model was correctly deduced from the ble spec
expect(result.current.scannedDevices[0].deviceModel.id).toBe(devices_1.DeviceModelId.nanoX);
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(1000);
});
expect(result.current.scannedDevices).toHaveLength(2);
expect(result.current.scannedDevices[1].deviceId).toBe(deviceIdB);
expect(result.current.scannedDevices[1].deviceModel.id).toBe(devices_1.DeviceModelId.stax);
});
});
describe("and when filterByDeviceModelIds is not null", () => {
it("should filter the scanning result by the given model ids", async () => {
const { result } = (0, react_1.renderHook)(() => (0, useBleDevicesScanning_1.useBleDevicesScanning)({
bleTransportListen: setupMockBleTransportListen(mockEmitValuesByObserver),
filterByDeviceModelIds: [devices_1.DeviceModelId.nanoX],
}));
// The first scanned device was a nanoX
expect(result.current.scannedDevices).toHaveLength(1);
expect(result.current.scannedDevices[0].deviceId).toBe(deviceIdA);
// The model was correctly deduced from the ble spec
expect(result.current.scannedDevices[0].deviceModel.id).toBe(devices_1.DeviceModelId.nanoX);
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(1000);
});
// The second scanned device was a stax, and was filtered out
expect(result.current.scannedDevices).toHaveLength(1);
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(1000);
});
// The third scanned device was a nanoX
expect(result.current.scannedDevices).toHaveLength(2);
expect(result.current.scannedDevices[1].deviceId).toBe(deviceIdC);
expect(result.current.scannedDevices[1].deviceModel.id).toBe(devices_1.DeviceModelId.nanoX);
});
});
describe("and when filterOutDevicesByDeviceIds is not null nor empty", () => {
it("should not add the scanned device if its ids is in the array", async () => {
const { result } = (0, react_1.renderHook)(() => (0, useBleDevicesScanning_1.useBleDevicesScanning)({
bleTransportListen: setupMockBleTransportListen(mockEmitValuesByObserver),
filterOutDevicesByDeviceIds: [deviceIdA, deviceIdC],
}));
// The first scanned device (deviceIdA) should be filtered out
expect(result.current.scannedDevices).toHaveLength(0);
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(1000);
});
// The second scanned device is deviceIdB and should be kept
expect(result.current.scannedDevices).toHaveLength(1);
expect(result.current.scannedDevices[0].deviceId).toBe(deviceIdB);
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(1000);
});
// The third scanned device (deviceIdC) should be filtered out
expect(result.current.scannedDevices).toHaveLength(1);
});
});
describe("and when the hook consumer stops the scanning", () => {
it("should stop the scanning", async () => {
let stopBleScanning = false;
const { result, rerender } = (0, react_1.renderHook)(() => (0, useBleDevicesScanning_1.useBleDevicesScanning)({
bleTransportListen: setupMockBleTransportListen(mockEmitValuesByObserver),
stopBleScanning,
}));
// At first the scanning finds device(s)
expect(result.current.scannedDevices).toHaveLength(1);
expect(result.current.scannedDevices[0].deviceId).toBe(deviceIdA);
expect(result.current.scannedDevices[0].deviceModel.id).toBe(devices_1.DeviceModelId.nanoX);
// Then the consumer stops the scanning
stopBleScanning = true;
rerender({
bleTransportListen: setupMockBleTransportListen(mockEmitValuesByObserver),
stopBleScanning,
});
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(2000);
});
// It should not find any new devices
expect(result.current.scannedDevices).toHaveLength(1);
});
});
});
describe("When the same device is being scanned several times", () => {
const deviceIdA = "ID_A";
const deviceIdB = "ID_B";
const mockEmitValuesByObserver = (observer) => {
observer.next({
type: "add",
descriptor: aTransportBleDevice({ id: deviceIdA }),
});
setTimeout(() => {
observer.next({
type: "add",
descriptor: aTransportBleDevice({ id: deviceIdA }),
});
}, 1000);
setTimeout(() => {
observer.next({
type: "add",
descriptor: aTransportBleDevice({ id: deviceIdB }),
});
}, 2000);
};
it("should update the list of scanned devices without any duplicate", async () => {
const { result } = (0, react_1.renderHook)(() => (0, useBleDevicesScanning_1.useBleDevicesScanning)({
bleTransportListen: setupMockBleTransportListen(mockEmitValuesByObserver),
}));
// The first time it gets the device from the scanning
expect(result.current.scannedDevices).toHaveLength(1);
expect(result.current.scannedDevices[0].deviceId).toBe(deviceIdA);
expect(result.current.scannedDevices[0].deviceModel.id).toBe(devices_1.DeviceModelId.nanoX);
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(1000);
});
// The second time it gets the same device from the scanning
// It should not have been added to the list
expect(result.current.scannedDevices).toHaveLength(1);
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(1000);
});
// The third time it gets a new device
expect(result.current.scannedDevices).toHaveLength(2);
expect(result.current.scannedDevices[1].deviceId).toBe(deviceIdB);
expect(result.current.scannedDevices[1].deviceModel.id).toBe(devices_1.DeviceModelId.nanoX);
});
});
describe("When a device is only seen after a cleaned scanning", () => {
const deviceIdA = "ID_A";
const deviceIdB = "ID_B";
const emitTimeOfDeviceB = 3000;
const mockEmitValuesByObserver = (observer) => {
observer.next({
type: "add",
descriptor: aTransportBleDevice({ id: deviceIdA }),
});
setTimeout(() => {
observer.next({
type: "add",
descriptor: aTransportBleDevice({ id: deviceIdB }),
});
}, emitTimeOfDeviceB);
};
it("should restart the scanning after a defined time and update the list of scanned devices", async () => {
const restartScanningTimeoutMs = emitTimeOfDeviceB;
// To avoid re-rendering the hook when mockEmitValuesByObserver
// emits a new value with the setTimeout
const bleTransportListen = setupMockBleTransportListen(mockEmitValuesByObserver);
const { result } = (0, react_1.renderHook)(() => (0, useBleDevicesScanning_1.useBleDevicesScanning)({
bleTransportListen,
restartScanningTimeoutMs,
}));
// The first time it gets the device from the scanning
expect(result.current.scannedDevices).toHaveLength(1);
expect(result.current.scannedDevices[0].deviceId).toBe(deviceIdA);
expect(result.current.scannedDevices[0].deviceModel.id).toBe(devices_1.DeviceModelId.nanoX);
const nbUnsubscribesHappeningBecauseOfRenderHook = mockBleTransportListenUnsubscribe.mock.calls.length;
// Advances by less than the first restart timeout
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(restartScanningTimeoutMs - 1000);
});
expect(mockBleTransportListenUnsubscribe).toBeCalledTimes(nbUnsubscribesHappeningBecauseOfRenderHook);
// Advances by the total time of the restart timeout
await (0, react_1.act)(async () => {
jest.advanceTimersByTime(1000);
});
expect(mockBleTransportListenUnsubscribe).toBeCalledTimes(nbUnsubscribesHappeningBecauseOfRenderHook + 1);
expect(result.current.scannedDevices).toHaveLength(2);
expect(result.current.scannedDevices[1].deviceId).toBe(deviceIdB);
expect(result.current.scannedDevices[1].deviceModel.id).toBe(devices_1.DeviceModelId.nanoX);
});
});
});
//# sourceMappingURL=useBleDevicesScanning.test.js.map