@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
478 lines • 19.9 kB
JavaScript
;
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 errors_1 = require("@ledgerhq/errors");
const hw_transport_mocker_1 = require("@ledgerhq/hw-transport-mocker");
const listApps_1 = require("./listApps");
const api_1 = __importDefault(require("../manager/api"));
const aDeviceInfo_1 = require("../mock/fixtures/aDeviceInfo");
const HttpManagerApiRepositoryFactory_1 = require("../device/factories/HttpManagerApiRepositoryFactory");
const isCustomLockScreenSupported_1 = require("../device/use-cases/isCustomLockScreenSupported");
const customLockScreenFetchSize_1 = __importDefault(require("../hw/customLockScreenFetchSize"));
const getDeviceNameUseCase_1 = require("../device/use-cases/getDeviceNameUseCase");
const currencies_1 = require("../currencies");
const mock_1 = require("./mock");
jest.useFakeTimers();
jest.mock("../hw/customLockScreenFetchSize");
jest.mock("../device/use-cases/getDeviceNameUseCase");
jest.mock("../currencies");
const mockedCustomLockScreenFetchSize = jest.mocked(customLockScreenFetchSize_1.default);
const mockedGetDeviceName = jest.mocked(getDeviceNameUseCase_1.getDeviceName);
const mockedListCryptoCurrencies = jest.mocked(currencies_1.listCryptoCurrencies);
const mockedCurrenciesByMarketCap = jest.mocked(currencies_1.currenciesByMarketcap);
const mockedListInstalledAppEvent = {
type: "result",
payload: [],
};
describe("listApps", () => {
let mockedManagerApiRepository;
let listAppsCommandSpy;
let listAppsWithManagerApiSpy;
beforeEach(() => {
jest
.spyOn(jest.requireActual("../device/use-cases/getLatestFirmwareForDeviceUseCase"), "getLatestFirmwareForDeviceUseCase")
.mockReturnValue(Promise.resolve(null));
mockedManagerApiRepository = new HttpManagerApiRepositoryFactory_1.StubManagerApiRepository();
mockedGetDeviceName.mockReturnValue(Promise.resolve("Mocked device name"));
mockedCurrenciesByMarketCap.mockReturnValue(Promise.resolve([]));
mockedListCryptoCurrencies.mockReturnValue([]);
listAppsCommandSpy = jest
.spyOn(jest.requireActual("../hw/listApps"), "default")
.mockReturnValue(Promise.resolve([]));
listAppsWithManagerApiSpy = jest
.spyOn(api_1.default, "listInstalledApps")
.mockReturnValue((0, rxjs_1.from)([mockedListInstalledAppEvent]));
});
afterEach(() => {
jest.clearAllTimers();
jest.restoreAllMocks();
});
it("should return an observable that errors if deviceInfo.isOSU is true", done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({ isOSU: true, isBootloader: false });
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
error: err => {
expect(err).toBeInstanceOf(errors_1.UnexpectedBootloader);
done();
},
complete: () => {
done("this observable should not complete");
},
});
jest.advanceTimersByTime(1);
});
it("should return an observable that errors if deviceInfo.isBootloader is true", done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({ isOSU: false, isBootloader: true });
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
error: err => {
expect(err).toBeInstanceOf(errors_1.UnexpectedBootloader);
done();
},
complete: () => {
done("this observable should not complete");
},
});
jest.advanceTimersByTime(1);
});
it("should return an observable that errors if transport.deviceModel.id is undefined, identifyTargetId returns a falsy value and deviceProxyModel is undefined", done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)({ deviceModel: null });
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({ isOSU: false, isBootloader: false, targetId: 0 });
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
error: err => {
expect(err.message).toBe("Bad usage of listAppsV2: missing deviceModelId");
done();
},
complete: () => {
done("this observable should not complete");
},
});
jest.advanceTimersByTime(1);
});
it("should call hwListApps() if deviceInfo.managerAllowed is true", done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: true,
targetId: 0x33200000,
});
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
complete: () => {
done();
},
error: () => {
done();
},
});
jest.advanceTimersByTime(1);
expect(listAppsCommandSpy).toHaveBeenCalled();
expect(listAppsWithManagerApiSpy).not.toHaveBeenCalled();
});
[
errors_1.StatusCodes.CLA_NOT_SUPPORTED,
errors_1.StatusCodes.INS_NOT_SUPPORTED,
errors_1.StatusCodes.UNKNOWN_APDU,
0x6e01,
0x6d01,
].forEach(statusCode => {
it(`should call ManagerAPI.listInstalledApps() if deviceInfo.managerAllowed is true but list apps APDU returns 0x${statusCode.toString(16)}`, done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: true,
targetId: 0x33200000,
});
listAppsCommandSpy.mockRejectedValue(new errors_1.TransportStatusError(statusCode));
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
complete: () => {
try {
expect(listAppsCommandSpy).toHaveBeenCalled();
expect(listAppsWithManagerApiSpy).toHaveBeenCalled();
done();
}
catch (e) {
done(e);
}
},
error: e => {
done(e);
},
});
jest.advanceTimersByTime(1);
});
});
it("should return an observable that errors if listApps() throws an error that is not a TransportStatusError", done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: true,
targetId: 0x33200000,
});
listAppsCommandSpy.mockRejectedValue(new Error("listApps failed"));
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
error: err => {
try {
expect(err).toEqual(new Error("listApps failed"));
done();
}
catch (e) {
done(e);
}
},
complete: () => {
done("this observable should not complete");
},
});
jest.advanceTimersByTime(1);
});
it("should call ManagerAPI.listInstalledApps() if deviceInfo.managerAllowed is false", () => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: false,
targetId: 0x33200000,
});
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe();
jest.advanceTimersByTime(1);
expect(listAppsCommandSpy).not.toHaveBeenCalled();
expect(listAppsWithManagerApiSpy).toHaveBeenCalled();
});
it("should return an observable that errors if getDeviceVersion() throws", done => {
jest.spyOn(mockedManagerApiRepository, "getDeviceVersion").mockImplementation(() => {
throw new Error("getDeviceVersion failed");
});
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: false,
targetId: 0x33200000,
});
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
error: err => {
expect(err.message).toBe("getDeviceVersion failed");
done();
},
complete: () => {
done("this observable should not complete");
},
});
jest.advanceTimersByTime(1);
});
it("should return an observable that errors if catalogForDevice() throws", done => {
jest.spyOn(mockedManagerApiRepository, "catalogForDevice").mockImplementation(() => {
throw new Error("catalogForDevice failed");
});
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: false,
targetId: 0x33200000,
});
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
error: err => {
expect(err.message).toBe("catalogForDevice failed");
done();
},
complete: () => {
done("this observable should not complete");
},
});
jest.advanceTimersByTime(1);
});
it("should return an observable that errors if getLanguagePackagesForDevice() throws", done => {
jest
.spyOn(mockedManagerApiRepository, "getLanguagePackagesForDevice")
.mockImplementation(() => {
throw new Error("getLanguagePackagesForDevice failed");
});
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: false,
targetId: 0x33200000,
});
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
error: err => {
expect(err.message).toBe("getLanguagePackagesForDevice failed");
done();
},
complete: () => {
done("this observable should not complete");
},
});
jest.advanceTimersByTime(1);
});
isCustomLockScreenSupported_1.supportedDeviceModelIds.forEach(deviceModelId => {
it(`should return customImageBlocks different than 0 for a ${deviceModelId} device with a custom lock screen`, done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)({ deviceModel: { id: deviceModelId } });
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: true,
targetId: 0x33200000,
});
mockedCustomLockScreenFetchSize.mockReturnValue(Promise.resolve(10));
let gotResult = false;
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
next: listAppsEvent => {
if (listAppsEvent.type === "result") {
gotResult = true;
const { result: { customImageBlocks }, } = listAppsEvent;
try {
expect(customImageBlocks).not.toBe(0);
}
catch (e) {
done(e);
}
}
},
complete: () => {
gotResult ? done() : done("this observable should not complete without a result");
},
error: error => {
done(error);
},
});
jest.advanceTimersByTime(1);
});
});
it("should keep apps with isDevTools if managerDevModeEnabled is true", done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: true,
targetId: 0x33200000,
});
mockedManagerApiRepository = {
...new HttpManagerApiRepositoryFactory_1.StubManagerApiRepository(),
catalogForDevice: () => Promise.resolve([
(0, mock_1.makeAppV2Mock)({ versionName: "Mocked dev app", isDevTools: true }),
(0, mock_1.makeAppV2Mock)({ versionName: "Another non dev app", isDevTools: false }),
]),
};
(0, listApps_1.listApps)({
managerDevModeEnabled: true,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
next: listAppsEvent => {
if (listAppsEvent.type === "result") {
const { result: { appsListNames }, } = listAppsEvent;
try {
expect(appsListNames).toEqual(["Mocked dev app", "Another non dev app"]);
done();
}
catch (e) {
done(e);
}
}
},
});
jest.advanceTimersByTime(1);
});
it("should not keep apps with isDevTools if managerDevModeEnabled is false", done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: true,
targetId: 0x33200000,
});
mockedManagerApiRepository = {
...new HttpManagerApiRepositoryFactory_1.StubManagerApiRepository(),
catalogForDevice: () => Promise.resolve([
(0, mock_1.makeAppV2Mock)({ versionName: "Mocked dev app", isDevTools: true }),
(0, mock_1.makeAppV2Mock)({ versionName: "Another non dev app", isDevTools: false }),
]),
};
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
next: listAppsEvent => {
if (listAppsEvent.type === "result") {
const { result: { appsListNames }, } = listAppsEvent;
try {
expect(appsListNames).toEqual(["Another non dev app"]);
done();
}
catch (e) {
done(e);
}
}
},
});
jest.advanceTimersByTime(1);
});
it("should keep apps with isDevTools if managerDevModeEnabled is disabled but those apps are installed", done => {
const transport = (0, hw_transport_mocker_1.aTransportBuilder)();
const deviceInfo = (0, aDeviceInfo_1.aDeviceInfoBuilder)({
isOSU: false,
isBootloader: false,
managerAllowed: true,
targetId: 0x33200000,
});
mockedManagerApiRepository = {
...new HttpManagerApiRepositoryFactory_1.StubManagerApiRepository(),
catalogForDevice: () => Promise.resolve([
(0, mock_1.makeAppV2Mock)({ versionName: "Mocked dev app", isDevTools: true }),
(0, mock_1.makeAppV2Mock)({ versionName: "Another non dev app", isDevTools: false }),
]),
getAppsByHash(hashes) {
const hashToApp = {
hash1: (0, mock_1.makeAppV2Mock)({ versionName: "Mocked dev app", isDevTools: true }),
hash2: (0, mock_1.makeAppV2Mock)({ versionName: "Another non dev app", isDevTools: false }),
};
return Promise.resolve(hashes.map(hash => hashToApp[hash]));
},
};
listAppsCommandSpy.mockResolvedValue([
{ hash: "hash1", name: "Mocked dev app" },
{ hash: "hash2", name: "Another non dev app" },
]);
(0, listApps_1.listApps)({
managerDevModeEnabled: false,
transport,
deviceInfo,
managerApiRepository: mockedManagerApiRepository,
forceProvider: 1,
}).subscribe({
next: listAppsEvent => {
if (listAppsEvent.type === "result") {
const { result: { appsListNames }, } = listAppsEvent;
try {
expect(appsListNames).toEqual(["Mocked dev app", "Another non dev app"]);
done();
}
catch (e) {
done(e);
}
}
},
});
jest.advanceTimersByTime(1);
});
});
//# sourceMappingURL=listApps.test.js.map