diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 84335c11..c1f34c77 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,4 +57,4 @@ jobs: browser: ${{ matrix.browser }} github-token: ${{ secrets.GITHUB_TOKEN }} build-configuration: "${{ matrix.environment == 'Production' && 'Release' || 'Debug' }}" - runtime-environment: "${{ matrix.environment }}" + runtime-environment: "${{ matrix.environment }}" \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Drivers/FastWebBrowserBase.cs b/src/Core/Riganti.Selenium.Core/Drivers/FastWebBrowserBase.cs index d296b72a..d6bbbfc3 100644 --- a/src/Core/Riganti.Selenium.Core/Drivers/FastWebBrowserBase.cs +++ b/src/Core/Riganti.Selenium.Core/Drivers/FastWebBrowserBase.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reflection; using OpenQA.Selenium; +using OpenQA.Selenium.Support.Extensions; using Riganti.Selenium.Core.Factories; namespace Riganti.Selenium.Core.Drivers @@ -67,7 +68,31 @@ protected virtual void CleanSessionAndLocalStorage() /// protected virtual void DeleteAllCookies() { + driverInstance.Manage().Cookies.DeleteAllCookies(); + + // Firefox driver doesn't list all cookies in Manage().Cookies - therefore JS invocation to remove all cookies + // Copied from https://stackoverflow.com/a/33366171 + driverInstance.ExecuteJavaScript( + @" +(function () { + var cookies = document.cookie.split(""; ""); + for (var c = 0; c < cookies.length; c++) { + var d = window.location.hostname.split("".""); + while (d.length > 0) { + var cookieBase = encodeURIComponent(cookies[c].split("";"")[0].split(""="")[0]) + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT; domain=' + d.join('.') + ' ;path='; + var p = location.pathname.split('/'); + document.cookie = cookieBase + '/'; + while (p.length > 0) { + document.cookie = cookieBase + p.join('/'); + p.pop(); + }; + d.shift(); + } + } +})(); +" + ); } /// diff --git a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/ChromeHelpers.cs b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/ChromeHelpers.cs index ba753a3f..684becef 100644 --- a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/ChromeHelpers.cs +++ b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/ChromeHelpers.cs @@ -1,19 +1,22 @@ -using OpenQA.Selenium.Chrome; +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; using Riganti.Selenium.Core.Factories; +using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Riganti.Selenium.Core.Drivers.Implementation { public static class ChromeHelpers { - public static ChromeDriver CreateChromeDriver(LocalWebBrowserFactory factory) { - + var options = new ChromeOptions(); options.AddArgument("test-type"); options.AddArgument("disable-popup-blocking"); options.AddArguments(factory.Capabilities); + options.BrowserVersion = factory.Options.TryGet(nameof(options.BrowserVersion)); if (factory.GetBooleanOption("disableExtensions")) { @@ -21,6 +24,5 @@ public static ChromeDriver CreateChromeDriver(LocalWebBrowserFactory factory) } return new ChromeDriver(options); } - } } \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/CoordinatorWebBrowserBase.cs b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/CoordinatorWebBrowserBase.cs index 87bc0910..568fa15c 100644 --- a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/CoordinatorWebBrowserBase.cs +++ b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/CoordinatorWebBrowserBase.cs @@ -13,6 +13,5 @@ public CoordinatorWebBrowserBase(CoordinatorWebBrowserFactoryBase factory, Conta { Lease = lease; } - } } \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/DictionaryExtensions.cs b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/DictionaryExtensions.cs new file mode 100644 index 00000000..fc81069a --- /dev/null +++ b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/DictionaryExtensions.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Riganti.Selenium.Core.Drivers.Implementation +{ + public static class DictionaryExtensions + { + + public static T2 TryGet(this IDictionary dic, T1 key) + { + if (dic is not null && dic.TryGetValue(key, out T2 value) && value is T2) + { + return value; + } + return default; + } + } +} \ No newline at end of file diff --git a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/EdgeHelpers.cs b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/EdgeHelpers.cs index 82556080..e53a1fc1 100644 --- a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/EdgeHelpers.cs +++ b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/EdgeHelpers.cs @@ -11,6 +11,7 @@ public static EdgeDriver CreateEdgeDriver(LocalWebBrowserFactory factory) { }; + options.BrowserVersion = factory.Options.TryGet(nameof(options.BrowserVersion)); return new EdgeDriver(options); } } diff --git a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/FirefoxHelpers.cs b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/FirefoxHelpers.cs index 8bea3836..fc1de1c5 100644 --- a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/FirefoxHelpers.cs +++ b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/FirefoxHelpers.cs @@ -1,5 +1,7 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO; +using Newtonsoft.Json; using OpenQA.Selenium.Firefox; using Riganti.Selenium.Core.Factories; @@ -7,68 +9,18 @@ namespace Riganti.Selenium.Core.Drivers.Implementation { public static class FirefoxHelpers { - private static string pathToFirefoxBinary; - private static FirefoxDriverService service; - + static FirefoxHelpers() { service = FirefoxDriverService.CreateDefaultService(); - // service.LogLevel = FirefoxDriverLogLevel.Trace; } public static FirefoxDriver CreateFirefoxDriver(LocalWebBrowserFactory factory) { - factory.LogInfo($"Creating firefox driver from '{pathToFirefoxBinary}'."); - - if (!string.IsNullOrWhiteSpace(pathToFirefoxBinary)) - { - return CreateAlternativeInstance(); - } - - try - { - return new FirefoxDriver(service, GetFirefoxOptions()); - } - catch (Exception e) - { - factory.LogInfo("Firefox driver could not be created."); - factory.LogError(e); - - var env = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); - if (env.Contains("(x86)")) - { - env = env.Replace("(x86)", "").Trim(); - } - var firefox = "Mozilla Firefox\\Firefox.exe"; - if (File.Exists(Path.Combine(env, firefox))) - { - return CreateAlternativeInstance(env, firefox); - } - - env = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); - if (File.Exists(Path.Combine(env, firefox))) - { - return CreateAlternativeInstance(env, firefox); - } - throw; - } - } - - private static FirefoxDriver CreateAlternativeInstance(string env, string firefox) - { - pathToFirefoxBinary = Path.Combine(env, firefox); - return CreateAlternativeInstance(); - } - - private static FirefoxDriver CreateAlternativeInstance() - { - var firefoxOptions = new FirefoxOptions() - { - BrowserExecutableLocation = pathToFirefoxBinary, - Profile = GetFirefoxProfile() - }; - return new FirefoxDriver(firefoxOptions); + var ffOptions = GetFirefoxOptions(factory.Options); + var driver = new FirefoxDriver(service, ffOptions); + return driver; } public static FirefoxProfile GetFirefoxProfile() @@ -80,9 +32,13 @@ public static FirefoxProfile GetFirefoxProfile() return profile; } - public static FirefoxOptions GetFirefoxOptions() + public static FirefoxOptions GetFirefoxOptions(System.Collections.Generic.IDictionary _options) { - var options = new FirefoxOptions { Profile = GetFirefoxProfile() }; + var options = new FirefoxOptions + { + Profile = GetFirefoxProfile() + }; + options.BrowserVersion = _options.TryGet(nameof(options.BrowserVersion)); return options; } } diff --git a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/InternetExplorerHelpers.cs b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/InternetExplorerHelpers.cs index 2e28cfd0..d9a0fc21 100644 --- a/src/Core/Riganti.Selenium.Core/Drivers/Implementation/InternetExplorerHelpers.cs +++ b/src/Core/Riganti.Selenium.Core/Drivers/Implementation/InternetExplorerHelpers.cs @@ -12,9 +12,8 @@ public static InternetExplorerDriver CreateInternetExplorerDriver(LocalWebBrowse { BrowserCommandLineArguments = "-private" }; - + options.BrowserVersion = factory.Options.TryGet(nameof(options.BrowserVersion)); return new InternetExplorerDriver(options); } - } } \ No newline at end of file diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 7a7f4acd..035c0d52 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,7 +4,7 @@ RIGANTI Basic utilities for performing UI tests based on selenium on CI servers. selenium;ui;tests;riganti;ci - 3.0.0-preview15-final + 3.0.0-preview17-browser-manager Icon.png git https://github.com/riganti/selenium-utils diff --git a/src/Integrations/Riganti.Selenium.xUnit/XunitTestSuiteRunner.cs b/src/Integrations/Riganti.Selenium.xUnit/XunitTestSuiteRunner.cs index f997524a..6f6a3fb8 100644 --- a/src/Integrations/Riganti.Selenium.xUnit/XunitTestSuiteRunner.cs +++ b/src/Integrations/Riganti.Selenium.xUnit/XunitTestSuiteRunner.cs @@ -23,30 +23,4 @@ public override void RunInAllBrowsers(ISeleniumTest testClass, Action "This reporter is a bit hack to close all resources when test execution ends."; - - // public bool IsEnvironmentallyEnabled => true; - - // public string RunnerSwitch => "riganti-selenium"; - - // public IMessageSink CreateMessageHandler(IRunnerLogger logger) - // { - // return new SeleniumMessageSink(); - // } - //} - //public class SeleniumMessageSink : IMessageSink - //{ - // public bool OnMessage(IMessageSinkMessage message) - // { - // if (message is TestAssemblyExecutionFinished) - // { - // if (Debugger.IsAttached) - // Debugger.Break(); - // } - // return true; - // } - //} } \ No newline at end of file diff --git a/src/Riganti.Selenium.DotVVM3Samples/Riganti.Selenium.DotVVM3.Samples.csproj b/src/Riganti.Selenium.DotVVM3Samples/Riganti.Selenium.DotVVM3.Samples.csproj index f08253e5..0cde2ce2 100644 --- a/src/Riganti.Selenium.DotVVM3Samples/Riganti.Selenium.DotVVM3.Samples.csproj +++ b/src/Riganti.Selenium.DotVVM3Samples/Riganti.Selenium.DotVVM3.Samples.csproj @@ -1,6 +1,6 @@  - net5.0 + net8.0 diff --git a/src/Tests/Riganti.Selenium.Core.Samples.Assert.Tests/seleniumconfig.json b/src/Tests/Riganti.Selenium.Core.Samples.Assert.Tests/seleniumconfig.json index d247e3cd..272c0ed3 100644 --- a/src/Tests/Riganti.Selenium.Core.Samples.Assert.Tests/seleniumconfig.json +++ b/src/Tests/Riganti.Selenium.Core.Samples.Assert.Tests/seleniumconfig.json @@ -1,7 +1,10 @@ { "factories": { "chrome:fast": { - "capabilities": [ "--window-size=1920,1080" ]//, "--headless", "--disable-gpu" ] + "capabilities": [ "--window-size=1920,1080", "--headless", "--disable-gpu" ], + "Options": { + "BrowserVersion": "124" + } } //"firefox:dev": { //} diff --git a/src/Tests/Riganti.Selenium.Core.Samples.Tests/BrowsersStabilityUiTests.cs b/src/Tests/Riganti.Selenium.Core.Samples.Tests/BrowsersStabilityUiTests.cs index a5448bc0..d16d6013 100644 --- a/src/Tests/Riganti.Selenium.Core.Samples.Tests/BrowsersStabilityUiTests.cs +++ b/src/Tests/Riganti.Selenium.Core.Samples.Tests/BrowsersStabilityUiTests.cs @@ -70,15 +70,24 @@ public void SelectMethod_XPathToRoot_ExpectedException() } [TestMethod] - [ExpectedSeleniumException(typeof(InvalidSelectorException))] public void SelectMethod_InvalidXPathSelector_ExpectedException() { - this.RunInAllBrowsers(browser => + try { - browser.NavigateToUrl("/test/ClickTest"); - var elem = browser.Single("#span"); - elem.Single("///***-*///@@##@šš+š++++---><<>''", By.XPath); - }); + this.RunInAllBrowsers(browser => + { + browser.NavigateToUrl("/test/ClickTest"); + var elem = browser.Single("#span"); + elem.Single("///***-*///@@##@šš+š++++---><<>''", By.XPath); + }); + } + catch (System.Exception) + { + // ignore + // reason: Firefox driver and Chrome driver throw different exceptions + return; + } + throw new System.Exception("SelectMethod_InvalidXPathSelector_ExpectedException was supposed to fail!!!"); } } } \ No newline at end of file diff --git a/src/Tests/Riganti.Selenium.Core.Samples.Tests/FunctionsUiTests.cs b/src/Tests/Riganti.Selenium.Core.Samples.Tests/FunctionsUiTests.cs index 5a304fb4..c8a7d4ee 100644 --- a/src/Tests/Riganti.Selenium.Core.Samples.Tests/FunctionsUiTests.cs +++ b/src/Tests/Riganti.Selenium.Core.Samples.Tests/FunctionsUiTests.cs @@ -253,7 +253,7 @@ public void CookieTest() browser.NavigateToUrl("/test/Cookies"); browser.First("#CookieIndicator").CheckIfInnerTextEquals("default value"); - browser.Click("#SetCookies").Wait(); + browser.Click("#SetCookies").Wait(1000); browser.NavigateToUrl("/test/Cookies"); browser.First("#CookieIndicator").CheckIfInnerTextEquals("new value"); }; diff --git a/src/Tests/Riganti.Selenium.Core.Samples.Tests/Profiles/seleniumconfig.chrome.json b/src/Tests/Riganti.Selenium.Core.Samples.Tests/Profiles/seleniumconfig.chrome.json index 3d5c2f1c..bd6d19b5 100644 --- a/src/Tests/Riganti.Selenium.Core.Samples.Tests/Profiles/seleniumconfig.chrome.json +++ b/src/Tests/Riganti.Selenium.Core.Samples.Tests/Profiles/seleniumconfig.chrome.json @@ -1,7 +1,10 @@ { "factories": { "chrome:fast": { - "capabilities": [ "--no-sandbox" ] + "capabilities": [ "--no-sandbox" ], + "Options": { + "BrowserVersion": "124" + } } }, "baseUrls": [ diff --git a/src/Tests/Riganti.Selenium.Core.Samples.Tests/SeleniumManagerTests.cs b/src/Tests/Riganti.Selenium.Core.Samples.Tests/SeleniumManagerTests.cs new file mode 100644 index 00000000..3c329f9d --- /dev/null +++ b/src/Tests/Riganti.Selenium.Core.Samples.Tests/SeleniumManagerTests.cs @@ -0,0 +1,36 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; +using OpenQA.Selenium; + +[TestClass] +public class SeleniumManagerTests +{ + [TestMethod] + public void GetBinariesVersion113() + { + var data1 = SeleniumManager.BinaryPaths("--browser firefox --driver geckodriver --browser-version 113"); + Console.WriteLine("Firefox binaries: " + JsonConvert.SerializeObject(data1)); + Assert.IsNotNull(data1["browser_path"]); + Assert.IsNotNull(data1["driver_path"]); + + var data2 = SeleniumManager.BinaryPaths("--browser chrome --driver chromedriver --browser-version 113"); + Console.WriteLine("Chrome binaries: " + JsonConvert.SerializeObject(data2)); + Assert.IsNotNull(data2["browser_path"]); + Assert.IsNotNull(data2["driver_path"]); + } + + [TestMethod] + public void GetBinariesVersionStable() + { + var data1 = SeleniumManager.BinaryPaths("--browser firefox --driver geckodriver --browser-version stable"); + Console.WriteLine("Firefox binaries: " + JsonConvert.SerializeObject(data1)); + Assert.IsNotNull(data1["browser_path"]); + Assert.IsNotNull(data1["driver_path"]); + + var data2 = SeleniumManager.BinaryPaths("--browser chrome --driver chromedriver --browser-version stable"); + Console.WriteLine("Chrome binaries: " + JsonConvert.SerializeObject(data2)); + Assert.IsNotNull(data2["browser_path"]); + Assert.IsNotNull(data2["driver_path"]); + } +} \ No newline at end of file diff --git a/src/Tests/Riganti.Selenium.Core.Samples.Tests/seleniumconfig.json b/src/Tests/Riganti.Selenium.Core.Samples.Tests/seleniumconfig.json index d1b32b0f..ed146148 100644 --- a/src/Tests/Riganti.Selenium.Core.Samples.Tests/seleniumconfig.json +++ b/src/Tests/Riganti.Selenium.Core.Samples.Tests/seleniumconfig.json @@ -1,8 +1,16 @@ { "factories": { "chrome:fast": { - "capabilities": [ "--window-size=1920,1080", "--headless", "--disable-gpu" ] - } + "capabilities": [ "--window-size=1920,1080", "--headless", "--disable-gpu" ], + "Options": { + "BrowserVersion": "124" + } + }, + //"firefox:fast": { + // "Options": { + // "BrowserVersion": "104" + // } + //} //"chrome:coordinator": { // "options": { // "coordinatorUrl": "http://localhost:62242/" diff --git a/src/Tests/Riganti.Selenium.Core.UnitTests/SeleniumManagerTests.cs b/src/Tests/Riganti.Selenium.Core.UnitTests/SeleniumManagerTests.cs new file mode 100644 index 00000000..decc18c6 --- /dev/null +++ b/src/Tests/Riganti.Selenium.Core.UnitTests/SeleniumManagerTests.cs @@ -0,0 +1,22 @@ +using System; +using System.Text.Json; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenQA.Selenium; + +[TestClass] +public class SeleniumManagerTests +{ + [TestMethod] + public void GetBinaries() + { + var data1 = SeleniumManager.BinaryPaths("--browser firefox --driver geckodriver --browser-version 104"); + Console.WriteLine("Firefox binaries: " + JsonSerializer.Serialize(data1)); + Assert.IsNotNull(data1["browser_path"]); + Assert.IsNotNull(data1["driver_path"]); + + var data2 = SeleniumManager.BinaryPaths("--browser chrome --driver chromedriver --browser-version 104"); + Console.WriteLine("Chrome binaries: " + JsonSerializer.Serialize(data2)); + Assert.IsNotNull(data2["browser_path"]); + Assert.IsNotNull(data2["driver_path"]); + } +} \ No newline at end of file diff --git a/src/Tests/Riganti.Selenium.Sandbox/seleniumconfig.json b/src/Tests/Riganti.Selenium.Sandbox/seleniumconfig.json index 085d8bb1..04e0096a 100644 --- a/src/Tests/Riganti.Selenium.Sandbox/seleniumconfig.json +++ b/src/Tests/Riganti.Selenium.Sandbox/seleniumconfig.json @@ -1,6 +1,10 @@ { "factories": { - "firefox:fast": {} + "firefox:fast": { + "Options": { + "BrowserVersion": "stable" + } + } }, "baseUrls": [ "http://localhost:6278/"