Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wallet] upgrade react-redux #812

Merged
merged 4 commits into from
Sep 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions packages/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@
"fuzzysort": "^1.1.4",
"google-libphonenumber": "^3.2.1",
"graphql": "^14.1.1",
"hoist-non-react-statics": "^3.1.0",
"i18next": "^11.9.1",
"instabug-reactnative": "^8.4.3",
"js-sha3": "^0.7.0",
Expand Down Expand Up @@ -122,8 +121,8 @@
"react-native-version-check": "^3.0.2",
"react-native-webview": "^5.12.1",
"react-navigation": "^3.9.0",
"react-redux": "^5.1.1",
"redux": "^4.0.0",
"react-redux": "^7.1.1",
"redux": "^4.0.4",
"redux-persist": "^5.9.1",
"redux-saga": "^1.0.1",
"redux-thunk": "^2.2.0",
Expand All @@ -144,14 +143,13 @@
"@types/enzyme-adapter-react-16": "1.0.4",
"@types/ethereumjs-util": "^5.2.0",
"@types/graphql": "^14.0.7",
"@types/hoist-non-react-statics": "^3.0.1",
"@types/isomorphic-fetch": "^0.0.35",
"@types/lodash": "^4.14.136",
"@types/react": "^16.8.19",
"@types/react-native": "^0.57.47",
"@types/react-native-fs": "^2.8.1",
"@types/react-native-keep-awake": "^2.0.1",
"@types/react-redux": "^5.0.21",
"@types/react-redux": "^7.1.2",
"@types/react-test-renderer": "^16.0.1",
"@types/redux-mock-store": "^1.0.0",
"@types/utf8": "^2.1.6",
Expand Down
16 changes: 6 additions & 10 deletions packages/mobile/src/account/Profile.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
const { mockNavigationServiceFor } = require('test/utils')
const { navigate } = mockNavigationServiceFor('Profile')
import { shallow } from 'enzyme'
import * as React from 'react'
import 'react-native'
import { fireEvent, render } from 'react-native-testing-library'
import { Provider } from 'react-redux'
import * as renderer from 'react-test-renderer'
import Profile from 'src/account/Profile'
import SettingsItem from 'src/account/SettingsItem'
import { Screens } from 'src/navigator/Screens'
import { createMockStore } from 'test/utils'
import { mockNavigation } from 'test/values'
Expand All @@ -21,17 +19,15 @@ function profileFactory() {

describe('Profile', () => {
it('renders correctly', () => {
const tree = renderer.create(profileFactory())
expect(tree).toMatchSnapshot()
const { toJSON } = render(profileFactory())
expect(toJSON()).toMatchSnapshot()
})

describe('when SettingsItem pressed', () => {
it('goes to Edit Profile Screen', () => {
const profile = shallow(profileFactory())
.dive()
.dive()
.dive()
profile.find(SettingsItem).simulate('press')
const { getByTestId } = render(profileFactory())

fireEvent.press(getByTestId('ProfileEditName'))
expect(navigate).toBeCalledWith(Screens.EditProfile)
})
})
Expand Down
6 changes: 5 additions & 1 deletion packages/mobile/src/account/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ export class Profile extends React.Component<Props> {
</View>
</View>
<View style={[style.container, style.underlinedBox]}>
<SettingsItem title={t('editName')} onPress={this.goToEditProfile} />
<SettingsItem
testID="ProfileEditName"
title={t('editName')}
onPress={this.goToEditProfile}
/>
</View>
</ScrollView>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ exports[`Profile renders correctly 1`] = `
"opacity": 1,
}
}
testID="ProfileEditName"
>
<View
style={
Expand Down
45 changes: 12 additions & 33 deletions packages/mobile/src/fees/CalculateFee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getStableTokenContract } from '@celo/walletkit'
import BigNumber from 'bignumber.js'
import React, { FunctionComponent, useEffect } from 'react'
import { useAsync, UseAsyncReturn } from 'react-async-hook'
import { connect } from 'react-redux'
import { useDispatch } from 'react-redux'
import { showError } from 'src/alert/actions'
import { ErrorMessages } from 'src/app/ErrorMessages'
import { getReclaimEscrowFee } from 'src/escrow/saga'
Expand Down Expand Up @@ -45,8 +45,6 @@ interface ReclaimEscrowProps extends CommonProps {
paymentID: string
}

type OwnProps = InviteProps | SendProps | ExchangeProps | ReclaimEscrowProps

// TODO: remove this once we use TS 3.5
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

Expand All @@ -56,29 +54,21 @@ export type PropsWithoutChildren =
| Omit<ExchangeProps, 'children'>
| Omit<ReclaimEscrowProps, 'children'>

interface DispatchProps {
showError: typeof showError
}

type Props = DispatchProps & OwnProps

const mapDispatchToProps = {
showError,
}
type Props = InviteProps | SendProps | ExchangeProps | ReclaimEscrowProps

function useAsyncShowError<R, Args extends any[]>(
asyncFunction: ((...args: Args) => Promise<R>) | (() => Promise<R>),
params: Args,
showErrorFunction: typeof showError
params: Args
): UseAsyncReturn<R, Args> {
const asyncResult = useAsync(asyncFunction, params)
const dispatch = useDispatch()

useEffect(
() => {
// Generic error banner
if (asyncResult.error) {
Logger.error('CalculateFee', 'Error calculating fee', asyncResult.error)
showErrorFunction(ErrorMessages.CALCULATE_FEE_FAILED)
dispatch(showError(ErrorMessages.CALCULATE_FEE_FAILED))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

}
},
[asyncResult.error]
Expand All @@ -87,38 +77,30 @@ function useAsyncShowError<R, Args extends any[]>(
return asyncResult
}

const CalculateInviteFee: FunctionComponent<DispatchProps & InviteProps> = (props) => {
const CalculateInviteFee: FunctionComponent<InviteProps> = (props) => {
const asyncResult = useAsyncShowError(
(account: string, amount: BigNumber, comment: string) =>
getInviteFee(account, getStableTokenContract, amount.valueOf(), comment),
[props.account, props.amount, props.comment],
props.showError
[props.account, props.amount, props.comment]
)
return props.children(asyncResult) as React.ReactElement
}

const CalculateSendFee: FunctionComponent<DispatchProps & SendProps> = (props) => {
const CalculateSendFee: FunctionComponent<SendProps> = (props) => {
const asyncResult = useAsyncShowError(
(account: string, recipientAddress: string, amount: BigNumber, comment: string) =>
getSendFee(account, getStableTokenContract, {
recipientAddress,
amount: amount.valueOf(),
comment,
}),
[props.account, props.recipientAddress, props.amount, props.comment],
props.showError
[props.account, props.recipientAddress, props.amount, props.comment]
)
return props.children(asyncResult) as React.ReactElement
}

const CalculateReclaimEscrowFee: FunctionComponent<DispatchProps & ReclaimEscrowProps> = (
props
) => {
const asyncResult = useAsyncShowError(
getReclaimEscrowFee,
[props.account, props.paymentID],
props.showError
)
const CalculateReclaimEscrowFee: FunctionComponent<ReclaimEscrowProps> = (props) => {
const asyncResult = useAsyncShowError(getReclaimEscrowFee, [props.account, props.paymentID])
return props.children(asyncResult) as React.ReactElement
}

Expand All @@ -135,7 +117,4 @@ const CalculateFee = (props: Props) => {
throw new Error(`Unsupported feeType: ${props.feeType}`)
}

export default connect<{}, DispatchProps, OwnProps, {}>(
null,
mapDispatchToProps
)(CalculateFee)
export default CalculateFee
29 changes: 19 additions & 10 deletions packages/mobile/src/home/WalletHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from 'react-native'
import { BoxShadow } from 'react-native-shadow'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import AccountInfo from 'src/account/AccountInfo'
import { hideAlert, showMessage } from 'src/alert/actions'
import componentWithAnalytics from 'src/analytics/wrapper'
Expand Down Expand Up @@ -66,6 +67,23 @@ interface DispatchProps {

type Props = StateProps & DispatchProps & WithNamespaces

// Use bindActionCreators to workaround a typescript error with the shorthand syntax with redux-thunk actions
// see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/37369
const mapDispatchToProps = (dispatch: any) =>
bindActionCreators(
{
refreshAllBalances,
resetStandbyTransactions,
initializeSentryUserContext,
exitBackupFlow,
setLoading,
showMessage,
hideAlert,
importContacts,
},
dispatch
)

const mapStateToProps = (state: RootState): StateProps => ({
loading: state.home.loading,
address: currentAccountSelector(state),
Expand Down Expand Up @@ -281,16 +299,7 @@ export default withDispatchAfterNavigate(
componentWithAnalytics(
connect<StateProps, DispatchProps, {}, RootState>(
mapStateToProps,
{
refreshAllBalances,
resetStandbyTransactions,
initializeSentryUserContext,
exitBackupFlow,
setLoading,
showMessage,
hideAlert,
importContacts,
}
mapDispatchToProps
)(withNamespaces(Namespaces.walletFlow5)(WalletHome))
)
)
4 changes: 4 additions & 0 deletions packages/mobile/src/navigator/WithDispatchAfterNavigate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export function withDispatchAfterNavigate<P extends {}>(
}

return connect<null, null, any>(null)(
// Can't get this to pass typescript validation
// Some other people have reported something similar in https://github.com/piotrwitek/react-redux-typescript-guide/issues/111
// Ignoring the error for now
// @ts-ignore Argument of type 'typeof WithDispatchAfterNavigateWrapper' is not assignable to parameter of type 'ComponentType<Matching<null & DispatchProp<AnyAction>, WrappedComponentProps>>' ...
class WithDispatchAfterNavigateWrapper extends React.Component<WrappedComponentProps> {
onDidFocus: NavigationEventCallback = (payload: NavigationEventPayload) => {
if (!payload.state || !payload.state.params) {
Expand Down
54 changes: 17 additions & 37 deletions packages/mobile/src/pincode/Pincode.test.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,28 @@
import { shallow } from 'enzyme'
import toJson from 'enzyme-to-json'
import * as React from 'react'
import { fireEvent, render } from 'react-native-testing-library'
import { Provider } from 'react-redux'
import * as renderer from 'react-test-renderer'
import Pincode, { Pincode as PincodeUnwrapped } from 'src/pincode/Pincode'
import { createMockStore, getMockI18nProps } from 'test/utils'
import Pincode from 'src/pincode/Pincode'
import { createMockStore } from 'test/utils'

describe('Pincode', () => {
it('renders correctly for education', () => {
const store = createMockStore()
const tree = renderer.create(
<Provider store={store}>
it('renders correctly', () => {
const { toJSON, getByTestId } = render(
<Provider store={createMockStore()}>
<Pincode />
</Provider>
)
expect(tree).toMatchSnapshot()
})

it('renders correctly for pin enter', () => {
const wrapper = shallow(
<PincodeUnwrapped
showError={jest.fn()}
hideAlert={jest.fn()}
pincodeSet={jest.fn()}
setPin={jest.fn()}
{...getMockI18nProps()}
/>
)
wrapper.find('Button').simulate('press')
expect(toJson(wrapper)).toMatchSnapshot()
})
// initial - education
expect(toJSON()).toMatchSnapshot()

it('renders correctly for pin re-enter', () => {
const wrapper = shallow(
<PincodeUnwrapped
showError={jest.fn()}
hideAlert={jest.fn()}
pincodeSet={jest.fn()}
setPin={jest.fn()}
{...getMockI18nProps()}
/>
)
wrapper.find('Button').simulate('press')
wrapper.find('Button').simulate('press')
expect(toJson(wrapper)).toMatchSnapshot()
// Press continue
fireEvent.press(getByTestId('Pincode-Education'))
expect(toJSON()).toMatchSnapshot()

fireEvent.press(getByTestId('Pincode-Enter'))
expect(toJSON()).toMatchSnapshot()

fireEvent.press(getByTestId('Pincode-ReEnter'))
expect(toJSON()).toMatchSnapshot()
})
})
22 changes: 16 additions & 6 deletions packages/mobile/src/pincode/Pincode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as React from 'react'
import { WithNamespaces, withNamespaces } from 'react-i18next'
import { ScrollView, StyleSheet, Text, View } from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { pincodeSet, setPin } from 'src/account/actions'
import { hideAlert, showError } from 'src/alert/actions'
import CeloAnalytics from 'src/analytics/CeloAnalytics'
Expand Down Expand Up @@ -43,12 +44,18 @@ interface State {

type Props = DispatchProps & WithNamespaces

const mapDispatchToProps = {
showError,
hideAlert,
pincodeSet,
setPin,
}
// Use bindActionCreators to workaround a typescript error with the shorthand syntax with redux-thunk actions
// see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/37369
const mapDispatchToProps = (dispatch: any) =>
bindActionCreators(
{
showError,
hideAlert,
pincodeSet,
setPin,
},
dispatch
)

export class Pincode extends React.Component<Props, State> {
static navigationOptions = nuxNavigationOptions
Expand Down Expand Up @@ -196,6 +203,7 @@ export class Pincode extends React.Component<Props, State> {
case Steps.PIN_REENTER:
return (
<Button
testID="Pincode-ReEnter"
text={t('verifyPin.finalPin')}
style={style.button}
standard={true}
Expand All @@ -207,6 +215,7 @@ export class Pincode extends React.Component<Props, State> {
case Steps.PIN_ENTER:
return (
<Button
testID="Pincode-Enter"
text={t('continue')}
style={style.button}
onPress={this.stepForward}
Expand All @@ -218,6 +227,7 @@ export class Pincode extends React.Component<Props, State> {
default:
return (
<Button
testID="Pincode-Education"
text={t('continue')}
style={style.button}
onPress={this.onPressEducation}
Expand Down
Loading