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:
parent
a67a5efca3
commit
b2a9b72c04
@ -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),
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
|
@ -19,10 +19,13 @@ describe('UserPreferencedCurrencyInput container', () => {
|
||||
useNativeCurrencyAsPrimaryCurrency: true,
|
||||
},
|
||||
},
|
||||
appState: {
|
||||
sendInputCurrencySwitched: false,
|
||||
},
|
||||
};
|
||||
|
||||
expect(mapStateToProps(mockState)).toStrictEqual({
|
||||
useNativeCurrencyAsPrimaryCurrency: true,
|
||||
sendInputCurrencySwitched: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
}
|
@ -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);
|
@ -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,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
176
ui/components/ui/currency-input/currency-input.js
Normal file
176
ui/components/ui/currency-input/currency-input.js
Normal 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,
|
||||
};
|
@ -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');
|
@ -1 +1 @@
|
||||
export { default } from './currency-input.container';
|
||||
export { default } from './currency-input';
|
||||
|
@ -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 };
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ export default class SendAmountRow extends Component {
|
||||
<UserPreferencedCurrencyInput
|
||||
error={inError}
|
||||
onChange={this.handleChange}
|
||||
value={amount}
|
||||
hexValue={amount}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -80,6 +80,9 @@ const baseStore = {
|
||||
},
|
||||
identities: { '0x0': { address: '0x0' } },
|
||||
},
|
||||
appState: {
|
||||
sendInputCurrencySwitched: false,
|
||||
},
|
||||
};
|
||||
|
||||
describe('Send Page', () => {
|
||||
|
@ -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';
|
||||
|
Loading…
Reference in New Issue
Block a user