Skip to content

Commit 5fa528b

Browse files
committed
Merge branch 'develop' into chore/ddw-1110-vasil
2 parents e3af396 + 45af27d commit 5fa528b

File tree

6 files changed

+685
-233
lines changed

6 files changed

+685
-233
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## vNext
44

5+
### Fixes
6+
7+
- Fixed incorrect amount of token sent ([PR 2962](https://github.com/input-output-hk/daedalus/pull/2962))
8+
59
### Chores
610

711
- Added Vasil-supported cardano-wallet ([PR 3001](https://github.com/input-output-hk/daedalus/pull/3001))

source/renderer/app/components/wallet/WalletSendForm.spec.tsx

Lines changed: 208 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,34 @@ import { DiscreetModeFeatureProvider } from '../../features/discreet-mode';
2020
import { BrowserLocalStorageBridge } from '../../features/local-storage';
2121
import { HwDeviceStatuses } from '../../domains/Wallet';
2222
import WalletTokenPicker from './tokens/wallet-token-picker/WalletTokenPicker';
23-
import WalletSendForm from './WalletSendForm';
23+
import WalletSendForm, { FormData } from './WalletSendForm';
24+
25+
jest.mock(
26+
'../../containers/wallet/dialogs/send-confirmation/SendConfirmation.container',
27+
() => {
28+
function Dialog({
29+
amount,
30+
formattedTotalAmount,
31+
}: {
32+
amount: number;
33+
formattedTotalAmount: number;
34+
}) {
35+
return (
36+
<div>
37+
<span data-testid="confirmation-dialog-ada-amount">{amount}</span>
38+
<span data-testid="confirmation-dialog-total-amount">
39+
{formattedTotalAmount}
40+
</span>
41+
</div>
42+
);
43+
}
44+
45+
return {
46+
__esModule: true,
47+
WalletSendConfirmationDialogContainer: Dialog,
48+
};
49+
}
50+
);
2451

2552
describe('wallet/Wallet Send Form', () => {
2653
beforeEach(() => addLocaleData([...en]));
@@ -50,11 +77,21 @@ describe('wallet/Wallet Send Form', () => {
5077
function SetupWallet({
5178
calculateTransactionFee,
5279
currentNumberFormat = NUMBER_OPTIONS[0].value,
80+
validationDebounceWait,
81+
validateAmount = jest.fn().mockResolvedValue(true),
82+
onTransactionFeeChange = jest.fn(),
5383
}: {
5484
calculateTransactionFee: (...args: Array<any>) => any;
85+
validateAmount?: (amount: string) => Promise<boolean>;
5586
currentNumberFormat?: string;
87+
validationDebounceWait?: number;
88+
onTransactionFeeChange?: () => Promise<void>;
5689
}) {
5790
const [tokenPickerOpen, setTokenPickerOpen] = useState<boolean>(false);
91+
const [state, setState] = useState<{
92+
isDialogOpen: boolean;
93+
formData: FormData;
94+
}>({ isDialogOpen: false, formData: null });
5895

5996
return (
6097
<TestDecorator>
@@ -65,15 +102,18 @@ describe('wallet/Wallet Send Form', () => {
65102
currencyMaxFractionalDigits={currencyMaxFractionalDigits}
66103
currencyMaxIntegerDigits={11}
67104
currentNumberFormat={currentNumberFormat}
68-
validateAmount={jest.fn().mockResolvedValue(true)}
105+
validateAmount={validateAmount}
69106
validateAssetAmount={jest.fn().mockResolvedValue(true)}
70107
calculateTransactionFee={calculateTransactionFee}
71108
walletAmount={new BigNumber(123)}
72109
assets={assets}
73110
addressValidator={() => true}
74-
onSubmit={jest.fn()}
111+
onSubmit={(formData) =>
112+
setState({ isDialogOpen: true, formData })
113+
}
75114
isDialogOpen={(dialog) =>
76-
dialog === WalletTokenPicker && tokenPickerOpen
115+
(dialog === WalletTokenPicker && tokenPickerOpen) ||
116+
state.isDialogOpen
77117
}
78118
isRestoreActive={false}
79119
hwDeviceStatus={HwDeviceStatuses.READY}
@@ -88,6 +128,9 @@ describe('wallet/Wallet Send Form', () => {
88128
walletName={faker.name.firstName()}
89129
onTokenPickerDialogClose={() => setTokenPickerOpen(false)}
90130
onTokenPickerDialogOpen={() => setTokenPickerOpen(true)}
131+
confirmationDialogData={state.formData}
132+
validationDebounceWait={validationDebounceWait}
133+
onTransactionFeeChange={onTransactionFeeChange}
91134
/>
92135
</MobxProvider>
93136
</DiscreetModeFeatureProvider>
@@ -185,6 +228,18 @@ describe('wallet/Wallet Send Form', () => {
185228
);
186229
}
187230

231+
function sleep(ms) {
232+
return new Promise((resolve) => {
233+
setTimeout(resolve, ms);
234+
});
235+
}
236+
237+
async function waitForTransactionFee() {
238+
const transactionFeeSpinner = screen.getByTestId('transaction-fee-spinner');
239+
240+
return waitForElementToBeRemoved(transactionFeeSpinner);
241+
}
242+
188243
test('should update Ada input field to minimum required and restore to original value when tokens are removed', async () => {
189244
expect.assertions(4);
190245

@@ -415,4 +470,153 @@ describe('wallet/Wallet Send Form', () => {
415470
assertAdaInput(minimumAda);
416471
assertMinimumAmountNoticeMessage(minimumAda);
417472
});
473+
474+
type Cases = [
475+
Array<[number, number]>,
476+
[number, number],
477+
Array<[number, number]>,
478+
[string, string, number]
479+
];
480+
481+
const cases: Cases[] = [
482+
[
483+
// ada inputs [delay, value]
484+
[
485+
[0, 2.5],
486+
[0, 1.5],
487+
],
488+
// validate amount [delay]
489+
[50, 5],
490+
// fee calculation [delay, value]
491+
[
492+
[50, 2],
493+
[0, 1],
494+
],
495+
['1.500000', '3.500000', 1],
496+
],
497+
[
498+
[
499+
[0, 2.5],
500+
[0, 1.5],
501+
],
502+
[0, 0],
503+
[
504+
[0, 1],
505+
[0, 2],
506+
],
507+
['1.500000', '3.500000', 1],
508+
],
509+
[
510+
[
511+
[50, 2.5],
512+
[0, 1.5],
513+
],
514+
[0, 0],
515+
[
516+
[0, 1],
517+
[0, 2],
518+
],
519+
['1.500000', '3.500000', 2],
520+
],
521+
];
522+
523+
cases.forEach(
524+
(
525+
[
526+
inputs,
527+
validateAmountParams,
528+
feeCalculationParams,
529+
[expectedAdaAmount, expectedTotalAmount, expectedTimesFeeCalled],
530+
],
531+
idx
532+
) => {
533+
test(`case ${idx}: should not allow to submit before fees are calculated`, async () => {
534+
expect.assertions(5);
535+
536+
const validationDebounceWait = 0;
537+
const onTransactionFeeChangeSpy = jest.fn();
538+
539+
const calculateTransactionFeeMock = jest.fn();
540+
541+
feeCalculationParams.forEach(([delay, value]) => {
542+
calculateTransactionFeeMock.mockImplementationOnce(
543+
() =>
544+
new Promise(async (resolve) => {
545+
await sleep(delay);
546+
resolve({
547+
fee: new BigNumber(value),
548+
minimumAda: new BigNumber(1),
549+
});
550+
})
551+
);
552+
});
553+
554+
const validateAmountMock = jest.fn();
555+
556+
validateAmountParams.forEach((delay) => {
557+
validateAmountMock.mockImplementationOnce(
558+
() =>
559+
new Promise(async (resolve) => {
560+
await sleep(delay);
561+
return resolve(true);
562+
})
563+
);
564+
});
565+
566+
render(
567+
<SetupWallet
568+
validateAmount={validateAmountMock}
569+
calculateTransactionFee={calculateTransactionFeeMock}
570+
validationDebounceWait={validationDebounceWait}
571+
onTransactionFeeChange={onTransactionFeeChangeSpy}
572+
/>
573+
);
574+
575+
enterReceiverAddress();
576+
577+
const adaField = await screen.findByLabelText('Ada');
578+
579+
for (const [delay, value] of inputs) {
580+
fireEvent.change(adaField, {
581+
target: {
582+
value,
583+
},
584+
});
585+
586+
await sleep(delay);
587+
}
588+
589+
const sendButton: HTMLButtonElement = screen.getByText('Send');
590+
expect(sendButton).not.toBeEnabled();
591+
592+
await waitForTransactionFee();
593+
594+
expect(sendButton).toBeEnabled();
595+
596+
fireEvent.keyPress(adaField, {
597+
key: 'Enter',
598+
code: 13,
599+
charCode: 13,
600+
target: adaField,
601+
});
602+
603+
const adaAmountConfirmation = await screen.findByTestId(
604+
'confirmation-dialog-ada-amount',
605+
{}
606+
);
607+
608+
expect(adaAmountConfirmation).toHaveTextContent(expectedAdaAmount);
609+
610+
const totalAmountConfirmation = screen.getByTestId(
611+
'confirmation-dialog-total-amount',
612+
{}
613+
);
614+
615+
expect(totalAmountConfirmation).toHaveTextContent(expectedTotalAmount);
616+
expect(onTransactionFeeChangeSpy).toHaveBeenCalledTimes(
617+
expectedTimesFeeCalled
618+
);
619+
});
620+
}
621+
);
418622
});

0 commit comments

Comments
 (0)