diff --git a/.github/uitest/uitest.ps1 b/.github/uitest/uitest.ps1 index 68e5c0a445..5e56394683 100644 --- a/.github/uitest/uitest.ps1 +++ b/.github/uitest/uitest.ps1 @@ -74,6 +74,7 @@ function Publish-Sample { "-p:PublishProfile=$root\.github\uitest\GenericPublish.pubxml", ` "-p:DeployOnBuild=true", ` "-p:Configuration=$config", ` + "-p:WarningLevel=0", ` "-p:SourceLinkCreate=true" Wait-Process -InputObject $msBuildProcess if ($msBuildProcess.ExitCode -ne 0) { @@ -192,6 +193,7 @@ try { "--no-restore", ` "--logger", ` "trx;LogFileName=$TrxName", ` + "-p:WarningLevel=0", ` "--results-directory", ` "$testResultsDir" Wait-Process -InputObject $uiTestProcess diff --git a/.github/uitest/uitest.sh b/.github/uitest/uitest.sh index 159025833c..108ebdc48c 100644 --- a/.github/uitest/uitest.sh +++ b/.github/uitest/uitest.sh @@ -168,6 +168,7 @@ function start_samples { PORT=$2 PID_VAR=$3 dotnet run --project "$ROOT/${PROJECT}" \ + -p:WarningLevel=0 \ --no-restore \ --configuration "$CONFIGURATION" \ -- \ diff --git a/src/Samples/Tests/Tests/Control/CheckBoxTests.cs b/src/Samples/Tests/Tests/Control/CheckBoxTests.cs index 3b731dff94..2bcc462c9b 100644 --- a/src/Samples/Tests/Tests/Control/CheckBoxTests.cs +++ b/src/Samples/Tests/Tests/Control/CheckBoxTests.cs @@ -187,7 +187,7 @@ public void Control_CheckBox_CheckBoxObjects() AssertUI.TextEquals(ul.ElementAt("li", 1), "3: Blue"); // click button - browser.Single("input[type=button]").Click().Wait(); + browser.Single("input[type=button]").Click(); AssertUI.IsNotChecked(checkboxes[0]); AssertUI.IsChecked(checkboxes[1]); AssertUI.IsNotChecked(checkboxes[2]); diff --git a/src/Samples/Tests/Tests/ErrorsTests.cs b/src/Samples/Tests/Tests/ErrorsTests.cs index bcedfea2f8..ec228b5656 100644 --- a/src/Samples/Tests/Tests/ErrorsTests.cs +++ b/src/Samples/Tests/Tests/ErrorsTests.cs @@ -8,6 +8,7 @@ using Xunit.Abstractions; using Riganti.Selenium.DotVVM; using OpenQA.Selenium; +using System.Net.Http; namespace DotVVM.Samples.Tests { @@ -313,7 +314,9 @@ public void Error_ExceptionWindow_DotNetReferenceSourceRedirect() var query = link.Substring(startQuery + 2); //Log("query: " + query); var specificLink = "https://referencesource.microsoft.com/api/symbols/?symbol=" + query; +#pragma warning disable SYSLIB0014 // obsolete warning, they can't remove this anyway :) using (var wc = new System.Net.WebClient()) +#pragma warning restore SYSLIB0014 { var downloadedString = wc.DownloadString(specificLink); if (downloadedString.IndexOf("No results found", StringComparison.OrdinalIgnoreCase) != -1) @@ -364,7 +367,9 @@ public void Error_ExceptionWindow_GitHubRedirect() var link = browser.FindElements("div.exceptionStackTrace span.docLinks a") .First(s => s.Children.Any(c => c.GetTagName() == "img" && ((c.GetAttribute("src")?.IndexOf("github", StringComparison.OrdinalIgnoreCase) ?? -1) > -1))) .GetAttribute("href"); +#pragma warning disable SYSLIB0014 // obsolete warning var wr = (System.Net.HttpWebRequest)System.Net.WebRequest.CreateHttp(link); +#pragma warning restore SYSLIB0014 using (var response = wr.GetResponse()) { diff --git a/src/Samples/Tests/Tests/Feature/ApiTests.cs b/src/Samples/Tests/Tests/Feature/ApiTests.cs index c8f84998a4..a28a467c38 100644 --- a/src/Samples/Tests/Tests/Feature/ApiTests.cs +++ b/src/Samples/Tests/Tests/Feature/ApiTests.cs @@ -9,6 +9,7 @@ using Riganti.Selenium.DotVVM; using Xunit; using Xunit.Abstractions; +using static DotVVM.Samples.Tests.UITestUtils; namespace DotVVM.Samples.Tests.Feature { @@ -24,43 +25,46 @@ public void Feature_Api_GetCollection() // click the first button (ID = 11) browser.WaitFor(() => { - browser.First(".id-company[data-company-id='11'] input[type=button]").Click() - .Wait(); + browser.First(".id-company[data-company-id='11'] input[type=button]").Click(); }, 30000, "Cannot find CompanyID = 11. Probably data are not loaded. (The page did not load in 5s.)"); // ensure that orders have been loaded - var orders = browser.FindElements(".id-order"); - AssertUI.Any(orders).Attribute("data-order-id", "6"); + WaitForIgnoringStaleElements(() => { + AssertUI.Any(browser.FindElements(".id-order"), waitForOptions: WaitForOptions.Disabled).Attribute("data-order-id", "6"); + }); - var idToDelete = orders[2].GetAttribute("data-order-id"); // every order has two elements (read-only and edit) + var idToDelete = browser.FindElements(".id-order")[2].GetAttribute("data-order-id"); // every order has two elements (read-only and edit) // delete order (ID = 7) - browser.First($".id-order[data-order-id='{idToDelete}'] input[type=button][value=Delete]").Click().Wait(); - orders = browser.FindElements(".id-order"); - AssertUI.Any(orders).Attribute("data-order-id", "6"); - AssertUI.All(orders).Attribute("data-order-id", s => s != idToDelete); + browser.First($".id-order[data-order-id='{idToDelete}'] input[type=button][value=Delete]").Click(); + WaitForIgnoringStaleElements(() => { + AssertUI.Any(browser.FindElements(".id-order"), WaitForOptions.Disabled).Attribute("data-order-id", "6"); + AssertUI.All(browser.FindElements(".id-order"), WaitForOptions.Disabled).Attribute("data-order-id", s => s != idToDelete); + }); // click the second button (ID = 12) - browser.First(".id-company[data-company-id='12'] input[type=button]").Click().Wait(); + browser.First(".id-company[data-company-id='12'] input[type=button]").Click(); + // ensure that orders have been loaded - orders = browser.FindElements(".id-order"); - AssertUI.Any(orders).Attribute("data-order-id", "2"); - AssertUI.Any(orders).Attribute("data-order-id", "9"); + WaitForIgnoringStaleElements(() => { + AssertUI.Any(browser.FindElements(".id-order"), WaitForOptions.Disabled).Attribute("data-order-id", "2"); + AssertUI.Any(browser.FindElements(".id-order"), WaitForOptions.Disabled).Attribute("data-order-id", "9"); + }); // edit order (ID = 2) - browser.First(".id-order[data-order-id='2'] input[type=button][value=Edit]").Click().Wait(); + browser.First(".id-order[data-order-id='2'] input[type=button][value=Edit]").Click(); browser.First(".id-order.id-edit input[type=text]").Clear().SendKeys("2000-01-01"); - browser.First(".id-order.id-edit input[type=button][value=Apply]").Click().Wait(); - browser.First(".id-order.id-edit input[type=button][value=Exit]").Click().Wait(); + browser.First(".id-order.id-edit input[type=button][value=Apply]").Click(); + browser.First(".id-order.id-edit input[type=button][value=Exit]").Click(); AssertUI.TextEquals(browser.First(".id-order[data-order-id='2'] .id-date"), "2000-01-01"); // change the order (ID = 2) date back so the test can be run once again - browser.First(".id-order[data-order-id='2'] input[type=button][value=Edit]").Click().Wait(); + browser.First(".id-order[data-order-id='2'] input[type=button][value=Edit]").Click(); browser.First(".id-order.id-edit input[type=text]").Clear().SendKeys("2010-01-01"); - browser.First(".id-order.id-edit input[type=button][value=Apply]").Click().Wait(); - browser.First(".id-order.id-edit input[type=button][value=Exit]").Click().Wait(); + browser.First(".id-order.id-edit input[type=button][value=Apply]").Click(); + browser.First(".id-order.id-edit input[type=button][value=Exit]").Click(); AssertUI.TextEquals(browser.First(".id-order[data-order-id='2'] .id-date"), "2010-01-01"); }); @@ -147,7 +151,7 @@ public void Feature_Api_AzureFunctionsApiTable() { r.First("input[type=checkbox]").Click(); } - browser.First(".form-grid input[type=button]").Click().Wait(); + browser.First(".form-grid input[type=button]").Click(); browser.ElementAt(".form-create input[type=button]", 1).Click(); // make sure it disappeared diff --git a/src/Samples/Tests/Tests/Feature/DictionaryTranslationTests.cs b/src/Samples/Tests/Tests/Feature/DictionaryTranslationTests.cs index 147bba5d9e..77a5720052 100644 --- a/src/Samples/Tests/Tests/Feature/DictionaryTranslationTests.cs +++ b/src/Samples/Tests/Tests/Feature/DictionaryTranslationTests.cs @@ -8,6 +8,7 @@ using Riganti.Selenium.DotVVM; using Xunit; using Xunit.Abstractions; +using static DotVVM.Samples.Tests.UITestUtils; namespace DotVVM.Samples.Tests.Feature { @@ -24,8 +25,11 @@ public void Feature_DictionaryTranslation_Clear() inputs.ElementAt(4).Click(); WaitForExecutor.WaitFor(() => { - AssertUI.Text(browser.ElementAt("span", 0), s => !s.Contains("KEY: "), waitForOptions: WaitForOptions.Disabled); - AssertUI.Text(browser.ElementAt("span", 1), s => !s.Contains("VAL: "), waitForOptions: WaitForOptions.Disabled); + StaleElementRetry(() => { + AssertUI.Text(browser.ElementAt("span", 0), s => !s.Contains("KEY: "), waitForOptions: WaitForOptions.Disabled); + AssertUI.Text(browser.ElementAt("span", 1), s => !s.Contains("VAL: "), waitForOptions: WaitForOptions.Disabled); + }); + }, options: WaitForOptions.LongerTimeout); }); diff --git a/src/Samples/Tests/Tests/Feature/ReturnedFileTests.cs b/src/Samples/Tests/Tests/Feature/ReturnedFileTests.cs index 4bc56af0c1..84f943fd03 100644 --- a/src/Samples/Tests/Tests/Feature/ReturnedFileTests.cs +++ b/src/Samples/Tests/Tests/Feature/ReturnedFileTests.cs @@ -65,7 +65,9 @@ private void ReturnedFileDownload(IBrowserWrapper browser, string fileContent) Assert.NotEmpty(downloadURL); string returnedFile; +#pragma warning disable SYSLIB0014 // obsolete using (var client = new WebClient()) +#pragma warning restore SYSLIB0014 { returnedFile = client.DownloadString(browser.GetAbsoluteUrl(downloadURL)); } diff --git a/src/Samples/Tests/Tests/SpaNavigationToEmptyUrlTests.cs b/src/Samples/Tests/Tests/SpaNavigationToEmptyUrlTests.cs index da7695614b..20090ec6d5 100644 --- a/src/Samples/Tests/Tests/SpaNavigationToEmptyUrlTests.cs +++ b/src/Samples/Tests/Tests/SpaNavigationToEmptyUrlTests.cs @@ -19,7 +19,7 @@ public void SpaNavigationToEmptyUrlTest() RunInAllBrowsers(browser => { browser.NavigateToUrl(SamplesRouteUrls.SpaNavigationToEmptyUrl); - browser.Single("a").Click().Wait(); + browser.Single("a").Click(); AssertUI.UrlEquals(browser, browser.BaseUrl); }); @@ -33,7 +33,7 @@ public void SpaNavigationToEmptyUrlTest_Redirect() RunInAllBrowsers(browser => { browser.NavigateToUrl(SamplesRouteUrls.SpaNavigationToEmptyUrl); - browser.Single("input[type=button]").Click().Wait(); + browser.Single("input[type=button]").Click(); AssertUI.UrlEquals(browser, browser.BaseUrl); }); diff --git a/src/Samples/Tests/Tests/UITestUtils.cs b/src/Samples/Tests/Tests/UITestUtils.cs new file mode 100644 index 0000000000..01d68f4886 --- /dev/null +++ b/src/Samples/Tests/Tests/UITestUtils.cs @@ -0,0 +1,31 @@ +using System; +using OpenQA.Selenium; +using Riganti.Selenium.Core; + +namespace DotVVM.Samples.Tests; +public static class UITestUtils +{ + + public static T StaleElementRetry(Func action, int attempts = 5) + { + if (attempts <= 0) + return action(); + + try + { + return action(); + } + catch (StaleElementReferenceException) + { + return StaleElementRetry(action, attempts - 1); + } + } + public static void StaleElementRetry(Action action, int attempts = 5) => + StaleElementRetry(() => { action(); return 0; }, attempts); + + + public static void WaitForIgnoringStaleElements(Action action, WaitForOptions options = null) + { + WaitForExecutor.WaitFor(() => StaleElementRetry(action), options); + } +}