diff --git a/packages/mobile/__mocks__/src/geth/network-config.ts b/packages/mobile/__mocks__/src/geth/network-config.ts new file mode 100644 index 00000000000..ebdd1b22677 --- /dev/null +++ b/packages/mobile/__mocks__/src/geth/network-config.ts @@ -0,0 +1,8 @@ +import { DEFAULT_SYNC_MODE, DEFAULT_TESTNET } from 'src/web3/testnets' + +export default { + [DEFAULT_TESTNET]: { + nodeDir: `.${DEFAULT_TESTNET}`, + syncMode: DEFAULT_SYNC_MODE, + }, +} diff --git a/packages/mobile/__mocks__/src/web3/testnets.ts b/packages/mobile/__mocks__/src/web3/testnets.ts new file mode 100644 index 00000000000..b1580c159c5 --- /dev/null +++ b/packages/mobile/__mocks__/src/web3/testnets.ts @@ -0,0 +1,4 @@ +import { GethSyncMode } from 'src/geth/consts' + +export const DEFAULT_TESTNET = 'integration' +export const DEFAULT_SYNC_MODE: GethSyncMode = GethSyncMode.Ultralight diff --git a/packages/mobile/__mocks__/web3.js b/packages/mobile/__mocks__/web3.js index 732d1ba45ee..5b0f6a1d222 100644 --- a/packages/mobile/__mocks__/web3.js +++ b/packages/mobile/__mocks__/web3.js @@ -43,13 +43,12 @@ export default class { }, getAccounts: () => {}, accounts: { - privateKeyToAccount: () => - '0x1129eb2fbccdc663f4923a6495c35b096249812b589f7c4cd1dba01e1edaf724', + privateKeyToAccount: () => ({ address: '0x0000000000000000000000000000000000007E57' }), wallet: { add: () => null, }, create: () => ({ - address: '0x1129eb2fbccdc663f4923a6495c35b096249812b589f7c4cd1dba01e1edaf724', + address: '0x0000000000000000000000000000000000007E57', privateKey: '0x1129eb2fbccdc663f4923a6495c35b096249812b589f7c4cd1dba01e1edaf724', }), }, diff --git a/packages/mobile/locales/en-US/global.json b/packages/mobile/locales/en-US/global.json index 075a019c67e..db9a3014954 100644 --- a/packages/mobile/locales/en-US/global.json +++ b/packages/mobile/locales/en-US/global.json @@ -62,7 +62,7 @@ "canNotRequestFromUnverified": "Can not request from unverified users", "restartApp": "Restart App", "loading": "Loading…", - "invalidBackup": "Invalid Backup Key", + "invalidBackupPhrase": "Invalid Backup Key", "importBackupFailed": "Importing Wallet Failed", "inviteFailed": "Failure sending invite", "importContactsFailed": "Failed to import contacts", diff --git a/packages/mobile/locales/en-US/nuxRestoreWallet3.json b/packages/mobile/locales/en-US/nuxRestoreWallet3.json index 5d7b2eb0f34..b51d5294eec 100644 --- a/packages/mobile/locales/en-US/nuxRestoreWallet3.json +++ b/packages/mobile/locales/en-US/nuxRestoreWallet3.json @@ -1,22 +1,14 @@ { - "welcomeCelo": "Welcome to Celo", - "enterInvite": - "Enter your invitation code. If you do not have one, ask someone in the Celo Community to invite you. By joining this application, you agree to share your name & phone number with us. Learn more at celo.org", - "fullName": "Full Name", - "invitationCode": "Invitation Code", - "submit": "Submit", - "alreadyHaveWallet": "Already have a Celo Wallet? Restore it", - "restoreYourWallet": { - "title": "Restore your Celo Wallet", - "userYourBackupKey": - "Already have a Celo Wallet? Use your secure Backup Key to restore your wallet to this phone.", - "warning": "Warning ", - "restoreInPrivate": "Restore your Wallet in private " - }, - "backupKeyPrompt": "Backup Key", + "title": "Restore your Celo Wallet", + "userYourBackupKey": + "Already have a Celo Wallet? Enter your Backup Key to restore it to this phone.", + "backupKeyPrompt": + "horse leopard dog monkey shark tiger lemur whale squid wolf squirrel mouse lion elephant cat shrimp bear penguin deer turtle fox zebra goat giraffe", "tip": "Tip: ", - "backupKeyTip": "Backup Key words are separated by a space", - "continue": "Continue", - "cancel": "Cancel", - "restoreWallet": "Restore Celo Wallet" + "backupKeyTip": "Backup Keys are 24 words long, separated by a space.", + "restoreWallet": "Restore", + "emptyWalletWarning": "This wallet is empty.", + "useEmptyAnyway": "Would you like to use it anyway?", + "useEmptyWallet": "Use Empty Wallet", + "tryAnotherKey": "Try Another Backup Key" } diff --git a/packages/mobile/locales/es-419/global.json b/packages/mobile/locales/es-419/global.json index 2aab3fe4c2b..ac19d046e6b 100755 --- a/packages/mobile/locales/es-419/global.json +++ b/packages/mobile/locales/es-419/global.json @@ -62,7 +62,7 @@ "canNotRequestFromUnverified": "No se puede solicitar a usuarios no verificados.", "restartApp": "Reiniciar la aplicación", "loading": "Cargando…", - "invalidBackup": "Clave de respaldo inválida", + "invalidBackupPhrase": "Clave de respaldo inválida", "importBackupFailed": "No se pudo importar el monedero", "inviteFailed": "Falló el envío de la invitación", "importContactsFailed": "Error al importar contactos", diff --git a/packages/mobile/locales/es-419/nuxRestoreWallet3.json b/packages/mobile/locales/es-419/nuxRestoreWallet3.json index f9046d0fb25..66a7c38b9ba 100755 --- a/packages/mobile/locales/es-419/nuxRestoreWallet3.json +++ b/packages/mobile/locales/es-419/nuxRestoreWallet3.json @@ -1,22 +1,14 @@ { - "welcomeCelo": "Te damos la bienvenida a Celo", - "enterInvite": - "Ingresegcódigo de invitación. Si no tiene uno, pídale a alguien de la comunidad de Celo que lo invite.\n\nAl unirse a esta aplicación, acuerda compartir tu nombre y número telefónico con nosotros. Obtenga más información en celo.org", - "fullName": "Nombre completo", - "invitationCode": "Código de invitación", - "submit": "Enviar", - "alreadyHaveWallet": "¿Ya tiene un Monedero Celo? Restáurelo", - "restoreWallet": "Restaurar el Monedero Celo", - "restoreYourWallet": { - "title": "Restaurar tu Monedero Celo", - "userYourBackupKey": - "¿Ya tiene un Monedero Celo? Use tu clave de respaldo segura para restaurar tu monedero a este teléfono.", - "warning": "¡Cuidado! ", - "restoreInPrivate": "Hágalo en privado" - }, - "backupKeyPrompt": "Clave de respaldo", + "title": "Restaurar tu Monedero Celo", + "userYourBackupKey": + "¿Ya tiene un Monedero Celo? Ingrese su Clave de Respaldo para restaurarla a este teléfono.", + "backupKeyPrompt": + "caballo leopardo perro mono tiburón tigre lémur ballena calamar lobo ardilla ratón león elefante gato camarones oso pingüino...", "tip": "Consejo: ", - "backupKeyTip": "las palabras de la clave de respaldo están separadas por un espacio", - "continue": "Continuar", - "cancel": "Cancelar" + "backupKeyTip": "Las Claves de Respaldo son de 24 palabras, separadas por un espacio.", + "restoreWallet": "Restaurar", + "emptyWalletWarning": "Este Monedero esta vacio", + "useEmptyAnyway": "¿Te gustaría usarlo de todos modos?", + "useEmptyWallet": "Usar Monedero Vacío", + "tryAnotherKey": "Probar con otra Clave de Respaldo" } diff --git a/packages/mobile/package.json b/packages/mobile/package.json index 99b80cc07ed..e32ead8fb00 100644 --- a/packages/mobile/package.json +++ b/packages/mobile/package.json @@ -48,7 +48,7 @@ "dependencies": { "@celo/client": "640a41f", "@celo/react-native-sms-retriever": "git+https://github.com/celo-org/react-native-sms-retriever#d3a2fdb", - "@celo/utils": "^0.1.0", + "@celo/utils": "^0.1.1", "@celo/walletkit": "^0.0.14", "@react-native-community/netinfo": "^2.0.4", "@segment/analytics-react-native": "^1.1.0-beta.1", diff --git a/packages/mobile/src/account/Account.test.tsx b/packages/mobile/src/account/Account.test.tsx index df035339d5e..50b3485b967 100644 --- a/packages/mobile/src/account/Account.test.tsx +++ b/packages/mobile/src/account/Account.test.tsx @@ -12,10 +12,6 @@ import { createMockStore } from 'test/utils' jest.useFakeTimers() -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('Account', () => { it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/account/DollarEducation.test.tsx b/packages/mobile/src/account/DollarEducation.test.tsx index ee7e3cf8490..4f5f43096bf 100644 --- a/packages/mobile/src/account/DollarEducation.test.tsx +++ b/packages/mobile/src/account/DollarEducation.test.tsx @@ -5,10 +5,6 @@ import * as renderer from 'react-test-renderer' import DollarEducation from 'src/account/DollarEducation' import { createMockStore } from 'test/utils' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('DollarEducation', () => { it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/account/EditProfile.test.tsx b/packages/mobile/src/account/EditProfile.test.tsx index b14985812e6..abbb731c1ac 100644 --- a/packages/mobile/src/account/EditProfile.test.tsx +++ b/packages/mobile/src/account/EditProfile.test.tsx @@ -6,10 +6,6 @@ import { setName } from 'src/account/actions' import { EditProfile } from 'src/account/EditProfile' import { createMockStore, getMockI18nProps } from 'test/utils' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - it('renders the EditProfile Component', () => { const store = createMockStore() const tree = renderer.create( diff --git a/packages/mobile/src/account/Education.test.tsx b/packages/mobile/src/account/Education.test.tsx index 47ea1435d1e..8b5f8964fe4 100644 --- a/packages/mobile/src/account/Education.test.tsx +++ b/packages/mobile/src/account/Education.test.tsx @@ -26,10 +26,6 @@ const educationProps = { onFinish: jest.fn(), } -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('Education', () => { it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/account/GoldEducation.test.tsx b/packages/mobile/src/account/GoldEducation.test.tsx index aed6c94c281..59fd095b407 100644 --- a/packages/mobile/src/account/GoldEducation.test.tsx +++ b/packages/mobile/src/account/GoldEducation.test.tsx @@ -5,10 +5,6 @@ import * as renderer from 'react-test-renderer' import GoldEducation from 'src/account/GoldEducation' import { createMockStore } from 'test/utils' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('GoldEducation', () => { it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/account/Invite.test.tsx b/packages/mobile/src/account/Invite.test.tsx index ebda67b487c..2587fddf254 100644 --- a/packages/mobile/src/account/Invite.test.tsx +++ b/packages/mobile/src/account/Invite.test.tsx @@ -6,10 +6,6 @@ import Invite from 'src/account/Invite' import { createMockStore } from 'test/utils' import { mockE164NumberToInvitableRecipient, mockNavigation } from 'test/values' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('Invite', () => { it('renders correctly with recipients', () => { const tree = renderer.create( diff --git a/packages/mobile/src/account/InviteReview.test.tsx b/packages/mobile/src/account/InviteReview.test.tsx index 177aed917a1..9db23d9bac7 100644 --- a/packages/mobile/src/account/InviteReview.test.tsx +++ b/packages/mobile/src/account/InviteReview.test.tsx @@ -18,15 +18,6 @@ jest.mock('src/identity/verification', () => { return { isPhoneVerified: jest.fn(() => true) } }) -jest.mock('src/web3/contracts', () => ({ - web3: { - utils: { - fromWei: jest.fn((x: any) => x / 1e18), - }, - }, - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('InviteReview', () => { it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/account/PhotosEducation.test.tsx b/packages/mobile/src/account/PhotosEducation.test.tsx index 7986a2d9085..c64dbb88fa7 100644 --- a/packages/mobile/src/account/PhotosEducation.test.tsx +++ b/packages/mobile/src/account/PhotosEducation.test.tsx @@ -5,10 +5,6 @@ import * as renderer from 'react-test-renderer' import PhotosEducation from 'src/account/PhotosEducation' import { createMockStore } from 'test/utils' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('PhotosEducation', () => { it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/account/Profile.test.tsx b/packages/mobile/src/account/Profile.test.tsx index e8e20fcdc62..61083866354 100644 --- a/packages/mobile/src/account/Profile.test.tsx +++ b/packages/mobile/src/account/Profile.test.tsx @@ -9,10 +9,6 @@ import { Screens } from 'src/navigator/Screens' import { createMockStore } from 'test/utils' import { mockNavigation } from 'test/values' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - function profileFactory() { return ( diff --git a/packages/mobile/src/app/App.test.tsx b/packages/mobile/src/app/App.test.tsx index ed4a8200f8b..45d557a9ea2 100644 --- a/packages/mobile/src/app/App.test.tsx +++ b/packages/mobile/src/app/App.test.tsx @@ -25,10 +25,6 @@ jest.mock('src/redux/sagas', () => { } }) -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('App', () => { it('renders an ApolloProvider', () => { const wrapper = shallow() diff --git a/packages/mobile/src/app/Debug.test.tsx b/packages/mobile/src/app/Debug.test.tsx index 8b7fa7d08db..ef0d7d5fefa 100644 --- a/packages/mobile/src/app/Debug.test.tsx +++ b/packages/mobile/src/app/Debug.test.tsx @@ -5,10 +5,6 @@ import * as renderer from 'react-test-renderer' import Debug from 'src/app/Debug' import { createMockStore } from 'test/utils' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('Debug', () => { it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/app/ErrorMessages.ts b/packages/mobile/src/app/ErrorMessages.ts index e74d1716448..6eebd9c425a 100644 --- a/packages/mobile/src/app/ErrorMessages.ts +++ b/packages/mobile/src/app/ErrorMessages.ts @@ -8,7 +8,8 @@ export enum ErrorMessages { NSF_DOLLARS = 'notEnoughDollarsError', NSF_TO_SEND = 'needMoreFundsToSend', INVALID_AMOUNT = 'invalidAmount', - INVALID_BACKUP = 'invalidBackup', + INVALID_BACKUP_PHRASE = 'invalidBackupPhrase', + EMPTY_BACKUP_PHRASE = 'emptyBackupPhrase', IMPORT_BACKUP_FAILED = 'importBackupFailed', INVALID_PHONE_NUMBER = 'nuxVerification2:invalidPhone', NOT_READY_FOR_CODE = 'nuxVerification2:notReadyForCode', diff --git a/packages/mobile/src/app/saga.test.ts b/packages/mobile/src/app/saga.test.ts index ab8940b2e3d..c71e8900c91 100644 --- a/packages/mobile/src/app/saga.test.ts +++ b/packages/mobile/src/app/saga.test.ts @@ -19,15 +19,6 @@ jest.mock('src/firebase/firebase', () => ({ getVersionInfo: jest.fn(async () => ({ deprecated: false })), })) -jest.mock('src/web3/contracts', () => ({ - web3: { - utils: { - fromWei: jest.fn((x: any) => x / 1e18), - }, - }, - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - const { navigate } = require('src/navigator/NavigationService') const { getVersionInfo } = require('src/firebase/firebase') diff --git a/packages/mobile/src/components/AccountOverview.test.tsx b/packages/mobile/src/components/AccountOverview.test.tsx index 40540837a40..91664707049 100644 --- a/packages/mobile/src/components/AccountOverview.test.tsx +++ b/packages/mobile/src/components/AccountOverview.test.tsx @@ -8,10 +8,6 @@ import { getMockI18nProps } from 'test/utils' const SAMPLE_BALANCE = '55.00001' const exchangeRatePair: ExchangeRatePair = { goldMaker: '0.11', dollarMaker: '10' } -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - it('renders correctly when ready', () => { const tree = renderer.create( ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - it('renders correctly', () => { const tree = renderer.create( ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('ReclaimPaymentConfirmationCard', () => { it('renders correctly for send payment confirmation', () => { const tree = renderer.create( diff --git a/packages/mobile/src/escrow/ReclaimPaymentConfirmationScreen.test.tsx b/packages/mobile/src/escrow/ReclaimPaymentConfirmationScreen.test.tsx index 076835df0a9..b48b1ae029f 100644 --- a/packages/mobile/src/escrow/ReclaimPaymentConfirmationScreen.test.tsx +++ b/packages/mobile/src/escrow/ReclaimPaymentConfirmationScreen.test.tsx @@ -12,15 +12,6 @@ const TEST_FEE = new BigNumber(10000000000000000) jest.mock('src/escrow/saga') -jest.mock('src/web3/contracts', () => ({ - web3: { - utils: { - fromWei: jest.fn((x: any) => x / 1e18), - }, - }, - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - const mockedGetReclaimEscrowFee = getReclaimEscrowFee as jest.Mock const store = createMockStore() diff --git a/packages/mobile/src/exchange/ExchangeTradeScreen.test.tsx b/packages/mobile/src/exchange/ExchangeTradeScreen.test.tsx index 946bb0777ba..3d6945a0d0f 100644 --- a/packages/mobile/src/exchange/ExchangeTradeScreen.test.tsx +++ b/packages/mobile/src/exchange/ExchangeTradeScreen.test.tsx @@ -18,10 +18,6 @@ jest.mock('src/shared/DisconnectBanner', () => ({ DisconnectBanner: () => null, })) -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - const store = createMockStore({ exchange: { exchangeRatePair, diff --git a/packages/mobile/src/fees/saga.test.ts b/packages/mobile/src/fees/saga.test.ts index 04029f0a0da..0d2b3d9dc7d 100644 --- a/packages/mobile/src/fees/saga.test.ts +++ b/packages/mobile/src/fees/saga.test.ts @@ -18,16 +18,6 @@ jest.mock('@celo/walletkit', () => ({ }, })) -jest.mock('src/web3/contracts', () => ({ - web3: { - utils: { - fromWei: jest.fn((x: any) => x / 1e18), - toWei: jest.fn((x: any) => x * 1e18), - }, - }, - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe(estimateFeeSaga, () => { beforeAll(() => { jest.useRealTimers() diff --git a/packages/mobile/src/home/CeloDollarsOverview.test.tsx b/packages/mobile/src/home/CeloDollarsOverview.test.tsx index 0e8be90d443..fee9ed981e0 100644 --- a/packages/mobile/src/home/CeloDollarsOverview.test.tsx +++ b/packages/mobile/src/home/CeloDollarsOverview.test.tsx @@ -4,10 +4,6 @@ import * as renderer from 'react-test-renderer' import CeloDollarsOverview from 'src/home/CeloDollarsOverview' import { createMockStore } from 'test/utils' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('CeloDollarsOverview', () => { it('renders correctly', () => { const tree = renderer.create( diff --git a/packages/mobile/src/home/NotificationBox.test.tsx b/packages/mobile/src/home/NotificationBox.test.tsx index 55e31e18cdc..7ed27c174cf 100644 --- a/packages/mobile/src/home/NotificationBox.test.tsx +++ b/packages/mobile/src/home/NotificationBox.test.tsx @@ -19,15 +19,6 @@ const storeData = { }, } -jest.mock('src/web3/contracts', () => ({ - web3: { - utils: { - fromWei: jest.fn((x: any) => x / 1e18), - }, - }, - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('NotificationBox', () => { it('Simple test', () => { // const store = createMockStore(storeData) diff --git a/packages/mobile/src/home/WalletHome.test.tsx b/packages/mobile/src/home/WalletHome.test.tsx index b580739b170..c812edc72f8 100644 --- a/packages/mobile/src/home/WalletHome.test.tsx +++ b/packages/mobile/src/home/WalletHome.test.tsx @@ -20,15 +20,6 @@ const storeData = { jest.mock('src/components/AccountOverview') jest.mock('src/home/TransactionsList') -jest.mock('src/web3/contracts', () => ({ - web3: { - utils: { - fromWei: jest.fn((x: any) => x / 1e18), - }, - }, - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('Testnet banner', () => { it('Shows testnet banner for 5 seconds', async () => { const store = createMockStore({ diff --git a/packages/mobile/src/home/saga.test.ts b/packages/mobile/src/home/saga.test.ts index e15a4d831ff..e289bf3fbb7 100644 --- a/packages/mobile/src/home/saga.test.ts +++ b/packages/mobile/src/home/saga.test.ts @@ -2,12 +2,7 @@ import { expectSaga } from 'redux-saga-test-plan' import { call, put, select } from 'redux-saga/effects' import { fetchGoldBalance } from 'src/goldToken/actions' import { refreshAllBalances, setLoading } from 'src/home/actions' -import { - _autoRefreshSaga, - _watchRefreshBalances, - refreshBalances, - withLoading, -} from 'src/home/saga' +import { autoRefreshSaga, refreshBalances, watchRefreshBalances, withLoading } from 'src/home/saga' import { fetchCurrentRate } from 'src/localCurrency/actions' import { shouldFetchCurrentRate } from 'src/localCurrency/selectors' import { shouldUpdateBalance } from 'src/redux/selectors' @@ -16,10 +11,6 @@ import { getConnectedAccount } from 'src/web3/saga' jest.useRealTimers() -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('refreshBalances', () => { test('ask for balance when geth and account are ready', () => expectSaga(refreshBalances) @@ -31,7 +22,7 @@ describe('refreshBalances', () => { describe('watchRefreshBalances', () => { test('reacts on REFRESH_BALANCES', async () => { - await expectSaga(_watchRefreshBalances) + await expectSaga(watchRefreshBalances) .put(setLoading(true)) .put(setLoading(false)) .provide([[call(getConnectedAccount), true]]) @@ -81,7 +72,7 @@ describe('autoRefreshSaga', () => { return next() } - await expectSaga(_autoRefreshSaga) + await expectSaga(autoRefreshSaga) .provide([ [select(shouldUpdateBalance), true], [select(shouldFetchCurrentRate), true], diff --git a/packages/mobile/src/home/saga.ts b/packages/mobile/src/home/saga.ts index 4aa7c89c2dd..53c87ebd69b 100644 --- a/packages/mobile/src/home/saga.ts +++ b/packages/mobile/src/home/saga.ts @@ -50,7 +50,7 @@ export function* refreshBalancesWithLoadingSaga() { ) } -function* autoRefreshSaga() { +export function* autoRefreshSaga() { while (true) { if (yield select(shouldUpdateBalance)) { yield put(refreshAllBalances()) @@ -62,7 +62,7 @@ function* autoRefreshSaga() { } } -function* autoRefreshWatcher() { +export function* autoRefreshWatcher() { while (yield take(Actions.START_BALANCE_AUTOREFRESH)) { // starts the task in the background const autoRefresh = yield fork(autoRefreshSaga) @@ -71,7 +71,7 @@ function* autoRefreshWatcher() { } } -function* watchRefreshBalances() { +export function* watchRefreshBalances() { yield takeLeading( Actions.REFRESH_BALANCES, withLoading(withTimeout(REFRESH_TIMEOUT, refreshBalances)) @@ -86,6 +86,3 @@ export function* homeSaga() { // keep us stuck on sync screen // yield spawn(refreshBalancesWithLoadingSaga) } - -export const _watchRefreshBalances = watchRefreshBalances -export const _autoRefreshSaga = autoRefreshSaga diff --git a/packages/mobile/src/identity/commentKey.test.ts b/packages/mobile/src/identity/commentKey.test.ts index 210f73d279f..95f6efd0a90 100644 --- a/packages/mobile/src/identity/commentKey.test.ts +++ b/packages/mobile/src/identity/commentKey.test.ts @@ -11,10 +11,6 @@ jest.mock('@celo/walletkit', () => ({ sendTransaction: jest.fn(async () => null), })) -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('Encrypt Comment', () => { it('Empty comment', async () => { expect(await encryptComment('', 'toAddr', 'fromAddr')).toBe('') diff --git a/packages/mobile/src/identity/contactMapping.test.ts b/packages/mobile/src/identity/contactMapping.test.ts index b1376a93475..ad0e7eaa284 100644 --- a/packages/mobile/src/identity/contactMapping.test.ts +++ b/packages/mobile/src/identity/contactMapping.test.ts @@ -33,10 +33,6 @@ const e164NumberRecipients = recipients!.e164NumberToRecipients const otherRecipients = recipients!.otherRecipients const allRecipients = { ...e164NumberRecipients, ...otherRecipients } -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('Import Contacts Saga', () => { it('imports contacts and creates contact mappings correctly', async () => { const attestationsContract = createMockContract(attestationsStub) diff --git a/packages/mobile/src/identity/verification.test.ts b/packages/mobile/src/identity/verification.test.ts index 3ca2985921c..2401738fdad 100644 --- a/packages/mobile/src/identity/verification.test.ts +++ b/packages/mobile/src/identity/verification.test.ts @@ -50,10 +50,6 @@ jest.mock('@celo/utils', () => ({ SignatureUtils: { parseSignature: jest.fn(() => ({ r: 'r', s: 's', v: 'v' })) }, })) -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - const attestationCode0: AttestationCode = { code: 'ab8049b95ac02e989aae8b61fddc10fe9b3ac3c6aebcd3e68be495570b2d3da15aabc691ab88de69648f988fab653ac943f67404e532cfd1013627f56365f36501', diff --git a/packages/mobile/src/import/ImportContacts.test.tsx b/packages/mobile/src/import/ImportContacts.test.tsx index 61efcbf5093..fa586bc1f5c 100644 --- a/packages/mobile/src/import/ImportContacts.test.tsx +++ b/packages/mobile/src/import/ImportContacts.test.tsx @@ -4,10 +4,6 @@ import * as renderer from 'react-test-renderer' import ImportContacts from 'src/import/ImportContacts' import { createMockStore, getMockI18nProps } from 'test/utils' -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - describe('ImportContacts Screen', () => { it('renders correctly', () => { const store = createMockStore() diff --git a/packages/mobile/src/import/ImportWallet.test.tsx b/packages/mobile/src/import/ImportWallet.test.tsx index 9c54bbc201b..b9ecdab1f19 100644 --- a/packages/mobile/src/import/ImportWallet.test.tsx +++ b/packages/mobile/src/import/ImportWallet.test.tsx @@ -5,7 +5,6 @@ import { mnemonicToSeedHex, validateMnemonic } from 'react-native-bip39' import { fireEvent, render } from 'react-native-testing-library' import { Provider } from 'react-redux' import * as renderer from 'react-test-renderer' -import { ErrorMessages } from 'src/app/ErrorMessages' import ImportWallet, { formatBackupPhraseOnEdit, formatBackupPhraseOnSubmit, @@ -17,10 +16,6 @@ jest.mock('src/geth/GethAwareButton', () => { return Button }) -jest.mock('src/web3/contracts', () => ({ - isZeroSyncMode: jest.fn().mockReturnValueOnce(false), -})) - const SPANISH_MNEMONIC = 'avance colmo poema momia cofre pata res verso secta cinco tubería yacer eterno observar ojo tabaco seta ruina bebé oral miembro gato suelo violín'.normalize( 'NFD' ) @@ -54,17 +49,19 @@ describe('ImportWallet', () => { const store = createMockStore() const tree = renderer.create( - + ) expect(tree).toMatchSnapshot() }) - it('renders with an error', () => { - const store = createMockStore({ alert: { underlyingError: ErrorMessages.INVALID_BACKUP } }) + it('renders with an empty wallet', () => { + const store = createMockStore({ + imports: { isWalletEmpty: true }, + }) const tree = renderer.create( - + ) expect(tree).toMatchSnapshot() @@ -80,29 +77,6 @@ describe('ImportWallet', () => { expect(wrapper.queryAllByProps({ disabled: true }).length).toBeGreaterThan(0) }) - it('shows an error with an invalid backup phrase', () => { - const error = jest.fn() - - const wrapper = render( - - - - ) - - fireEvent.changeText( - wrapper.getByTestId('ImportWalletBackupKeyInputField'), - BAD_ENGLISH_MNEMONIC - ) - fireEvent.press(wrapper.getByTestId('ImportWalletButton')) - expect(error).toHaveBeenCalledWith(ErrorMessages.INVALID_BACKUP) - }) - it('calls assign account with the proper private key', () => { const importFn = jest.fn() @@ -110,9 +84,10 @@ describe('ImportWallet', () => { @@ -123,7 +98,7 @@ describe('ImportWallet', () => { MULTILINE_ENGLISH_MNEMONIC_EXTRA_SPACES ) fireEvent.press(wrapper.getByTestId('ImportWalletButton')) - expect(importFn).toHaveBeenCalledWith(ENGLISH_MNEMONIC) + expect(importFn).toHaveBeenCalledWith(ENGLISH_MNEMONIC, false) }) }) diff --git a/packages/mobile/src/import/ImportWallet.tsx b/packages/mobile/src/import/ImportWallet.tsx index 33e37a35a57..d3765e6c9ea 100644 --- a/packages/mobile/src/import/ImportWallet.tsx +++ b/packages/mobile/src/import/ImportWallet.tsx @@ -1,27 +1,22 @@ -import { BtnTypes } from '@celo/react-components/components/Button' +import Button, { BtnTypes } from '@celo/react-components/components/Button' import colors from '@celo/react-components/styles/colors' import { fontStyles } from '@celo/react-components/styles/fonts' import { componentStyles } from '@celo/react-components/styles/styles' import * as React from 'react' import { WithNamespaces, withNamespaces } from 'react-i18next' import { ActivityIndicator, Keyboard, StyleSheet, Text, TextInput, View } from 'react-native' -import { validateMnemonic } from 'react-native-bip39' import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view' import { connect } from 'react-redux' -import { hideAlert, showError } from 'src/alert/actions' -import { errorSelector } from 'src/alert/reducer' +import { hideAlert } from 'src/alert/actions' import CeloAnalytics from 'src/analytics/CeloAnalytics' import { CustomEventNames } from 'src/analytics/constants' -import { ErrorMessages } from 'src/app/ErrorMessages' import GethAwareButton from 'src/geth/GethAwareButton' import { Namespaces } from 'src/i18n' import NuxLogo from 'src/icons/NuxLogo' -import { importBackupPhrase } from 'src/import/actions' +import { importBackupPhrase, tryAnotherBackupPhrase } from 'src/import/actions' import { nuxNavigationOptions } from 'src/navigator/Headers' import { RootState } from 'src/redux/reducers' -import Logger from 'src/utils/Logger' - -const TAG = 'ImportWallet' +import { getMoneyDisplayValue } from 'src/utils/formatting' // Because of a RN bug, we can't fully clean the text as the user types // https://github.com/facebook/react-native/issues/11068 @@ -36,49 +31,33 @@ export const formatBackupPhraseOnSubmit = (phrase: string) => interface State { backupPhrase: string - isSubmitting: boolean } interface DispatchProps { importBackupPhrase: typeof importBackupPhrase - showError: typeof showError + tryAnotherBackupPhrase: typeof tryAnotherBackupPhrase hideAlert: typeof hideAlert } interface StateProps { - error: ErrorMessages | null + isImportingWallet: boolean + isWalletEmpty: boolean } type Props = StateProps & DispatchProps & WithNamespaces const mapStateToProps = (state: RootState): StateProps => { return { - error: errorSelector(state), + isImportingWallet: state.imports.isImportingWallet, + isWalletEmpty: state.imports.isWalletEmpty, } } -const displayedErrors = [ErrorMessages.INVALID_BACKUP, ErrorMessages.IMPORT_BACKUP_FAILED] - -const hasDisplayedError = (error: ErrorMessages | null) => { - return error && displayedErrors.includes(error) -} - export class ImportWallet extends React.Component { static navigationOptions = nuxNavigationOptions - static getDerivedStateFromProps(props: Props, state: State): State | null { - if (hasDisplayedError(props.error) && state.isSubmitting) { - return { - ...state, - isSubmitting: false, - } - } - return null - } - state = { backupPhrase: '', - isSubmitting: false, } setBackupPhrase = (input: string) => { @@ -92,102 +71,112 @@ export class ImportWallet extends React.Component { CeloAnalytics.track(CustomEventNames.import_phrase_input) } - onSubmit = () => { - try { - this.setState({ - isSubmitting: true, - }) - - Keyboard.dismiss() - this.props.hideAlert() - CeloAnalytics.track(CustomEventNames.import_wallet_submit) - - const formattedPhrase = formatBackupPhraseOnSubmit(this.state.backupPhrase) - this.setState({ - backupPhrase: formattedPhrase, - }) - - if (!validateMnemonic(formattedPhrase)) { - Logger.warn(TAG, 'Invalid mnemonic') - this.props.showError(ErrorMessages.INVALID_BACKUP) - this.setState({ - isSubmitting: false, - }) - return - } - - this.props.importBackupPhrase(formattedPhrase) - } catch (error) { - this.setState({ - isSubmitting: false, - }) - Logger.error(TAG, 'Error importing wallet', error) - this.props.showError(ErrorMessages.IMPORT_BACKUP_FAILED) - } + onPressRestore = () => { + Keyboard.dismiss() + this.props.hideAlert() + CeloAnalytics.track(CustomEventNames.import_wallet_submit) + + const formattedPhrase = formatBackupPhraseOnSubmit(this.state.backupPhrase) + this.setState({ + backupPhrase: formattedPhrase, + }) + + this.props.importBackupPhrase(formattedPhrase, false) + } + + onPressUseEmpty = () => { + this.props.importBackupPhrase(this.state.backupPhrase, true) + } + + onPressTryAnotherKey = () => { + this.props.tryAnotherBackupPhrase() } isBackupPhraseValid() { - return this.state.backupPhrase.trim().split(/\s+/g).length >= 12 + return ( + formatBackupPhraseOnEdit(this.state.backupPhrase) + .trim() + .split(/\s+/g).length >= 12 + ) } render() { - const { backupPhrase, isSubmitting } = this.state - const { t, error } = this.props + const { backupPhrase } = this.state + const { t, isImportingWallet, isWalletEmpty } = this.props return ( - - - {t('restoreYourWallet.title')} - - {t('restoreYourWallet.userYourBackupKey')} - - {t('backupKeyTip')} - - - {t('restoreYourWallet.warning')} - - {t('restoreYourWallet.restoreInPrivate')} - - - + + + {t('title')} + {t('userYourBackupKey')} + + + + + {t('tip')} + {t('backupKeyTip')} + + + + {isImportingWallet && ( + + + + )} + + - - - {isSubmitting && ( - - - + + )} + {isWalletEmpty && ( // TODO use backup icon instead of Nuxlogo when we have one + <> + + + {getMoneyDisplayValue(0)} + {t('emptyWalletWarning')} + {t('useEmptyAnyway')} + + +