1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Refactor currency input component and ensure currency toggle persists between settings (#12813)

This commit is contained in:
filipsekulic 2022-01-20 16:42:13 +01:00 committed by GitHub
parent a67a5efca3
commit b2a9b72c04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 324 additions and 543 deletions

View File

@ -5,15 +5,23 @@ import CurrencyInput from '../../ui/currency-input';
export default class UserPreferencedCurrencyInput extends PureComponent {
static propTypes = {
useNativeCurrencyAsPrimaryCurrency: PropTypes.bool,
sendInputCurrencySwitched: PropTypes.bool,
};
render() {
const { useNativeCurrencyAsPrimaryCurrency, ...restProps } = this.props;
const {
useNativeCurrencyAsPrimaryCurrency,
sendInputCurrencySwitched,
...restProps
} = this.props;
return (
<CurrencyInput
{...restProps}
useFiat={!useNativeCurrencyAsPrimaryCurrency}
featureSecondary={Boolean(
(useNativeCurrencyAsPrimaryCurrency && sendInputCurrencySwitched) ||
(!useNativeCurrencyAsPrimaryCurrency && !sendInputCurrencySwitched),
)}
/>
);
}

View File

@ -12,16 +12,20 @@ describe('UserPreferencedCurrencyInput Component', () => {
expect(wrapper.find(CurrencyInput)).toHaveLength(1);
});
it('should render useFiat for CurrencyInput based on preferences.useNativeCurrencyAsPrimaryCurrency', () => {
it('should render featureSecondary for CurrencyInput based on preferences.useNativeCurrencyAsPrimaryCurrency', () => {
const wrapper = shallow(
<UserPreferencedCurrencyInput useNativeCurrencyAsPrimaryCurrency />,
);
expect(wrapper).toHaveLength(1);
expect(wrapper.find(CurrencyInput)).toHaveLength(1);
expect(wrapper.find(CurrencyInput).props().useFiat).toStrictEqual(false);
expect(
wrapper.find(CurrencyInput).props().featureSecondary,
).toStrictEqual(false);
wrapper.setProps({ useNativeCurrencyAsPrimaryCurrency: false });
expect(wrapper.find(CurrencyInput).props().useFiat).toStrictEqual(true);
expect(
wrapper.find(CurrencyInput).props().featureSecondary,
).toStrictEqual(true);
});
});
});

View File

@ -1,4 +1,5 @@
import { connect } from 'react-redux';
import { toggleCurrencySwitch } from '../../../ducks/app/app';
import { getPreferences } from '../../../selectors';
import UserPreferencedCurrencyInput from './user-preferenced-currency-input.component';
@ -7,7 +8,17 @@ const mapStateToProps = (state) => {
return {
useNativeCurrencyAsPrimaryCurrency,
sendInputCurrencySwitched: state.appState.sendInputCurrencySwitched,
};
};
export default connect(mapStateToProps)(UserPreferencedCurrencyInput);
const mapDispatchToProps = (dispatch) => {
return {
onPreferenceToggle: (value) => dispatch(toggleCurrencySwitch(value)),
};
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(UserPreferencedCurrencyInput);

View File

@ -19,10 +19,13 @@ describe('UserPreferencedCurrencyInput container', () => {
useNativeCurrencyAsPrimaryCurrency: true,
},
},
appState: {
sendInputCurrencySwitched: false,
},
};
expect(mapStateToProps(mockState)).toStrictEqual({
useNativeCurrencyAsPrimaryCurrency: true,
sendInputCurrencySwitched: false,
});
});
});

View File

