1+ using System . Diagnostics ;
2+
3+ using BTCPayServer . Plugins . Monero . Services ;
14using BTCPayServer . Rating ;
25using BTCPayServer . Services . Rates ;
6+ using BTCPayServer . Tests ;
37using BTCPayServer . Tests . Mocks ;
48
59using Xunit ;
@@ -9,6 +13,7 @@ namespace BTCPayServer.Plugins.IntegrationTests.Monero;
913
1014public class MoneroPluginIntegrationTest ( ITestOutputHelper helper ) : MoneroAndBitcoinIntegrationTestBase ( helper )
1115{
16+
1217 [ Fact ]
1318 public async Task EnableMoneroPluginSuccessfully ( )
1419 {
@@ -36,8 +41,101 @@ public async Task EnableMoneroPluginSuccessfully()
3641 await s . RegisterNewUser ( true ) ;
3742 await s . CreateNewStore ( preferredExchange : "Kraken" ) ;
3843 await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
39- await s . Page . Locator ( "input#PrimaryAddress" ) . FillAsync ( "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ) ;
40- await s . Page . Locator ( "input#PrivateViewKey" ) . FillAsync ( "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ) ;
44+ await s . Page . Locator ( "input#PrimaryAddress" ) . FillAsync (
45+ "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ) ;
46+ await s . Page . Locator ( "input#PrivateViewKey" )
47+ . FillAsync ( "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ) ;
48+ await s . Page . Locator ( "input#RestoreHeight" ) . FillAsync ( "0" ) ;
49+ await s . Page . Locator ( "input#WalletPassword" ) . FillAsync ( "pass123" ) ;
50+ await s . Page . ClickAsync ( "button[name='command'][value='set-wallet-details']" ) ;
51+ await s . Page . CheckAsync ( "#Enabled" ) ;
52+ await s . Page . SelectOptionAsync ( "#SettlementConfirmationThresholdChoice" , "2" ) ;
53+ await s . Page . ClickAsync ( "#SaveButton" ) ;
54+ var classList = await s . Page . Locator ( "svg.icon-checkmark" ) . GetAttributeAsync ( "class" ) ;
55+ Assert . Contains ( "text-success" , classList ) ;
56+
57+ // Set rate provider
58+ await s . Page . Locator ( "#menu-item-General" ) . ClickAsync ( ) ;
59+ await s . Page . Locator ( "#menu-item-Rates" ) . ClickAsync ( ) ;
60+ await s . Page . FillAsync ( "#DefaultCurrencyPairs" , "BTC_USD,XMR_USD,XMR_BTC" ) ;
61+ await s . Page . SelectOptionAsync ( "#PrimarySource_PreferredExchange" , "kraken" ) ;
62+ await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
63+
64+ // Generate a new invoice
65+ await s . Page . Locator ( "a.nav-link[href*='invoices']" ) . ClickAsync ( ) ;
66+ await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
67+ await s . Page . FillAsync ( "#Amount" , "4.20" ) ;
68+ await s . Page . FillAsync ( "#BuyerEmail" , "monero@monero.com" ) ;
69+ await Task . Delay ( TimeSpan . FromSeconds ( 25 ) ) ; // wallet-rpc needs some time to sync. refactor this later
70+ await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
71+
72+ // View the invoice
73+ var href = await s . Page . Locator ( "a[href^='/i/']" ) . GetAttributeAsync ( "href" ) ;
74+ var invoiceId = href ? . Split ( "/i/" ) . Last ( ) ;
75+ await s . Page . Locator ( $ "a[href='/i/{ invoiceId } ']") . ClickAsync ( ) ;
76+ await s . Page . ClickAsync ( "#DetailsToggle" ) ;
77+
78+ // Verify the total fiat amount is $4.20
79+ var totalFiat = await s . Page . Locator ( "#PaymentDetails-TotalFiat dd.clipboard-button" )
80+ . InnerTextAsync ( ) ;
81+ Assert . Equal ( "$4.20" , totalFiat ) ;
82+
83+ await s . Page . GoBackAsync ( ) ;
84+ await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
85+
86+ // Create a new account label
87+ await s . Page . FillAsync ( "#NewAccountLabel" , "tst-account" ) ;
88+ await s . Page . ClickAsync ( "button[name='command'][value='add-account']" ) ;
89+
90+ // Select primary Account Index
91+ await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
92+ await s . Page . SelectOptionAsync ( "#AccountIndex" , "1" ) ;
93+ await s . Page . ClickAsync ( "#SaveButton" ) ;
94+
95+ // Verify selected account index
96+ await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
97+ var selectedValue = await s . Page . Locator ( "#AccountIndex" ) . InputValueAsync ( ) ;
98+ Assert . Equal ( "1" , selectedValue ) ;
99+
100+ // Select confirmation time to 0
101+ await s . Page . SelectOptionAsync ( "#SettlementConfirmationThresholdChoice" , "3" ) ;
102+ await s . Page . ClickAsync ( "#SaveButton" ) ;
103+
104+ await CleanUp ( s ) ;
105+ }
106+
107+ [ Fact ]
108+ public async Task EnableMoneroPluginSuccessfullySecond ( )
109+ {
110+ await using var s = CreatePlaywrightTester ( ) ;
111+ await s . StartAsync ( ) ;
112+
113+ if ( s . Server . PayTester . MockRates )
114+ {
115+ var rateProviderFactory = s . Server . PayTester . GetService < RateProviderFactory > ( ) ;
116+ rateProviderFactory . Providers . Clear ( ) ;
117+
118+ var coinAverageMock = new MockRateProvider ( ) ;
119+ coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_USD" ) , new BidAsk ( 5000m ) ) ) ;
120+ coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_EUR" ) , new BidAsk ( 4000m ) ) ) ;
121+ coinAverageMock . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_BTC" ) , new BidAsk ( 4500m ) ) ) ;
122+ rateProviderFactory . Providers . Add ( "coingecko" , coinAverageMock ) ;
123+
124+ var kraken = new MockRateProvider ( ) ;
125+ kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "BTC_USD" ) , new BidAsk ( 0.1m ) ) ) ;
126+ kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_USD" ) , new BidAsk ( 0.1m ) ) ) ;
127+ kraken . ExchangeRates . Add ( new PairRate ( CurrencyPair . Parse ( "XMR_BTC" ) , new BidAsk ( 0.1m ) ) ) ;
128+ rateProviderFactory . Providers . Add ( "kraken" , kraken ) ;
129+ }
130+
131+ await s . RegisterNewUser ( true ) ;
132+ await s . CreateNewStore ( preferredExchange : "Kraken" ) ;
133+ await s . Page . Locator ( "a.nav-link[href*='monerolike/XMR']" ) . ClickAsync ( ) ;
134+ await s . Page . Locator ( "input#PrimaryAddress" )
135+ . FillAsync (
136+ "43Pnj6ZKGFTJhaLhiecSFfLfr64KPJZw7MyGH73T6PTDekBBvsTAaWEUSM4bmJqDuYLizhA13jQkMRPpz9VXBCBqQQb6y5L" ) ;
137+ await s . Page . Locator ( "input#PrivateViewKey" )
138+ . FillAsync ( "1bfa03b0c78aa6bc8292cf160ec9875657d61e889c41d0ebe5c54fd3a2c4b40e" ) ;
41139 await s . Page . Locator ( "input#RestoreHeight" ) . FillAsync ( "0" ) ;
42140 await s . Page . Locator ( "input#WalletPassword" ) . FillAsync ( "pass123" ) ;
43141 await s . Page . ClickAsync ( "button[name='command'][value='set-wallet-details']" ) ;
@@ -48,8 +146,8 @@ public async Task EnableMoneroPluginSuccessfully()
48146 Assert . Contains ( "text-success" , classList ) ;
49147
50148 // Set rate provider
51- await s . Page . Locator ( "#StoreNav -General" ) . ClickAsync ( ) ;
52- await s . Page . Locator ( "#mainNav #StoreNav -Rates" ) . ClickAsync ( ) ;
149+ await s . Page . Locator ( "#menu-item -General" ) . ClickAsync ( ) ;
150+ await s . Page . Locator ( "#menu-item -Rates" ) . ClickAsync ( ) ;
53151 await s . Page . FillAsync ( "#DefaultCurrencyPairs" , "BTC_USD,XMR_USD,XMR_BTC" ) ;
54152 await s . Page . SelectOptionAsync ( "#PrimarySource_PreferredExchange" , "kraken" ) ;
55153 await s . Page . Locator ( "#page-primary" ) . ClickAsync ( ) ;
@@ -92,5 +190,65 @@ public async Task EnableMoneroPluginSuccessfully()
92190 // Select confirmation time to 0
93191 await s . Page . SelectOptionAsync ( "#SettlementConfirmationThresholdChoice" , "3" ) ;
94192 await s . Page . ClickAsync ( "#SaveButton" ) ;
193+
194+ await CleanUp ( s ) ;
195+ }
196+
197+ private static async Task CleanUp ( PlaywrightTester playwrightTester )
198+ {
199+ MoneroRPCProvider moneroRpcProvider = playwrightTester . Server . PayTester . GetService < MoneroRPCProvider > ( ) ;
200+ if ( moneroRpcProvider . IsAvailable ( "XMR" ) )
201+ {
202+ await moneroRpcProvider . CloseWallet ( "XMR" ) ;
203+ await moneroRpcProvider . UpdateSummary ( "XMR" ) ;
204+ }
205+
206+ if ( playwrightTester . Server . PayTester . InContainer )
207+ {
208+ moneroRpcProvider . DeleteWallet ( ) ;
209+ }
210+ else
211+ {
212+ await RemoveWalletFromLocalDocker ( ) ;
213+ }
214+ }
215+
216+ static async Task RemoveWalletFromLocalDocker ( )
217+ {
218+ try
219+ {
220+ var removeWalletFromDocker = new ProcessStartInfo
221+ {
222+ FileName = "docker" ,
223+ Arguments = "exec xmr_wallet sh -c \" rm -rf /wallet/*\" " ,
224+ RedirectStandardOutput = true ,
225+ RedirectStandardError = true
226+ } ;
227+
228+ using var process = Process . Start ( removeWalletFromDocker ) ;
229+ if ( process is null )
230+ {
231+ return ;
232+ }
233+
234+ var stdout = await process . StandardOutput . ReadToEndAsync ( ) ;
235+ var stderr = await process . StandardError . ReadToEndAsync ( ) ;
236+
237+ await process . WaitForExitAsync ( ) ;
238+
239+ if ( ! string . IsNullOrWhiteSpace ( stdout ) )
240+ {
241+ Console . WriteLine ( stdout ) ;
242+ }
243+
244+ if ( ! string . IsNullOrWhiteSpace ( stderr ) )
245+ {
246+ Console . WriteLine ( stderr ) ;
247+ }
248+ }
249+ catch ( Exception ex )
250+ {
251+ Console . WriteLine ( $ "Cleanup failed: { ex } ") ;
252+ }
95253 }
96254}
0 commit comments