Skip to content

Commit 0907629

Browse files
matheusdalexlyp
authored andcommitted
[inputs] Fix some DcrInput instances (#2360)
The latest chage to DcrInput broke some input combinations. This fixes them and adds a set of unit tests to ensure the proper behavior of DcrInput in DCR mode.
1 parent c401c46 commit 0907629

File tree

4 files changed

+266
-17
lines changed

4 files changed

+266
-17
lines changed

app/components/inputs/DcrInput.js

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ import { MAX_DCR_AMOUNT } from "constants";
1717
export const FixedDcrInput = ({ currencyDisplay, ...props }) =>
1818
<FloatInput {...{ ...props, unit: currencyDisplay, maxFracDigits: 8 }} />;
1919

20+
function countDecimalDigits(s) {
21+
for (let i = s.length-1; i >= 0; i--) {
22+
if (s[i] === ".") return s.length - i - 1;
23+
}
24+
return 0;
25+
}
26+
2027
/**
2128
* DcrInput provides a way to receive decred amount inputs. Instead of the usual
2229
* value/onChange pair, it uses amount/onChangeAmount to track values in decred
@@ -32,21 +39,36 @@ class DcrInput extends React.Component {
3239
constructor(props) {
3340
super(props);
3441
this.state = {
35-
decimal: false
42+
decimal: false,
43+
decimalDigits: 0
3644
};
3745
}
3846

47+
componentDidUpdate(prevProps) {
48+
if (this.props.amount !== prevProps.amount && !this.props.amount && this.props.amount !== 0) {
49+
// Amount just got cleared, so clear decimalDigits as well to display a
50+
// blank input.
51+
this.setState({ decimalDigits: 0 });
52+
}
53+
}
54+
3955
// amountToDisplayStr converts the given amount in atoms to the appropriate
4056
// string to display given the current config of this input.
4157
amountToDisplayStr(amount) {
42-
if (!amount && !this.state.decimal) return amount;
43-
if (!amount) return "0.";
58+
if (!amount) {
59+
if (this.state.decimal) {
60+
return "0.";
61+
} else if (this.state.decimalDigits) {
62+
return (0).toFixed(this.state.decimalDigits);
63+
}
64+
return amount;
65+
}
4466
const { unitDivisor } = this.props;
4567
let scaled = amount / unitDivisor;
4668
if (this.state.decimal) {
47-
scaled += ".";
69+
return scaled.toFixed(0) + ".";
4870
}
49-
return scaled;
71+
return scaled.toFixed(this.state.decimalDigits);
5072
}
5173

5274
// typedValueToAmount converts the given string value typed into the input to
@@ -60,14 +82,15 @@ class DcrInput extends React.Component {
6082
let amount;
6183
const value = e.target.value;
6284
const decimal = value && value.length > 0 && value[value.length-1] == ".";
85+
const decimalDigits = countDecimalDigits(value);
6386
if (value) {
6487
amount = this.typedValueToAmount(value);
6588

6689
// Pre-validate if <= max supply
6790
if (amount > MAX_DCR_AMOUNT) return;
6891
}
6992
if (onChangeAmount) onChangeAmount({ ...e, value, atomValue: amount });
70-
this.setState({ decimal });
93+
this.setState({ decimal, decimalDigits });
7194
}
7295

7396
render() {

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@
8080
}
8181
],
8282
"window": {
83-
"width":540,
84-
"height":315
83+
"width": 540,
84+
"height": 315
8585
}
8686
},
8787
"files": [
@@ -167,6 +167,8 @@
167167
"@babel/preset-flow": "^7.0.0",
168168
"@babel/preset-react": "^7.0.0",
169169
"@babel/register": "^7.0.0",
170+
"@testing-library/jest-dom": "^4.2.4",
171+
"@testing-library/react": "^9.3.2",
170172
"babel-core": "^7.0.0-bridge.0",
171173
"babel-eslint": "^10.0.3",
172174
"babel-jest": "^24.9.0",
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { DcrInput } from "inputs";
2+
import { Provider } from "react-redux";
3+
4+
import { createStore } from "redux";
5+
import { render, fireEvent } from "@testing-library/react";
6+
import "@testing-library/jest-dom/extend-expect";
7+
8+
const reducer = s => s;
9+
10+
// Test DcrInput component which loops back amount after an onChangeAmount event.
11+
// This is roughly how users of DcrInput behave.
12+
@autobind
13+
class TestDcrInput extends React.Component {
14+
constructor(props) {
15+
super(props);
16+
this.state = { amount: 0 };
17+
}
18+
onChangeAmount({ atomValue }) {
19+
this.setState({ amount: atomValue });
20+
}
21+
render() {
22+
return <DcrInput amount={this.state.amount} onChangeAmount={this.onChangeAmount} />;
23+
}
24+
}
25+
26+
function renderWithRedux(
27+
ui,
28+
{ initialState, store = createStore(reducer, initialState) } = {}
29+
) {
30+
return {
31+
...render(<Provider store={store}>{ui}</Provider>),
32+
store
33+
};
34+
}
35+
36+
describe("DcrInput in DCR mode works", () => {
37+
38+
let queries;
39+
40+
const expectAfterChange = (targetValue, displayValue) => {
41+
const { getByRole } = queries;
42+
fireEvent.change(getByRole("textbox"), { target: { value: targetValue } });
43+
expect(getByRole("textbox")).toHaveValue(displayValue);
44+
};
45+
46+
beforeEach(() => {
47+
queries = renderWithRedux(
48+
<TestDcrInput />,
49+
{ initialState: { settings: { currentSettings: { currencyDisplay: "DCR" } } } }
50+
);
51+
});
52+
53+
54+
test.each(
55+
[
56+
[ null, "" ],
57+
[ undefined, "0" ],
58+
[ "", "" ],
59+
[ "0", "0" ],
60+
[ "0.", "0." ],
61+
[ ".", "0." ],
62+
[ "0.0", "0.0" ],
63+
[ "0.01", "0.01" ],
64+
[ "0.010", "0.010" ],
65+
[ "0.0000000", "0.0000000" ],
66+
[ "0.00000000", "0.00000000" ],
67+
[ "0.00000001", "0.00000001" ],
68+
[ "0.1", "0.1" ],
69+
[ "0.99999999", "0.99999999" ],
70+
[ "1", "1" ],
71+
[ "1.", "1." ],
72+
[ "1.0", "1.0" ],
73+
[ "1.01", "1.01" ],
74+
[ "1.010", "1.010" ],
75+
[ "1.0000000", "1.0000000" ],
76+
[ "1.00000001", "1.00000001" ],
77+
[ "1.1", "1.1" ],
78+
[ "1.10", "1.10" ],
79+
[ "1.101", "1.101" ],
80+
[ "1.00000000", "1.00000000" ],
81+
[ "1.00000001", "1.00000001" ],
82+
[ "1.000000001", "1.00000000" ],
83+
[ "123.918", "123.918" ],
84+
[ "102891.28183707", "102891.28183707" ],
85+
[ "20999999.9999999", "20999999.9999999" ],
86+
[ "20999999.99999999", "20999999.99999999" ],
87+
[ "a", "" ],
88+
[ "1a", "1" ],
89+
[ "1.2b", "1.2" ],
90+
[ "1.2.", "1.2" ],
91+
[ "1.2.2", "1.2" ],
92+
[ "1,", "1." ],
93+
[ "1,2", "1.2" ]
94+
],
95+
)("'%s' into '%s'", expectAfterChange);
96+
});

0 commit comments

Comments
 (0)