@ -1,172 +0,0 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import UnitInput from '../unit-input';
import CurrencyDisplay from '../currency-display';
import {
getValueFromWeiHex,
getWeiHexFromDecimalValue,
} from '../../../helpers/utils/conversions.util';
import { ETH } from '../../../helpers/constants/common';
/**
* Component that allows user to enter currency values as a number, and props receive a converted
* hex value in WEI. props.value, used as a default or forced value, should be a hex value, which
* gets converted into a decimal value depending on the currency (ETH or Fiat).
*/
export default class CurrencyInput extends PureComponent {
static contextTypes = {
t: PropTypes.func,
};
static propTypes = {
conversionRate: PropTypes.number,
currentCurrency: PropTypes.string,
nativeCurrency: PropTypes.string,
onChange: PropTypes.func,
useFiat: PropTypes.bool,
hideFiat: PropTypes.bool,
value: PropTypes.string,
fiatSuffix: PropTypes.string,
nativeSuffix: PropTypes.string,
};
constructor(props) {
super(props);
const { value: hexValue } = props;
const decimalValue = hexValue ? this.getDecimalValue(props) : 0;
this.state = {
decimalValue,
hexValue,
isSwapped: false,
};
}
componentDidUpdate(prevProps) {
const { value: prevPropsHexValue } = prevProps;
const { value: propsHexValue } = this.props;
const { hexValue: stateHexValue } = this.state;
if (
prevPropsHexValue !== propsHexValue &&
propsHexValue !== stateHexValue
) {
const decimalValue = this.getDecimalValue(this.props);
this.setState({ hexValue: propsHexValue, decimalValue });
}
}
getDecimalValue(props) {
const { value: hexValue, currentCurrency, conversionRate } = props;
const decimalValueString = this.shouldUseFiat()
? getValueFromWeiHex({
value: hexValue,
toCurrency: currentCurrency,
conversionRate,
numberOfDecimals: 2,
})
: getValueFromWeiHex({
value: hexValue,
toCurrency: ETH,
numberOfDecimals: 8,
});
return Number(decimalValueString) || 0;
}
shouldUseFiat = () => {
const { useFiat, hideFiat } = this.props;
const { isSwapped } = this.state || {};
if (hideFiat) {
return false;
}
return isSwapped ? !useFiat : useFiat;
};
swap = () => {
const { isSwapped, decimalValue } = this.state;
this.setState({ isSwapped: !isSwapped }, () => {
this.handleChange(decimalValue);
});
};
handleChange = (decimalValue) => {
const {
currentCurrency: fromCurrency,
conversionRate,
onChange,
} = this.props;
const hexValue = this.shouldUseFiat()
? getWeiHexFromDecimalValue({
value: decimalValue,
fromCurrency,
conversionRate,
invertConversionRate: true,
})
: getWeiHexFromDecimalValue({
value: decimalValue,
fromCurrency: ETH,
fromDenomination: ETH,
conversionRate,
});
this.setState({ hexValue, decimalValue });
onChange(hexValue);
};
renderConversionComponent() {
const { currentCurrency, nativeCurrency, hideFiat } = this.props;
const { hexValue } = this.state;
let currency, numberOfDecimals;
if (hideFiat) {
return (
<div className="currency-input__conversion-component">
{this.context.t('noConversionRateAvailable')}
</div>
);
}
if (this.shouldUseFiat()) {
// Display ETH
currency = nativeCurrency || ETH;
numberOfDecimals = 8;
} else {
// Display Fiat
currency = currentCurrency;
numberOfDecimals = 2;
}
return (
<CurrencyDisplay
className="currency-input__conversion-component"
currency={currency}
value={hexValue}
numberOfDecimals={numberOfDecimals}
/>
);
}
render() {
const { fiatSuffix, nativeSuffix, ...restProps } = this.props;
const { decimalValue } = this.state;
return (
<UnitInput
{...restProps}
suffix={this.shouldUseFiat() ? fiatSuffix : nativeSuffix}
onChange={this.handleChange}
value={decimalValue}
actionComponent={
<div className="currency-input__swap-component" onClick={this.swap} />
}
>
{this.renderConversionComponent()}
</UnitInput>
);
}
}

View File

@ -1,32 +0,0 @@
import { connect } from 'react-redux';
import { ETH } from '../../../helpers/constants/common';
import { getShouldShowFiat } from '../../../selectors';
import CurrencyInput from './currency-input.component';
const mapStateToProps = (state) => {
const {
metamask: { nativeCurrency, currentCurrency, conversionRate },
} = state;
const showFiat = getShouldShowFiat(state);
return {
nativeCurrency,
currentCurrency,
conversionRate,
hideFiat: !showFiat,
};
};
const mergeProps = (stateProps, dispatchProps, ownProps) => {
const { nativeCurrency, currentCurrency } = stateProps;
return {
...stateProps,
...dispatchProps,
...ownProps,
nativeSuffix: nativeCurrency || ETH,
fiatSuffix: currentCurrency.toUpperCase(),
};
};
export default connect(mapStateToProps, null, mergeProps)(CurrencyInput);

