From 54798dcc3c4c565011fca179def168188696fa38 Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Wed, 1 Aug 2018 16:36:11 +0200 Subject: [PATCH 01/17] add typing to all commands and api calls. fixes #1348 --- .gitignore | 8 -- src/commands/getCurrentFirmware.js | 3 +- src/commands/getDeviceInfo.js | 6 +- src/commands/getIsGenuine.js | 2 +- src/commands/getLatestFirmwareForDevice.js | 4 +- src/commands/installApp.js | 6 +- src/commands/installMcu.js | 2 +- src/commands/installOsuFirmware.js | 2 +- src/commands/listAppVersions.js | 4 +- src/commands/listApps.js | 5 +- src/commands/listCategories.js | 5 +- src/commands/shouldFlashMcu.js | 3 +- src/commands/uninstallApp.js | 10 +- src/components/GenuineCheck.js | 2 +- src/components/ManagerPage/AppSearchBar.js | 6 +- src/components/ManagerPage/AppsList.js | 22 +-- src/components/ManagerPage/Dashboard.js | 2 +- src/components/ManagerPage/FirmwareUpdate.js | 5 +- src/components/ManagerPage/index.js | 2 +- src/components/modals/UpdateFirmware/index.js | 4 +- src/helpers/apps/installApp.js | 14 +- src/helpers/apps/listAppVersions.js | 15 +- src/helpers/apps/listApps.js | 3 +- src/helpers/apps/listCategories.js | 5 +- src/helpers/apps/uninstallApp.js | 15 +- src/helpers/devices/getCurrentFirmware.js | 5 +- src/helpers/devices/getDeviceInfo.js | 12 +- src/helpers/devices/getDeviceVersion.js | 6 +- src/helpers/devices/getIsGenuine.js | 12 +- .../devices/getLatestFirmwareForDevice.js | 36 +++-- src/helpers/devices/shouldFlashMcu.js | 2 +- src/helpers/firmware/getFirmwareInfo.js | 3 +- src/helpers/firmware/getNextMCU.js | 5 +- src/helpers/firmware/installFinalFirmware.js | 10 +- src/helpers/firmware/installMcu.js | 9 +- src/helpers/firmware/installOsuFirmware.js | 2 +- src/helpers/types.js | 132 +++++++++++++++++- 37 files changed, 270 insertions(+), 119 deletions(-) diff --git a/.gitignore b/.gitignore index 65ca3013..40e58245 100644 --- a/.gitignore +++ b/.gitignore @@ -10,11 +10,3 @@ /build/linux/arch/src /build/linux/arch/*.tar.gz /build/linux/arch/*.tar.xz - -# TODO this should be in devs global gitignore -# it makes no sense to have it here -*.log -.DS_Store -.vscode -thumbs.db -jsconfig.json diff --git a/src/commands/getCurrentFirmware.js b/src/commands/getCurrentFirmware.js index 773220ae..d4ae0c86 100644 --- a/src/commands/getCurrentFirmware.js +++ b/src/commands/getCurrentFirmware.js @@ -4,6 +4,7 @@ import { createCommand, Command } from 'helpers/ipc' import { fromPromise } from 'rxjs/observable/fromPromise' import getCurrentFirmware from 'helpers/devices/getCurrentFirmware' +import type { FinalFirmware } from 'helpers/types' type Input = { deviceId: string | number, @@ -11,7 +12,7 @@ type Input = { provider: number, } -type Result = * +type Result = FinalFirmware const cmd: Command = createCommand('getCurrentFirmware', data => fromPromise(getCurrentFirmware(data)), diff --git a/src/commands/getDeviceInfo.js b/src/commands/getDeviceInfo.js index 67c585fd..9cbbfae1 100644 --- a/src/commands/getDeviceInfo.js +++ b/src/commands/getDeviceInfo.js @@ -5,13 +5,15 @@ import { fromPromise } from 'rxjs/observable/fromPromise' import { withDevice } from 'helpers/deviceAccess' import getDeviceInfo from 'helpers/devices/getDeviceInfo' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo } from 'helpers/types' type Input = { devicePath: string, } -const cmd: Command = createCommand('getDeviceInfo', ({ devicePath }) => +type Result = DeviceInfo + +const cmd: Command = createCommand('getDeviceInfo', ({ devicePath }) => fromPromise(withDevice(devicePath)(transport => getDeviceInfo(transport))), ) diff --git a/src/commands/getIsGenuine.js b/src/commands/getIsGenuine.js index a1bb645d..e3e163b8 100644 --- a/src/commands/getIsGenuine.js +++ b/src/commands/getIsGenuine.js @@ -2,7 +2,7 @@ import { createCommand, Command } from 'helpers/ipc' import { fromPromise } from 'rxjs/observable/fromPromise' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo } from 'helpers/types' import getIsGenuine from 'helpers/devices/getIsGenuine' import { withDevice } from 'helpers/deviceAccess' diff --git a/src/commands/getLatestFirmwareForDevice.js b/src/commands/getLatestFirmwareForDevice.js index d216d2eb..e88f6a50 100644 --- a/src/commands/getLatestFirmwareForDevice.js +++ b/src/commands/getLatestFirmwareForDevice.js @@ -2,11 +2,11 @@ import { createCommand, Command } from 'helpers/ipc' import { fromPromise } from 'rxjs/observable/fromPromise' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo, OsuFirmware } from 'helpers/types' import getLatestFirmwareForDevice from '../helpers/devices/getLatestFirmwareForDevice' -type Result = * +type Result = ?(OsuFirmware & { shouldFlashMcu: boolean }) const cmd: Command = createCommand('getLatestFirmwareForDevice', data => fromPromise(getLatestFirmwareForDevice(data)), diff --git a/src/commands/installApp.js b/src/commands/installApp.js index 7fcc7db7..cd1a2e81 100644 --- a/src/commands/installApp.js +++ b/src/commands/installApp.js @@ -6,15 +6,15 @@ import { fromPromise } from 'rxjs/observable/fromPromise' import { withDevice } from 'helpers/deviceAccess' import installApp from 'helpers/apps/installApp' -import type { LedgerScriptParams } from 'helpers/types' +import type { ApplicationVersion } from 'helpers/types' type Input = { - app: LedgerScriptParams, + app: ApplicationVersion, devicePath: string, targetId: string | number, } -type Result = * +type Result = void const cmd: Command = createCommand( 'installApp', diff --git a/src/commands/installMcu.js b/src/commands/installMcu.js index 7d85e40b..660bd546 100644 --- a/src/commands/installMcu.js +++ b/src/commands/installMcu.js @@ -10,7 +10,7 @@ type Input = { devicePath: string, } -type Result = * +type Result = void const cmd: Command = createCommand('installMcu', ({ devicePath }) => fromPromise(withDevice(devicePath)(transport => installMcu(transport))), diff --git a/src/commands/installOsuFirmware.js b/src/commands/installOsuFirmware.js index f73a76d4..83b29a39 100644 --- a/src/commands/installOsuFirmware.js +++ b/src/commands/installOsuFirmware.js @@ -14,7 +14,7 @@ type Input = { firmware: Firmware, } -type Result = * +type Result = { success: boolean } const cmd: Command = createCommand( 'installOsuFirmware', diff --git a/src/commands/listAppVersions.js b/src/commands/listAppVersions.js index 494d7168..a802b2c6 100644 --- a/src/commands/listAppVersions.js +++ b/src/commands/listAppVersions.js @@ -2,11 +2,11 @@ import { createCommand, Command } from 'helpers/ipc' import { fromPromise } from 'rxjs/observable/fromPromise' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo, ApplicationVersion } from 'helpers/types' import listAppVersions from 'helpers/apps/listAppVersions' -type Result = * +type Result = Array const cmd: Command = createCommand('listAppVersions', deviceInfo => fromPromise(listAppVersions(deviceInfo)), diff --git a/src/commands/listApps.js b/src/commands/listApps.js index f049def3..13f78609 100644 --- a/src/commands/listApps.js +++ b/src/commands/listApps.js @@ -4,10 +4,11 @@ import { createCommand, Command } from 'helpers/ipc' import { fromPromise } from 'rxjs/observable/fromPromise' import listApps from 'helpers/apps/listApps' +import type { Application } from 'helpers/types' -type Input = {} +type Input = void -type Result = * +type Result = Array const cmd: Command = createCommand('listApps', () => fromPromise(listApps())) diff --git a/src/commands/listCategories.js b/src/commands/listCategories.js index 3632a47f..641b4ad8 100644 --- a/src/commands/listCategories.js +++ b/src/commands/listCategories.js @@ -4,10 +4,11 @@ import { createCommand, Command } from 'helpers/ipc' import { fromPromise } from 'rxjs/observable/fromPromise' import listCategories from 'helpers/apps/listCategories' +import type { Category } from 'helpers/types' -type Input = {} +type Input = void -type Result = * +type Result = Array const cmd: Command = createCommand('listCategories', () => fromPromise(listCategories()), diff --git a/src/commands/shouldFlashMcu.js b/src/commands/shouldFlashMcu.js index 3bae3f04..f58c629c 100644 --- a/src/commands/shouldFlashMcu.js +++ b/src/commands/shouldFlashMcu.js @@ -2,9 +2,10 @@ import { createCommand, Command } from 'helpers/ipc' import { fromPromise } from 'rxjs/observable/fromPromise' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import shouldFlashMcu from 'helpers/devices/shouldFlashMcu' +import type { DeviceInfo } from 'helpers/types' + type Result = boolean const cmd: Command = createCommand('shouldFlashMcu', data => diff --git a/src/commands/uninstallApp.js b/src/commands/uninstallApp.js index 59a61a3d..9b6df8a2 100644 --- a/src/commands/uninstallApp.js +++ b/src/commands/uninstallApp.js @@ -6,20 +6,20 @@ import { withDevice } from 'helpers/deviceAccess' import uninstallApp from 'helpers/apps/uninstallApp' -import type { LedgerScriptParams } from 'helpers/types' +import type { ApplicationVersion } from 'helpers/types' type Input = { - app: LedgerScriptParams, + app: ApplicationVersion, devicePath: string, targetId: string | number, } -type Result = * +type Result = void const cmd: Command = createCommand( 'uninstallApp', - ({ devicePath, targetId, ...rest }) => - fromPromise(withDevice(devicePath)(transport => uninstallApp(transport, targetId, rest))), + ({ devicePath, targetId, ...app }) => + fromPromise(withDevice(devicePath)(transport => uninstallApp(transport, targetId, app))), ) export default cmd diff --git a/src/components/GenuineCheck.js b/src/components/GenuineCheck.js index b1012d4d..0b79cf69 100644 --- a/src/components/GenuineCheck.js +++ b/src/components/GenuineCheck.js @@ -9,7 +9,7 @@ import { delay, createCancelablePolling } from 'helpers/promise' import logger from 'logger' import type { T, Device } from 'types/common' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo } from 'helpers/types' import { GENUINE_TIMEOUT, DEVICE_INFOS_TIMEOUT, GENUINE_CACHE_DELAY } from 'config/constants' diff --git a/src/components/ManagerPage/AppSearchBar.js b/src/components/ManagerPage/AppSearchBar.js index cad33077..a9292f14 100644 --- a/src/components/ManagerPage/AppSearchBar.js +++ b/src/components/ManagerPage/AppSearchBar.js @@ -3,7 +3,7 @@ import React, { PureComponent, Fragment } from 'react' import styled from 'styled-components' -import type { LedgerScriptParams } from 'helpers/types' +import type { ApplicationVersion } from 'helpers/types' import Box from 'components/base/Box' import Space from 'components/base/Space' @@ -23,8 +23,8 @@ const CrossContainer = styled(Box).attrs({ ` type Props = { - list: Array, - children: (list: Array) => React$Node, + list: Array, + children: (list: Array) => React$Node, } type State = { diff --git a/src/components/ManagerPage/AppsList.js b/src/components/ManagerPage/AppsList.js index ae2644fe..e2f8bf1c 100644 --- a/src/components/ManagerPage/AppsList.js +++ b/src/components/ManagerPage/AppsList.js @@ -7,8 +7,7 @@ import { translate } from 'react-i18next' import { connect } from 'react-redux' import { compose } from 'redux' import type { Device, T } from 'types/common' -import type { LedgerScriptParams } from 'helpers/types' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { Application, ApplicationVersion, DeviceInfo } from 'helpers/types' import { developerModeSelector } from 'reducers/settings' import listApps from 'commands/listApps' @@ -66,7 +65,7 @@ type Props = { type State = { status: Status, error: ?Error, - filteredAppVersionsList: LedgerScriptParams[], + filteredAppVersionsList: Array, appsLoaded: boolean, app: string, mode: Mode, @@ -102,9 +101,14 @@ class AppsList extends PureComponent { filterAppVersions = (applicationsList, compatibleAppVersionsList) => { if (!this.props.isDevMode) { - return compatibleAppVersionsList.filter( - version => applicationsList.find(e => e.id === version.app).category !== 2, - ) + return compatibleAppVersionsList.filter(version => { + const app = applicationsList.find(e => e.id === version.app) + if (app) { + return app.category !== 2 + } + + return false + }) } return compatibleAppVersionsList } @@ -112,7 +116,7 @@ class AppsList extends PureComponent { async fetchAppList() { try { const { deviceInfo } = this.props - const applicationsList = await listApps.send({}).toPromise() + const applicationsList: Array = await listApps.send().toPromise() const compatibleAppVersionsList = await listAppVersions.send(deviceInfo).toPromise() const filteredAppVersionsList = this.filterAppVersions( applicationsList, @@ -131,7 +135,7 @@ class AppsList extends PureComponent { } } - handleInstallApp = (app: LedgerScriptParams) => async () => { + handleInstallApp = (app: ApplicationVersion) => async () => { this.setState({ status: 'busy', app: app.name, mode: 'installing' }) try { const { @@ -146,7 +150,7 @@ class AppsList extends PureComponent { } } - handleUninstallApp = (app: LedgerScriptParams) => async () => { + handleUninstallApp = (app: ApplicationVersion) => async () => { this.setState({ status: 'busy', app: app.name, mode: 'uninstalling' }) try { const { diff --git a/src/components/ManagerPage/Dashboard.js b/src/components/ManagerPage/Dashboard.js index 2f04caff..3e726fab 100644 --- a/src/components/ManagerPage/Dashboard.js +++ b/src/components/ManagerPage/Dashboard.js @@ -4,7 +4,7 @@ import { translate } from 'react-i18next' import styled from 'styled-components' import type { T, Device } from 'types/common' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo } from 'helpers/types' import Box from 'components/base/Box' import Text from 'components/base/Text' diff --git a/src/components/ManagerPage/FirmwareUpdate.js b/src/components/ManagerPage/FirmwareUpdate.js index c289054c..dcaba901 100644 --- a/src/components/ManagerPage/FirmwareUpdate.js +++ b/src/components/ManagerPage/FirmwareUpdate.js @@ -9,7 +9,7 @@ import invariant from 'invariant' import type { Device, T } from 'types/common' -import type { LedgerScriptParams } from 'helpers/types' +import type { DeviceInfo, OsuFirmware } from 'helpers/types' import type { StepId } from 'components/modals/UpdateFirmware' import getLatestFirmwareForDevice from 'commands/getLatestFirmwareForDevice' @@ -19,7 +19,6 @@ import installFinalFirmware from 'commands/installFinalFirmware' import installMcu from 'commands/installMcu' import DisclaimerModal from 'components/modals/UpdateFirmware/Disclaimer' import UpdateModal from 'components/modals/UpdateFirmware' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' import Tooltip from 'components/base/Tooltip' import Box, { Card } from 'components/base/Box' @@ -43,7 +42,7 @@ type Props = { } type State = { - latestFirmware: ?LedgerScriptParams & ?{ shouldFlashMcu: boolean }, + latestFirmware: ?OsuFirmware & ?{ shouldFlashMcu: boolean }, modal: ModalStatus, stepId: ?StepId, shouldFlash: boolean, diff --git a/src/components/ManagerPage/index.js b/src/components/ManagerPage/index.js index 956d7c90..7c9631b2 100644 --- a/src/components/ManagerPage/index.js +++ b/src/components/ManagerPage/index.js @@ -6,7 +6,7 @@ import { openURL } from 'helpers/linking' import { urls } from 'config/urls' import type { Device } from 'types/common' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo } from 'helpers/types' import Dashboard from './Dashboard' diff --git a/src/components/modals/UpdateFirmware/index.js b/src/components/modals/UpdateFirmware/index.js index b6aac554..716db238 100644 --- a/src/components/modals/UpdateFirmware/index.js +++ b/src/components/modals/UpdateFirmware/index.js @@ -10,7 +10,7 @@ import SyncSkipUnderPriority from 'components/SyncSkipUnderPriority' import type { StepProps as DefaultStepProps, Step } from 'components/base/Stepper' import type { ModalStatus } from 'components/ManagerPage/FirmwareUpdate' -import type { LedgerScriptParams } from 'helpers/types' +import type { OsuFirmware } from 'helpers/types' import { FreezeDeviceChangeEvents } from '../../ManagerPage/HookDeviceChange' import StepFullFirmwareInstall from './steps/01-step-install-full-firmware' @@ -56,7 +56,7 @@ const createSteps = ({ t, shouldFlashMcu }: { t: T, shouldFlashMcu: boolean }): return steps } -export type Firmware = LedgerScriptParams & { shouldFlashMcu: boolean } +export type Firmware = OsuFirmware & { shouldFlashMcu: boolean } export type StepProps = DefaultStepProps & { firmware: Firmware, diff --git a/src/helpers/apps/installApp.js b/src/helpers/apps/installApp.js index b5bb00f9..ce45f797 100644 --- a/src/helpers/apps/installApp.js +++ b/src/helpers/apps/installApp.js @@ -1,13 +1,12 @@ // @flow -import qs from 'qs' import type Transport from '@ledgerhq/hw-transport' -import { BASE_SOCKET_URL } from 'config/constants' import { createDeviceSocket } from 'helpers/socket' -import type { LedgerScriptParams } from 'helpers/types' +import type { ApplicationVersion } from 'helpers/types' import { createCustomErrorClass } from 'helpers/errors' +import { WS_INSTALL } from 'helpers/urls' const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace') const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') @@ -37,8 +36,8 @@ function remapError(promise) { export default async function installApp( transport: Transport<*>, targetId: string | number, - { app }: { app: LedgerScriptParams }, -): Promise<*> { + { app }: { app: ApplicationVersion }, +): Promise { const params = { targetId, perso: app.perso, @@ -47,6 +46,7 @@ export default async function installApp( firmwareKey: app.firmware_key, hash: app.hash, } - const url = `${BASE_SOCKET_URL}/install?${qs.stringify(params)}` - return remapError(createDeviceSocket(transport, url).toPromise()) + + const url = WS_INSTALL(params) + await remapError(createDeviceSocket(transport, url).toPromise()) } diff --git a/src/helpers/apps/listAppVersions.js b/src/helpers/apps/listAppVersions.js index b29ba127..bc48fc6a 100644 --- a/src/helpers/apps/listAppVersions.js +++ b/src/helpers/apps/listAppVersions.js @@ -1,14 +1,19 @@ // @flow import network from 'api/network' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo, DeviceVersion, FinalFirmware, ApplicationVersion } from 'helpers/types' import { APPLICATIONS_BY_DEVICE } from 'helpers/urls' import getDeviceVersion from 'helpers/devices/getDeviceVersion' import getCurrentFirmware from 'helpers/devices/getCurrentFirmware' -export default async (deviceInfo: DeviceInfo) => { - const deviceData = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId) - const firmwareData = await getCurrentFirmware({ +type NetworkResponse = { data: { application_versions: Array } } + +export default async (deviceInfo: DeviceInfo): Promise> => { + const deviceData: DeviceVersion = await getDeviceVersion( + deviceInfo.targetId, + deviceInfo.providerId, + ) + const firmwareData: FinalFirmware = await getCurrentFirmware({ deviceId: deviceData.id, fullVersion: deviceInfo.fullVersion, provider: deviceInfo.providerId, @@ -20,6 +25,6 @@ export default async (deviceInfo: DeviceInfo) => { } const { data: { application_versions }, - } = await network({ method: 'POST', url: APPLICATIONS_BY_DEVICE, data: params }) + }: NetworkResponse = await network({ method: 'POST', url: APPLICATIONS_BY_DEVICE, data: params }) return application_versions.length > 0 ? application_versions : [] } diff --git a/src/helpers/apps/listApps.js b/src/helpers/apps/listApps.js index 372d5ad1..14fed369 100644 --- a/src/helpers/apps/listApps.js +++ b/src/helpers/apps/listApps.js @@ -2,8 +2,9 @@ import network from 'api/network' import { GET_APPLICATIONS } from 'helpers/urls' +import type { Application } from 'helpers/types' -export default async () => { +export default async (): Promise> => { const { data } = await network({ method: 'GET', url: GET_APPLICATIONS }) return data.length > 0 ? data : [] } diff --git a/src/helpers/apps/listCategories.js b/src/helpers/apps/listCategories.js index 59836572..1c903b0a 100644 --- a/src/helpers/apps/listCategories.js +++ b/src/helpers/apps/listCategories.js @@ -2,8 +2,9 @@ import network from 'api/network' import { GET_CATEGORIES } from 'helpers/urls' +import type { Category } from 'helpers/types' -export default async () => { - const { data } = await network({ method: 'GET', url: GET_CATEGORIES }) +export default async (): Promise> => { + const { data }: { data: Array } = await network({ method: 'GET', url: GET_CATEGORIES }) return data.length > 0 ? data : [] } diff --git a/src/helpers/apps/uninstallApp.js b/src/helpers/apps/uninstallApp.js index 5bf3dd68..7ce6fef3 100644 --- a/src/helpers/apps/uninstallApp.js +++ b/src/helpers/apps/uninstallApp.js @@ -1,12 +1,11 @@ // @flow -import qs from 'qs' import type Transport from '@ledgerhq/hw-transport' -import { BASE_SOCKET_URL } from 'config/constants' import { createDeviceSocket } from 'helpers/socket' -import type { LedgerScriptParams } from 'helpers/types' -import { createCustomErrorClass } from '../errors' +import type { ApplicationVersion } from 'helpers/types' +import { createCustomErrorClass } from 'helpers/errors' +import { WS_INSTALL } from 'helpers/urls' const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') const ManagerUninstallBTCDep = createCustomErrorClass('ManagerUninstallBTCDep') @@ -30,8 +29,8 @@ function remapError(promise) { export default async function uninstallApp( transport: Transport<*>, targetId: string | number, - { app }: { app: LedgerScriptParams }, -): Promise<*> { + { app }: { app: ApplicationVersion }, +): Promise { const params = { targetId, perso: app.perso, @@ -40,6 +39,6 @@ export default async function uninstallApp( firmwareKey: app.delete_key, hash: app.hash, } - const url = `${BASE_SOCKET_URL}/install?${qs.stringify(params)}` - return remapError(createDeviceSocket(transport, url).toPromise()) + const url = WS_INSTALL(params) + await remapError(createDeviceSocket(transport, url).toPromise()) } diff --git a/src/helpers/devices/getCurrentFirmware.js b/src/helpers/devices/getCurrentFirmware.js index a98c01d5..c4ef5979 100644 --- a/src/helpers/devices/getCurrentFirmware.js +++ b/src/helpers/devices/getCurrentFirmware.js @@ -2,6 +2,7 @@ import network from 'api/network' import { GET_CURRENT_FIRMWARE } from 'helpers/urls' +import type { FinalFirmware } from 'helpers/types' type Input = { fullVersion: string, @@ -9,8 +10,8 @@ type Input = { provider: number, } -export default async (input: Input): Promise<*> => { - const { data } = await network({ +export default async (input: Input): Promise => { + const { data }: { data: FinalFirmware } = await network({ method: 'POST', url: GET_CURRENT_FIRMWARE, data: { diff --git a/src/helpers/devices/getDeviceInfo.js b/src/helpers/devices/getDeviceInfo.js index c3972e3d..24b6d7d1 100644 --- a/src/helpers/devices/getDeviceInfo.js +++ b/src/helpers/devices/getDeviceInfo.js @@ -5,17 +5,7 @@ import type Transport from '@ledgerhq/hw-transport' import getFirmwareInfo from 'helpers/firmware/getFirmwareInfo' import { FORCE_PROVIDER } from 'config/constants' -export type DeviceInfo = { - targetId: string | number, - seVersion: string, - isBootloader: boolean, - flags: string, - mcuVersion: string, - isOSU: boolean, - providerName: string, - providerId: number, - fullVersion: string, -} +import type { DeviceInfo } from 'helpers/types' const PROVIDERS = { '': 1, diff --git a/src/helpers/devices/getDeviceVersion.js b/src/helpers/devices/getDeviceVersion.js index 698bc1fa..c681cfa9 100644 --- a/src/helpers/devices/getDeviceVersion.js +++ b/src/helpers/devices/getDeviceVersion.js @@ -2,8 +2,10 @@ import { GET_DEVICE_VERSION } from 'helpers/urls' import network from 'api/network' -export default async (targetId: string | number, provider: number): Promise<*> => { - const { data } = await network({ +import type { DeviceVersion } from 'helpers/types' + +export default async (targetId: string | number, provider: number): Promise => { + const { data }: { data: DeviceVersion } = await network({ method: 'POST', url: GET_DEVICE_VERSION, data: { diff --git a/src/helpers/devices/getIsGenuine.js b/src/helpers/devices/getIsGenuine.js index 9ea7c56d..3357042b 100644 --- a/src/helpers/devices/getIsGenuine.js +++ b/src/helpers/devices/getIsGenuine.js @@ -2,23 +2,29 @@ import type Transport from '@ledgerhq/hw-transport' import { SKIP_GENUINE } from 'config/constants' import { WS_GENUINE } from 'helpers/urls' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo, FinalFirmware, DeviceVersion } from 'helpers/types' import { createDeviceSocket } from 'helpers/socket' import getCurrentFirmware from './getCurrentFirmware' import getDeviceVersion from './getDeviceVersion' export default async (transport: Transport<*>, deviceInfo: DeviceInfo): Promise => { - const deviceVersion = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId) - const firmware = await getCurrentFirmware({ + const deviceVersion: DeviceVersion = await getDeviceVersion( + deviceInfo.targetId, + deviceInfo.providerId, + ) + + const firmware: FinalFirmware = await getCurrentFirmware({ deviceId: deviceVersion.id, fullVersion: deviceInfo.fullVersion, provider: deviceInfo.providerId, }) + const params = { targetId: deviceInfo.targetId, perso: firmware.perso, } + const url = WS_GENUINE(params) return SKIP_GENUINE ? new Promise(resolve => setTimeout(() => resolve('0000'), 1000)) diff --git a/src/helpers/devices/getLatestFirmwareForDevice.js b/src/helpers/devices/getLatestFirmwareForDevice.js index 9bbf7296..80e14af8 100644 --- a/src/helpers/devices/getLatestFirmwareForDevice.js +++ b/src/helpers/devices/getLatestFirmwareForDevice.js @@ -1,7 +1,13 @@ // @flow import network from 'api/network' import { GET_LATEST_FIRMWARE } from 'helpers/urls' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { + DeviceInfo, + DeviceVersion, + FinalFirmware, + OsuFirmware, + McuVersion, +} from 'helpers/types' import getFinalFirmwareById from 'helpers/firmware/getFinalFirmwareById' import getMcus from 'helpers/firmware/getMcus' @@ -9,19 +15,31 @@ import getMcus from 'helpers/firmware/getMcus' import getCurrentFirmware from './getCurrentFirmware' import getDeviceVersion from './getDeviceVersion' -export default async (deviceInfo: DeviceInfo) => { +type NetworkResponse = { + data: { + result: string, + se_firmware_osu_version: OsuFirmware, + }, +} + +type Result = ?(OsuFirmware & { shouldFlashMcu: boolean }) + +export default async (deviceInfo: DeviceInfo): Promise => { // Get device infos from targetId - const deviceVersion = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId) + const deviceVersion: DeviceVersion = await getDeviceVersion( + deviceInfo.targetId, + deviceInfo.providerId, + ) // Get firmware infos with firmware name and device version - const seFirmwareVersion = await getCurrentFirmware({ + const seFirmwareVersion: FinalFirmware = await getCurrentFirmware({ fullVersion: deviceInfo.fullVersion, deviceId: deviceVersion.id, provider: deviceInfo.providerId, }) // Fetch next possible firmware - const { data } = await network({ + const { data }: NetworkResponse = await network({ method: 'POST', url: GET_LATEST_FIRMWARE, data: { @@ -37,11 +55,13 @@ export default async (deviceInfo: DeviceInfo) => { const { se_firmware_osu_version } = data const { next_se_firmware_final_version } = se_firmware_osu_version - const seFirmwareFinalVersion = await getFinalFirmwareById(next_se_firmware_final_version) + const seFirmwareFinalVersion: FinalFirmware = await getFinalFirmwareById( + next_se_firmware_final_version, + ) - const mcus = await getMcus() + const mcus: Array = await getMcus() - const currentMcuVersionId = mcus + const currentMcuVersionId: Array = mcus .filter(mcu => mcu.name === deviceInfo.mcuVersion) .map(mcu => mcu.id) diff --git a/src/helpers/devices/shouldFlashMcu.js b/src/helpers/devices/shouldFlashMcu.js index dba76d75..1ed0a768 100644 --- a/src/helpers/devices/shouldFlashMcu.js +++ b/src/helpers/devices/shouldFlashMcu.js @@ -1,7 +1,7 @@ // @flow import network from 'api/network' import { GET_LATEST_FIRMWARE } from 'helpers/urls' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo } from 'helpers/types' import getFinalFirmwareById from 'helpers/firmware/getFinalFirmwareById' import getMcus from 'helpers/firmware/getMcus' diff --git a/src/helpers/firmware/getFirmwareInfo.js b/src/helpers/firmware/getFirmwareInfo.js index fc3033a1..b3c4a81c 100644 --- a/src/helpers/firmware/getFirmwareInfo.js +++ b/src/helpers/firmware/getFirmwareInfo.js @@ -1,6 +1,7 @@ // @flow import type Transport from '@ledgerhq/hw-transport' +import type { FirmwareInfo } from 'helpers/types' const APDUS = { GET_FIRMWARE: [0xe0, 0x01, 0x00, 0x00], @@ -12,7 +13,7 @@ const APDUS = { /** * Retrieve targetId and firmware version from device */ -export default async function getFirmwareInfo(transport: Transport<*>) { +export default async function getFirmwareInfo(transport: Transport<*>): Promise { const res = await transport.send(...APDUS.GET_FIRMWARE) const byteArray = [...res] const data = byteArray.slice(0, byteArray.length - 2) diff --git a/src/helpers/firmware/getNextMCU.js b/src/helpers/firmware/getNextMCU.js index 7565e379..3ab9337f 100644 --- a/src/helpers/firmware/getNextMCU.js +++ b/src/helpers/firmware/getNextMCU.js @@ -3,11 +3,14 @@ import network from 'api/network' import { GET_NEXT_MCU } from 'helpers/urls' import { createCustomErrorClass } from 'helpers/errors' +import type { OsuFirmware } from 'helpers/types' const LatestMCUInstalledError = createCustomErrorClass('LatestMCUInstalledError') +type NetworkResponse = { data: OsuFirmware | 'default' } + export default async (bootloaderVersion: string): Promise<*> => { - const { data } = await network({ + const { data }: NetworkResponse = await network({ method: 'POST', url: GET_NEXT_MCU, data: { diff --git a/src/helpers/firmware/installFinalFirmware.js b/src/helpers/firmware/installFinalFirmware.js index a588e0e5..be13f6c1 100644 --- a/src/helpers/firmware/installFinalFirmware.js +++ b/src/helpers/firmware/installFinalFirmware.js @@ -1,6 +1,6 @@ // @flow import type Transport from '@ledgerhq/hw-transport' -import type { DeviceInfo } from 'helpers/devices/getDeviceInfo' +import type { DeviceInfo, DeviceVersion, OsuFirmware, FinalFirmware } from 'helpers/types' import { WS_INSTALL } from 'helpers/urls' import { createDeviceSocket } from 'helpers/socket' @@ -23,19 +23,19 @@ function remapSocketError(promise) { }) } -type Result = Promise<{ success: boolean, error?: string }> +type Result = Promise<{ success: boolean }> export default async (transport: Transport<*>): Result => { try { const deviceInfo: DeviceInfo = await getDeviceInfo(transport) - const device = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId) - const firmware = await getOsuFirmware({ + const device: DeviceVersion = await getDeviceVersion(deviceInfo.targetId, deviceInfo.providerId) + const firmware: OsuFirmware = await getOsuFirmware({ deviceId: device.id, version: deviceInfo.fullVersion, provider: deviceInfo.providerId, }) const { next_se_firmware_final_version } = firmware - const nextFirmware = await getFinalFirmwareById(next_se_firmware_final_version) + const nextFirmware: FinalFirmware = await getFinalFirmwareById(next_se_firmware_final_version) const params = { targetId: deviceInfo.targetId, diff --git a/src/helpers/firmware/installMcu.js b/src/helpers/firmware/installMcu.js index aca208c8..d0ffb39e 100644 --- a/src/helpers/firmware/installMcu.js +++ b/src/helpers/firmware/installMcu.js @@ -7,6 +7,8 @@ import getNextMCU from 'helpers/firmware/getNextMCU' import getDeviceInfo from 'helpers/devices/getDeviceInfo' import { createCustomErrorClass } from 'helpers/errors' +import type { DeviceInfo } from 'helpers/types' + const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') function remapSocketError(promise) { @@ -20,16 +22,15 @@ function remapSocketError(promise) { }) } -type Result = Promise<*> +type Result = Promise export default async (transport: Transport<*>): Result => { - const deviceInfo = await getDeviceInfo(transport) - const { seVersion: version, targetId } = deviceInfo + const { seVersion: version, targetId }: DeviceInfo = await getDeviceInfo(transport) const nextVersion = await getNextMCU(version) const params = { targetId, version: nextVersion.name, } const url = WS_MCU(params) - return remapSocketError(createDeviceSocket(transport, url).toPromise()) + await remapSocketError(createDeviceSocket(transport, url).toPromise()) } diff --git a/src/helpers/firmware/installOsuFirmware.js b/src/helpers/firmware/installOsuFirmware.js index 603404e5..1121c340 100644 --- a/src/helpers/firmware/installOsuFirmware.js +++ b/src/helpers/firmware/installOsuFirmware.js @@ -27,7 +27,7 @@ function remapError(promise) { }) } -type Result = Promise<{ success: boolean, error?: any }> +type Result = Promise<{ success: boolean }> export default async ( transport: Transport<*>, diff --git a/src/helpers/types.js b/src/helpers/types.js index 56ac3f50..a9bea673 100644 --- a/src/helpers/types.js +++ b/src/helpers/types.js @@ -1,14 +1,134 @@ // @flow +type Id = number + export type LedgerScriptParams = { - firmware?: string, - firmware_key?: string, + firmware: string, + firmwareKey: string, delete?: string, - delete_key?: string, + deleteKey?: string, targetId?: string | number, + hash: string, + perso: string, +} + +export type DeviceInfo = { + targetId: string | number, + seVersion: string, + isBootloader: boolean, + flags: string, + mcuVersion: string, + isOSU: boolean, + providerName: string, + providerId: number, + fullVersion: string, +} + +export type DeviceVersion = { + id: Id, + name: string, + display_name: string, + target_id: string, + description: string, + device: Id, + providers: Array, + mcu_versions: Array, + se_firmware_final_versions: Array, + osu_versions: Array, + application_versions: Array, + date_creation: string, + date_last_modified: string, +} + +export type McuVersion = { + id: Id, + mcu: Id, + name: string, + description: ?string, + providers: Array, + from_bootloader_version: string, + device_versions: Array, + se_firmware_final_versions: Array, + date_creation: string, + date_last_modified: string, +} + +export type FirmwareInfo = { + targetId: Id, + seVersion: string, + flags: string, + mcuVersion: string, +} + +type BaseFirmware = { + id: Id, + name: string, + description: ?string, + display_name: ?string, + notes: ?string, + perso: string, + firmware: string, + firmware_key: string, + hash: string, + date_creation: string, + date_last_modified: string, + device_versions: Array, + providers: Array, +} + +export type OsuFirmware = BaseFirmware & { + next_se_firmware_final_version: Id, + previous_se_firmware_final_version: Array, +} + +export type FinalFirmware = BaseFirmware & { + version: string, + se_firmware: Id, + osu_versions: Array, + mcu_versions: Array, + application_versions: Array, +} + +export type ApplicationVersion = { + id: Id, name: string, version: string, + app: Id, + description: ?string, + display_name: string, icon: string, - app?: number, - hash?: string, - perso?: string, + picture: Id, + notes: ?string, + perso: string, + hash: string, + firmware: string, + firmware_key: string, + delete: string, + delete_key: string, + device_versions: Array, + se_firmware_final_versions: Array, + providers: Array, + date_creation: string, + date_last_modified: string, +} + +export type Application = { + id: Id, + name: string, + description: ?string, + application_versions: Array, + providers: Array, + category: Id, + publisher: ?Id, + date_creation: string, + date_last_modified: string, +} + +export type Category = { + id: Id, + name: string, + description: ?string, + providers: Array, + applications: Array, + date_creation: string, + date_last_modified: string, } From 166cd11ae61e4bd7b12ba55c597580e97bca1d8a Mon Sep 17 00:00:00 2001 From: "Valentin D. Pinkman" Date: Wed, 1 Aug 2018 17:24:49 +0200 Subject: [PATCH 02/17] centralize custom errors. fixes #1116 --- src/api/Ethereum.js | 4 +-- src/api/Fees.js | 4 +-- src/api/network.js | 6 +--- src/bridge/EthereumJSBridge.js | 4 +-- src/bridge/LibcoreBridge.js | 3 +- src/bridge/RippleJSBridge.js | 4 +-- src/commands/libcoreGetFees.js | 4 +-- src/commands/libcoreHardReset.js | 4 +-- src/components/EnsureDeviceApp.js | 3 +- src/components/IsUnlocked.js | 4 +-- .../SettingsPage/DisablePasswordModal.js | 4 +-- src/components/SettingsPage/PasswordForm.js | 4 +-- src/components/SettingsPage/PasswordModal.js | 4 +-- .../modals/AccountSettingRenderBody.js | 5 +-- .../modals/Send/fields/RecipientField.js | 4 +-- src/config/errors.js | 36 ++++++++++++++++--- src/helpers/apps/installApp.js | 12 +++---- src/helpers/apps/uninstallApp.js | 5 +-- src/helpers/debugAppInfosForCurrency/btc.js | 3 -- src/helpers/firmware/getNextMCU.js | 4 +-- src/helpers/firmware/installFinalFirmware.js | 5 ++- src/helpers/firmware/installMcu.js | 4 +-- src/helpers/firmware/installOsuFirmware.js | 10 +++--- src/helpers/getAddressForCurrency/btc.js | 4 +-- src/helpers/libcore.js | 5 ++- src/helpers/socket.js | 14 ++++---- 26 files changed, 72 insertions(+), 91 deletions(-) diff --git a/src/api/Ethereum.js b/src/api/Ethereum.js index 68f72f90..12a01c6b 100644 --- a/src/api/Ethereum.js +++ b/src/api/Ethereum.js @@ -1,12 +1,10 @@ // @flow import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types' import { BigNumber } from 'bignumber.js' -import { createCustomErrorClass } from 'helpers/errors' +import { LedgerAPINotAvailable } from 'config/errors' import network from './network' import { blockchainBaseURL } from './Ledger' -export const LedgerAPINotAvailable = createCustomErrorClass('LedgerAPINotAvailable') - export type Block = { height: number } // TODO more fields actually export type Tx = { hash: string, diff --git a/src/api/Fees.js b/src/api/Fees.js index 19d32e77..fb380905 100644 --- a/src/api/Fees.js +++ b/src/api/Fees.js @@ -2,12 +2,10 @@ import invariant from 'invariant' import LRU from 'lru-cache' import type { Currency } from '@ledgerhq/live-common/lib/types' -import { createCustomErrorClass } from 'helpers/errors' +import { FeeEstimationFailed } from 'config/errors' import { blockchainBaseURL } from './Ledger' import network from './network' -const FeeEstimationFailed = createCustomErrorClass('FeeEstimationFailed') - export type Fees = { [_: string]: number, } diff --git a/src/api/network.js b/src/api/network.js index 8743b401..eac84f7f 100644 --- a/src/api/network.js +++ b/src/api/network.js @@ -3,13 +3,9 @@ import axios from 'axios' import { GET_CALLS_RETRY, GET_CALLS_TIMEOUT } from 'config/constants' import { retry } from 'helpers/promise' import logger from 'logger' -import { createCustomErrorClass } from 'helpers/errors' +import { LedgerAPIErrorWithMessage, LedgerAPIError, NetworkDown } from 'config/errors' import anonymizer from 'helpers/anonymizer' -export const LedgerAPIErrorWithMessage = createCustomErrorClass('LedgerAPIErrorWithMessage') -export const LedgerAPIError = createCustomErrorClass('LedgerAPIError') -export const NetworkDown = createCustomErrorClass('NetworkDown') - const userFriendlyError = (p: Promise, { url, method, startTime }): Promise => p.catch(error => { let errorToThrow diff --git a/src/bridge/EthereumJSBridge.js b/src/bridge/EthereumJSBridge.js index 12dccc6e..b2aaabda 100644 --- a/src/bridge/EthereumJSBridge.js +++ b/src/bridge/EthereumJSBridge.js @@ -15,11 +15,9 @@ import { getDerivations } from 'helpers/derivations' import getAddressCommand from 'commands/getAddress' import signTransactionCommand from 'commands/signTransaction' import { getAccountPlaceholderName, getNewAccountPlaceholderName } from 'helpers/accountName' -import { createCustomErrorClass } from 'helpers/errors' +import { NotEnoughBalance } from 'config/errors' import type { EditProps, WalletBridge } from './types' -const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance') - // TODO in future it would be neat to support eip55 type Transaction = { diff --git a/src/bridge/LibcoreBridge.js b/src/bridge/LibcoreBridge.js index fd11f02e..d9638460 100644 --- a/src/bridge/LibcoreBridge.js +++ b/src/bridge/LibcoreBridge.js @@ -11,11 +11,10 @@ import libcoreSyncAccount from 'commands/libcoreSyncAccount' import libcoreSignAndBroadcast from 'commands/libcoreSignAndBroadcast' import libcoreGetFees from 'commands/libcoreGetFees' import libcoreValidAddress from 'commands/libcoreValidAddress' -import { createCustomErrorClass } from 'helpers/errors' +import { NotEnoughBalance } from 'config/errors' import type { WalletBridge, EditProps } from './types' const NOT_ENOUGH_FUNDS = 52 -const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance') const notImplemented = new Error('LibcoreBridge: not implemented') diff --git a/src/bridge/RippleJSBridge.js b/src/bridge/RippleJSBridge.js index a201b621..e12655a5 100644 --- a/src/bridge/RippleJSBridge.js +++ b/src/bridge/RippleJSBridge.js @@ -20,11 +20,9 @@ import { import FeesRippleKind from 'components/FeesField/RippleKind' import AdvancedOptionsRippleKind from 'components/AdvancedOptions/RippleKind' import { getAccountPlaceholderName, getNewAccountPlaceholderName } from 'helpers/accountName' -import { createCustomErrorClass } from 'helpers/errors' +import { NotEnoughBalance } from 'config/errors' import type { WalletBridge, EditProps } from './types' -const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance') - type Transaction = { amount: BigNumber, recipient: string, diff --git a/src/commands/libcoreGetFees.js b/src/commands/libcoreGetFees.js index e6d5a005..ab96ff30 100644 --- a/src/commands/libcoreGetFees.js +++ b/src/commands/libcoreGetFees.js @@ -6,9 +6,7 @@ import withLibcore from 'helpers/withLibcore' import { createCommand, Command } from 'helpers/ipc' import * as accountIdHelper from 'helpers/accountId' import { isValidAddress, libcoreAmountToBigNumber, bigNumberToLibcoreAmount } from 'helpers/libcore' -import { createCustomErrorClass } from 'helpers/errors' - -const InvalidAddress = createCustomErrorClass('InvalidAddress') +import { InvalidAddress } from 'config/errors' type BitcoinLikeTransaction = { // TODO we rename this Transaction concept into transactionInput diff --git a/src/commands/libcoreHardReset.js b/src/commands/libcoreHardReset.js index 6b52a6a9..fa06e17d 100644 --- a/src/commands/libcoreHardReset.js +++ b/src/commands/libcoreHardReset.js @@ -3,9 +3,7 @@ import { createCommand } from 'helpers/ipc' import { fromPromise } from 'rxjs/observable/fromPromise' import withLibcore from 'helpers/withLibcore' -import { createCustomErrorClass } from 'helpers/errors' - -const HardResetFail = createCustomErrorClass('HardResetFail') +import { HardResetFail } from 'config/errors' const cmd = createCommand('libcoreHardReset', () => fromPromise( diff --git a/src/components/EnsureDeviceApp.js b/src/components/EnsureDeviceApp.js index 4748a0a9..6bb0e89c 100644 --- a/src/components/EnsureDeviceApp.js +++ b/src/components/EnsureDeviceApp.js @@ -12,7 +12,6 @@ import getAddress from 'commands/getAddress' import { createCancelablePolling } from 'helpers/promise' import { standardDerivation } from 'helpers/derivations' import { isSegwitPath } from 'helpers/bip32' -import { BtcUnmatchedApp } from 'helpers/getAddressForCurrency/btc' import DeviceInteraction from 'components/DeviceInteraction' import Text from 'components/base/Text' @@ -21,7 +20,7 @@ import IconUsb from 'icons/Usb' import type { Device } from 'types/common' -import { WrongDeviceForAccount, CantOpenDevice } from 'config/errors' +import { WrongDeviceForAccount, CantOpenDevice, BtcUnmatchedApp } from 'config/errors' import { getCurrentDevice } from 'reducers/devices' const usbIcon = diff --git a/src/components/IsUnlocked.js b/src/components/IsUnlocked.js index ecd90d79..381edfff 100644 --- a/src/components/IsUnlocked.js +++ b/src/components/IsUnlocked.js @@ -17,7 +17,7 @@ import hardReset from 'helpers/hardReset' import { fetchAccounts } from 'actions/accounts' import { isLocked, unlock } from 'reducers/application' -import { createCustomErrorClass } from 'helpers/errors' +import { PasswordIncorrectError } from 'config/errors' import Box from 'components/base/Box' import InputPassword from 'components/base/InputPassword' @@ -26,8 +26,6 @@ import IconArrowRight from 'icons/ArrowRight' import Button from './base/Button/index' import ConfirmModal from './base/Modal/ConfirmModal' -const PasswordIncorrectError = createCustomErrorClass('PasswordIncorrect') - type InputValue = { password: string, } diff --git a/src/components/SettingsPage/DisablePasswordModal.js b/src/components/SettingsPage/DisablePasswordModal.js index bd177544..17b9a0fa 100644 --- a/src/components/SettingsPage/DisablePasswordModal.js +++ b/src/components/SettingsPage/DisablePasswordModal.js @@ -1,7 +1,7 @@ // @flow import React, { PureComponent } from 'react' -import { createCustomErrorClass } from 'helpers/errors' +import { PasswordIncorrectError } from 'config/errors' import db from 'helpers/db' import Box from 'components/base/Box' @@ -12,8 +12,6 @@ import { Modal, ModalContent, ModalBody, ModalTitle, ModalFooter } from 'compone import type { T } from 'types/common' -const PasswordIncorrectError = createCustomErrorClass('PasswordIncorrect') - type Props = { t: T, onClose: Function, diff --git a/src/components/SettingsPage/PasswordForm.js b/src/components/SettingsPage/PasswordForm.js index 6f03c6bd..b523fd2e 100644 --- a/src/components/SettingsPage/PasswordForm.js +++ b/src/components/SettingsPage/PasswordForm.js @@ -6,12 +6,10 @@ import Box from 'components/base/Box' import InputPassword from 'components/base/InputPassword' import Label from 'components/base/Label' -import { createCustomErrorClass } from 'helpers/errors' +import { PasswordsDontMatchError } from 'config/errors' import type { T } from 'types/common' -const PasswordsDontMatchError = createCustomErrorClass('PasswordsDontMatch') - type Props = { t: T, hasPassword: boolean, diff --git a/src/components/SettingsPage/PasswordModal.js b/src/components/SettingsPage/PasswordModal.js index a364ebce..596d2398 100644 --- a/src/components/SettingsPage/PasswordModal.js +++ b/src/components/SettingsPage/PasswordModal.js @@ -5,15 +5,13 @@ import React, { PureComponent } from 'react' import type { T } from 'types/common' import db from 'helpers/db' -import { createCustomErrorClass } from 'helpers/errors' +import { PasswordIncorrectError } from 'config/errors' import Box from 'components/base/Box' import Button from 'components/base/Button' import { Modal, ModalContent, ModalBody, ModalTitle, ModalFooter } from 'components/base/Modal' import PasswordForm from './PasswordForm' -const PasswordIncorrectError = createCustomErrorClass('PasswordIncorrect') - type Props = { t: T, onClose: () => void, diff --git a/src/components/modals/AccountSettingRenderBody.js b/src/components/modals/AccountSettingRenderBody.js index 2ec155ab..86594ced 100644 --- a/src/components/modals/AccountSettingRenderBody.js +++ b/src/components/modals/AccountSettingRenderBody.js @@ -17,7 +17,7 @@ import { setDataModal } from 'reducers/modals' import { getBridgeForCurrency } from 'bridge' -import { createCustomErrorClass } from 'helpers/errors' +import { AccountNameRequiredError, EnpointConfigError } from 'config/errors' import TrackPage from 'analytics/TrackPage' import Spoiler from 'components/base/Spoiler' @@ -36,9 +36,6 @@ import { ConfirmModal, } from 'components/base/Modal' -const AccountNameRequiredError = createCustomErrorClass('AccountNameRequired') -const EnpointConfigError = createCustomErrorClass('EnpointConfig') - type State = { accountName: ?string, accountUnit: ?Unit, diff --git a/src/components/modals/Send/fields/RecipientField.js b/src/components/modals/Send/fields/RecipientField.js index 67c69e60..a8be45ba 100644 --- a/src/components/modals/Send/fields/RecipientField.js +++ b/src/components/modals/Send/fields/RecipientField.js @@ -9,7 +9,7 @@ import Box from 'components/base/Box' import LabelWithExternalIcon from 'components/base/LabelWithExternalIcon' import RecipientAddress from 'components/RecipientAddress' import { track } from 'analytics/segment' -import { createCustomErrorClass } from 'helpers/errors' +import { InvalidAddress } from 'config/errors' type Props = { t: T, @@ -20,8 +20,6 @@ type Props = { autoFocus?: boolean, } -const InvalidAddress = createCustomErrorClass('InvalidAddress') - class RecipientField extends Component, { isValid: boolean }> { state = { isValid: true, diff --git a/src/config/errors.js b/src/config/errors.js index d6140d6c..069389b8 100644 --- a/src/config/errors.js +++ b/src/config/errors.js @@ -4,15 +4,41 @@ import { createCustomErrorClass } from 'helpers/errors' -export const DisconnectedDevice = createCustomErrorClass('DisconnectedDevice') -export const UserRefusedOnDevice = createCustomErrorClass('UserRefusedOnDevice') // TODO rename because it's just for transaction refusal +export const AccountNameRequiredError = createCustomErrorClass('AccountNameRequired') +export const BtcUnmatchedApp = createCustomErrorClass('BtcUnmatchedApp') export const CantOpenDevice = createCustomErrorClass('CantOpenDevice') export const DeviceAppVerifyNotSupported = createCustomErrorClass('DeviceAppVerifyNotSupported') -export const UserRefusedAddress = createCustomErrorClass('UserRefusedAddress') -export const WrongDeviceForAccount = createCustomErrorClass('WrongDeviceForAccount') -export const DeviceNotGenuineError = createCustomErrorClass('DeviceNotGenuine') export const DeviceGenuineSocketEarlyClose = createCustomErrorClass('DeviceGenuineSocketEarlyClose') +export const DeviceNotGenuineError = createCustomErrorClass('DeviceNotGenuine') +export const DeviceSocketFail = createCustomErrorClass('DeviceSocketFail') +export const DeviceSocketNoBulkStatus = createCustomErrorClass('DeviceSocketNoBulkStatus') +export const DeviceSocketNoHandler = createCustomErrorClass('DeviceSocketNoHandler') +export const DisconnectedDevice = createCustomErrorClass('DisconnectedDevice') +export const EnpointConfigError = createCustomErrorClass('EnpointConfig') +export const FeeEstimationFailed = createCustomErrorClass('FeeEstimationFailed') +export const HardResetFail = createCustomErrorClass('HardResetFail') +export const InvalidAddress = createCustomErrorClass('InvalidAddress') +export const LatestMCUInstalledError = createCustomErrorClass('LatestMCUInstalledError') +export const LedgerAPIError = createCustomErrorClass('LedgerAPIError') +export const LedgerAPIErrorWithMessage = createCustomErrorClass('LedgerAPIErrorWithMessage') +export const LedgerAPINotAvailable = createCustomErrorClass('LedgerAPINotAvailable') +export const ManagerAppAlreadyInstalledError = createCustomErrorClass('ManagerAppAlreadyInstalled') +export const ManagerAppRelyOnBTCError = createCustomErrorClass('ManagerAppRelyOnBTC') +export const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') +export const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace') +export const ManagerUninstallBTCDep = createCustomErrorClass('ManagerUninstallBTCDep') +export const NetworkDown = createCustomErrorClass('NetworkDown') +export const NoAddressesFound = createCustomErrorClass('NoAddressesFound') +export const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance') +export const PasswordsDontMatchError = createCustomErrorClass('PasswordsDontMatch') +export const PasswordIncorrectError = createCustomErrorClass('PasswordIncorrect') export const TimeoutTagged = createCustomErrorClass('TimeoutTagged') +export const UserRefusedAddress = createCustomErrorClass('UserRefusedAddress') +export const UserRefusedFirmwareUpdate = createCustomErrorClass('UserRefusedFirmwareUpdate') +export const UserRefusedOnDevice = createCustomErrorClass('UserRefusedOnDevice') // TODO rename because it's just for transaction refusal +export const WebsocketConnectionError = createCustomErrorClass('WebsocketConnectionError') +export const WebsocketConnectionFailed = createCustomErrorClass('WebsocketConnectionFailed') +export const WrongDeviceForAccount = createCustomErrorClass('WrongDeviceForAccount') // db stuff, no need to translate export const NoDBPathGiven = createCustomErrorClass('NoDBPathGiven') diff --git a/src/helpers/apps/installApp.js b/src/helpers/apps/installApp.js index ce45f797..875890bc 100644 --- a/src/helpers/apps/installApp.js +++ b/src/helpers/apps/installApp.js @@ -4,14 +4,14 @@ import type Transport from '@ledgerhq/hw-transport' import { createDeviceSocket } from 'helpers/socket' import type { ApplicationVersion } from 'helpers/types' - -import { createCustomErrorClass } from 'helpers/errors' import { WS_INSTALL } from 'helpers/urls' -const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace') -const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') -const ManagerAppAlreadyInstalledError = createCustomErrorClass('ManagerAppAlreadyInstalled') -const ManagerAppRelyOnBTCError = createCustomErrorClass('ManagerAppRelyOnBTC') +import { + ManagerNotEnoughSpaceError, + ManagerDeviceLockedError, + ManagerAppAlreadyInstalledError, + ManagerAppRelyOnBTCError, +} from 'config/errors' function remapError(promise) { return promise.catch((e: Error) => { diff --git a/src/helpers/apps/uninstallApp.js b/src/helpers/apps/uninstallApp.js index 7ce6fef3..b3c2b98b 100644 --- a/src/helpers/apps/uninstallApp.js +++ b/src/helpers/apps/uninstallApp.js @@ -4,12 +4,9 @@ import type Transport from '@ledgerhq/hw-transport' import { createDeviceSocket } from 'helpers/socket' import type { ApplicationVersion } from 'helpers/types' -import { createCustomErrorClass } from 'helpers/errors' +import { ManagerDeviceLockedError, ManagerUninstallBTCDep } from 'config/errors' import { WS_INSTALL } from 'helpers/urls' -const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') -const ManagerUninstallBTCDep = createCustomErrorClass('ManagerUninstallBTCDep') - function remapError(promise) { return promise.catch((e: Error) => { switch (true) { diff --git a/src/helpers/debugAppInfosForCurrency/btc.js b/src/helpers/debugAppInfosForCurrency/btc.js index b7375e7c..74e7460a 100644 --- a/src/helpers/debugAppInfosForCurrency/btc.js +++ b/src/helpers/debugAppInfosForCurrency/btc.js @@ -1,9 +1,6 @@ // @flow import type Transport from '@ledgerhq/hw-transport' -import { createCustomErrorClass } from '../errors' - -export const BtcUnmatchedApp = createCustomErrorClass('BtcUnmatchedApp') export default async (transport: Transport<*>) => { const r = await transport.send(0xe0, 0xc4, 0, 0) diff --git a/src/helpers/firmware/getNextMCU.js b/src/helpers/firmware/getNextMCU.js index 3ab9337f..fcb82cd7 100644 --- a/src/helpers/firmware/getNextMCU.js +++ b/src/helpers/firmware/getNextMCU.js @@ -2,10 +2,8 @@ import network from 'api/network' import { GET_NEXT_MCU } from 'helpers/urls' -import { createCustomErrorClass } from 'helpers/errors' import type { OsuFirmware } from 'helpers/types' - -const LatestMCUInstalledError = createCustomErrorClass('LatestMCUInstalledError') +import { LatestMCUInstalledError } from 'config/errors' type NetworkResponse = { data: OsuFirmware | 'default' } diff --git a/src/helpers/firmware/installFinalFirmware.js b/src/helpers/firmware/installFinalFirmware.js index be13f6c1..7857ffb8 100644 --- a/src/helpers/firmware/installFinalFirmware.js +++ b/src/helpers/firmware/installFinalFirmware.js @@ -4,13 +4,12 @@ import type { DeviceInfo, DeviceVersion, OsuFirmware, FinalFirmware } from 'help import { WS_INSTALL } from 'helpers/urls' import { createDeviceSocket } from 'helpers/socket' -import { createCustomErrorClass } from 'helpers/errors' import getDeviceVersion from 'helpers/devices/getDeviceVersion' import getOsuFirmware from 'helpers/devices/getOsuFirmware' import getDeviceInfo from 'helpers/devices/getDeviceInfo' -import getFinalFirmwareById from './getFinalFirmwareById' +import { ManagerDeviceLockedError } from 'config/errors' -const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') +import getFinalFirmwareById from './getFinalFirmwareById' function remapSocketError(promise) { return promise.catch((e: Error) => { diff --git a/src/helpers/firmware/installMcu.js b/src/helpers/firmware/installMcu.js index d0ffb39e..18cd4872 100644 --- a/src/helpers/firmware/installMcu.js +++ b/src/helpers/firmware/installMcu.js @@ -5,12 +5,10 @@ import { WS_MCU } from 'helpers/urls' import { createDeviceSocket } from 'helpers/socket' import getNextMCU from 'helpers/firmware/getNextMCU' import getDeviceInfo from 'helpers/devices/getDeviceInfo' -import { createCustomErrorClass } from 'helpers/errors' +import { ManagerDeviceLockedError } from 'config/errors' import type { DeviceInfo } from 'helpers/types' -const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') - function remapSocketError(promise) { return promise.catch((e: Error) => { switch (true) { diff --git a/src/helpers/firmware/installOsuFirmware.js b/src/helpers/firmware/installOsuFirmware.js index 1121c340..04a9ba33 100644 --- a/src/helpers/firmware/installOsuFirmware.js +++ b/src/helpers/firmware/installOsuFirmware.js @@ -6,11 +6,11 @@ import { createDeviceSocket } from 'helpers/socket' import type { Firmware } from 'components/modals/UpdateFirmware' -import { createCustomErrorClass } from '../errors' - -const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace') -const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked') -const UserRefusedFirmwareUpdate = createCustomErrorClass('UserRefusedFirmwareUpdate') +import { + ManagerNotEnoughSpaceError, + ManagerDeviceLockedError, + UserRefusedFirmwareUpdate, +} from 'config/errors' function remapError(promise) { return promise.catch((e: Error) => { diff --git a/src/helpers/getAddressForCurrency/btc.js b/src/helpers/getAddressForCurrency/btc.js index f0ed669a..8155a25d 100644 --- a/src/helpers/getAddressForCurrency/btc.js +++ b/src/helpers/getAddressForCurrency/btc.js @@ -3,10 +3,8 @@ import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types' import Btc from '@ledgerhq/hw-app-btc' import type Transport from '@ledgerhq/hw-transport' +import { BtcUnmatchedApp } from 'config/errors' import getBitcoinLikeInfo from '../devices/getBitcoinLikeInfo' -import { createCustomErrorClass } from '../errors' - -export const BtcUnmatchedApp = createCustomErrorClass('BtcUnmatchedApp') export default async ( transport: Transport<*>, diff --git a/src/helpers/libcore.js b/src/helpers/libcore.js index 630c0c14..4f3a39c1 100644 --- a/src/helpers/libcore.js +++ b/src/helpers/libcore.js @@ -14,12 +14,11 @@ import type { NJSAccount, NJSOperation } from '@ledgerhq/ledger-core/src/ledgerc import { isSegwitPath, isUnsplitPath } from 'helpers/bip32' import * as accountIdHelper from 'helpers/accountId' -import { createCustomErrorClass, deserializeError } from './errors' +import { NoAddressesFound } from 'config/errors' +import { deserializeError } from './errors' import { getAccountPlaceholderName, getNewAccountPlaceholderName } from './accountName' import { timeoutTagged } from './promise' -const NoAddressesFound = createCustomErrorClass('NoAddressesFound') - // TODO: put that info inside currency itself const SPLITTED_CURRENCIES = { bitcoin_cash: { diff --git a/src/helpers/socket.js b/src/helpers/socket.js index 5611a3a5..cf9d29a8 100644 --- a/src/helpers/socket.js +++ b/src/helpers/socket.js @@ -5,13 +5,13 @@ import logger from 'logger' import Websocket from 'ws' import type Transport from '@ledgerhq/hw-transport' import { Observable } from 'rxjs' -import { createCustomErrorClass } from './errors' - -const WebsocketConnectionError = createCustomErrorClass('WebsocketConnectionError') -const WebsocketConnectionFailed = createCustomErrorClass('WebsocketConnectionFailed') -const DeviceSocketFail = createCustomErrorClass('DeviceSocketFail') -const DeviceSocketNoBulkStatus = createCustomErrorClass('DeviceSocketNoBulkStatus') -const DeviceSocketNoHandler = createCustomErrorClass('DeviceSocketNoHandler') +import { + WebsocketConnectionError, + WebsocketConnectionFailed, + DeviceSocketFail, + DeviceSocketNoBulkStatus, + DeviceSocketNoHandler, +} from 'config/errors' /** * use Ledger WebSocket API to exchange data with the device From a9801bb50c6a319a4dc6eb88a70fec45744340ef Mon Sep 17 00:00:00 2001 From: Arnaud97234 Date: Wed, 1 Aug 2018 17:57:19 +0200 Subject: [PATCH 03/17] Implement e2e tests with spectron --- .eslintrc | 1 + package.json | 8 +- src/components/DashboardPage/EmptyState.js | 16 +- src/components/Onboarding/OnboardingFooter.js | 8 +- src/components/Onboarding/steps/Analytics.js | 2 +- src/components/Onboarding/steps/Finish.js | 4 +- src/components/SettingsPage/DevModeButton.js | 2 +- src/components/SettingsPage/index.js | 2 +- src/components/TopBar/index.js | 2 +- src/components/modals/Disclaimer.js | 4 +- test-e2e/nav_to_settings.spec.js | 73 +++++ yarn.lock | 249 ++++++++++++++++-- 12 files changed, 339 insertions(+), 32 deletions(-) create mode 100644 test-e2e/nav_to_settings.spec.js diff --git a/.eslintrc b/.eslintrc index 6be03c28..a5c7283d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -21,6 +21,7 @@ "jest": false, "describe": false, "beforeEach": false, + "afterEach": false, "test": false, "it": false, "expect": false, diff --git a/package.json b/package.json index 3323be9f..b12c70ee 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,11 @@ "dist": "bash ./scripts/dist.sh", "dist:dir": "bash ./scripts/dist-dir.sh", "compile": "bash ./scripts/compile.sh", - "lint": "eslint src webpack .storybook", + "lint": "eslint src webpack .storybook test-e2e", "flow": "flow", - "test": "jest", - "prettier": "prettier --write \"{src,webpack,.storybook}/**/*.{js,json}\"", + "test": "jest src", + "test-e2e": "jest test-e2e", + "prettier": "prettier --write \"{src,webpack,.storybook,test-e2e}/**/*.{js,json}\"", "ci": "yarn lint && yarn flow && yarn prettier && yarn test", "storybook": "NODE_ENV=development STORYBOOK_ENV=1 start-storybook -s ./static -p 4444", "publish-storybook": "bash ./scripts/legacy/publish-storybook.sh", @@ -158,6 +159,7 @@ "prettier": "^1.13.5", "react-hot-loader": "^4.3.2", "react-test-renderer": "^16.4.1", + "spectron": "^3.8.0", "webpack": "^4.6.0", "webpack-bundle-analyzer": "^2.11.1", "webpack-cli": "^2.0.14", diff --git a/src/components/DashboardPage/EmptyState.js b/src/components/DashboardPage/EmptyState.js index 0a0d63e3..5891ad4e 100644 --- a/src/components/DashboardPage/EmptyState.js +++ b/src/components/DashboardPage/EmptyState.js @@ -45,15 +45,25 @@ class EmptyState extends PureComponent { height="157" /> - {t('app:emptyState.dashboard.title')} + {t('app:emptyState.dashboard.title')} {t('app:emptyState.dashboard.desc')} - - diff --git a/src/components/Onboarding/OnboardingFooter.js b/src/components/Onboarding/OnboardingFooter.js index 3db431cc..a1abaf6d 100644 --- a/src/components/Onboarding/OnboardingFooter.js +++ b/src/components/Onboarding/OnboardingFooter.js @@ -26,7 +26,13 @@ const OnboardingFooter = ({ - diff --git a/src/components/Onboarding/steps/Analytics.js b/src/components/Onboarding/steps/Analytics.js index 81213aa2..03f3c184 100644 --- a/src/components/Onboarding/steps/Analytics.js +++ b/src/components/Onboarding/steps/Analytics.js @@ -70,7 +70,7 @@ class Analytics extends PureComponent { deviceType={onboarding.isLedgerNano ? 'Nano S' : 'Blue'} /> - {t('onboarding:analytics.title')} + {t('onboarding:analytics.title')} {t('onboarding:analytics.desc')} diff --git a/src/components/Onboarding/steps/Finish.js b/src/components/Onboarding/steps/Finish.js index 969791e6..eaa1b515 100644 --- a/src/components/Onboarding/steps/Finish.js +++ b/src/components/Onboarding/steps/Finish.js @@ -103,11 +103,11 @@ export default class Finish extends Component { - {t('onboarding:finish.title')} + {t('onboarding:finish.title')} {t('onboarding:finish.desc')} - diff --git a/src/components/SettingsPage/DevModeButton.js b/src/components/SettingsPage/DevModeButton.js index 8e53a2d1..e4947f14 100644 --- a/src/components/SettingsPage/DevModeButton.js +++ b/src/components/SettingsPage/DevModeButton.js @@ -27,7 +27,7 @@ class DevModeButton extends PureComponent { return ( - + ) } diff --git a/src/components/SettingsPage/index.js b/src/components/SettingsPage/index.js index 582add79..43b7c96d 100644 --- a/src/components/SettingsPage/index.js +++ b/src/components/SettingsPage/index.js @@ -106,7 +106,7 @@ class SettingsPage extends PureComponent { return ( - + {t('app:settings.title')} diff --git a/src/components/TopBar/index.js b/src/components/TopBar/index.js index fc9e597b..780981c8 100644 --- a/src/components/TopBar/index.js +++ b/src/components/TopBar/index.js @@ -109,7 +109,7 @@ class TopBar extends PureComponent { )} - t('app:settings.title')}> + t('app:settings.title')} data-e2eId="setting_button"> diff --git a/src/components/modals/Disclaimer.js b/src/components/modals/Disclaimer.js index 4ceaa006..f4acc488 100644 --- a/src/components/modals/Disclaimer.js +++ b/src/components/modals/Disclaimer.js @@ -25,7 +25,7 @@ class DisclaimerModal extends PureComponent { name={MODAL_DISCLAIMER} render={({ onClose }) => ( - {t('app:disclaimerModal.title')} + {t('app:disclaimerModal.title')} @@ -34,7 +34,7 @@ class DisclaimerModal extends PureComponent {

