From a95411cf2cde80f3063103ace4464414aea572f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Standa=20Luke=C5=A1?= Date: Sun, 23 Oct 2022 16:20:29 +0200 Subject: [PATCH 1/4] Fix warnings in the test project --- .../Tests/Tests/Control/CheckBoxTests.cs | 2 +- src/Samples/Tests/Tests/ErrorsTests.cs | 5 +++++ src/Samples/Tests/Tests/Feature/ApiTests.cs | 21 +++++++++---------- .../Tests/Tests/Feature/ReturnedFileTests.cs | 2 ++ .../Tests/SpaNavigationToEmptyUrlTests.cs | 4 ++-- 5 files changed, 20 insertions(+), 14 deletions(-) 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..45716ed1be 100644 --- a/src/Samples/Tests/Tests/Feature/ApiTests.cs +++ b/src/Samples/Tests/Tests/Feature/ApiTests.cs @@ -24,8 +24,7 @@ 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 @@ -35,13 +34,13 @@ public void Feature_Api_GetCollection() var idToDelete = orders[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(); + browser.First($".id-order[data-order-id='{idToDelete}'] input[type=button][value=Delete]").Click(); orders = browser.FindElements(".id-order"); AssertUI.Any(orders).Attribute("data-order-id", "6"); AssertUI.All(orders).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"); @@ -49,18 +48,18 @@ public void Feature_Api_GetCollection() AssertUI.Any(orders).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 +146,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/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); }); From cf53748dcdf4d8b3e61039b049e7ea4c89aafbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Standa=20Luke=C5=A1?= Date: Sun, 23 Oct 2022 16:21:18 +0200 Subject: [PATCH 2/4] Disable warnings in CI non-warning runs It just leads to having 10 times the same warning on a line. Warnings should be caught by the NoWarn build --- .github/uitest/uitest.ps1 | 2 ++ .github/uitest/uitest.sh | 1 + 2 files changed, 3 insertions(+) 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" \ -- \ From 9aafca04230e7845be2955764803ce31baf2564b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Standa=20Luke=C5=A1?= Date: Wed, 2 Nov 2022 14:48:57 +0100 Subject: [PATCH 3/4] Avoid stale elements in few more flaky tests --- src/Samples/Tests/Tests/Feature/ApiTests.cs | 22 ++++++++++------- .../Feature/DictionaryTranslationTests.cs | 8 +++++-- src/Samples/Tests/Tests/UITestUtils.cs | 24 +++++++++++++++++++ 3 files changed, 43 insertions(+), 11 deletions(-) create mode 100644 src/Samples/Tests/Tests/UITestUtils.cs diff --git a/src/Samples/Tests/Tests/Feature/ApiTests.cs b/src/Samples/Tests/Tests/Feature/ApiTests.cs index 45716ed1be..2be182d4ec 100644 --- a/src/Samples/Tests/Tests/Feature/ApiTests.cs +++ b/src/Samples/Tests/Tests/Feature/ApiTests.cs @@ -28,24 +28,28 @@ public void Feature_Api_GetCollection() }, 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"); + WaitForExecutor.WaitFor(() => { + 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(); - orders = browser.FindElements(".id-order"); - AssertUI.Any(orders).Attribute("data-order-id", "6"); - AssertUI.All(orders).Attribute("data-order-id", s => s != idToDelete); + WaitForExecutor.WaitFor(() => { + 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(); + // 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"); + WaitForExecutor.WaitFor(() => { + 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(); 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/UITestUtils.cs b/src/Samples/Tests/Tests/UITestUtils.cs new file mode 100644 index 0000000000..f2b9dcc2cf --- /dev/null +++ b/src/Samples/Tests/Tests/UITestUtils.cs @@ -0,0 +1,24 @@ +using System; +using OpenQA.Selenium; + +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); +} From ea2af16765c74c525131e88b2a1511cf364b1193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Standa=20Luke=C5=A1?= Date: Wed, 2 Nov 2022 16:56:59 +0100 Subject: [PATCH 4/4] ui tests: avoid stale ements in ApiTests --- src/Samples/Tests/Tests/Feature/ApiTests.cs | 7 ++++--- src/Samples/Tests/Tests/UITestUtils.cs | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Samples/Tests/Tests/Feature/ApiTests.cs b/src/Samples/Tests/Tests/Feature/ApiTests.cs index 2be182d4ec..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 { @@ -28,7 +29,7 @@ public void Feature_Api_GetCollection() }, 30000, "Cannot find CompanyID = 11. Probably data are not loaded. (The page did not load in 5s.)"); // ensure that orders have been loaded - WaitForExecutor.WaitFor(() => { + WaitForIgnoringStaleElements(() => { AssertUI.Any(browser.FindElements(".id-order"), waitForOptions: WaitForOptions.Disabled).Attribute("data-order-id", "6"); }); @@ -36,7 +37,7 @@ public void Feature_Api_GetCollection() // delete order (ID = 7) browser.First($".id-order[data-order-id='{idToDelete}'] input[type=button][value=Delete]").Click(); - WaitForExecutor.WaitFor(() => { + 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); }); @@ -46,7 +47,7 @@ public void Feature_Api_GetCollection() // ensure that orders have been loaded - WaitForExecutor.WaitFor(() => { + 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"); }); diff --git a/src/Samples/Tests/Tests/UITestUtils.cs b/src/Samples/Tests/Tests/UITestUtils.cs index f2b9dcc2cf..01d68f4886 100644 --- a/src/Samples/Tests/Tests/UITestUtils.cs +++ b/src/Samples/Tests/Tests/UITestUtils.cs @@ -1,5 +1,6 @@ using System; using OpenQA.Selenium; +using Riganti.Selenium.Core; namespace DotVVM.Samples.Tests; public static class UITestUtils @@ -21,4 +22,10 @@ public static T StaleElementRetry(Func action, int attempts = 5) } 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); + } }