diff --git a/BTCPayServer.Tests/PlaywrightTester.cs b/BTCPayServer.Tests/PlaywrightTester.cs index d4add1fcb..29e69917d 100644 --- a/BTCPayServer.Tests/PlaywrightTester.cs +++ b/BTCPayServer.Tests/PlaywrightTester.cs @@ -323,7 +323,7 @@ namespace BTCPayServer.Tests await GoToUrl("/login"); } public async Task Logout() - { + { await Page.Locator("#menu-item-Account").ClickAsync(); await Page.Locator("#Nav-Logout").ClickAsync(); } diff --git a/BTCPayServer.Tests/PlaywrightTests.cs b/BTCPayServer.Tests/PlaywrightTests.cs index 228445917..f73fa5e2b 100644 --- a/BTCPayServer.Tests/PlaywrightTests.cs +++ b/BTCPayServer.Tests/PlaywrightTests.cs @@ -2335,8 +2335,7 @@ namespace BTCPayServer.Tests foreach (var path in storeSettingsPaths) { // should have view access to settings, but no submit buttons or create links s.TestLogs.LogInformation($"Checking access to store page {path} as manager"); - await s.AssertPageAccess(true, $"/stores/{storeId}/{path}"); - await s.Page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); + await s.AssertPageAccess(true, $"stores/{storeId}/{path}"); Assert.False(await s.Page.GetByRole(AriaRole.Button, new() { Name = "Save" }).IsVisibleAsync()); } await s.Logout(); @@ -2438,6 +2437,245 @@ namespace BTCPayServer.Tests Assert.False(string.IsNullOrEmpty(pairingCode2)); } + [Fact] + [Trait("Lightning", "Lightning")] + public async Task CanCreateStores() + { + await using var s = CreatePlaywrightTester(); + s.Server.ActivateLightning(); + await s.StartAsync(); + var alice = await s.RegisterNewUser(true); + var (storeName, storeId) = await s.CreateNewStore(); + var storeUrl = $"/stores/{storeId}"; + + await s.GoToStore(storeId); + Assert.Contains(storeName, await s.Page.ContentAsync()); + Assert.DoesNotContain("id=\"Dashboard\"", await s.Page.ContentAsync()); + + // verify steps for wallet setup are displayed correctly + await s.GoToStore(storeId, StoreNavPages.Dashboard); + await s.Page.WaitForSelectorAsync("#SetupGuide-StoreDone"); + await s.Page.WaitForSelectorAsync("#SetupGuide-Wallet"); + await s.Page.WaitForSelectorAsync("#SetupGuide-Lightning"); + + // setup onchain wallet + await s.Page.Locator("#SetupGuide-Wallet").ClickAsync(); + await s.AddDerivationScheme(); + await s.Page.AssertNoError(); + + await s.GoToStore(storeId, StoreNavPages.Dashboard); + await s.Page.WaitForSelectorAsync("#Dashboard"); + Assert.DoesNotContain("id=\"SetupGuide\"", await s.Page.ContentAsync()); + + // setup offchain wallet + await s.Page.Locator("#menu-item-LightningSettings-BTC").ClickAsync(); + await s.AddLightningNode(); + await s.Page.AssertNoError(); + await s.FindAlertMessage(partialText: "BTC Lightning node updated."); + + // Only click on section links if they exist + if (await s.Page.Locator("#SectionNav .nav-link").CountAsync() > 0) + { + await s.ClickOnAllSectionLinks(); + } + + await s.GoToInvoices(storeId); + Assert.Contains("There are no invoices matching your criteria.", await s.Page.ContentAsync()); + var invoiceId = await s.CreateInvoice(storeId); + await s.FindAlertMessage(); + + var invoiceUrl = s.Page.Url; + + //let's test archiving an invoice + Assert.DoesNotContain("Archived", await s.Page.Locator("#btn-archive-toggle").InnerTextAsync()); + await s.Page.Locator("#btn-archive-toggle").ClickAsync(); + Assert.Contains("Unarchive", await s.Page.Locator("#btn-archive-toggle").InnerTextAsync()); + + //check that it no longer appears in list + await s.GoToInvoices(storeId); + Assert.DoesNotContain(invoiceId, await s.Page.ContentAsync()); + + //ok, let's unarchive and see that it shows again + await s.Page.GotoAsync(invoiceUrl); + await s.Page.Locator("#btn-archive-toggle").ClickAsync(); + await s.FindAlertMessage(); + Assert.DoesNotContain("Unarchive", await s.Page.Locator("#btn-archive-toggle").InnerTextAsync()); + await s.GoToInvoices(storeId); + Assert.Contains(invoiceId, await s.Page.ContentAsync()); + + // archive via list + await s.Page.Locator($".mass-action-select[value=\"{invoiceId}\"]").ClickAsync(); + await s.Page.Locator("#ArchiveSelected").ClickAsync(); + Assert.Contains("1 invoice archived", await (await s.FindAlertMessage()).InnerTextAsync()); + Assert.DoesNotContain(invoiceId, await s.Page.ContentAsync()); + + // unarchive via list + await s.Page.Locator("#StatusOptionsToggle").ClickAsync(); + await s.Page.Locator("#StatusOptionsIncludeArchived").ClickAsync(); + Assert.Contains(invoiceId, await s.Page.ContentAsync()); + await s.Page.Locator($".mass-action-select[value=\"{invoiceId}\"]").ClickAsync(); + await s.Page.Locator("#UnarchiveSelected").ClickAsync(); + Assert.Contains("1 invoice unarchived", await (await s.FindAlertMessage()).InnerTextAsync()); + Assert.Contains(invoiceId, await s.Page.ContentAsync()); + + // When logout out we should not be able to access store and invoice details + await s.GoToUrl("/account"); + await s.Logout(); + await s.GoToUrl(storeUrl); + Assert.Contains("ReturnUrl", s.Page.Url); + await s.Page.GotoAsync(invoiceUrl); + Assert.Contains("ReturnUrl", s.Page.Url); + await s.GoToRegister(); + + // When logged in as different user we should not be able to access store and invoice details + var bob = await s.RegisterNewUser(); + await s.GoToUrl(storeUrl); + Assert.Contains("ReturnUrl", s.Page.Url); + await s.Page.GotoAsync(invoiceUrl); + Assert.Contains("ReturnUrl", s.Page.Url); + // s.AssertAccessDenied(); // TODO: Playwright equivalent if needed + await s.GoToUrl("/account"); + await s.Logout(); + + // Let's add Bob as an employee to alice's store + await s.LogIn(alice); + await s.AddUserToStore(storeId, bob, "Employee"); + await s.Logout(); + + // Bob should not have access to store, but should have access to invoice + await s.LogIn(bob); + await s.GoToUrl(storeUrl); + Assert.Contains("ReturnUrl", s.Page.Url); + await s.GoToUrl(invoiceUrl); + await s.Page.AssertNoError(); + await s.GoToUrl("/account"); + await s.Logout(); + await s.LogIn(alice); + + // Check if we can enable the payment button + await s.GoToStore(storeId, StoreNavPages.PayButton); + await s.Page.Locator("#enable-pay-button").ClickAsync(); + await s.Page.Locator("#disable-pay-button").ClickAsync(); + await s.FindAlertMessage(); + await s.GoToStore(storeId); + Assert.False(await s.Page.Locator("#AnyoneCanCreateInvoice").IsCheckedAsync()); + await s.Page.Locator("#AnyoneCanCreateInvoice").CheckAsync(); + await s.ClickPagePrimary(); + await s.FindAlertMessage(); + Assert.True(await s.Page.Locator("#AnyoneCanCreateInvoice").IsCheckedAsync()); + + // Store settings: Set and unset brand color + await s.GoToStore(storeId); + await s.Page.Locator("#BrandColor").FillAsync("#f7931a"); + await s.ClickPagePrimary(); + Assert.Contains("Store successfully updated", await (await s.FindAlertMessage()).InnerTextAsync()); + Assert.Equal("#f7931a", await s.Page.Locator("#BrandColor").InputValueAsync()); + await s.Page.Locator("#BrandColor").FillAsync(""); + await s.ClickPagePrimary(); + Assert.Contains("Store successfully updated", await (await s.FindAlertMessage()).InnerTextAsync()); + Assert.Equal(string.Empty, await s.Page.Locator("#BrandColor").InputValueAsync()); + + // Alice should be able to delete the store + await s.GoToStore(storeId); + await s.Page.Locator("#DeleteStore").ClickAsync(); + await s.Page.Locator("#ConfirmInput").FillAsync("DELETE"); + await s.Page.Locator("#ConfirmContinue").ClickAsync(); + await s.GoToUrl(storeUrl); + Assert.Contains("ReturnUrl", s.Page.Url); + + // Archive store + (storeName, storeId) = await s.CreateNewStore(); + + await s.Page.Locator("#StoreSelectorToggle").ClickAsync(); + Assert.Contains(storeName, await s.Page.Locator("#StoreSelectorMenu").InnerTextAsync()); + await s.Page.Locator($"#StoreSelectorMenuItem-{storeId}").ClickAsync(); + await s.GoToStore(storeId); + await s.Page.Locator("#btn-archive-toggle").ClickAsync(); + Assert.Contains("The store has been archived and will no longer appear in the stores list by default.", await (await s.FindAlertMessage()).InnerTextAsync()); + + await s.Page.Locator("#StoreSelectorToggle").ClickAsync(); + Assert.DoesNotContain(storeName, await s.Page.Locator("#StoreSelectorMenu").InnerTextAsync()); + Assert.Contains("1 Archived Store", await s.Page.Locator("#StoreSelectorMenu").InnerTextAsync()); + await s.Page.Locator("#StoreSelectorArchived").ClickAsync(); + + var storeLink = s.Page.Locator($"#Store-{storeId}"); + Assert.Contains(storeName, await storeLink.InnerTextAsync()); + await s.GoToStore(storeId); + await s.Page.Locator("#btn-archive-toggle").ClickAsync(); + Assert.Contains("The store has been unarchived and will appear in the stores list by default again.", await (await s.FindAlertMessage()).InnerTextAsync()); + } + + [Fact] + public async Task CanUseCoinSelection() + { + await using var s = CreatePlaywrightTester(); + await s.StartAsync(); + await s.RegisterNewUser(true); + var (_, storeId) = await s.CreateNewStore(); + await s.GenerateWallet("BTC", "", false, true); + var walletId = new WalletId(storeId, "BTC"); + await s.GoToWallet(walletId, WalletsNavPages.Receive); + var addressStr = await s.Page.Locator("#Address").GetAttributeAsync("data-text"); + var address = BitcoinAddress.Create(addressStr!, ((BTCPayNetwork)s.Server.NetworkProvider.GetNetwork("BTC")).NBitcoinNetwork); + await s.Server.ExplorerNode.GenerateAsync(1); + for (int i = 0; i < 6; i++) + { + await s.Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(1.0m)); + } + var handlers = s.Server.PayTester.GetService(); + var targetTx = await s.Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(1.2m)); + var tx = await s.Server.ExplorerNode.GetRawTransactionAsync(targetTx); + var spentOutpoint = new OutPoint(targetTx, tx.Outputs.FindIndex(txout => txout.Value == Money.Coins(1.2m))); + var pmi = PaymentTypes.CHAIN.GetPaymentMethodId(walletId.CryptoCode); + await TestUtils.EventuallyAsync(async () => + { + var store = await s.Server.PayTester.StoreRepository.FindStore(storeId); + var x = store.GetPaymentMethodConfig(pmi, handlers); + var wallet = s.Server.PayTester.GetService().GetWallet(walletId.CryptoCode); + wallet.InvalidateCache(x.AccountDerivation); + Assert.Contains( + await wallet.GetUnspentCoins(x.AccountDerivation), + coin => coin.OutPoint == spentOutpoint); + }); + await s.Server.ExplorerNode.GenerateAsync(1); + await s.GoToWallet(walletId, WalletsNavPages.Send); + await s.Page.Locator("#toggleInputSelection").ClickAsync(); + await s.Page.Locator($"[id='{spentOutpoint}']").WaitForAsync(); + Assert.Equal("true", (await s.Page.Locator("[name='InputSelection']").InputValueAsync()).ToLowerInvariant()); + + // Select All test + await s.Page.Locator("#select-all-checkbox").ClickAsync(); + var selectedOptions = await s.Page.Locator("[name='SelectedInputs'] option[selected]").AllAsync(); + var listItems = await s.Page.Locator("li.list-group-item").AllAsync(); + Assert.Equal(listItems.Count, selectedOptions.Count); + await s.Page.Locator("#select-all-checkbox").ClickAsync(); + selectedOptions = await s.Page.Locator("[name='SelectedInputs'] option[selected]").AllAsync(); + Assert.Empty(selectedOptions); + + await s.Page.Locator($"[id='{spentOutpoint}']").ClickAsync(); + selectedOptions = await s.Page.Locator("[name='SelectedInputs'] option[selected]").AllAsync(); + Assert.Single(selectedOptions); + + var bob = new NBitcoin.Key().PubKey.Hash.GetAddress(NBitcoin.Network.RegTest); + await s.Page.Locator("[name='Outputs[0].DestinationAddress']").FillAsync(bob.ToString()); + var amountInput = s.Page.Locator("[name='Outputs[0].Amount']"); + await amountInput.FillAsync("0.3"); + var checkboxElement = s.Page.Locator("input[type='checkbox'][name='Outputs[0].SubtractFeesFromOutput']"); + if (!await checkboxElement.IsCheckedAsync()) + { + await checkboxElement.ClickAsync(); + } + await s.Page.Locator("#SignTransaction").ClickAsync(); + await s.Page.Locator("button[value='broadcast']").ClickAsync(); + var happyElement = await s.FindAlertMessage(); + var happyText = await happyElement.InnerTextAsync(); + var txid = System.Text.RegularExpressions.Regex.Match(happyText, @"\((.*)\)").Groups[1].Value; + + tx = await s.Server.ExplorerNode.GetRawTransactionAsync(new uint256(txid)); + Assert.Single(tx.Inputs); + Assert.Equal(spentOutpoint, tx.Inputs[0].PrevOut); + } + } } diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index e29e02310..7d4f8fe1c 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -134,168 +134,6 @@ namespace BTCPayServer.Tests }); } - [Fact(Timeout = TestTimeout)] - [Trait("Lightning", "Lightning")] - public async Task CanCreateStores() - { - using var s = CreateSeleniumTester(); - s.Server.ActivateLightning(); - await s.StartAsync(); - var alice = s.RegisterNewUser(true); - (string storeName, string storeId) = s.CreateNewStore(); - var storeUrl = $"/stores/{storeId}"; - - s.GoToStore(); - Assert.Contains(storeName, s.Driver.PageSource); - Assert.DoesNotContain("id=\"Dashboard\"", s.Driver.PageSource); - - // verify steps for wallet setup are displayed correctly - s.GoToStore(StoreNavPages.Dashboard); - Assert.True(s.Driver.FindElement(By.Id("SetupGuide-StoreDone")).Displayed); - Assert.True(s.Driver.FindElement(By.Id("SetupGuide-Wallet")).Displayed); - Assert.True(s.Driver.FindElement(By.Id("SetupGuide-Lightning")).Displayed); - - // setup onchain wallet - s.Driver.FindElement(By.Id("SetupGuide-Wallet")).Click(); - s.AddDerivationScheme(); - s.Driver.AssertNoError(); - - s.GoToStore(StoreNavPages.Dashboard); - Assert.DoesNotContain("id=\"SetupGuide\"", s.Driver.PageSource); - Assert.True(s.Driver.FindElement(By.Id("Dashboard")).Displayed); - - // setup offchain wallet - s.Driver.FindElement(By.CssSelector("[data-testid='Lightning-BTC']")).Click(); - s.AddLightningNode(); - s.Driver.AssertNoError(); - var successAlert = s.FindAlertMessage(); - Assert.Contains("BTC Lightning node updated.", successAlert.Text); - - s.ClickOnAllSectionLinks(); - - s.GoToInvoices(); - Assert.Contains("There are no invoices matching your criteria.", s.Driver.PageSource); - var invoiceId = s.CreateInvoice(); - s.FindAlertMessage(); - - var invoiceUrl = s.Driver.Url; - - //let's test archiving an invoice - Assert.DoesNotContain("Archived", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text); - s.Driver.FindElement(By.Id("btn-archive-toggle")).Click(); - Assert.Contains("Unarchive", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text); - - //check that it no longer appears in list - s.GoToInvoices(); - Assert.DoesNotContain(invoiceId, s.Driver.PageSource); - - //ok, let's unarchive and see that it shows again - s.Driver.Navigate().GoToUrl(invoiceUrl); - s.Driver.FindElement(By.Id("btn-archive-toggle")).Click(); - s.FindAlertMessage(); - Assert.DoesNotContain("Unarchive", s.Driver.FindElement(By.Id("btn-archive-toggle")).Text); - s.GoToInvoices(); - Assert.Contains(invoiceId, s.Driver.PageSource); - - // archive via list - s.Driver.FindElement(By.CssSelector($".mass-action-select[value=\"{invoiceId}\"]")).Click(); - s.Driver.FindElement(By.Id("ArchiveSelected")).Click(); - Assert.Contains("1 invoice archived", s.FindAlertMessage().Text); - Assert.DoesNotContain(invoiceId, s.Driver.PageSource); - - // unarchive via list - s.Driver.FindElement(By.Id("StatusOptionsToggle")).Click(); - s.Driver.FindElement(By.Id("StatusOptionsIncludeArchived")).Click(); - Assert.Contains(invoiceId, s.Driver.PageSource); - s.Driver.FindElement(By.CssSelector($".mass-action-select[value=\"{invoiceId}\"]")).Click(); - s.Driver.FindElement(By.Id("UnarchiveSelected")).Click(); - Assert.Contains("1 invoice unarchived", s.FindAlertMessage().Text); - Assert.Contains(invoiceId, s.Driver.PageSource); - - // When logout out we should not be able to access store and invoice details - s.Logout(); - s.GoToUrl(storeUrl); - Assert.Contains("ReturnUrl", s.Driver.Url); - s.Driver.Navigate().GoToUrl(invoiceUrl); - Assert.Contains("ReturnUrl", s.Driver.Url); - s.GoToRegister(); - - // When logged in as different user we should not be able to access store and invoice details - var bob = s.RegisterNewUser(); - s.GoToUrl(storeUrl); - Assert.Contains("ReturnUrl", s.Driver.Url); - s.Driver.Navigate().GoToUrl(invoiceUrl); - s.AssertAccessDenied(); - s.GoToHome(); - s.Logout(); - - // Let's add Bob as an employee to alice's store - s.LogIn(alice); - s.AddUserToStore(storeId, bob, "Employee"); - s.Logout(); - - // Bob should not have access to store, but should have access to invoice - s.LogIn(bob); - s.GoToUrl(storeUrl); - Assert.Contains("ReturnUrl", s.Driver.Url); - s.GoToUrl(invoiceUrl); - s.Driver.AssertNoError(); - - s.Logout(); - s.LogIn(alice); - - // Check if we can enable the payment button - s.GoToStore(StoreNavPages.PayButton); - s.Driver.FindElement(By.Id("enable-pay-button")).Click(); - s.Driver.FindElement(By.Id("disable-pay-button")).Click(); - s.FindAlertMessage(); - s.GoToStore(); - Assert.False(s.Driver.FindElement(By.Id("AnyoneCanCreateInvoice")).Selected); - s.Driver.SetCheckbox(By.Id("AnyoneCanCreateInvoice"), true); - s.ClickPagePrimary(); - s.FindAlertMessage(); - Assert.True(s.Driver.FindElement(By.Id("AnyoneCanCreateInvoice")).Selected); - - // Store settings: Set and unset brand color - s.GoToStore(); - s.Driver.FindElement(By.Id("BrandColor")).SendKeys("#f7931a"); - s.ClickPagePrimary(); - Assert.Contains("Store successfully updated", s.FindAlertMessage().Text); - Assert.Equal("#f7931a", s.Driver.FindElement(By.Id("BrandColor")).GetAttribute("value")); - s.Driver.FindElement(By.Id("BrandColor")).Clear(); - s.ClickPagePrimary(); - Assert.Contains("Store successfully updated", s.FindAlertMessage().Text); - Assert.Equal(string.Empty, s.Driver.FindElement(By.Id("BrandColor")).GetAttribute("value")); - - // Alice should be able to delete the store - s.GoToStore(); - s.Driver.FindElement(By.Id("DeleteStore")).Click(); - s.Driver.WaitForElement(By.Id("ConfirmInput")).SendKeys("DELETE"); - s.Driver.FindElement(By.Id("ConfirmContinue")).Click(); - s.GoToUrl(storeUrl); - Assert.Contains("ReturnUrl", s.Driver.Url); - - // Archive store - (storeName, storeId) = s.CreateNewStore(); - - s.Driver.FindElement(By.Id("StoreSelectorToggle")).Click(); - Assert.Contains(storeName, s.Driver.FindElement(By.Id("StoreSelectorMenu")).Text); - s.Driver.FindElement(By.Id($"StoreSelectorMenuItem-{storeId}")).Click(); - s.GoToStore(); - s.Driver.FindElement(By.Id("btn-archive-toggle")).Click(); - Assert.Contains("The store has been archived and will no longer appear in the stores list by default.", s.FindAlertMessage().Text); - - s.Driver.FindElement(By.Id("StoreSelectorToggle")).Click(); - Assert.DoesNotContain(storeName, s.Driver.FindElement(By.Id("StoreSelectorMenu")).Text); - Assert.Contains("1 Archived Store", s.Driver.FindElement(By.Id("StoreSelectorMenu")).Text); - s.Driver.FindElement(By.Id("StoreSelectorArchived")).Click(); - - var storeLink = s.Driver.FindElement(By.Id($"Store-{storeId}")); - Assert.Contains(storeName, storeLink.Text); - s.GoToStore(storeId); - s.Driver.FindElement(By.Id("btn-archive-toggle")).Click(); - Assert.Contains("The store has been unarchived and will appear in the stores list by default again.", s.FindAlertMessage().Text); - } [Fact(Timeout = TestTimeout)] public async Task CanCreateAppPoS() @@ -702,83 +540,6 @@ namespace BTCPayServer.Tests s.Driver.SwitchTo().Window(s.Driver.WindowHandles[0]); Assert.Equal("Settled", s.Driver.WaitForElement(By.CssSelector("[data-test='status']")).Text); } - - [Fact(Timeout = TestTimeout)] - public async Task CanUseCoinSelection() - { - using var s = CreateSeleniumTester(); - await s.StartAsync(); - s.RegisterNewUser(true); - (_, string storeId) = s.CreateNewStore(); - s.GenerateWallet("BTC", "", false, true); - var walletId = new WalletId(storeId, "BTC"); - s.GoToWallet(walletId, WalletsNavPages.Receive); - var addressStr = s.Driver.FindElement(By.Id("Address")).GetAttribute("data-text"); - var address = BitcoinAddress.Create(addressStr, - ((BTCPayNetwork)s.Server.NetworkProvider.GetNetwork("BTC")).NBitcoinNetwork); - await s.Server.ExplorerNode.GenerateAsync(1); - for (int i = 0; i < 6; i++) - { - await s.Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(1.0m)); - } - var handlers = s.Server.PayTester.GetService(); - var targetTx = await s.Server.ExplorerNode.SendToAddressAsync(address, Money.Coins(1.2m)); - var tx = await s.Server.ExplorerNode.GetRawTransactionAsync(targetTx); - var spentOutpoint = new OutPoint(targetTx, - tx.Outputs.FindIndex(txout => txout.Value == Money.Coins(1.2m))); - var pmi = PaymentTypes.CHAIN.GetPaymentMethodId(walletId.CryptoCode); - await TestUtils.EventuallyAsync(async () => - { - var store = await s.Server.PayTester.StoreRepository.FindStore(storeId); - var x = store.GetPaymentMethodConfig(pmi, handlers); - var wallet = s.Server.PayTester.GetService().GetWallet(walletId.CryptoCode); - wallet.InvalidateCache(x.AccountDerivation); - Assert.Contains( - await wallet.GetUnspentCoins(x.AccountDerivation), - coin => coin.OutPoint == spentOutpoint); - }); - await s.Server.ExplorerNode.GenerateAsync(1); - s.GoToWallet(walletId); - s.Driver.WaitForAndClick(By.Id("toggleInputSelection")); - s.Driver.WaitForElement(By.Id(spentOutpoint.ToString())); - Assert.Equal("true", - s.Driver.FindElement(By.Name("InputSelection")).GetAttribute("value").ToLowerInvariant()); - - //Select All test - s.Driver.WaitForAndClick(By.Id("select-all-checkbox")); - var inputSelectionSelectAll = s.Driver.FindElement(By.Name("SelectedInputs")); - TestUtils.Eventually(() => { - var selectedOptions = inputSelectionSelectAll.FindElements(By.CssSelector("option[selected]")); - var listItems = s.Driver.FindElements(By.CssSelector("li.list-group-item")); - Assert.Equal(listItems.Count, selectedOptions.Count); - }); - s.Driver.WaitForAndClick(By.Id("select-all-checkbox")); - TestUtils.Eventually(() => { - var selectedOptions = inputSelectionSelectAll.FindElements(By.CssSelector("option[selected]")); - Assert.Empty(selectedOptions); - }); - - s.Driver.FindElement(By.Id(spentOutpoint.ToString())); - s.Driver.FindElement(By.Id(spentOutpoint.ToString())).Click(); - var inputSelectionSelect = s.Driver.FindElement(By.Name("SelectedInputs")); - Assert.Single(inputSelectionSelect.FindElements(By.CssSelector("[selected]"))); - - var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); - SetTransactionOutput(s, 0, bob, 0.3m); - s.Driver.FindElement(By.Id("SignTransaction")).Click(); - s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); - var happyElement = s.FindAlertMessage(); - var happyText = happyElement.Text; - var txid = Regex.Match(happyText, @"\((.*)\)").Groups[1].Value; - - tx = await s.Server.ExplorerNode.GetRawTransactionAsync(new uint256(txid)); - Assert.Single(tx.Inputs); - Assert.Equal(spentOutpoint, tx.Inputs[0].PrevOut); - } - - - - [Fact] [Trait("Selenium", "Selenium")] [Trait("Lightning", "Lightning")]