@@ -9,6 +9,7 @@ import * as accountApi from '@/api/account';
99import * as coinsApi from '@/api/coins' ;
1010import * as keystoresApi from '@/api/keystores' ;
1111import * as lightningApi from '@/api/lightning' ;
12+ import { TLightningErrorCode } from '@/api/lightning-errors' ;
1213import { RatesContext } from '@/contexts/RatesContext' ;
1314import { LightningTopUp } from './topup' ;
1415
@@ -17,14 +18,20 @@ vi.mock('@/i18n/i18n');
1718vi . mock ( './topup-form' , ( ) => ( {
1819 TopUpForm : ( {
1920 balanceLimitError,
21+ btcAccounts,
2022 canReview,
23+ errorHandling,
24+ minimumAmountError,
2125 onAmountChange,
2226 onFeeTargetChange,
2327 onReview,
2428 sendError,
2529 } : {
2630 balanceLimitError ?: string ;
31+ btcAccounts : accountApi . TAccount [ ] ;
2732 canReview : boolean ;
33+ errorHandling : { amountError ?: string } ;
34+ minimumAmountError ?: string ;
2835 onAmountChange : ( amount : string ) => void ;
2936 onFeeTargetChange : ( feeTarget : accountApi . FeeTargetCode ) => void ;
3037 onReview : ( ) => void ;
@@ -34,7 +41,10 @@ vi.mock('./topup-form', () => ({
3441 < button onClick = { ( ) => onAmountChange ( '100000' ) } > Set amount</ button >
3542 < button onClick = { ( ) => onFeeTargetChange ( 'economy' ) } > Set fee target</ button >
3643 < button disabled = { ! canReview } onClick = { onReview } > Review</ button >
44+ < span data-testid = "btc-accounts" > { btcAccounts . map ( account => account . code ) . join ( ',' ) } </ span >
3745 < span data-testid = "balance-limit-error" > { balanceLimitError } </ span >
46+ < span data-testid = "amount-error" > { minimumAmountError || errorHandling . amountError } </ span >
47+ < span data-testid = "fiat-amount-error" > { errorHandling . amountError } </ span >
3848 < span data-testid = "send-error" > { sendError } </ span >
3949 </ >
4050 ) ,
@@ -79,7 +89,7 @@ const lightningBalance = (marginSat = 150000): lightningApi.TLightningBalance =>
7989 incoming : amount ( '0' ) ,
8090} ) ;
8191
82- const renderTopUp = ( ) => render (
92+ const renderTopUp = ( activeAccounts = [ account ] ) => render (
8393 < MemoryRouter >
8494 < RatesContext . Provider value = { {
8595 defaultCurrency : 'USD' ,
@@ -91,18 +101,39 @@ const renderTopUp = () => render(
91101 updateDefaultCurrency : vi . fn ( ) ,
92102 removeFromActiveCurrencies : vi . fn ( ) ,
93103 } } >
94- < LightningTopUp activeAccounts = { [ account ] } hasAccounts />
104+ < LightningTopUp activeAccounts = { activeAccounts } hasAccounts />
95105 </ RatesContext . Provider >
96106 </ MemoryRouter >
97107) ;
98108
99109describe ( 'LightningTopUp' , ( ) => {
100110 beforeEach ( ( ) => {
101111 vi . restoreAllMocks ( ) ;
102- vi . spyOn ( accountApi , 'getBalance' ) . mockResolvedValue ( { success : true , balance : lightningBalance ( ) } ) ;
103112 vi . spyOn ( lightningApi , 'subscribeLightningBalance' ) . mockReturnValue ( vi . fn ( ) ) ;
104113 } ) ;
105114
115+ it ( 'shows every Bitcoin account without loading its balance' , async ( ) => {
116+ const emptyAccount : accountApi . TAccount = {
117+ ...account ,
118+ code : 'empty-btc-account' ,
119+ name : 'Empty Bitcoin Account' ,
120+ keystore : {
121+ ...account . keystore ,
122+ connected : false ,
123+ } ,
124+ } ;
125+ const getBalance = vi . spyOn ( accountApi , 'getBalance' ) . mockResolvedValue ( {
126+ success : true ,
127+ balance : lightningBalance ( 200000 ) ,
128+ } ) ;
129+ vi . spyOn ( lightningApi , 'getLightningBalance' ) . mockResolvedValue ( lightningBalance ( ) ) ;
130+
131+ renderTopUp ( [ account , emptyAccount ] ) ;
132+
133+ expect ( await screen . findByTestId ( 'btc-accounts' ) ) . toHaveTextContent ( 'btc-account,empty-btc-account' ) ;
134+ expect ( getBalance ) . not . toHaveBeenCalled ( ) ;
135+ } ) ;
136+
106137 it ( 'prepares and sends a top-up through the dedicated endpoint' , async ( ) => {
107138 vi . spyOn ( lightningApi , 'getLightningBalance' ) . mockResolvedValue ( lightningBalance ( ) ) ;
108139 vi . spyOn ( coinsApi , 'convertToCurrency' ) . mockResolvedValue ( { success : true , fiatAmount : '100' } ) ;
@@ -154,4 +185,24 @@ describe('LightningTopUp', () => {
154185 await waitFor ( ( ) => expect ( screen . getByTestId ( 'balance-limit-error' ) ) . toHaveTextContent ( 'Maximum top-up amount' ) ) ;
155186 expect ( screen . getByRole ( 'button' , { name : 'Review' } ) ) . toBeDisabled ( ) ;
156187 } ) ;
188+
189+ it ( 'shows the minimum-amount error returned by the prepare endpoint' , async ( ) => {
190+ vi . spyOn ( lightningApi , 'getLightningBalance' ) . mockResolvedValue ( lightningBalance ( ) ) ;
191+ vi . spyOn ( lightningApi , 'postPrepareTopUp' ) . mockResolvedValue ( {
192+ success : false ,
193+ errorCode : TLightningErrorCode . AMOUNT_BELOW_MINIMUM ,
194+ minAmountSat : 1000 ,
195+ } ) ;
196+ vi . spyOn ( coinsApi , 'convertToCurrency' ) . mockResolvedValue ( { success : true , fiatAmount : '0.01' } ) ;
197+ renderTopUp ( ) ;
198+
199+ fireEvent . click ( await screen . findByRole ( 'button' , { name : 'Set amount' } ) ) ;
200+ fireEvent . click ( screen . getByRole ( 'button' , { name : 'Set fee target' } ) ) ;
201+
202+ await waitFor ( ( ) => expect ( screen . getByTestId ( 'amount-error' ) ) . toHaveTextContent (
203+ 'The amount must be at least 1000 sats.'
204+ ) ) ;
205+ expect ( screen . getByTestId ( 'fiat-amount-error' ) ) . toBeEmptyDOMElement ( ) ;
206+ expect ( screen . getByRole ( 'button' , { name : 'Review' } ) ) . toBeDisabled ( ) ;
207+ } ) ;
157208} ) ;
0 commit comments