mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-17 22:14:26 +01:00
Migrate CanManageWallet test to Playwright (#6797)
This commit is contained in:
@@ -1493,238 +1493,6 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact(Timeout = TestTimeout)]
|
||||
public async Task CanManageWallet()
|
||||
{
|
||||
using var s = CreateSeleniumTester();
|
||||
await s.StartAsync();
|
||||
s.RegisterNewUser(true);
|
||||
(_, string storeId) = s.CreateNewStore();
|
||||
const string cryptoCode = "BTC";
|
||||
|
||||
// In this test, we try to spend from a manual seed. We import the xpub 49'/0'/0',
|
||||
// then try to use the seed to sign the transaction
|
||||
s.GenerateWallet(cryptoCode, "", true);
|
||||
|
||||
//let's test quickly the wallet send page
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
s.Driver.FindElement(By.Id("WalletNav-Send")).Click();
|
||||
//you cannot use the Sign with NBX option without saving private keys when generating the wallet.
|
||||
Assert.DoesNotContain("nbx-seed", s.Driver.PageSource);
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
||||
s.Driver.FindElement(By.Id("SignTransaction")).Click();
|
||||
Assert.Contains("Destination Address field is required", s.Driver.PageSource);
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
||||
s.Driver.FindElement(By.Id("CancelWizard")).Click();
|
||||
s.Driver.FindElement(By.Id("WalletNav-Receive")).Click();
|
||||
|
||||
//generate a receiving address
|
||||
Assert.True(s.Driver.FindElement(By.CssSelector("#address-tab .qr-container")).Displayed);
|
||||
// no previous page in the wizard, hence no back button
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
||||
var receiveAddr = s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text");
|
||||
|
||||
// Can add a label?
|
||||
await TestUtils.EventuallyAsync(async () =>
|
||||
{
|
||||
s.Driver.WaitForElement(By.CssSelector("div.label-manager input")).Click();
|
||||
await Task.Delay(500);
|
||||
s.Driver.WaitForElement(By.CssSelector("div.label-manager input")).SendKeys("test-label" + Keys.Enter);
|
||||
await Task.Delay(500);
|
||||
s.Driver.WaitForElement(By.CssSelector("div.label-manager input")).SendKeys("label2" + Keys.Enter);
|
||||
});
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
s.Driver.Navigate().Refresh();
|
||||
Assert.NotNull(s.Driver.FindElement(By.CssSelector("[data-value='test-label']")));
|
||||
});
|
||||
|
||||
Assert.True(s.Driver.FindElement(By.CssSelector("#address-tab .qr-container")).Displayed);
|
||||
Assert.Equal(receiveAddr, s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text"));
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
Assert.Contains("test-label", s.Driver.PageSource);
|
||||
});
|
||||
|
||||
// Remove a label
|
||||
s.Driver.WaitForElement(By.CssSelector("[data-value='test-label']")).Click();
|
||||
await Task.Delay(500);
|
||||
s.Driver.ExecuteJavaScript("var l=document.querySelector('[data-value=\"test-label\"]');l.click();l.nextSibling.dispatchEvent(new KeyboardEvent('keydown', {'key': 'Delete', keyCode: 8}));");
|
||||
await Task.Delay(500);
|
||||
await s.Driver.Navigate().RefreshAsync();
|
||||
Assert.DoesNotContain("test-label", s.Driver.PageSource);
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
||||
|
||||
//send money to addr and ensure it changed
|
||||
var sess = await s.Server.ExplorerClient.CreateWebsocketNotificationSessionAsync();
|
||||
await s.Server.ExplorerNode.SendToAddressAsync(BitcoinAddress.Create(receiveAddr, Network.RegTest),
|
||||
Money.Parse("0.1"));
|
||||
await sess.WaitNext<NewTransactionEvent>(e => e.Outputs.FirstOrDefault()?.Address.ToString() == receiveAddr);
|
||||
await Task.Delay(200);
|
||||
s.Driver.Navigate().Refresh();
|
||||
s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
|
||||
Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text"));
|
||||
receiveAddr = s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text");
|
||||
s.Driver.FindElement(By.Id("CancelWizard")).Click();
|
||||
|
||||
// Check the label is applied to the tx
|
||||
s.Driver.WaitWalletTransactionsLoaded();
|
||||
// Sometimes this fails in local, but not CI
|
||||
Assert.Equal("label2", s.Driver.FindElement(By.XPath("//*[@id=\"WalletTransactionsList\"]//*[contains(@class, 'transaction-label')]")).Text);
|
||||
|
||||
//change the wallet and ensure old address is not there and generating a new one does not result in the prev one
|
||||
s.GenerateWallet(cryptoCode, "", true);
|
||||
s.GoToWallet(null, WalletsNavPages.Receive);
|
||||
s.Driver.FindElement(By.CssSelector("button[value=generate-new-address]")).Click();
|
||||
Assert.NotEqual(receiveAddr, s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text"));
|
||||
|
||||
var invoiceId = s.CreateInvoice(storeId);
|
||||
var invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
||||
var btc = PaymentTypes.CHAIN.GetPaymentMethodId("BTC");
|
||||
var address = invoice.GetPaymentPrompt(btc).Destination;
|
||||
|
||||
//wallet should have been imported to bitcoin core wallet in watch only mode.
|
||||
var result =
|
||||
await s.Server.ExplorerNode.GetAddressInfoAsync(BitcoinAddress.Create(address, Network.RegTest));
|
||||
Assert.True(result.IsWatchOnly);
|
||||
s.GoToStore(storeId);
|
||||
var mnemonic = s.GenerateWallet(cryptoCode, "", true, true);
|
||||
|
||||
//lets import and save private keys
|
||||
invoiceId = s.CreateInvoice(storeId);
|
||||
invoice = await s.Server.PayTester.InvoiceRepository.GetInvoice(invoiceId);
|
||||
address = invoice.GetPaymentPrompt(btc).Destination;
|
||||
result = await s.Server.ExplorerNode.GetAddressInfoAsync(
|
||||
BitcoinAddress.Create(address, Network.RegTest));
|
||||
//spendable from bitcoin core wallet!
|
||||
Assert.False(result.IsWatchOnly);
|
||||
var tx = s.Server.ExplorerNode.SendToAddress(BitcoinAddress.Create(address, Network.RegTest),
|
||||
Money.Coins(3.0m));
|
||||
await s.Server.ExplorerNode.GenerateAsync(1);
|
||||
|
||||
s.GoToStore(storeId);
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
s.ClickOnAllSectionLinks();
|
||||
|
||||
// Make sure wallet info is correct
|
||||
s.GoToWalletSettings(cryptoCode);
|
||||
Assert.Contains(mnemonic.DeriveExtKey().GetPublicKey().GetHDFingerPrint().ToString(),
|
||||
s.Driver.FindElement(By.Id("AccountKeys_0__MasterFingerprint")).GetAttribute("value"));
|
||||
Assert.Contains("m/84'/1'/0'",
|
||||
s.Driver.FindElement(By.Id("AccountKeys_0__AccountKeyPath")).GetAttribute("value"));
|
||||
|
||||
// Make sure we can rescan, because we are admin!
|
||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("Rescan")).Click();
|
||||
Assert.Contains("The batch size make sure", s.Driver.PageSource);
|
||||
|
||||
// Check the tx sent earlier arrived
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
s.Driver.WaitWalletTransactionsLoaded();
|
||||
s.Driver.FindElement(By.CssSelector($"[data-text='{tx}']"));
|
||||
|
||||
var walletTransactionUri = new Uri(s.Driver.Url);
|
||||
|
||||
// Send to bob
|
||||
s.Driver.FindElement(By.Id("WalletNav-Send")).Click();
|
||||
var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest);
|
||||
SetTransactionOutput(s, 0, bob, 1);
|
||||
s.Driver.FindElement(By.Id("SignTransaction")).Click();
|
||||
// Back button should lead back to the previous page inside the send wizard
|
||||
var backUrl = s.Driver.FindElement(By.Id("GoBack")).GetAttribute("href");
|
||||
Assert.EndsWith($"/send?returnUrl={Uri.EscapeDataString(walletTransactionUri.AbsolutePath)}", backUrl);
|
||||
// Cancel button should lead to the page that referred to the send wizard
|
||||
var cancelUrl = s.Driver.FindElement(By.Id("CancelWizard")).GetAttribute("href");
|
||||
Assert.EndsWith(walletTransactionUri.AbsolutePath, cancelUrl);
|
||||
|
||||
// Broadcast
|
||||
Assert.Contains(bob.ToString(), s.Driver.PageSource);
|
||||
Assert.Contains("1.00000000", s.Driver.PageSource);
|
||||
s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click();
|
||||
Assert.Equal(walletTransactionUri.ToString(), s.Driver.Url);
|
||||
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
s.Driver.FindElement(By.Id("WalletNav-Send")).Click();
|
||||
|
||||
var jack = new Key().PubKey.Hash.GetAddress(Network.RegTest);
|
||||
SetTransactionOutput(s, 0, jack, 0.01m);
|
||||
s.Driver.FindElement(By.Id("SignTransaction")).Click();
|
||||
s.Driver.WaitForElement(By.CssSelector("button[value=broadcast]"));
|
||||
Assert.Contains(jack.ToString(), s.Driver.PageSource);
|
||||
Assert.Contains("0.01000000", s.Driver.PageSource);
|
||||
Assert.EndsWith("psbt/ready", s.Driver.Url);
|
||||
s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click();
|
||||
Assert.Equal(walletTransactionUri.ToString(), s.Driver.Url);
|
||||
var bip21 = invoice.EntityToDTO(s.Server.PayTester.GetService<Dictionary<PaymentMethodId, IPaymentMethodBitpayAPIExtension>>(), s.Server.PayTester.GetService<CurrencyNameTable>()).CryptoInfo.First().PaymentUrls.BIP21;
|
||||
//let's make bip21 more interesting
|
||||
bip21 += "&label=Solid Snake&message=Snake? Snake? SNAAAAKE!";
|
||||
var parsedBip21 = new BitcoinUrlBuilder(bip21, Network.RegTest);
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
s.Driver.FindElement(By.Id("WalletNav-Send")).Click();
|
||||
s.Driver.FindElement(By.Id("bip21parse")).Click();
|
||||
s.Driver.SwitchTo().Alert().SendKeys(bip21);
|
||||
s.Driver.SwitchTo().Alert().Accept();
|
||||
s.FindAlertMessage(StatusMessageModel.StatusSeverity.Info);
|
||||
Assert.Equal(parsedBip21.Amount.ToString(false),
|
||||
s.Driver.FindElement(By.Id("Outputs_0__Amount")).GetAttribute("value"));
|
||||
Assert.Equal(parsedBip21.Address.ToString(),
|
||||
s.Driver.FindElement(By.Id("Outputs_0__DestinationAddress")).GetAttribute("value"));
|
||||
|
||||
s.Driver.FindElement(By.Id("CancelWizard")).Click();
|
||||
s.GoToWalletSettings(cryptoCode);
|
||||
var settingsUri = new Uri(s.Driver.Url);
|
||||
s.Driver.FindElement(By.Id("ActionsDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("ViewSeed")).Click();
|
||||
|
||||
// Seed backup page
|
||||
var recoveryPhrase = s.Driver.FindElements(By.Id("RecoveryPhrase")).First()
|
||||
.GetAttribute("data-mnemonic");
|
||||
Assert.Equal(mnemonic.ToString(), recoveryPhrase);
|
||||
Assert.Contains("The recovery phrase will also be stored on the server as a hot wallet.",
|
||||
s.Driver.PageSource);
|
||||
|
||||
// No confirmation, just a link to return to the wallet
|
||||
Assert.Empty(s.Driver.FindElements(By.Id("confirm")));
|
||||
s.Driver.FindElement(By.Id("proceed")).Click();
|
||||
Assert.Equal(settingsUri.ToString(), s.Driver.Url);
|
||||
|
||||
// Once more, test the cancel link of the wallet send page leads back to the previous page
|
||||
s.Driver.FindElement(By.Id("WalletNav-Send")).Click();
|
||||
cancelUrl = s.Driver.FindElement(By.Id("CancelWizard")).GetAttribute("href");
|
||||
Assert.EndsWith(settingsUri.AbsolutePath, cancelUrl);
|
||||
// no previous page in the wizard, hence no back button
|
||||
Assert.True(s.Driver.ElementDoesNotExist(By.Id("GoBack")));
|
||||
s.Driver.FindElement(By.Id("CancelWizard")).Click();
|
||||
Assert.Equal(settingsUri.ToString(), s.Driver.Url);
|
||||
|
||||
// Transactions list contains export, ensure functions are present.
|
||||
s.Driver.FindElement(By.Id($"StoreNav-Wallet{cryptoCode}")).Click();
|
||||
|
||||
s.Driver.FindElement(By.ClassName("mass-action-select-all")).Click();
|
||||
s.Driver.FindElement(By.Id("BumpFee"));
|
||||
|
||||
// JSON export
|
||||
s.Driver.FindElement(By.Id("ExportDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("ExportJSON")).Click();
|
||||
Thread.Sleep(1000);
|
||||
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.Last());
|
||||
Assert.Contains(s.WalletId.ToString(), s.Driver.Url);
|
||||
Assert.EndsWith("export?format=json", s.Driver.Url);
|
||||
Assert.Contains("\"Amount\": \"3.00000000\"", s.Driver.PageSource);
|
||||
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.First());
|
||||
|
||||
// CSV export
|
||||
s.Driver.FindElement(By.Id("ExportDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("ExportCSV")).Click();
|
||||
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.First());
|
||||
|
||||
// BIP-329 export
|
||||
s.Driver.FindElement(By.Id("ExportDropdownToggle")).Click();
|
||||
s.Driver.FindElement(By.Id("ExportBIP329")).Click();
|
||||
s.Driver.SwitchTo().Window(s.Driver.WindowHandles.First());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Selenium", "Selenium")]
|
||||
[Trait("Lightning", "Lightning")]
|
||||
|
||||
Reference in New Issue
Block a user