UNPKG

@ledgerhq/live-common

Version:
215 lines • 9.42 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const hw_transport_1 = __importDefault(require("@ledgerhq/hw-transport")); const errors_1 = require("@ledgerhq/errors"); const getDeviceInfo_1 = __importDefault(require("./getDeviceInfo")); const getDeviceRunningMode_1 = require("./getDeviceRunningMode"); const aDeviceInfo_1 = require("../mock/fixtures/aDeviceInfo"); jest.useFakeTimers(); // Only mocks withDevice jest.mock("./deviceAccess", () => { const originalModule = jest.requireActual("./deviceAccess"); return { ...originalModule, withDevice: jest.fn().mockReturnValue(job => { return (0, rxjs_1.from)(job(new hw_transport_1.default())); }), }; }); // Needs to mock the timer from rxjs used in retryWhileErrors jest.mock("rxjs", () => { const originalModule = jest.requireActual("rxjs"); return { ...originalModule, timer: jest.fn(), }; }); const mockedTimer = jest.mocked(rxjs_1.timer); jest.mock("./getDeviceInfo"); const mockedGetDeviceInfo = jest.mocked(getDeviceInfo_1.default); const A_DEVICE_ID = ""; describe("getDeviceRunningMode", () => { beforeEach(() => { // @ts-expect-error the mocked function reflect an incorrect signature mockedTimer.mockReturnValue((0, rxjs_1.of)(1)); }); afterEach(() => { mockedTimer.mockClear(); mockedGetDeviceInfo.mockClear(); }); describe("When the device is in bootloader mode", () => { it("pushes an event bootloaderMode", done => { const aDeviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({ isBootloader: true }); mockedGetDeviceInfo.mockResolvedValue(aDeviceInfo); (0, getDeviceRunningMode_1.getDeviceRunningMode)({ deviceId: A_DEVICE_ID }).subscribe({ next: event => { try { expect(event.type).toBe("bootloaderMode"); done(); } catch (expectError) { done(expectError); } }, error: error => { // It should not reach here done(error); }, }); jest.advanceTimersByTime(1); }); describe("but for now it is restarting and/or in a unknown state", () => { it("it should wait and retry until the device is in bootloader", done => { const aDeviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({ isBootloader: true }); const nbAcceptedErrors = 3; let count = 0; // Could not simply mockedRejectValueOnce several times followed by // a mockedResolveValueOnce. Needed to transform getDeviceInfo // into an Observable. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mockedGetDeviceInfo.mockImplementation(() => { return new rxjs_1.Observable(o => { if (count < nbAcceptedErrors) { count++; o.error(new errors_1.DisconnectedDevice()); } else { o.next(aDeviceInfo); } }); }); (0, getDeviceRunningMode_1.getDeviceRunningMode)({ deviceId: A_DEVICE_ID, }).subscribe({ next: event => { try { expect(mockedTimer).toBeCalledTimes(nbAcceptedErrors); expect(event.type).toBe("bootloaderMode"); done(); } catch (expectError) { done(expectError); } }, error: error => { // It should not reach here done(error); }, }); // No need to handle the timer with a specific value as rxjs timer has been mocked // because we could not advance the timer every time the retryWhileErrors is called jest.advanceTimersByTime(1); }); }); }); describe("When the device is NOT in bootloader mode and unlocked", () => { it("pushes an event mainMode", done => { const aDeviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({ isBootloader: false }); mockedGetDeviceInfo.mockResolvedValue(aDeviceInfo); (0, getDeviceRunningMode_1.getDeviceRunningMode)({ deviceId: A_DEVICE_ID }).subscribe({ next: event => { try { expect(event.type).toBe("mainMode"); done(); } catch (expectError) { done(expectError); } }, error: error => { // It should not reach here done(error); }, }); jest.advanceTimersByTime(1); }); }); describe("When the device is locked (not in bootloader)", () => { describe("And is not responsive", () => { it("waits for a given time and pushes an event lockedDevice", done => { const unresponsiveTimeoutMs = 5000; // The deviceInfo will not be returned before the timeout // leading to an "unresponsive device" const aDeviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({ isBootloader: false }); mockedGetDeviceInfo.mockResolvedValue((0, rxjs_1.firstValueFrom)((0, rxjs_1.of)(aDeviceInfo).pipe((0, operators_1.delay)(unresponsiveTimeoutMs + 1000)))); (0, getDeviceRunningMode_1.getDeviceRunningMode)({ deviceId: A_DEVICE_ID, unresponsiveTimeoutMs, }).subscribe({ next: event => { try { expect(event.type).toBe("lockedDevice"); done(); } catch (expectError) { done(expectError); } }, error: error => { // It should not reach here done(error); }, }); jest.advanceTimersByTime(unresponsiveTimeoutMs + 1); }); }); describe("And the device responds with a locked device error", () => { it("pushes an event lockedDevice", done => { mockedGetDeviceInfo.mockRejectedValue(new errors_1.LockedDeviceError()); (0, getDeviceRunningMode_1.getDeviceRunningMode)({ deviceId: A_DEVICE_ID, }).subscribe({ next: event => { try { expect(event.type).toBe("lockedDevice"); done(); } catch (expectError) { done(expectError); } }, error: error => { // It should not reach here done(error); }, }); jest.advanceTimersByTime(1); }); }); describe("And the transport lib throws CantOpenDevice errors", () => { it("pushes an event disconnectedOrlockedDevice after a given number of retry", done => { const cantOpenDeviceRetryLimit = 3; mockedGetDeviceInfo.mockRejectedValue(new errors_1.CantOpenDevice()); (0, getDeviceRunningMode_1.getDeviceRunningMode)({ deviceId: A_DEVICE_ID, cantOpenDeviceRetryLimit, }).subscribe({ next: event => { try { expect(mockedTimer).toBeCalledTimes(cantOpenDeviceRetryLimit); expect(event.type).toBe("disconnectedOrlockedDevice"); done(); } catch (expectError) { done(expectError); } }, error: error => { // It should not reach here done(error); }, }); // No need to handle the timer with a specific value as rxjs timer has been mocked // because we could not advance the timer every time the retryWhileErrors is called jest.advanceTimersByTime(1); }); }); }); }); //# sourceMappingURL=getDeviceRunningMode.test.js.map