Skip to content

Commit

Permalink
Merge pull request #867 from CityOfZion/dev
Browse files Browse the repository at this point in the history
[Release] neon-wallet v0.2.2
  • Loading branch information
mhuggins authored Mar 14, 2018
2 parents e616894 + e1eaf8e commit 2e04f76
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 15 deletions.
5 changes: 4 additions & 1 deletion __mocks__/neon-js.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ neonjs.wallet = {
Account: jest.fn(() => { return { address } }),
getVerificationScriptFromPublicKey: jest.fn(() => scriptHash),
isAddress: jest.fn(() => true),
isNEP2: jest.fn(() => true)
isNEP2: jest.fn(() => true),
isWIF: jest.fn(() => false),
isPrivateKey: jest.fn(() => false),
isPublicKey: jest.fn(() => false)
}

module.exports = neonjs
132 changes: 132 additions & 0 deletions __tests__/actions/authActions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { wallet } from 'neon-js'

import { wifLoginActions } from '../../app/actions/authActions'

describe('authActions', () => {
describe('wifLoginActions', () => {
describe('request', () => {
const wif = 'KxB52D1FGe5xBn6YeezNwj7grhkHZxq7bv2tmaCPoT4rxApMwMvU'
const address = 'ASJQLBnhAs6fSgBv2R7KtRZjC8A9fAmcNW'
const privateKey = '1c7a992d0e68b7b23cb430ba596bd68cecde042410d81e9e95ee19dc1bcd739d'

test('returns an action object', () => {
expect(wifLoginActions.request({ wif })).toEqual({
batch: false,
type: 'AUTH/REQ/REQUEST',
meta: {
id: 'AUTH',
type: 'REQ/REQUEST'
},
payload: {
fn: expect.any(Function)
}
})
})

describe('with valid WIF', () => {
let wifMock, keyMock, accountMock

beforeEach(() => {
wifMock = jest.spyOn(wallet, 'isWIF').mockImplementation((str) => false)
keyMock = jest.spyOn(wallet, 'isPrivateKey').mockImplementation((str) => true)
accountMock = jest.spyOn(wallet, 'Account').mockImplementation((str) => ({ WIF: wif, address }))
})

afterEach(() => {
wifMock.mockRestore()
keyMock.mockRestore()
accountMock.mockRestore()
})

test('returns authenticated account data', () => {
const request = wifLoginActions.request({ wif })
expect(request.payload.fn({})).toEqual({ wif, address, isHardwareLogin: false })
})
})

describe('with valid private key', () => {
let wifMock, keyMock, accountMock

beforeEach(() => {
wifMock = jest.spyOn(wallet, 'isWIF').mockImplementation((str) => false)
keyMock = jest.spyOn(wallet, 'isPrivateKey').mockImplementation((str) => true)
accountMock = jest.spyOn(wallet, 'Account').mockImplementation((str) => ({ WIF: wif, address }))
})

afterEach(() => {
wifMock.mockRestore()
keyMock.mockRestore()
accountMock.mockRestore()
})

test('returns authenticated account data', () => {
const request = wifLoginActions.request({ wif: privateKey })
expect(request.payload.fn({})).toEqual({ wif, address, isHardwareLogin: false })
})
})

describe('with invalid private key', () => {
let wifMock, keyMock

beforeEach(() => {
wifMock = jest.spyOn(wallet, 'isWIF').mockImplementation((str) => false)
keyMock = jest.spyOn(wallet, 'isPrivateKey').mockImplementation((str) => false)
})

afterEach(() => {
wifMock.mockRestore()
keyMock.mockRestore()
})

test('throws an error', () => {
const request = wifLoginActions.request({ wif })
expect(() => request.payload.fn({})).toThrowError('That is not a valid private key')
})
})
})

describe('retry', () => {
const wif = 'KxB52D1FGe5xBn6YeezNwj7grhkHZxq7bv2tmaCPoT4rxApMwMvU'

test('returns an action object', () => {
expect(wifLoginActions.retry({ wif })).toEqual({
batch: false,
type: 'AUTH/REQ/RETRY',
meta: {
id: 'AUTH',
type: 'REQ/RETRY'
},
payload: {
fn: expect.any(Function)
}
})
})
})

describe('cancel', () => {
test('returns an action object', () => {
expect(wifLoginActions.cancel()).toEqual({
batch: false,
type: 'AUTH/REQ/CANCEL',
meta: {
id: 'AUTH',
type: 'REQ/CANCEL'
}
})
})
})

describe('reset', () => {
test('returns an action object', () => {
expect(wifLoginActions.reset()).toEqual({
batch: false,
type: 'AUTH/REQ/RESET',
meta: {
id: 'AUTH',
type: 'REQ/RESET'
}
})
})
})
})
})
14 changes: 13 additions & 1 deletion __tests__/components/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,19 @@ const initialState = {
api: {
APP: {
batch: true,
mapping: ['NETWORK', 'PRICES', 'SETTINGS']
mapping: ['ACCOUNTS', 'BLOCK_HEIGHT', 'SETTINGS']
},
ACCOUNTS: {
batch: false,
state: LOADED,
data: [],
loadedCount: 1
},
BLOCK_HEIGHT: {
batch: false,
state: LOADED,
data: 2000000,
loadedCount: 1
},
NETWORK: {
batch: false,
Expand Down
4 changes: 3 additions & 1 deletion __tests__/sagas/requestSaga.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ describe('requestSaga', () => {

it('performs the action', () => {
const request = call(requestState.fn, storeState, actionState.payload, sagaActions)
const response = request.CALL.fn(...request.CALL.args).next().value
const fn = request.CALL.fn(...request.CALL.args)
fn.next() // account for delay
const response = fn.next().value
const result = response.CALL.fn(...response.CALL.args)
expect(result).toEqual('my foo baz')
})
Expand Down
2 changes: 0 additions & 2 deletions app/actions/appActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
import createBatchActions from '../util/api/createBatchActions'
import accountsActions from './accountsActions'
import blockHeightActions from './blockHeightActions'
import pricesActions from './pricesActions'
import settingsActions from './settingsActions'

export const ID = 'APP'

export default createBatchActions(ID, {
accounts: accountsActions,
blockHeight: blockHeightActions,
prices: pricesActions,
settings: settingsActions
})
8 changes: 6 additions & 2 deletions app/actions/authActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,13 @@ type AccountType = ?{
export const ID = 'AUTH'

export const wifLoginActions = createRequestActions(ID, ({ wif }: WifLoginProps) => (state: Object): AccountType => {
if (!wallet.isWIF(wif) && !wallet.isPrivateKey(wif)) {
throw new Error('That is not a valid private key')
}

const account = new wallet.Account(wif)

return { wif, address: account.address, isHardwareLogin: false }
return { wif: account.WIF, address: account.address, isHardwareLogin: false }
})

export const nep2LoginActions = createRequestActions(ID, ({ passphrase, encryptedWIF }: Nep2LoginProps) => async (state: Object): Promise<AccountType> => {
Expand All @@ -51,7 +55,7 @@ export const nep2LoginActions = createRequestActions(ID, ({ passphrase, encrypte

await upgradeNEP6AddAddresses(encryptedWIF, wif)

return { wif, address: account.address, isHardwareLogin: false }
return { wif: account.WIF, address: account.address, isHardwareLogin: false }
})

export const ledgerLoginActions = createRequestActions(ID, ({ publicKey }: LedgerLoginProps) => (state: Object): AccountType => {
Expand Down
13 changes: 13 additions & 0 deletions app/containers/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import appActions from '../../actions/appActions'
import authActions from '../../actions/authActions'
import accountActions from '../../actions/accountActions'
import networkActions from '../../actions/networkActions'
import pricesActions from '../../actions/pricesActions'
import withFetch from '../../hocs/api/withFetch'
import withReload from '../../hocs/api/withReload'
import withProgressComponents from '../../hocs/api/withProgressComponents'
import withLoginRedirect from '../../hocs/auth/withLoginRedirect'
import withLogoutRedirect from '../../hocs/auth/withLogoutRedirect'
import withLogoutReset from '../../hocs/auth/withLogoutReset'
import withCurrencyData from '../../hocs/withCurrencyData'
import withNetworkData from '../../hocs/withNetworkData'
import alreadyLoaded from '../../hocs/api/progressStrategies/alreadyLoadedStrategy'
import { checkVersion } from '../../modules/metadata'
Expand Down Expand Up @@ -55,6 +57,17 @@ export default compose(
strategy: alreadyLoaded
}),

// Fetch prices data based based upon the selected currency. Reload data with the currency changes.
withCurrencyData(),
withFetch(pricesActions),
withReload(pricesActions, ['currency']),
withProgressComponents(pricesActions, {
[LOADING]: Loading,
[FAILED]: Failed
}, {
strategy: alreadyLoaded
}),

// Navigate to the home or dashboard when the user logs in or out.
withLoginRedirect,
withLogoutRedirect,
Expand Down
3 changes: 2 additions & 1 deletion app/core/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ export const TOKENS = {
NRVE: 'a721d5893480260bd28ca1f395f2c465d0b5b1c2',
IAM: '891daf0e1750a1031ebe23030828ad7781d874d6',
ONT: 'ceab719b8baa2310f232ee0d277c061704541cfb',
THOR: '67a5086bac196b67d5fd20745b0dc9db4d2930ed'
THOR: '67a5086bac196b67d5fd20745b0dc9db4d2930ed',
CGE: '34579e4614ac1a7bd295372d3de8621770c76cdc'
}

export const ENDED_ICO_TOKENS = ['DBC', 'RPX', 'QLC', 'RHT']
Expand Down
2 changes: 1 addition & 1 deletion app/hocs/withFailureNotification.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function withFailureNotification (actions: Actions, message: Mess

class ErrorNotifier extends React.Component<Props> {
componentWillReceiveProps (nextProps) {
if (hasError(nextProps) && (!hasError(this.props) || progressChangedToError(this.props, nextProps))) {
if (hasError(nextProps) && progressChangedToError(this.props, nextProps)) {
const showErrorNotification = nextProps[NOTIFICATION_PROP]
showErrorNotification({ message: nextProps[ERROR_PROP] })
}
Expand Down
3 changes: 2 additions & 1 deletion app/sagas/requestSaga.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import { call, put, race, take } from 'redux-saga/effects'
import { type Saga } from 'redux-saga'
import { delay, type Saga } from 'redux-saga'

import { actionMatcher } from '../util/api/matchers'
import {
Expand All @@ -24,6 +24,7 @@ type SagaActions = {
export function createSagaActions (meta: ActionMeta): SagaActions {
function * request (state: Object, payload: Payload, actions: SagaActions) {
try {
yield delay(0) // allow request state to propagate
const result = yield call(payload.fn, state)
yield put(actions.success(result))
} catch (err) {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Neon",
"version": "0.2.1",
"version": "0.2.2",
"main": "./main.js",
"description": "Light wallet for NEO blockchain",
"homepage": "https://github.com/CityOfZion/neon-wallet",
Expand Down Expand Up @@ -80,7 +80,7 @@
"history": "4.7.2",
"isomorphic-fetch": "2.2.1",
"lodash": "4.17.4",
"neon-js": "git+https://github.com/cityofzion/neon-js.git#3.3.1",
"neon-js": "git+https://github.com/cityofzion/neon-js.git#3.3.3",
"qrcode": "0.9.0",
"raf": "3.4.0",
"react": "16.1.1",
Expand Down
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6555,9 +6555,9 @@ neo-async@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.0.tgz#76b1c823130cca26acfbaccc8fbaf0a2fa33b18f"

"neon-js@git+https://github.com/cityofzion/neon-js.git#3.3.1":
version "3.3.1"
resolved "git+https://github.com/cityofzion/neon-js.git#292f07b39a056b12497192e8af350338a8936e8c"
"neon-js@git+https://github.com/cityofzion/neon-js.git#3.3.3":
version "3.3.3"
resolved "git+https://github.com/cityofzion/neon-js.git#f962c255ef0790e4d64af3c825f3c2f44a9627f6"
dependencies:
axios "^0.17.1"
bignumber.js "^5.0.0"
Expand Down

0 comments on commit 2e04f76

Please sign in to comment.