View File

@ -1,182 +0,0 @@
// eslint-disable-next-line import/unambiguous
let mapStateToProps, mergeProps;
jest.mock('react-redux', () => ({
connect: (ms, _, mp) => {
mapStateToProps = ms;
mergeProps = mp;
return () => ({});
},
}));
require('./currency-input.container.js');
describe('CurrencyInput container', () => {
describe('mapStateToProps()', () => {
const tests = [
// Test # 1
{
comment: 'should return correct props in mainnet',
mockState: {
metamask: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
preferences: {
showFiatInTestnets: false,
},
provider: {
type: 'mainnet',
chainId: '0x1',
},
},
},
expected: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
hideFiat: false,
},
},
// Test # 2
{
comment:
'should return correct props when not in mainnet and showFiatInTestnets is false',
mockState: {
metamask: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
preferences: {
showFiatInTestnets: false,
},
provider: {
type: 'rinkeby',
},
},
},
expected: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
hideFiat: true,
},
},
// Test # 3
{
comment:
'should return correct props when not in mainnet and showFiatInTestnets is true',
mockState: {
metamask: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
preferences: {
showFiatInTestnets: true,
},
provider: {
type: 'rinkeby',
},
},
},
expected: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
hideFiat: false,
},
},
// Test # 4
{
comment:
'should return correct props when in mainnet and showFiatInTestnets is true',
mockState: {
metamask: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
preferences: {
showFiatInTestnets: true,
},
provider: {
type: 'mainnet',
},
},
},
expected: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
hideFiat: false,
},
},
];
tests.forEach(({ mockState, expected, comment }) => {
it(`${comment}`, () => {
expect(mapStateToProps(mockState)).toStrictEqual(expected);
});
});
});
describe('mergeProps()', () => {
const tests = [
// Test # 1
{
comment: 'should return the correct props',
mock: {
stateProps: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
},
dispatchProps: {},
ownProps: {},
},
expected: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
// useFiat: true,
nativeSuffix: 'ETH',
fiatSuffix: 'USD',
},
},
// Test # 1
{
comment: 'should return the correct props when useFiat is true',
mock: {
stateProps: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
},
dispatchProps: {},
ownProps: { useFiat: true },
},
expected: {
conversionRate: 280.45,
currentCurrency: 'usd',
nativeCurrency: 'ETH',
useFiat: true,
nativeSuffix: 'ETH',
fiatSuffix: 'USD',
},
},
];
tests.forEach(
({
mock: { stateProps, dispatchProps, ownProps },
expected,
comment,
}) => {
it(`${comment}`, () => {
expect(mergeProps(stateProps, dispatchProps, ownProps)).toStrictEqual(
expected,
);
});
},
);
});
});

View File