{t('app:disclaimerModal.desc_2')}

- diff --git a/test-e2e/nav_to_settings.spec.js b/test-e2e/nav_to_settings.spec.js new file mode 100644 index 00000000..84a942fc --- /dev/null +++ b/test-e2e/nav_to_settings.spec.js @@ -0,0 +1,73 @@ +const Application = require('spectron').Application + +let app + +const TIMEOUT = 50 * 1000 + +describe('Application launch', () => { + beforeEach(async () => { + app = new Application({ + path: './dist/ledger-live-desktop-1.1.0-linux-x86_64.AppImage', + env: { + SKIP_ONBOARDING: '1', + }, + }) + await app.start() + }, TIMEOUT) + + afterEach(async () => { + if (app && app.isRunning()) { + await app.stop() + } + }, TIMEOUT) + + test( + 'Start app and set developper mode ', + async () => { + const title = await app.client.getTitle() + expect(title).toEqual('Ledger Live') + await app.client.waitUntilWindowLoaded() + await app.client.pause(2000) + /* await app.client.waitUntil(function(){ + return app.client.getText('//*[@id="app"]/div/div/div/div[1]/div/div/div[3]/div[1]/div[1]/div[1]/div[1]') === 'Technical data *' + }, 2000, 'Test', 200) +*/ + + // Post Onboarding + const title_onboarding = await app.client.getText('[data-e2eId=onboarding_title]') + expect(title_onboarding).toEqual('Analytics and bug reports') + await app.client.saveScreenshot('./test-e2e/snap_Start.png') + await app.client.click('[data-e2eId=continue_button]') + await app.client.pause(1000) + + const title_finish = await app.client.getText('[data-e2eId=finish_title]') + expect(title_finish).toEqual('Your device is ready!') + await app.client.saveScreenshot('./test-e2e/snap_Finish.png') + await app.client.click('[data-e2eId=continue_button]') + await app.client.pause(1000) + + const title_disclaimer = await app.client.getText('[data-e2eId=disclaimer_title]') + expect(title_disclaimer).toEqual('Trade safely') + await app.client.saveScreenshot('./test-e2e/snap_Disclaimer.png') + await app.client.click('[data-e2eId=continue_button]') + await app.client.pause(1000) + + // Dashboard EmptyState + const title_dashboard_empty = await app.client.getText('[data-e2eId=dashboard_empty_title]') + expect(title_dashboard_empty).toEqual('Add accounts to your portfolio') + await app.client.saveScreenshot('./test-e2e/snap_emptyState.png') + + // Open Settings + await app.client.click('[data-e2eId=setting_button]') + await app.client.pause(1000) + const title_settings = await app.client.getText('[data-e2eId=settings_title]') + expect(title_settings).toEqual('Settings') + await app.client.saveScreenshot('./test-e2e/snap_settings.png') + // DevMode ON + await app.client.click('[data-e2eId=devMode_button]') + await app.client.pause(500) + await app.client.saveScreenshot('./test-e2e/snap_settings_devMode.png') + }, + TIMEOUT, + ) +}) diff --git a/yarn.lock b/yarn.lock index 760f1ce9..07a5729c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2213,6 +2213,30 @@ aproba@^1.0.3, aproba@^1.1.1, aproba@^1.1.2, aproba@~1.2.0: version "2.0.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" +archiver-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174" + dependencies: + glob "^7.0.0" + graceful-fs "^4.1.0" + lazystream "^1.0.0" + lodash "^4.8.0" + normalize-path "^2.0.0" + readable-stream "^2.0.0" + +archiver@~2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-2.1.1.tgz#ff662b4a78201494a3ee544d3a33fe7496509ebc" + dependencies: + archiver-utils "^1.3.0" + async "^2.0.0" + buffer-crc32 "^0.2.1" + glob "^7.0.0" + lodash "^4.8.0" + readable-stream "^2.0.0" + tar-stream "^1.5.0" + zip-stream "^1.2.0" + archy@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" @@ -2414,7 +2438,7 @@ async@^1.4.0, async@^1.5.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.1.2, async@^2.1.4, async@^2.6.0, async@^2.6.1: +async@^2.0.0, async@^2.1.2, async@^2.1.4, async@^2.6.0, async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: @@ -3889,6 +3913,10 @@ buffer-alloc@^1.1.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" +buffer-crc32@^0.2.1: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" @@ -3928,6 +3956,13 @@ buffer@^5.0.3: base64-js "^1.0.2" ieee754 "^1.1.4" +buffer@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.0.tgz#53cf98241100099e9eeae20ee6d51d21b16e541e" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + buffers@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" @@ -4612,6 +4647,15 @@ component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" +compress-commons@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f" + dependencies: + buffer-crc32 "^0.2.1" + crc32-stream "^2.0.0" + normalize-path "^2.0.0" + readable-stream "^2.0.0" + compressible@~2.0.13: version "2.0.14" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" @@ -4774,6 +4818,19 @@ cosmiconfig@^4.0.0: parse-json "^4.0.0" require-from-string "^2.0.1" +crc32-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" + dependencies: + crc "^3.4.4" + readable-stream "^2.0.0" + +crc@^3.4.4: + version "3.8.0" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" + dependencies: + buffer "^5.1.0" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -4935,6 +4992,12 @@ css-loader@^0.28.11: postcss-value-parser "^3.3.0" source-list-map "^2.0.0" +css-parse@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" + dependencies: + css "^2.0.0" + css-select-base-adapter@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.0.tgz#0102b3d14630df86c3eb9fa9f5456270106cf990" @@ -4991,10 +5054,23 @@ css-url-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec" +css-value@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea" + css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" +css@^2.0.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.3.tgz#f861f4ba61e79bedc962aa548e5780fd95cbc6be" + dependencies: + inherits "^2.0.1" + source-map "^0.1.38" + source-map-resolve "^0.5.1" + urix "^0.1.0" + cssesc@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" @@ -5383,6 +5459,10 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +deepmerge@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.0.1.tgz#25c1c24f110fb914f80001b925264dd77f3f4312" + default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -5508,6 +5588,10 @@ detect-port-alt@1.1.6: address "^1.0.1" debug "^2.6.0" +dev-null@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dev-null/-/dev-null-0.1.1.tgz#5a205ce3c2b2ef77b6238d6ba179eb74c6a0e818" + dezalgo@^1.0.0, dezalgo@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" @@ -5754,6 +5838,10 @@ ejs@^2.5.7, ejs@^2.5.9, ejs@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" +ejs@~2.5.6: + version "2.5.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" + electron-builder-lib@20.14.7, electron-builder-lib@~20.14.6: version "20.14.7" resolved "https://registry.yarnpkg.com/electron-builder-lib/-/electron-builder-lib-20.14.7.tgz#db91977dd13b0a288e1da5629183807a9847de21" @@ -5803,6 +5891,13 @@ electron-builder@20.14.7: update-notifier "^2.5.0" yargs "^11.0.0" +electron-chromedriver@~1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-1.8.0.tgz#901714133cf6f6093d365e1f44a52d99624d8241" + dependencies: + electron-download "^4.1.0" + extract-zip "^1.6.5" + electron-context-menu@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/electron-context-menu/-/electron-context-menu-0.10.0.tgz#97fce2b805e03ac2b1dae11eb6a68b064b78d633" @@ -5855,6 +5950,20 @@ electron-download@^3.0.1: semver "^5.3.0" sumchecker "^1.2.0" +electron-download@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.0.tgz#bf932c746f2f87ffcc09d1dd472f2ff6b9187845" + dependencies: + debug "^2.2.0" + env-paths "^1.0.0" + fs-extra "^2.0.0" + minimist "^1.2.0" + nugget "^2.0.0" + path-exists "^3.0.0" + rc "^1.1.2" + semver "^5.3.0" + sumchecker "^2.0.1" + electron-is-dev@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/electron-is-dev/-/electron-is-dev-0.3.0.tgz#14e6fda5c68e9e4ecbeff9ccf037cbd7c05c5afe" @@ -6632,7 +6741,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^1.0.3: +extract-zip@^1.0.3, extract-zip@^1.6.5: version "1.6.7" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" dependencies: @@ -6994,6 +7103,13 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-extra@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + fs-extra@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" @@ -7102,6 +7218,12 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gaze@~1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + dependencies: + globule "^1.0.0" + genfun@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/genfun/-/genfun-4.0.1.tgz#ed10041f2e4a7f1b0a38466d17a5c3e27df1dfc1" @@ -7222,7 +7344,7 @@ glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.2: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1, glob@~7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -7305,6 +7427,14 @@ globby@^8.0.0, globby@^8.0.1: pify "^3.0.0" slash "^1.0.0" +globule@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + got@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" @@ -7362,7 +7492,7 @@ got@^8.3.1: url-parse-lax "^3.0.0" url-to-options "^1.0.1" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.11: +graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.11: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -7949,7 +8079,7 @@ inline-style-prefixer@^3.0.6: bowser "^1.7.3" css-in-js-utils "^2.0.0" -inquirer@3.3.0, inquirer@^3.0.6: +inquirer@3.3.0, inquirer@^3.0.6, inquirer@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: @@ -9071,6 +9201,12 @@ lazy-val@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc" +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + dependencies: + readable-stream "^2.0.5" + lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" @@ -9350,7 +9486,7 @@ lodash@^3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1: +lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.0, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.8.0, lodash@~4.17.10: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" @@ -9763,7 +9899,7 @@ minimatch@3.0.3: dependencies: brace-expansion "^1.0.0" -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -10132,7 +10268,7 @@ normalize-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" -normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: @@ -10180,6 +10316,10 @@ npm-install-checks@~3.0.0: dependencies: semver "^2.3.0 || 3.x || 4 || 5" +npm-install-package@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/npm-install-package/-/npm-install-package-2.1.0.tgz#d7efe3cfcd7ab00614b896ea53119dc9ab259125" + npm-lifecycle@^2.0.1, npm-lifecycle@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-2.0.3.tgz#696bedf1143371163e9cc16fe872357e25d8d90e" @@ -10552,7 +10692,7 @@ opn@^5.1.0: dependencies: is-wsl "^1.1.0" -optimist@^0.6.1: +optimist@^0.6.1, optimist@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: @@ -11561,7 +11701,7 @@ pushdata-bitcoin@^1.0.1: dependencies: bitcoin-ops "^1.3.0" -q@^1.1.2: +q@^1.1.2, q@~1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -12140,7 +12280,7 @@ read@1, read@~1.0.1, read@~1.0.7: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -12516,7 +12656,7 @@ request-promise-native@^1.0.5: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@^2.45.0, request@^2.74.0, request@^2.83.0, request@^2.85.0: +request@^2.45.0, request@^2.74.0, request@^2.81.0, request@^2.83.0, request@^2.85.0: version "2.87.0" resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" dependencies: @@ -12647,6 +12787,10 @@ retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" +rgb2hex@~0.1.4: + version "0.1.9" + resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.1.9.tgz#5d3e0e14b0177b568e6f0d5b43e34fbfdb670346" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -13233,7 +13377,7 @@ source-list-map@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" -source-map-resolve@^0.5.0: +source-map-resolve@^0.5.0, source-map-resolve@^0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" dependencies: @@ -13268,6 +13412,12 @@ source-map@0.7.3, source-map@^0.7.2: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" +source-map@^0.1.38: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + dependencies: + amdefine ">=0.0.4" + source-map@^0.4.4, source-map@~0.4.1: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" @@ -13335,6 +13485,16 @@ spdy@^3.4.1: select-hose "^2.0.0" spdy-transport "^2.0.18" +spectron@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/spectron/-/spectron-3.8.0.tgz#122c3562fd7e92b7cdf6f94094aa495b150dfa51" + dependencies: + dev-null "^0.1.1" + electron-chromedriver "~1.8.0" + request "^2.81.0" + split "^1.0.0" + webdriverio "^4.8.0" + speedometer@~0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" @@ -13345,6 +13505,12 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +split@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -13641,7 +13807,7 @@ sumchecker@^1.2.0: debug "^2.2.0" es6-promise "^4.0.5" -sumchecker@^2.0.2: +sumchecker@^2.0.1, sumchecker@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e" dependencies: @@ -13673,6 +13839,12 @@ supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0: dependencies: has-flag "^3.0.0" +supports-color@~5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.0.1.tgz#1c5331f22250c84202805b2f17adf16699f3a39a" + dependencies: + has-flag "^2.0.0" + svg-tag-names@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/svg-tag-names/-/svg-tag-names-1.1.1.tgz#9641b29ef71025ee094c7043f7cdde7d99fbd50a" @@ -13765,7 +13937,7 @@ tar-fs@^1.13.0: pump "^1.0.0" tar-stream "^1.1.2" -tar-stream@^1.1.2: +tar-stream@^1.1.2, tar-stream@^1.5.0: version "1.6.1" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.1.tgz#f84ef1696269d6223ca48f6e1eeede3f7e81f395" dependencies: @@ -13863,7 +14035,7 @@ through2@~0.2.3: readable-stream "~1.1.9" xtend "~2.1.1" -"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8, through@~2.3.6: +through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8, through@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -14347,7 +14519,7 @@ url-to-options@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" -url@^0.11.0: +url@^0.11.0, url@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" dependencies: @@ -14584,6 +14756,36 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" +wdio-dot-reporter@~0.0.8: + version "0.0.10" + resolved "https://registry.yarnpkg.com/wdio-dot-reporter/-/wdio-dot-reporter-0.0.10.tgz#facfb7c9c5984149951f59cbc3cd0752101cf0e0" + +webdriverio@^4.8.0: + version "4.13.1" + resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.13.1.tgz#624ef4ca569f3c9a5e8e9b11302b4431eda1fb8a" + dependencies: + archiver "~2.1.0" + babel-runtime "^6.26.0" + css-parse "^2.0.0" + css-value "~0.0.1" + deepmerge "~2.0.1" + ejs "~2.5.6" + gaze "~1.1.2" + glob "~7.1.1" + inquirer "~3.3.0" + json-stringify-safe "~5.0.1" + mkdirp "~0.5.1" + npm-install-package "~2.1.0" + optimist "~0.6.1" + q "~1.5.0" + request "^2.83.0" + rgb2hex "~0.1.4" + safe-buffer "~5.1.1" + supports-color "~5.0.0" + url "~0.11.0" + wdio-dot-reporter "~0.0.8" + wgxpath "~1.0.0" + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -14810,6 +15012,10 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" +wgxpath@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wgxpath/-/wgxpath-1.0.0.tgz#eef8a4b9d558cc495ad3a9a2b751597ecd9af690" + whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" @@ -15280,6 +15486,15 @@ yeoman-generator@^2.0.5: through2 "^2.0.0" yeoman-environment "^2.0.5" +zip-stream@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04" + dependencies: + archiver-utils "^1.3.0" + compress-commons "^1.2.0" + lodash "^4.8.0" + readable-stream "^2.0.0" + zxcvbn@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/zxcvbn/-/zxcvbn-4.4.2.tgz#28ec17cf09743edcab056ddd8b1b06262cc73c30" From 3665442893727b4bb78aa09dc316d2927210ac54 Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 3 Aug 2018 10:03:13 +0200 Subject: [PATCH 04/17] Bump Arch PKGBUILD --- build/linux/arch/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/linux/arch/PKGBUILD b/build/linux/arch/PKGBUILD index b00dc702..2947605f 100644 --- a/build/linux/arch/PKGBUILD +++ b/build/linux/arch/PKGBUILD @@ -2,7 +2,7 @@ # shellcheck disable=SC2154,SC2034,SC2164 pkgname=ledger-live -pkgver=1.0.7 +pkgver=1.1.0 pkgrel=1 pkgdesc="Open source companion app for your Ledger devices" arch=('x86_64') @@ -15,7 +15,7 @@ changelog= source=("https://github.com/LedgerHQ/ledger-live-desktop/archive/v${pkgver}.tar.gz" "ledger-live.desktop") -md5sums=('d60d772a03c0a1c59df07f93b0268a4c' +md5sums=('5dc6bd1e8d6dedcfe760d1c75565aad8' '52705147909a0a988907a23a71199092') # TODO sign with ledger pgp validpgpkeys=() From 7bac09bb653948dcf0f53a2dcf10ed58f8b1ae4e Mon Sep 17 00:00:00 2001 From: meriadec Date: Fri, 3 Aug 2018 10:55:39 +0200 Subject: [PATCH 05/17] Update e2e identifiers to prevent React warning Also, remove screenshots while e2e testing because not used for now. --- src/components/DashboardPage/EmptyState.js | 6 ++-- src/components/Onboarding/OnboardingFooter.js | 2 +- src/components/Onboarding/steps/Analytics.js | 2 +- src/components/Onboarding/steps/Finish.js | 4 +-- src/components/SettingsPage/DevModeButton.js | 2 +- src/components/SettingsPage/index.js | 2 +- src/components/TopBar/index.js | 2 +- src/components/modals/Disclaimer.js | 4 +-- test-e2e/nav_to_settings.spec.js | 31 +++++++------------ 9 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/components/DashboardPage/EmptyState.js b/src/components/DashboardPage/EmptyState.js index 5891ad4e..f3ffe2b5 100644 --- a/src/components/DashboardPage/EmptyState.js +++ b/src/components/DashboardPage/EmptyState.js @@ -45,7 +45,7 @@ class EmptyState extends PureComponent { height="157" /> - {t('app:emptyState.dashboard.title')} + {t('app:emptyState.dashboard.title')} {t('app:emptyState.dashboard.desc')} @@ -54,7 +54,7 @@ class EmptyState extends PureComponent { primary style={{ minWidth: 120 }} onClick={this.handleInstallApp} - data-e2eId="dashboard_empty_OpenManager" + data-e2e="dashboard_empty_OpenManager" > {t('app:emptyState.dashboard.buttons.installApp')} @@ -62,7 +62,7 @@ class EmptyState extends PureComponent { outline style={{ minWidth: 120 }} onClick={() => openModal(MODAL_ADD_ACCOUNTS)} - data-e2eId="dashboard_empty_AddAccounts" + data-e2e="dashboard_empty_AddAccounts" > {t('app:emptyState.dashboard.buttons.addAccount')} diff --git a/src/components/Onboarding/OnboardingFooter.js b/src/components/Onboarding/OnboardingFooter.js index a1abaf6d..e9ee8cac 100644 --- a/src/components/Onboarding/OnboardingFooter.js +++ b/src/components/Onboarding/OnboardingFooter.js @@ -27,7 +27,7 @@ const OnboardingFooter = ({ {t('app:common.back')} diff --git a/src/components/SettingsPage/DevModeButton.js b/src/components/SettingsPage/DevModeButton.js index e4947f14..2d8c8c3e 100644 --- a/src/components/SettingsPage/DevModeButton.js +++ b/src/components/SettingsPage/DevModeButton.js @@ -27,7 +27,7 @@ class DevModeButton extends PureComponent { return ( - + ) } diff --git a/src/components/SettingsPage/index.js b/src/components/SettingsPage/index.js index 43b7c96d..30b1cedb 100644 --- a/src/components/SettingsPage/index.js +++ b/src/components/SettingsPage/index.js @@ -106,7 +106,7 @@ class SettingsPage extends PureComponent { return ( - + {t('app:settings.title')} diff --git a/src/components/TopBar/index.js b/src/components/TopBar/index.js index 780981c8..11b5c9b3 100644 --- a/src/components/TopBar/index.js +++ b/src/components/TopBar/index.js @@ -109,7 +109,7 @@ class TopBar extends PureComponent { )} - t('app:settings.title')} data-e2eId="setting_button"> + t('app:settings.title')} data-e2e="setting_button"> diff --git a/src/components/modals/Disclaimer.js b/src/components/modals/Disclaimer.js index f4acc488..fb493733 100644 --- a/src/components/modals/Disclaimer.js +++ b/src/components/modals/Disclaimer.js @@ -25,7 +25,7 @@ class DisclaimerModal extends PureComponent { name={MODAL_DISCLAIMER} render={({ onClose }) => ( - {t('app:disclaimerModal.title')} + {t('app:disclaimerModal.title')} @@ -34,7 +34,7 @@ class DisclaimerModal extends PureComponent {

{t('app:disclaimerModal.desc_2')}

- diff --git a/test-e2e/nav_to_settings.spec.js b/test-e2e/nav_to_settings.spec.js index 84a942fc..d2516b91 100644 --- a/test-e2e/nav_to_settings.spec.js +++ b/test-e2e/nav_to_settings.spec.js @@ -28,45 +28,36 @@ describe('Application launch', () => { expect(title).toEqual('Ledger Live') await app.client.waitUntilWindowLoaded() await app.client.pause(2000) - /* await app.client.waitUntil(function(){ - return app.client.getText('//*[@id="app"]/div/div/div/div[1]/div/div/div[3]/div[1]/div[1]/div[1]/div[1]') === 'Technical data *' - }, 2000, 'Test', 200) -*/ // Post Onboarding - const title_onboarding = await app.client.getText('[data-e2eId=onboarding_title]') + const title_onboarding = await app.client.getText('[data-e2e=onboarding_title]') expect(title_onboarding).toEqual('Analytics and bug reports') - await app.client.saveScreenshot('./test-e2e/snap_Start.png') - await app.client.click('[data-e2eId=continue_button]') + await app.client.click('[data-e2e=continue_button]') await app.client.pause(1000) - const title_finish = await app.client.getText('[data-e2eId=finish_title]') + const title_finish = await app.client.getText('[data-e2e=finish_title]') expect(title_finish).toEqual('Your device is ready!') - await app.client.saveScreenshot('./test-e2e/snap_Finish.png') - await app.client.click('[data-e2eId=continue_button]') + await app.client.click('[data-e2e=continue_button]') await app.client.pause(1000) - const title_disclaimer = await app.client.getText('[data-e2eId=disclaimer_title]') + const title_disclaimer = await app.client.getText('[data-e2e=disclaimer_title]') expect(title_disclaimer).toEqual('Trade safely') - await app.client.saveScreenshot('./test-e2e/snap_Disclaimer.png') - await app.client.click('[data-e2eId=continue_button]') + await app.client.click('[data-e2e=continue_button]') await app.client.pause(1000) // Dashboard EmptyState - const title_dashboard_empty = await app.client.getText('[data-e2eId=dashboard_empty_title]') + const title_dashboard_empty = await app.client.getText('[data-e2e=dashboard_empty_title]') expect(title_dashboard_empty).toEqual('Add accounts to your portfolio') - await app.client.saveScreenshot('./test-e2e/snap_emptyState.png') // Open Settings - await app.client.click('[data-e2eId=setting_button]') + await app.client.click('[data-e2e=setting_button]') await app.client.pause(1000) - const title_settings = await app.client.getText('[data-e2eId=settings_title]') + const title_settings = await app.client.getText('[data-e2e=settings_title]') expect(title_settings).toEqual('Settings') - await app.client.saveScreenshot('./test-e2e/snap_settings.png') + // DevMode ON - await app.client.click('[data-e2eId=devMode_button]') + await app.client.click('[data-e2e=devMode_button]') await app.client.pause(500) - await app.client.saveScreenshot('./test-e2e/snap_settings_devMode.png') }, TIMEOUT, ) From d4305b5b38e157dee5af30b0daf11ef98b7524ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Renaudeau?= Date: Fri, 3 Aug 2018 09:27:41 +0200 Subject: [PATCH 06/17] Fix a JS bug when you have no txs but have balance --- src/bridge/EthereumJSBridge.js | 4 +++- src/components/AccountPage/AccountHeaderActions.js | 3 ++- src/components/AccountPage/index.js | 3 ++- .../modals/AddAccounts/steps/03-step-import.js | 9 +++++---- src/helpers/isAccountEmpty.js | 10 ++++++++++ 5 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 src/helpers/isAccountEmpty.js diff --git a/src/bridge/EthereumJSBridge.js b/src/bridge/EthereumJSBridge.js index b2aaabda..db53cf2e 100644 --- a/src/bridge/EthereumJSBridge.js +++ b/src/bridge/EthereumJSBridge.js @@ -246,7 +246,9 @@ const EthereumBridge: WalletBridge = { } for (let i = 0; i < 50; i++) { const api = apiForCurrency(account.currency) - const { block } = txs[txs.length - 1] + const last = txs[txs.length - 1] + if (!last) break + const { block } = last if (!block) break const next = await api.getTransactions(account.freshAddress, block.hash) if (next.txs.length === 0) break diff --git a/src/components/AccountPage/AccountHeaderActions.js b/src/components/AccountPage/AccountHeaderActions.js index 12b26a90..9ae4abb7 100644 --- a/src/components/AccountPage/AccountHeaderActions.js +++ b/src/components/AccountPage/AccountHeaderActions.js @@ -7,6 +7,7 @@ import { translate } from 'react-i18next' import styled from 'styled-components' import type { Account } from '@ledgerhq/live-common/lib/types' import Tooltip from 'components/base/Tooltip' +import isAccountEmpty from 'helpers/isAccountEmpty' import { MODAL_SEND, MODAL_RECEIVE, MODAL_SETTINGS_ACCOUNT } from 'config/constants' @@ -61,7 +62,7 @@ class AccountHeaderActions extends PureComponent { const { account, openModal, t } = this.props return ( - {account.operations.length > 0 || !account.balance.isZero() ? ( + {!isAccountEmpty(account) ? (