diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index 599aca5e9..7efe66746 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -138,26 +138,37 @@ retry: } public IWebElement FindAlertMessage(params StatusMessageModel.StatusSeverity[] severity) { - var className = string.Join(", ", severity.Select(statusSeverity => $".alert-{StatusMessageModel.ToString(statusSeverity)}")); - IWebElement el; + int retry = 0; + retry: try { - var elements = Driver.FindElements(By.CssSelector(className)); - el = elements.FirstOrDefault(e => e.Displayed); - if (el is null) - el = elements.FirstOrDefault(); - if (el is null) + var className = string.Join(", ", severity.Select(statusSeverity => $".alert-{StatusMessageModel.ToString(statusSeverity)}")); + IWebElement el; + try + { + var elements = Driver.FindElements(By.CssSelector(className)); + el = elements.FirstOrDefault(e => e.Displayed); + if (el is null) + el = elements.FirstOrDefault(); + if (el is null) + el = Driver.WaitForElement(By.CssSelector(className)); + } + catch (NoSuchElementException) + { el = Driver.WaitForElement(By.CssSelector(className)); + } + if (el is null) + throw new NoSuchElementException($"Unable to find {className}"); + if (!el.Displayed) + throw new ElementNotVisibleException($"{className} is present, but not displayed: {el.GetAttribute("id")} - Text: {el.Text}"); + return el; } - catch (NoSuchElementException) + // Selenium sometimes sucks... + catch (StaleElementReferenceException) when (retry < 5) { - el = Driver.WaitForElement(By.CssSelector(className)); + retry++; + goto retry; } - if (el is null) - throw new NoSuchElementException($"Unable to find {className}"); - if (!el.Displayed) - throw new ElementNotVisibleException($"{className} is present, but not displayed: {el.GetAttribute("id")} - Text: {el.Text}"); - return el; } public string Link(string relativeLink) diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index dee563d2d..74259cbed 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -866,6 +866,7 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("SaveEmailRules")).Click(); // Ensure that the rule is created + s.FindAlertMessage(); Assert.DoesNotContain("There are no rules yet.", s.Driver.PageSource); Assert.Contains("invoicecreated@gmail.com", s.Driver.PageSource); Assert.Contains("Invoice {Invoice.Id} created", s.Driver.PageSource); @@ -881,6 +882,7 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("SaveEmailRules")).Click(); // Validate the second rule is added + s.FindAlertMessage(); Assert.Contains("statuschanged@gmail.com", s.Driver.PageSource); Assert.Contains("Status changed!", s.Driver.PageSource); @@ -897,20 +899,27 @@ namespace BTCPayServer.Tests s.Driver.FindElement(By.Id("SaveEmailRules")).Click(); // Validate that the email is updated in the list of email rules + s.FindAlertMessage(); Assert.Contains("changedagain@gmail.com", s.Driver.PageSource); Assert.DoesNotContain("statuschanged@gmail.com", s.Driver.PageSource); // Delete both email rules - var deleteLinks = s.Driver.FindElements(By.XPath("//a[contains(text(), 'Delete')]")); + var deleteLinks = s.Driver.FindElements(By.XPath("//a[contains(text(), 'Remove')]")); Assert.True(deleteLinks.Count == 2, "Expected exactly two delete buttons but found a different number."); deleteLinks[0].Click(); + s.Driver.WaitForElement(By.Id("ConfirmInput")).SendKeys("REMOVE"); + s.Driver.FindElement(By.Id("ConfirmContinue")).Click(); - deleteLinks = s.Driver.FindElements(By.XPath("//a[contains(text(), 'Delete')]")); // Refresh list + s.FindAlertMessage(); + deleteLinks = s.Driver.FindElements(By.XPath("//a[contains(text(), 'Remove')]")); // Refresh list Assert.True(deleteLinks.Count == 1, "Expected one delete button remaining."); deleteLinks[0].Click(); + s.Driver.WaitForElement(By.Id("ConfirmInput")).SendKeys("REMOVE"); + s.Driver.FindElement(By.Id("ConfirmContinue")).Click(); + s.FindAlertMessage(); // Validate that there are no more rules Assert.Contains("There are no rules yet.", s.Driver.PageSource); } diff --git a/BTCPayServer/Controllers/UIStoresController.EmailRules.cs b/BTCPayServer/Controllers/UIStoresController.EmailRules.cs index 5a66d0b22..9f960cbad 100644 --- a/BTCPayServer/Controllers/UIStoresController.EmailRules.cs +++ b/BTCPayServer/Controllers/UIStoresController.EmailRules.cs @@ -72,6 +72,7 @@ namespace BTCPayServer.Controllers store.SetStoreBlob(blob); await _storeRepo.UpdateStore(store); + this.TempData.SetStatusSuccess(StringLocalizer["Email rule successfully created"]); return RedirectToAction(nameof(StoreEmailRulesList), new { storeId }); } @@ -111,6 +112,7 @@ namespace BTCPayServer.Controllers store.SetStoreBlob(blob); await _storeRepo.UpdateStore(store); + this.TempData.SetStatusSuccess(StringLocalizer["Email rule successfully updated"]); return RedirectToAction(nameof(StoreEmailRulesList), new { storeId }); } @@ -128,6 +130,7 @@ namespace BTCPayServer.Controllers store.SetStoreBlob(blob); await _storeRepo.UpdateStore(store); + this.TempData.SetStatusSuccess(StringLocalizer["Email rule successfully deleted"]); return RedirectToAction(nameof(StoreEmailRulesList), new { storeId }); } diff --git a/BTCPayServer/Views/UIStores/StoreEmailRulesList.cshtml b/BTCPayServer/Views/UIStores/StoreEmailRulesList.cshtml index e949b7fbf..cd86b799c 100644 --- a/BTCPayServer/Views/UIStores/StoreEmailRulesList.cshtml +++ b/BTCPayServer/Views/UIStores/StoreEmailRulesList.cshtml @@ -1,3 +1,4 @@ +@using BTCPayServer.Abstractions.Models @using BTCPayServer.Client @using BTCPayServer.TagHelpers @using Microsoft.AspNetCore.Mvc.TagHelpers @@ -38,7 +39,7 @@ Customer Email To Subject - Actions + @@ -49,12 +50,11 @@ @(rule.value.CustomerEmail ? "Yes" : "No") @rule.value.To @rule.value.Subject - - Edit - - -
- Delete -
+ +
+ Edit + {0}.", Html.Encode(rule.value.Trigger)]" data-confirm-input="@StringLocalizer["REMOVE"]" text-translate="true">Remove +
} @@ -68,3 +68,5 @@ else There are no rules yet.

} + +