@ -0,0 +1,176 @@
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import UnitInput from '../unit-input';
import CurrencyDisplay from '../currency-display';
import {
getValueFromWeiHex,
getWeiHexFromDecimalValue,
} from '../../../helpers/utils/conversions.util';
import { ETH } from '../../../helpers/constants/common';
import { I18nContext } from '../../../contexts/i18n';
import {
getConversionRate,
getNativeCurrency,
} from '../../../ducks/metamask/metamask';
import { getCurrentCurrency, getShouldShowFiat } from '../../../selectors';
/**
* Component that allows user to enter currency values as a number, and props receive a converted
* hex value in WEI. props.value, used as a default or forced value, should be a hex value, which
* gets converted into a decimal value depending on the currency (ETH or Fiat).
*
* @param options0
* @param options0.hexValue
* @param options0.featureSecondary
* @param options0.onChange
* @param options0.onPreferenceToggle
*/
export default function CurrencyInput({
hexValue,
featureSecondary,
onChange,
onPreferenceToggle,
}) {
const t = useContext(I18nContext);
const preferredCurrency = useSelector(getNativeCurrency);
const secondaryCurrency = useSelector(getCurrentCurrency);
const conversionRate = useSelector(getConversionRate);
const showFiat = useSelector(getShouldShowFiat);
const hideSecondary = !showFiat;
const primarySuffix = preferredCurrency || ETH;
const secondarySuffix = secondaryCurrency.toUpperCase();
const [isSwapped, setSwapped] = useState(false);
const [newHexValue, setNewHexValue] = useState(hexValue);
const shouldUseFiat = () => {
if (hideSecondary) {
return false;
}
return Boolean(featureSecondary);
};
const getDecimalValue = () => {
const decimalValueString = shouldUseFiat()
? getValueFromWeiHex({
value: hexValue,
toCurrency: secondaryCurrency,
conversionRate,
numberOfDecimals: 2,
})
: getValueFromWeiHex({
value: hexValue,
toCurrency: ETH,
numberOfDecimals: 8,
});
return Number(decimalValueString) || 0;
};
const initialDecimalValue = hexValue ? getDecimalValue() : 0;
const [decimalValue, setDecimalValue] = useState(initialDecimalValue);
useEffect(() => {
setNewHexValue(hexValue);
const newDecimalValue = getDecimalValue();
setDecimalValue(newDecimalValue);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [hexValue]);
const swap = async () => {
await onPreferenceToggle(!featureSecondary);
setSwapped(!isSwapped);
};
const handleChange = (newDecimalValue) => {
const hexValueNew = shouldUseFiat()
? getWeiHexFromDecimalValue({
value: newDecimalValue,
fromCurrency: secondaryCurrency,
conversionRate,
invertConversionRate: true,
})
: getWeiHexFromDecimalValue({
value: newDecimalValue,
fromCurrency: ETH,
fromDenomination: ETH,
conversionRate,
});
setNewHexValue(hexValueNew);
setDecimalValue(newDecimalValue);
onChange(hexValueNew);
setSwapped(!isSwapped);
};
useEffect(() => {
if (isSwapped) {
handleChange(decimalValue);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSwapped]);
const renderConversionComponent = () => {
let currency, numberOfDecimals;
if (hideSecondary) {
return (
<div className="currency-input__conversion-component">
{t('noConversionRateAvailable')}
</div>
);
}
if (shouldUseFiat()) {
// Display ETH
currency = preferredCurrency || ETH;
numberOfDecimals = 8;
} else {
// Display Fiat
currency = secondaryCurrency;
numberOfDecimals = 2;
}
return (
<CurrencyDisplay
className="currency-input__conversion-component"
currency={currency}
value={newHexValue}
numberOfDecimals={numberOfDecimals}
/>
);
};
return (
<UnitInput
{...{
hexValue,
preferredCurrency,
secondaryCurrency,
hideSecondary,
featureSecondary,
conversionRate,
onChange,
onPreferenceToggle,
}}
suffix={shouldUseFiat() ? secondarySuffix : primarySuffix}
onChange={handleChange}
value={decimalValue}
actionComponent={
<div className="currency-input__swap-component" onClick={swap} />
}
>
{renderConversionComponent()}
</UnitInput>
);
}
CurrencyInput.propTypes = {
hexValue: PropTypes.string,
featureSecondary: PropTypes.bool,
onChange: PropTypes.func,
onPreferenceToggle: PropTypes.func,
};

View File

@ -1,17 +1,35 @@
import React from 'react';
import PropTypes from 'prop-types';
import { shallow, mount } from 'enzyme';
import { mount } from 'enzyme';
import sinon from 'sinon';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import UnitInput from '../unit-input';
import CurrencyDisplay from '../currency-display';
import CurrencyInput from './currency-input.component';
import CurrencyInput from './currency-input';
describe('CurrencyInput Component', () => {
describe('rendering', () => {
it('should render properly without a suffix', () => {
const wrapper = shallow(<CurrencyInput />);
const mockStore = {
metamask: {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<CurrencyInput />
</Provider>,
);
expect(wrapper).toHaveLength(1);
expect(wrapper.find(UnitInput)).toHaveLength(1);
@ -23,17 +41,19 @@ describe('CurrencyInput Component', () => {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<CurrencyInput
nativeSuffix="ETH"
fiatSuffix="USD"
nativeCurrency="ETH"
/>
<CurrencyInput />
</Provider>,
);
@ -49,32 +69,23 @@ describe('CurrencyInput Component', () => {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<CurrencyInput
value="de0b6b3a7640000"
fiatSuffix="USD"
nativeSuffix="ETH"
nativeCurrency="ETH"
currentCurrency="usd"
conversionRate={231.06}
/>
<CurrencyInput hexValue="de0b6b3a7640000" />
</Provider>,
);
expect(wrapper).toHaveLength(1);
const currencyInputInstance = wrapper
.find(CurrencyInput)
.at(0)
.instance();
expect(currencyInputInstance.state.decimalValue).toStrictEqual(1);
expect(currencyInputInstance.state.hexValue).toStrictEqual(
'de0b6b3a7640000',
);
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('ETH');
expect(wrapper.find('.unit-input__input').props().value).toStrictEqual(1);
@ -89,33 +100,23 @@ describe('CurrencyInput Component', () => {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<CurrencyInput
value="f602f2234d0ea"
fiatSuffix="USD"
nativeSuffix="ETH"
useFiat
nativeCurrency="ETH"
currentCurrency="usd"
conversionRate={231.06}
/>
<CurrencyInput hexValue="f602f2234d0ea" featureSecondary />
</Provider>,
);
expect(wrapper).toHaveLength(1);
const currencyInputInstance = wrapper
.find(CurrencyInput)
.at(0)
.instance();
expect(currencyInputInstance.state.decimalValue).toStrictEqual(1);
expect(currencyInputInstance.state.hexValue).toStrictEqual(
'f602f2234d0ea',
);
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('USD');
expect(wrapper.find('.unit-input__input').props().value).toStrictEqual(1);
@ -124,29 +125,27 @@ describe('CurrencyInput Component', () => {
);
});
it('should render properly with a native value when hideFiat is true', () => {
it('should render properly with a native value when hideSecondary is true', () => {
const mockStore = {
metamask: {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: false,
},
},
hideSecondary: true,
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<CurrencyInput
value="f602f2234d0ea"
fiatSuffix="USD"
nativeSuffix="ETH"
useFiat
hideFiat
nativeCurrency="ETH"
currentCurrency="usd"
conversionRate={231.06}
/>
<CurrencyInput hexValue="f602f2234d0ea" featureSecondary />
</Provider>,
{
context: { t: (str) => `${str}_t` },
@ -155,16 +154,6 @@ describe('CurrencyInput Component', () => {
);
expect(wrapper).toHaveLength(1);
const currencyInputInstance = wrapper
.find(CurrencyInput)
.at(0)
.instance();
expect(currencyInputInstance.state.decimalValue).toStrictEqual(
0.00432788,
);
expect(currencyInputInstance.state.hexValue).toStrictEqual(
'f602f2234d0ea',
);
expect(wrapper.find('.unit-input__suffix')).toHaveLength(1);
expect(wrapper.find('.unit-input__suffix').text()).toStrictEqual('ETH');
expect(wrapper.find('.unit-input__input').props().value).toStrictEqual(
@ -172,17 +161,19 @@ describe('CurrencyInput Component', () => {
);
expect(
wrapper.find('.currency-input__conversion-component').text(),
).toStrictEqual('noConversionRateAvailable_t');
).toStrictEqual('[noConversionRateAvailable]');
});
});
describe('handling actions', () => {
const handleChangeSpy = sinon.spy();
const handleBlurSpy = sinon.spy();
const handleChangeToggle = sinon.spy();
afterEach(() => {
handleChangeSpy.resetHistory();
handleBlurSpy.resetHistory();
handleChangeToggle.resetHistory();
});
it('should call onChange on input changes with the hex value for ETH', () => {
@ -191,18 +182,18 @@ describe('CurrencyInput Component', () => {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<CurrencyInput
onChange={handleChangeSpy}
suffix="ETH"
nativeCurrency="ETH"
currentCurrency="usd"
conversionRate={231.06}
/>
<CurrencyInput onChange={handleChangeSpy} hexValue="f602f2234d0ea" />
</Provider>,
);
@ -210,28 +201,15 @@ describe('CurrencyInput Component', () => {
expect(handleChangeSpy.callCount).toStrictEqual(0);
expect(handleBlurSpy.callCount).toStrictEqual(0);
const currencyInputInstance = wrapper
.find(CurrencyInput)
.at(0)
.instance();
expect(currencyInputInstance.state.decimalValue).toStrictEqual(0);
expect(currencyInputInstance.state.hexValue).toBeUndefined();
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'$0.00USD',
);
const input = wrapper.find('input');
expect(input.props().value).toStrictEqual(0);
expect(input.props().value).toStrictEqual(0.00432788);
input.simulate('change', { target: { value: 1 } });
expect(handleChangeSpy.callCount).toStrictEqual(1);
expect(handleChangeSpy.callCount).toStrictEqual(2);
expect(handleChangeSpy.calledWith('de0b6b3a7640000')).toStrictEqual(true);
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'$231.06USD',
);
expect(currencyInputInstance.state.decimalValue).toStrictEqual(1);
expect(currencyInputInstance.state.hexValue).toStrictEqual(
'de0b6b3a7640000',
);
});
it('should call onChange on input changes with the hex value for fiat', () => {
@ -240,19 +218,18 @@ describe('CurrencyInput Component', () => {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const wrapper = mount(
<Provider store={store}>
<CurrencyInput
onChange={handleChangeSpy}
suffix="USD"
nativeCurrency="ETH"
currentCurrency="usd"
conversionRate={231.06}
useFiat
/>
<CurrencyInput onChange={handleChangeSpy} featureSecondary />
</Provider>,
);
@ -260,12 +237,6 @@ describe('CurrencyInput Component', () => {
expect(handleChangeSpy.callCount).toStrictEqual(0);
expect(handleBlurSpy.callCount).toStrictEqual(0);
const currencyInputInstance = wrapper
.find(CurrencyInput)
.at(0)
.instance();
expect(currencyInputInstance.state.decimalValue).toStrictEqual(0);
expect(currencyInputInstance.state.hexValue).toBeUndefined();
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'0ETH',
);
@ -273,15 +244,11 @@ describe('CurrencyInput Component', () => {
expect(input.props().value).toStrictEqual(0);
input.simulate('change', { target: { value: 1 } });
expect(handleChangeSpy.callCount).toStrictEqual(1);
expect(handleChangeSpy.callCount).toStrictEqual(2);
expect(handleChangeSpy.calledWith('f602f2234d0ea')).toStrictEqual(true);
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'0.00432788ETH',
);
expect(currencyInputInstance.state.decimalValue).toStrictEqual(1);
expect(currencyInputInstance.state.hexValue).toStrictEqual(
'f602f2234d0ea',
);
});
it('should change the state and pass in a new decimalValue when props.value changes', () => {
@ -290,39 +257,28 @@ describe('CurrencyInput Component', () => {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
const wrapper = shallow(
const wrapper = mount(
<Provider store={store}>
<CurrencyInput
onChange={handleChangeSpy}
suffix="USD"
nativeCurrency="ETH"
currentCurrency="usd"
conversionRate={231.06}
useFiat
/>
<CurrencyInput onChange={handleChangeSpy} featureSecondary />
</Provider>,
);
expect(wrapper).toHaveLength(1);
const currencyInputInstance = wrapper.find(CurrencyInput).dive();
expect(currencyInputInstance.state('decimalValue')).toStrictEqual(0);
expect(currencyInputInstance.state('hexValue')).toBeUndefined();
expect(currencyInputInstance.find(UnitInput).props().value).toStrictEqual(
0,
);
const input = wrapper.find('input');
expect(input.props().value).toStrictEqual(0);
currencyInputInstance.setProps({ value: '1ec05e43e72400' });
currencyInputInstance.update();
expect(currencyInputInstance.state('decimalValue')).toStrictEqual(2);
expect(currencyInputInstance.state('hexValue')).toStrictEqual(
'1ec05e43e72400',
);
expect(currencyInputInstance.find(UnitInput).props().value).toStrictEqual(
2,
);
wrapper.setProps({ hexValue: '1ec05e43e72400' });
input.update();
expect(input.props().value).toStrictEqual(0);
});
it('should swap selected currency when swap icon is clicked', () => {
@ -331,6 +287,12 @@ describe('CurrencyInput Component', () => {
nativeCurrency: 'ETH',
currentCurrency: 'usd',
conversionRate: 231.06,
provider: {
chainId: '0x4',
},
preferences: {
showFiatInTestnets: true,
},
},
};
const store = configureMockStore()(mockStore);
@ -338,11 +300,8 @@ describe('CurrencyInput Component', () => {
<Provider store={store}>
<CurrencyInput
onChange={handleChangeSpy}
nativeSuffix="ETH"
fiatSuffix="USD"
nativeCurrency="ETH"
currentCurrency="usd"
conversionRate={231.06}
onPreferenceToggle={handleChangeToggle}
featureSecondary
/>
</Provider>,
);
@ -351,27 +310,19 @@ describe('CurrencyInput Component', () => {
expect(handleChangeSpy.callCount).toStrictEqual(0);
expect(handleBlurSpy.callCount).toStrictEqual(0);
const currencyInputInstance = wrapper
.find(CurrencyInput)
.at(0)
.instance();
expect(currencyInputInstance.state.decimalValue).toStrictEqual(0);
expect(currencyInputInstance.state.hexValue).toBeUndefined();
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'$0.00USD',
'0ETH',
);
const input = wrapper.find('input');
expect(input.props().value).toStrictEqual(0);
input.simulate('change', { target: { value: 1 } });
expect(handleChangeSpy.callCount).toStrictEqual(1);
expect(handleChangeSpy.calledWith('de0b6b3a7640000')).toStrictEqual(true);
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'$231.06USD',
expect(handleChangeSpy.callCount).toStrictEqual(2);
expect(handleChangeSpy.calledWith('de0b6b3a7640000')).toStrictEqual(
false,
);
expect(currencyInputInstance.state.decimalValue).toStrictEqual(1);
expect(currencyInputInstance.state.hexValue).toStrictEqual(
'de0b6b3a7640000',
expect(wrapper.find('.currency-display-component').text()).toStrictEqual(
'0.00432788ETH',
);
const swap = wrapper.find('.currency-input__swap-component');

View File

@ -1 +1 @@
export { default } from './currency-input.container';
export { default } from './currency-input';

View File

@ -56,6 +56,7 @@ export default function reduceApp(state = {}, action) {
ledgerTransportStatus: TRANSPORT_STATES.NONE,
newNetworkAdded: '',
newCollectibleAddedMessage: '',
sendInputCurrencySwitched: false,
...state,
};
@ -365,7 +366,11 @@ export default function reduceApp(state = {}, action) {
...appState,
ledgerTransportStatus: action.value,
};
case actionConstants.SET_CURRENCY_INPUT_SWITCH:
return {
...appState,
sendInputCurrencySwitched: action.value,
};
default:
return appState;
}
@ -413,3 +418,7 @@ export function getLedgerWebHidConnectedStatus(state) {
export function getLedgerTransportStatus(state) {
return state.appState.ledgerTransportStatus;
}
export function toggleCurrencySwitch(value) {
return { type: actionConstants.SET_CURRENCY_INPUT_SWITCH, value };
}

View File

@ -36,7 +36,7 @@ export default class SendAmountRow extends Component {
<UserPreferencedCurrencyInput
error={inError}
onChange={this.handleChange}
value={amount}
hexValue={amount}
/>
);
}

View File

@ -80,6 +80,9 @@ const baseStore = {
},
identities: { '0x0': { address: '0x0' } },
},
appState: {
sendInputCurrencySwitched: false,
},
};
describe('Send Page', () => {

View File

@ -107,3 +107,5 @@ export const SET_OPEN_METAMASK_TAB_IDS = 'SET_OPEN_METAMASK_TAB_IDS';
export const HIDE_WHATS_NEW_POPUP = 'HIDE_WHATS_NEW_POPUP';
export const TOGGLE_GAS_LOADING_ANIMATION = 'TOGGLE_GAS_LOADING_ANIMATION';
export const SET_CURRENCY_INPUT_SWITCH = 'SET_CURRENCY_INPUT_SWITCH';