diff --git a/BTCPayServer.Tests/BTCPayServer.Tests.csproj b/BTCPayServer.Tests/BTCPayServer.Tests.csproj index bd0492c3f..e94ae0358 100644 --- a/BTCPayServer.Tests/BTCPayServer.Tests.csproj +++ b/BTCPayServer.Tests/BTCPayServer.Tests.csproj @@ -23,7 +23,7 @@ - + all @@ -53,8 +53,4 @@ - - - - diff --git a/BTCPayServer.Tests/CheckoutUITests.cs b/BTCPayServer.Tests/CheckoutUITests.cs index 3f92e8913..18bfd3c2b 100644 --- a/BTCPayServer.Tests/CheckoutUITests.cs +++ b/BTCPayServer.Tests/CheckoutUITests.cs @@ -1,10 +1,13 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using BTCPayServer.Payments; using BTCPayServer.Tests.Logging; using BTCPayServer.Views.Stores; using NBitcoin; using OpenQA.Selenium; +using OpenQA.Selenium.Support.UI; using Xunit; using Xunit.Abstractions; diff --git a/BTCPayServer.Tests/Extensions.cs b/BTCPayServer.Tests/Extensions.cs index abd228dcd..aec47e6ef 100644 --- a/BTCPayServer.Tests/Extensions.cs +++ b/BTCPayServer.Tests/Extensions.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using OpenQA.Selenium; +using OpenQA.Selenium.Support.Extensions; using OpenQA.Selenium.Support.UI; using Xunit; @@ -27,46 +28,12 @@ namespace BTCPayServer.Tests public static void AssertNoError(this IWebDriver driver) { - try - { - Assert.NotEmpty(driver.FindElements(By.ClassName("navbar-brand"))); - if (driver.PageSource.Contains("alert-danger")) - { - foreach (var dangerAlert in driver.FindElements(By.ClassName("alert-danger"))) - Assert.False(dangerAlert.Displayed, "No alert should be displayed"); - } - } - catch - { - StringBuilder builder = new StringBuilder(); - builder.AppendLine(); - foreach (var logKind in new[] { LogType.Browser, LogType.Client, LogType.Driver, LogType.Server }) - { - try - { - var logs = driver.Manage().Logs.GetLog(logKind); - builder.AppendLine($"Selenium [{logKind}]:"); - foreach (var entry in logs) - { - builder.AppendLine($"[{entry.Level}]: {entry.Message}"); - } - } - catch - { - // ignored - } - - builder.AppendLine("---------"); - } - Logs.Tester.LogInformation(builder.ToString()); - builder = new StringBuilder(); - builder.AppendLine("Selenium [Sources]:"); - builder.AppendLine(driver.PageSource); - builder.AppendLine("---------"); - Logs.Tester.LogInformation(builder.ToString()); - throw; - } + Assert.NotEmpty(driver.FindElements(By.ClassName("navbar-brand"))); + if (!driver.PageSource.Contains("alert-danger")) return; + foreach (var dangerAlert in driver.FindElements(By.ClassName("alert-danger"))) + Assert.False(dangerAlert.Displayed, $"No alert should be displayed, but found this on {driver.Url}: {dangerAlert.Text}"); } + public static T AssertViewModel(this IActionResult result) { Assert.NotNull(result); @@ -112,6 +79,13 @@ namespace BTCPayServer.Tests wait.Until(d=>((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete")); wait.Until(d=>((IJavaScriptExecutor)d).ExecuteScript("return typeof(jQuery) === 'undefined' || jQuery.active === 0").Equals(true)); } + + // Open collapse via JS, because if we click the link it triggers the toggle animation. + // This leads to Selenium trying to click the button while it is moving resulting in an error. + public static void ToggleCollapse(this IWebDriver driver, string collapseId) + { + driver.ExecuteJavaScript($"document.getElementById('{collapseId}').classList.add('show')"); + } public static IWebElement WaitForElement(this IWebDriver driver, By selector) { diff --git a/BTCPayServer.Tests/PayJoinTests.cs b/BTCPayServer.Tests/PayJoinTests.cs index 7aaac48db..61b7aa472 100644 --- a/BTCPayServer.Tests/PayJoinTests.cs +++ b/BTCPayServer.Tests/PayJoinTests.cs @@ -271,10 +271,8 @@ namespace BTCPayServer.Tests s.Driver.SwitchTo().Alert().Accept(); Assert.False(string.IsNullOrEmpty(s.Driver.FindElement(By.Id("PayJoinBIP21")) .GetAttribute("value"))); - s.Driver.FindElement(By.Id("SendMenu")).Click(); - var nbxSeedButton = s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")); - new WebDriverWait(s.Driver, SeleniumTester.ImplicitWait).Until(d=> nbxSeedButton.Enabled); - nbxSeedButton.Click(); + s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); + s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); await s.Server.WaitForEvent(() => { s.Driver.FindElement(By.CssSelector("button[value=payjoin]")).Click(); @@ -309,7 +307,7 @@ namespace BTCPayServer.Tests .GetAttribute("value"))); s.Driver.FindElement(By.Id("FeeSatoshiPerByte")).Clear(); s.Driver.FindElement(By.Id("FeeSatoshiPerByte")).SendKeys("2"); - s.Driver.FindElement(By.Id("SendMenu")).Click(); + s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); var txId = await s.Server.WaitForEvent(() => { diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index 641c4c09f..44e4e9590 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -63,21 +63,17 @@ namespace BTCPayServer.Tests } options.AddArguments($"window-size={windowSize.Width}x{windowSize.Height}"); options.AddArgument("shm-size=2g"); + options.AddArgument("start-maximized"); var cds = ChromeDriverService.CreateDefaultService(chromeDriverPath); + cds.EnableVerboseLogging = true; cds.Port = Utils.FreeTcpPort(); cds.HostName = "127.0.0.1"; cds.Start(); Driver = new ChromeDriver(cds, options, // A bit less than test timeout TimeSpan.FromSeconds(50)); - - if (runInBrowser) - { - // ensure maximized window size - // otherwise TESTS WILL FAIL because of different hierarchy in navigation menu - Driver.Manage().Window.Maximize(); - } + Driver.Manage().Window.Maximize(); Logs.Tester.LogInformation($"Selenium: Using {Driver.GetType()}"); Logs.Tester.LogInformation($"Selenium: Browsing to {Server.PayTester.ServerUri}"); @@ -159,11 +155,8 @@ namespace BTCPayServer.Tests Driver.FindElement(By.Id("ScriptPubKeyType")).Click(); Driver.FindElement(By.CssSelector($"#ScriptPubKeyType option[value={format}]")).Click(); - - // Open advanced settings via JS, because if we click the link it triggers the toggle animation. - // This leads to Selenium trying to click the button while it is moving resulting in an error. - Driver.ExecuteJavaScript("document.getElementById('AdvancedSettings').classList.add('show')"); - + + Driver.ToggleCollapse("AdvancedSettings"); Driver.SetCheckbox(By.Id("ImportKeysToRPC"), importkeys); Driver.FindElement(By.Id("Continue")).Click(); @@ -370,7 +363,7 @@ namespace BTCPayServer.Tests Driver.FindElement(By.Id("bip21parse")).Click(); Driver.SwitchTo().Alert().SendKeys(bip21); Driver.SwitchTo().Alert().Accept(); - Driver.FindElement(By.Id("SendMenu")).Click(); + Driver.FindElement(By.Id("SendDropdownToggle")).Click(); Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); } diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index bd8e7a9f6..14dab0213 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -78,16 +78,16 @@ namespace BTCPayServer.Tests Assert.Contains("server/services/lndseedbackup/BTC", s.Driver.PageSource); s.Driver.Navigate().GoToUrl(s.Link("/server/services/lndseedbackup/BTC")); s.Driver.FindElement(By.Id("details")).Click(); - var seedEl = s.Driver.FindElement(By.Id("SeedTextArea")); + var seedEl = s.Driver.FindElement(By.Id("Seed")); Assert.True(seedEl.Displayed); Assert.Contains("about over million", seedEl.Text, StringComparison.OrdinalIgnoreCase); - var passEl = s.Driver.FindElement(By.Id("PasswordInput")); + var passEl = s.Driver.FindElement(By.Id("WalletPassword")); Assert.True(passEl.Displayed); Assert.Contains(passEl.Text, "hellorockstar", StringComparison.OrdinalIgnoreCase); s.Driver.FindElement(By.Id("delete")).Click(); s.Driver.FindElement(By.Id("continue")).Click(); s.FindAlertMessage(); - seedEl = s.Driver.FindElement(By.Id("SeedTextArea")); + seedEl = s.Driver.FindElement(By.Id("Seed")); Assert.Contains("Seed removed", seedEl.Text, StringComparison.OrdinalIgnoreCase); } } @@ -574,7 +574,6 @@ namespace BTCPayServer.Tests } } - [Fact(Timeout = TestTimeout)] public async Task CanUseCoinSelection() { @@ -611,7 +610,7 @@ namespace BTCPayServer.Tests }); await s.Server.ExplorerNode.GenerateAsync(1); s.GoToWallet(walletId); - s.Driver.FindElement(By.Id("advancedSettings")).Click(); + s.Driver.ToggleCollapse("AdvancedSettings"); s.Driver.WaitForAndClick(By.Id("toggleInputSelection")); s.Driver.FindElement(By.Id(spentOutpoint.ToString())); Assert.Equal("true", s.Driver.FindElement(By.Name("InputSelection")).GetAttribute("value").ToLowerInvariant()); @@ -622,7 +621,7 @@ namespace BTCPayServer.Tests var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); SetTransactionOutput(s, 0, bob, 0.3m); - s.Driver.FindElement(By.Id("SendMenu")).Click(); + s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); s.Driver.FindElement(By.Id("spendWithNBxplorer")).Click(); s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); var happyElement = s.FindAlertMessage(); @@ -643,15 +642,14 @@ namespace BTCPayServer.Tests await s.StartAsync(); s.RegisterNewUser(true); var (storeName, storeId) = s.CreateNewStore(); - s.GoToStore(storeId, Views.Stores.StoreNavPages.Webhooks); + s.GoToStore(storeId, StoreNavPages.Webhooks); Logs.Tester.LogInformation("Let's create two webhooks"); for (var i = 0; i < 2; i++) { s.Driver.FindElement(By.Id("CreateWebhook")).Click(); s.Driver.FindElement(By.Name("PayloadUrl")).SendKeys($"http://127.0.0.1/callback{i}"); - new SelectElement(s.Driver.FindElement(By.Name("Everything"))) - .SelectByValue("false"); + new SelectElement(s.Driver.FindElement(By.Id("Everything"))).SelectByValue("false"); s.Driver.FindElement(By.Id("InvoiceCreated")).Click(); s.Driver.FindElement(By.Id("InvoiceProcessing")).Click(); s.Driver.FindElement(By.Name("add")).Click(); @@ -745,9 +743,8 @@ namespace BTCPayServer.Tests Logs.Tester.LogInformation("Let's see if we can delete store with some webhooks inside"); s.GoToStore(storeId); - // Open danger zone via JS, because if we click the link it triggers the toggle animation. - // This leads to Selenium trying to click the button while it is moving resulting in an error. - s.Driver.ExecuteJavaScript("document.getElementById('danger-zone').classList.add('show')"); + + s.Driver.ToggleCollapse("danger-zone"); s.Driver.FindElement(By.Id("delete-store")).Click(); s.Driver.FindElement(By.Id("continue")).Click(); s.FindAlertMessage(); @@ -771,7 +768,7 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("Wallets")).Click(); s.Driver.FindElement(By.LinkText("Manage")).Click(); s.Driver.FindElement(By.Id("WalletSend")).Click(); - s.Driver.FindElement(By.Id("SendMenu")).Click(); + s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); //you cannot use the Sign with NBX option without saving private keys when generating the wallet. Assert.DoesNotContain("nbx-seed", s.Driver.PageSource); @@ -858,7 +855,7 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("WalletSend")).Click(); var bob = new Key().PubKey.Hash.GetAddress(Network.RegTest); SetTransactionOutput(s, 0, bob, 1); - s.Driver.FindElement(By.Id("SendMenu")).Click(); + s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); s.Driver.FindElement(By.CssSelector("button[value=seed]")).Click(); // Input the seed @@ -879,15 +876,17 @@ namespace BTCPayServer.Tests var jack = new Key().PubKey.Hash.GetAddress(Network.RegTest); SetTransactionOutput(s, 0, jack, 0.01m); - s.Driver.FindElement(By.Id("SendMenu")).Click(); - + s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); + Assert.Contains(jack.ToString(), s.Driver.PageSource); Assert.Contains("0.01000000", s.Driver.PageSource); s.Driver.FindElement(By.CssSelector("button[value=analyze-psbt]")).Click(); Assert.EndsWith("psbt", s.Driver.Url); - s.Driver.FindElement(By.CssSelector("#OtherActions")).Click(); + + s.Driver.FindElement(By.Id("OtherActionsDropdownToggle")).Click(); s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); + Assert.EndsWith("psbt/ready", s.Driver.Url); s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); Assert.Equal(walletTransactionLink, s.Driver.Url); @@ -903,13 +902,12 @@ namespace BTCPayServer.Tests 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")); + 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.GoToWallet(new WalletId(storeId, "BTC"), WalletsNavPages.Settings); var walletUrl = s.Driver.Url; - - s.Driver.FindElement(By.Id("SettingsMenu")).Click(); + s.Driver.FindElement(By.Id("OtherActionsDropdownToggle")).Click(); s.Driver.FindElement(By.CssSelector("button[value=view-seed]")).Click(); // Seed backup page @@ -989,14 +987,12 @@ namespace BTCPayServer.Tests Assert.NotEmpty(s.Driver.FindElements(By.ClassName("payout"))); s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-selectAllCheckbox")).Click(); - s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-actions")).Click(); s.Driver.FindElement(By.Id($"{PayoutState.AwaitingApproval}-approve-pay")).Click(); - - s.Driver.FindElement(By.Id("SendMenu")).Click(); + + s.Driver.FindElement(By.Id("SendDropdownToggle")).Click(); s.Driver.FindElement(By.CssSelector("button[value=nbx-seed]")).Click(); s.Driver.FindElement(By.CssSelector("button[value=broadcast]")).Click(); - s.FindAlertMessage(); TestUtils.Eventually(() => @@ -1053,8 +1049,9 @@ namespace BTCPayServer.Tests private static void CanSetupEmailCore(SeleniumTester s) { - s.Driver.FindElement(By.ClassName("dropdown-toggle")).Click(); + s.Driver.FindElement(By.Id("QuickFillDropdownToggle")).Click(); s.Driver.FindElement(By.ClassName("dropdown-item")).Click(); + s.Driver.FindElement(By.Id("Settings_Login")).SendKeys("test@gmail.com"); s.Driver.FindElement(By.CssSelector("button[value=\"Save\"]")).Submit(); s.FindAlertMessage(); diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index 4f38bd257..933011a77 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -47,7 +47,7 @@ - + @@ -90,7 +90,6 @@ - @@ -126,15 +125,10 @@ - - - - - - + diff --git a/BTCPayServer/Components/NotificationsDropdown/Default.cshtml b/BTCPayServer/Components/NotificationsDropdown/Default.cshtml index 829c4aed7..518ac4ecf 100644 --- a/BTCPayServer/Components/NotificationsDropdown/Default.cshtml +++ b/BTCPayServer/Components/NotificationsDropdown/Default.cshtml @@ -9,12 +9,12 @@ @if (Model.UnseenCount > 0) {