diff --git a/dotnet/private/dotnet_nunit_test_suite.bzl b/dotnet/private/dotnet_nunit_test_suite.bzl index 9c468eadb83f4..4fc22910d535d 100644 --- a/dotnet/private/dotnet_nunit_test_suite.bzl +++ b/dotnet/private/dotnet_nunit_test_suite.bzl @@ -88,7 +88,7 @@ _BROWSERS = { "ActiveDriverConfig=IE", ], "data": [], - "tags": [], + "tags": ["exclusive-if-local"], # IE cannot run in parallel. "target_compatible_with": ["@platforms//os:windows"], }, "safari": { @@ -97,7 +97,7 @@ _BROWSERS = { "ActiveDriverConfig=Safari", ], "data": [], - "tags": [], + "tags": ["exclusive-if-local"], # Safari cannot run in parallel. "target_compatible_with": ["@platforms//os:osx"], }, "remote": { diff --git a/dotnet/test/remote/AssemblyTeardown.cs b/dotnet/test/remote/AssemblyTeardown.cs index a89860208fe92..3284a284871dd 100644 --- a/dotnet/test/remote/AssemblyTeardown.cs +++ b/dotnet/test/remote/AssemblyTeardown.cs @@ -20,6 +20,9 @@ using NUnit.Framework; using OpenQA.Selenium.Testing.NUnit; +[assembly: Parallelizable(ParallelScope.Fixtures)] +[assembly: SingleSessionBrowser(Browser.Safari, Browser.IE)] + [SetUpFixture] #pragma warning disable // Outside a namespace to affect the entire assembly public class AssemblyTeardown : AssemblyFixtureBase diff --git a/dotnet/test/remote/RemoteWebDriverSpecificTests.cs b/dotnet/test/remote/RemoteWebDriverSpecificTests.cs index e7e1dc69cdc9e..bdba841af7909 100644 --- a/dotnet/test/remote/RemoteWebDriverSpecificTests.cs +++ b/dotnet/test/remote/RemoteWebDriverSpecificTests.cs @@ -52,7 +52,7 @@ public void Teardown() [NeedsFreshDriver(IsCreatedAfterTest = true)] public void ShouldBeAbleToCreateRemoteWebDriverWithNoSlashAtEndOfUri() { - EnvironmentManager.Instance.CloseCurrentDriver(); + CloseDriver(); DriverOptions options = OperatingSystem.IsWindows() ? new EdgeOptions() : new ChromeOptions(); RemoteWebDriver noSlashDriver = new RemoteWebDriver(RemoteSeleniumServer.ServerUri, options); noSlashDriver.Url = Urls.JavascriptPage; diff --git a/dotnet/test/support/AssemblyFixture.cs b/dotnet/test/support/AssemblyFixture.cs index 1f945fec08ed5..9e5949162bda8 100644 --- a/dotnet/test/support/AssemblyFixture.cs +++ b/dotnet/test/support/AssemblyFixture.cs @@ -17,6 +17,9 @@ // under the License. // +[assembly: Parallelizable(ParallelScope.Fixtures)] +[assembly: SingleSessionBrowser(Browser.Safari, Browser.IE)] + namespace OpenQA.Selenium.Support.Tests; [SetUpFixture] diff --git a/dotnet/test/testing.nunit/AssemblyFixtureBase.cs b/dotnet/test/testing.nunit/AssemblyFixtureBase.cs index 3706d78dacb3b..d95add8664bbf 100644 --- a/dotnet/test/testing.nunit/AssemblyFixtureBase.cs +++ b/dotnet/test/testing.nunit/AssemblyFixtureBase.cs @@ -42,7 +42,6 @@ public async Task RunBeforeAnyTestAsync() [OneTimeTearDown] public async Task RunAfterAnyTestsAsync() { - EnvironmentManager.Instance.CloseCurrentDriver(); await EnvironmentManager.Instance.WebServer.StopAsync(); if (StartRemoteServer) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/DefaultSafariDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/DefaultSafariDriver.cs index c4f133390a1df..68610d8f414c4 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/DefaultSafariDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/DefaultSafariDriver.cs @@ -26,7 +26,7 @@ namespace OpenQA.Selenium.Testing.NUnit.DriverConfigs; // constructor. public class DefaultSafariDriver : SafariDriver { - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public DefaultSafariDriver(SafariOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/DevChannelChromeDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/DevChannelChromeDriver.cs index 637aa71b82ca9..7edefa1e7b86f 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/DevChannelChromeDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/DevChannelChromeDriver.cs @@ -48,7 +48,7 @@ public DevChannelChromeDriver() { } - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public DevChannelChromeDriver(ChromeOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/DevChannelEdgeDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/DevChannelEdgeDriver.cs index 8de489ad0d674..3921acf557bf5 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/DevChannelEdgeDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/DevChannelEdgeDriver.cs @@ -28,7 +28,7 @@ public DevChannelEdgeDriver() { } - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public DevChannelEdgeDriver(EdgeOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/EdgeInternetExplorerModeDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/EdgeInternetExplorerModeDriver.cs index 07a8f4a56b93d..5da174e566e4a 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/EdgeInternetExplorerModeDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/EdgeInternetExplorerModeDriver.cs @@ -31,7 +31,7 @@ public EdgeInternetExplorerModeDriver() { } - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public EdgeInternetExplorerModeDriver(InternetExplorerOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/NightlyChannelFirefoxDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/NightlyChannelFirefoxDriver.cs index 494f50fc1b033..9601da30ebbd2 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/NightlyChannelFirefoxDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/NightlyChannelFirefoxDriver.cs @@ -31,7 +31,7 @@ public NightlyChannelFirefoxDriver() { } - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public NightlyChannelFirefoxDriver(FirefoxOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/SafariTechnologyPreviewDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/SafariTechnologyPreviewDriver.cs index e6ed775a2b08e..2d130dfb0ab5b 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/SafariTechnologyPreviewDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/SafariTechnologyPreviewDriver.cs @@ -31,7 +31,7 @@ public SafariTechnologyPreviewDriver() { } - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public SafariTechnologyPreviewDriver(SafariOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/StableChannelChromeDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/StableChannelChromeDriver.cs index b7752d779ab47..c883b62367065 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/StableChannelChromeDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/StableChannelChromeDriver.cs @@ -28,7 +28,7 @@ public StableChannelChromeDriver() { } - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public StableChannelChromeDriver(ChromeOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/StableChannelEdgeDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/StableChannelEdgeDriver.cs index cd2b6bd0244af..cd9c2b0feeff9 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/StableChannelEdgeDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/StableChannelEdgeDriver.cs @@ -29,7 +29,7 @@ public StableChannelEdgeDriver() { } - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public StableChannelEdgeDriver(EdgeOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverConfigs/StableChannelFirefoxDriver.cs b/dotnet/test/testing.nunit/DriverConfigs/StableChannelFirefoxDriver.cs index e60a868436168..20becc3d8cb39 100644 --- a/dotnet/test/testing.nunit/DriverConfigs/StableChannelFirefoxDriver.cs +++ b/dotnet/test/testing.nunit/DriverConfigs/StableChannelFirefoxDriver.cs @@ -31,7 +31,7 @@ public StableChannelFirefoxDriver() { } - // Required for dynamic setting with `EnvironmentManager.Instance.CreateDriverInstance(options)` + // Required for dynamic setting with `DriverFactory.CreateDriver(options)` public StableChannelFirefoxDriver(FirefoxOptions options) : base(options) { diff --git a/dotnet/test/testing.nunit/DriverTestFixture.cs b/dotnet/test/testing.nunit/DriverTestFixture.cs index f5483622f7c31..ab7f686194fb8 100644 --- a/dotnet/test/testing.nunit/DriverTestFixture.cs +++ b/dotnet/test/testing.nunit/DriverTestFixture.cs @@ -44,17 +44,20 @@ public bool IsNativeEventsEnabled } } + protected DriverFactory DriverFactory { get; private set; } + [OneTimeSetUp] - public void SetUp() + public void InitFixtureDriver() { - Driver = EnvironmentManager.Instance.GetCurrentDriver(); + DriverFactory = CreateDriverFactory(); + Driver = CreateDriverInstance(); } [OneTimeTearDown] - public void TearDown() + public void DisposeFixtureDriver() { - EnvironmentManager.Instance.CloseCurrentDriver(); Driver?.Dispose(); + Driver = null; } [TearDown] @@ -63,16 +66,30 @@ public void ResetOnError() if (TestContext.CurrentContext.Result.Outcome == ResultState.Error) { Driver?.Dispose(); - Driver = EnvironmentManager.Instance.CreateFreshDriver(); + Driver = CreateDriverInstance(); } } - /// - /// Exists because a given test might require a fresh driver. - /// - protected void CreateFreshDriver() + protected virtual DriverFactory CreateDriverFactory() + { + return new DriverFactory(EnvironmentManager.Instance); + } + + protected IWebDriver CreateDriverInstance(DriverOptions options = null) + { + return DriverFactory.CreateDriver(options); + } + + protected internal void CloseDriver() + { + Driver?.Dispose(); + Driver = null; + } + + protected internal void CreateFreshDriver() { - Driver = EnvironmentManager.Instance.CreateFreshDriver(); + CloseDriver(); + Driver = CreateDriverInstance(); } protected void WaitFor(Func waitFunction, string timeoutMessage) @@ -87,17 +104,16 @@ protected T WaitFor(Func waitFunction, string timeoutMessage) protected T WaitFor(Func waitFunction, TimeSpan timeout, string timeoutMessage) { - var waiter = new WebDriverWait(Driver, timeout) + // Not bound to Driver: callers may wait on a local driver while the fixture driver is closed. + var waiter = new DefaultWait>(waitFunction) { + Timeout = timeout, PollingInterval = TimeSpan.FromMilliseconds(100), Message = $"Condition timed out: {timeoutMessage}", }; waiter.IgnoreExceptionTypes(typeof(Exception)); - return waiter.Until((driver) => - { - return waitFunction(); - }); + return waiter.Until(func => func()); } } diff --git a/dotnet/test/testing.nunit/Environment/DriverFactory.cs b/dotnet/test/testing.nunit/Environment/DriverFactory.cs index 2db7a8674422f..0a40012072b0c 100644 --- a/dotnet/test/testing.nunit/Environment/DriverFactory.cs +++ b/dotnet/test/testing.nunit/Environment/DriverFactory.cs @@ -17,6 +17,7 @@ // under the License. // +using System.Collections.Concurrent; using System.IO; using System.Reflection; using OpenQA.Selenium.Chrome; @@ -30,20 +31,37 @@ namespace OpenQA.Selenium.Testing.NUnit.Environment; public class DriverFactory { + private static readonly ConcurrentDictionary driverTypes = new(); + + private readonly Type driverType; private readonly string driverPath; private readonly string browserBinaryLocation; + private readonly bool headless; private readonly Dictionary serviceTypes = new Dictionary(); private readonly Dictionary optionsTypes = new Dictionary(); - public DriverFactory(string driverPath, string browserBinaryLocation) + public DriverFactory(EnvironmentManager environment) { - this.driverPath = driverPath; - this.browserBinaryLocation = browserBinaryLocation; + this.driverType = driverTypes.GetOrAdd(environment.DriverTypeName, ResolveDriverType); + this.driverPath = environment.DriverServiceLocation; + this.browserBinaryLocation = environment.BrowserLocation; + this.headless = environment.Headless; this.PopulateServiceTypes(); this.PopulateOptionsTypes(); } + private static Type ResolveDriverType(string driverTypeName) + { + // Bazel uses unpredictable assembly names to execute tests, so search all loaded assemblies. + return AppDomain.CurrentDomain.GetAssemblies() + .AsEnumerable() + .Reverse() + .Select(assembly => assembly.GetType(driverTypeName)) + .FirstOrDefault(t => t != null) + ?? throw new ArgumentOutOfRangeException(nameof(driverTypeName), $"Unable to find driver type {driverTypeName}"); + } + private void PopulateOptionsTypes() { this.optionsTypes[Browser.Chrome] = typeof(ChromeOptions); @@ -64,12 +82,7 @@ private void PopulateServiceTypes() public event EventHandler DriverStarting; - public IWebDriver CreateDriver(Type driverType, bool logging = false) - { - return CreateDriverWithOptions(driverType, null, logging); - } - - public IWebDriver CreateDriverWithOptions(Type driverType, DriverOptions driverOptions, bool logging = false) + public IWebDriver CreateDriver(DriverOptions driverOptions = null, bool logging = false) { Browser browser = Browser.All; DriverService service = null; @@ -84,7 +97,7 @@ public IWebDriver CreateDriverWithOptions(Type driverType, DriverOptions driverO var chromeOptions = (ChromeOptions)options; chromeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage"); - if (EnvironmentManager.Instance.Headless) + if (this.headless) { chromeOptions.AddArgument("--headless"); } @@ -106,7 +119,7 @@ public IWebDriver CreateDriverWithOptions(Type driverType, DriverOptions driverO var edgeOptions = (EdgeOptions)options; edgeOptions.AddArguments("--no-sandbox", "--disable-dev-shm-usage"); - if (EnvironmentManager.Instance.Headless) + if (this.headless) { edgeOptions.AddArgument("--headless"); } @@ -135,7 +148,7 @@ public IWebDriver CreateDriverWithOptions(Type driverType, DriverOptions driverO { browser = Browser.Firefox; options = GetDriverOptions(driverType, driverOptions); - if (EnvironmentManager.Instance.Headless) + if (this.headless) { ((FirefoxOptions)options).AddArgument("-headless"); } diff --git a/dotnet/test/testing.nunit/Environment/EnvironmentManager.cs b/dotnet/test/testing.nunit/Environment/EnvironmentManager.cs index 1eb21d99b7d25..abee6831cfccc 100644 --- a/dotnet/test/testing.nunit/Environment/EnvironmentManager.cs +++ b/dotnet/test/testing.nunit/Environment/EnvironmentManager.cs @@ -26,10 +26,7 @@ namespace OpenQA.Selenium.Testing.NUnit.Environment; public class EnvironmentManager { - private static EnvironmentManager instance; - private readonly Type driverType; - private IWebDriver driver; - private readonly DriverFactory driverFactory; + private static readonly Lazy instance = new(() => new EnvironmentManager()); private EnvironmentManager() { @@ -69,22 +66,9 @@ private EnvironmentManager() DriverConfig driverConfig = env.DriverConfigs[activeDriverConfig]; Headless = bool.TryParse(headless, out bool isHeadless) && isHeadless; - - this.driverFactory = new DriverFactory(driverServiceLocation, browserLocation); - this.driverFactory.DriverStarting += OnDriverStarting; - - // Search for the driver type in the all assemblies, - // bazel uses unpredictable assembly names to execute tests - driverType = AppDomain.CurrentDomain.GetAssemblies() - .AsEnumerable() - .Reverse() - .Select(assembly => assembly.GetType(driverConfig.DriverTypeName)) - .FirstOrDefault(t => t != null); - - if (driverType == null) - { - throw new ArgumentOutOfRangeException($"Unable to find driver type {driverConfig.DriverTypeName}"); - } + DriverServiceLocation = driverServiceLocation; + BrowserLocation = browserLocation; + DriverTypeName = driverConfig.DriverTypeName; Browser = driverConfig.BrowserValue; RemoteCapabilities = driverConfig.RemoteCapabilities; @@ -142,17 +126,20 @@ private EnvironmentManager() { RemoteServer?.StopAsync().Wait(); WebServer?.StopAsync().Wait(); - CloseCurrentDriver(); } - public event EventHandler DriverStarting; - - public static EnvironmentManager Instance => instance ??= new EnvironmentManager(); + public static EnvironmentManager Instance => instance.Value; public Browser Browser { get; } public bool Headless { get; } + public string DriverTypeName { get; } + + public string DriverServiceLocation { get; } + + public string BrowserLocation { get; } + public string CurrentDirectory { get @@ -173,39 +160,6 @@ public string CurrentDirectory public string RemoteCapabilities { get; } - public IWebDriver GetCurrentDriver() - { - return driver ?? CreateFreshDriver(); - } - - public IWebDriver CreateDriverInstance() - { - return driverFactory.CreateDriver(driverType); - } - - public IWebDriver CreateDriverInstance(DriverOptions options) - { - return driverFactory.CreateDriverWithOptions(driverType, options); - } - - public IWebDriver CreateFreshDriver() - { - CloseCurrentDriver(); - driver = CreateDriverInstance(); - return driver; - } - - public void CloseCurrentDriver() - { - driver?.Quit(); - driver = null; - } - - protected void OnDriverStarting(object sender, DriverStartingEventArgs e) - { - this.DriverStarting?.Invoke(sender, e); - } - private static string FindProjectRoot(string startDirectory) { // Walk up until we find a directory containing common/ and dotnet/ diff --git a/dotnet/test/testing.nunit/NeedsFreshDriverAttribute.cs b/dotnet/test/testing.nunit/NeedsFreshDriverAttribute.cs index 7a376c7555559..dfaebebdb0d4d 100644 --- a/dotnet/test/testing.nunit/NeedsFreshDriverAttribute.cs +++ b/dotnet/test/testing.nunit/NeedsFreshDriverAttribute.cs @@ -18,7 +18,6 @@ // using NUnit.Framework.Interfaces; -using OpenQA.Selenium.Testing.NUnit.Environment; namespace OpenQA.Selenium.Testing.NUnit; @@ -32,8 +31,7 @@ public override void BeforeTest(ITest test) { if (test.Fixture is DriverTestFixture fixtureInstance && this.IsCreatedBeforeTest) { - EnvironmentManager.Instance.CreateFreshDriver(); - fixtureInstance.Driver = EnvironmentManager.Instance.GetCurrentDriver(); + fixtureInstance.CreateFreshDriver(); } base.BeforeTest(test); @@ -43,8 +41,7 @@ public override void AfterTest(ITest test) { if (test.Fixture is DriverTestFixture fixtureInstance && this.IsCreatedAfterTest) { - EnvironmentManager.Instance.CreateFreshDriver(); - fixtureInstance.Driver = EnvironmentManager.Instance.GetCurrentDriver(); + fixtureInstance.CreateFreshDriver(); } base.AfterTest(test); diff --git a/dotnet/test/testing.nunit/SingleSessionBrowserAttribute.cs b/dotnet/test/testing.nunit/SingleSessionBrowserAttribute.cs new file mode 100644 index 0000000000000..383eb12887a0e --- /dev/null +++ b/dotnet/test/testing.nunit/SingleSessionBrowserAttribute.cs @@ -0,0 +1,45 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using NUnit.Framework.Interfaces; +using NUnit.Framework.Internal; +using OpenQA.Selenium.Testing.NUnit.Environment; + +namespace OpenQA.Selenium.Testing.NUnit; + +/// +/// Runs the whole assembly sequentially when the active browser supports only one session at a time. +/// +/// +/// An explicit NumberOfTestWorkers run setting takes precedence over this attribute. +/// +[AttributeUsage(AttributeTargets.Assembly)] +public sealed class SingleSessionBrowserAttribute(params Browser[] browsers) : NUnitAttribute, IApplyToTest +{ + public IReadOnlyList Browsers { get; } = browsers; + + public void ApplyToTest(Test test) + { + if (Browsers.Contains(EnvironmentManager.Instance.Browser)) + { + // Zero workers makes NUnit use the sequential dispatcher, ignoring [Parallelizable]. + test.Properties.Set(PropertyNames.LevelOfParallelism, 0); + } + } +} diff --git a/dotnet/test/webdriver/AlertsTests.cs b/dotnet/test/webdriver/AlertsTests.cs index 7b868033b18fc..d43f339fb9526 100644 --- a/dotnet/test/webdriver/AlertsTests.cs +++ b/dotnet/test/webdriver/AlertsTests.cs @@ -17,7 +17,6 @@ // under the License. // -using OpenQA.Selenium.Testing.NUnit.Environment; namespace OpenQA.Selenium.Tests; @@ -451,7 +450,7 @@ public void CanQuitWhenAnAlertIsPresent() Driver.Url = CreateAlertPage("cheese"); Driver.FindElement(By.Id("alert")).Click(); IAlert alert = WaitFor(AlertToBePresent, "No alert found"); - EnvironmentManager.Instance.CloseCurrentDriver(); + CloseDriver(); } [Test] diff --git a/dotnet/test/webdriver/AssemblyFixture.cs b/dotnet/test/webdriver/AssemblyFixture.cs index 98b77c84ed2be..f3147eabd77da 100644 --- a/dotnet/test/webdriver/AssemblyFixture.cs +++ b/dotnet/test/webdriver/AssemblyFixture.cs @@ -17,6 +17,9 @@ // under the License. // +[assembly: Parallelizable(ParallelScope.Fixtures)] +[assembly: SingleSessionBrowser(Browser.Safari, Browser.IE)] + namespace OpenQA.Selenium.Tests; [SetUpFixture] diff --git a/dotnet/test/webdriver/BiDi/BiDiFixture.cs b/dotnet/test/webdriver/BiDi/BiDiFixture.cs index ba706cfd9b11f..fac2364a5dc34 100644 --- a/dotnet/test/webdriver/BiDi/BiDiFixture.cs +++ b/dotnet/test/webdriver/BiDi/BiDiFixture.cs @@ -42,7 +42,7 @@ public async Task BiDiSetUp() UnhandledPromptBehavior = UnhandledPromptBehavior.Ignore, }; - driver = EnvironmentManager.Instance.CreateDriverInstance(options); + driver = new DriverFactory(EnvironmentManager.Instance).CreateDriver(options); bidi = await driver.AsBiDiAsync(); diff --git a/dotnet/test/webdriver/CookieImplementationTests.cs b/dotnet/test/webdriver/CookieImplementationTests.cs index 4890d614a442d..0327935581c3c 100644 --- a/dotnet/test/webdriver/CookieImplementationTests.cs +++ b/dotnet/test/webdriver/CookieImplementationTests.cs @@ -21,7 +21,6 @@ using System.Text; using System.Text.RegularExpressions; using OpenQA.Selenium.Internal; -using OpenQA.Selenium.Testing.NUnit.Environment; namespace OpenQA.Selenium.Tests; @@ -874,7 +873,7 @@ private void GotoValidDomainAndClearCookies(string page) // This may mask some errors, where DeleteAllCookies doesn't fully // delete all it should, but that's a tradeoff we need to be willing // to make. - Driver = EnvironmentManager.Instance.CreateFreshDriver(); + CreateFreshDriver(); GoToPage(page); } } diff --git a/dotnet/test/webdriver/CorrectEventFiringTests.cs b/dotnet/test/webdriver/CorrectEventFiringTests.cs index 1d6e49d76103a..5f84e65c6ff07 100644 --- a/dotnet/test/webdriver/CorrectEventFiringTests.cs +++ b/dotnet/test/webdriver/CorrectEventFiringTests.cs @@ -42,7 +42,7 @@ public void ShouldFireFocusEventWhenClicking() [IgnoreBrowser(Browser.Safari, "Safari driver does not support multiple instances")] public void ShouldFireFocusEventInNonTopmostWindow() { - IWebDriver driver2 = EnvironmentManager.Instance.CreateDriverInstance(); + IWebDriver driver2 = CreateDriverInstance(); try { // topmost @@ -283,7 +283,7 @@ public void SendingKeysToAnotherElementShouldCauseTheBlurEventToFire() [IgnoreBrowser(Browser.Safari, "Safari driver does not support multiple instances")] public void SendingKeysToAnotherElementShouldCauseTheBlurEventToFireInNonTopmostWindow() { - IWebDriver driver2 = EnvironmentManager.Instance.CreateDriverInstance(); + IWebDriver driver2 = CreateDriverInstance(); IWebElement element; IWebElement element2; try diff --git a/dotnet/test/webdriver/DevTools/DevToolsTestFixture.cs b/dotnet/test/webdriver/DevTools/DevToolsTestFixture.cs index bfc28c2befbab..485e7277c2bad 100644 --- a/dotnet/test/webdriver/DevTools/DevToolsTestFixture.cs +++ b/dotnet/test/webdriver/DevTools/DevToolsTestFixture.cs @@ -34,7 +34,11 @@ public abstract class DevToolsTestFixture : DriverTestFixture [SetUp] public void Setup() { - Driver = EnvironmentManager.Instance.GetCurrentDriver(); + if (Driver is null) + { + CreateFreshDriver(); + } + devTools = Driver as IDevTools; if (devTools == null) { @@ -51,9 +55,8 @@ public void Teardown() if (session != null) { session.Dispose(); - EnvironmentManager.Instance.CloseCurrentDriver(); + CloseDriver(); session = null; - Driver = null; } } } diff --git a/dotnet/test/webdriver/DownloadsTests.cs b/dotnet/test/webdriver/DownloadsTests.cs index ea51c12f81859..0cb96e35079dc 100644 --- a/dotnet/test/webdriver/DownloadsTests.cs +++ b/dotnet/test/webdriver/DownloadsTests.cs @@ -20,7 +20,6 @@ using System.IO; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Support.UI; -using OpenQA.Selenium.Testing.NUnit.Environment; namespace OpenQA.Selenium.Tests; @@ -32,7 +31,7 @@ public class DownloadsTests : DriverTestFixture [SetUp] public void ResetDriver() { - EnvironmentManager.Instance.CloseCurrentDriver(); + CloseDriver(); InitLocalDriver(); } @@ -45,7 +44,7 @@ public void QuitAdditionalDriver() localDriver = null; } - EnvironmentManager.Instance.CreateFreshDriver(); + CreateFreshDriver(); } [Test] @@ -105,7 +104,7 @@ private void InitLocalDriver() DownloadableFilesOptions options = new DownloadableFilesOptions(); options.EnableDownloads = true; - localDriver = EnvironmentManager.Instance.CreateDriverInstance(options); + localDriver = CreateDriverInstance(options); } public class DownloadableFilesOptions : DriverOptions diff --git a/dotnet/test/webdriver/Firefox/FirefoxDriverServiceTests.cs b/dotnet/test/webdriver/Firefox/FirefoxDriverServiceTests.cs index 6629eb9194910..fbc3d20038a38 100644 --- a/dotnet/test/webdriver/Firefox/FirefoxDriverServiceTests.cs +++ b/dotnet/test/webdriver/Firefox/FirefoxDriverServiceTests.cs @@ -24,6 +24,7 @@ namespace OpenQA.Selenium.Tests.Firefox; [TestFixture] +[NonParallelizable] [IgnoreBrowser(Browser.Chrome)] [IgnoreBrowser(Browser.Edge)] [IgnoreBrowser(Browser.Safari)] diff --git a/dotnet/test/webdriver/Internal/Logging/LogTests.cs b/dotnet/test/webdriver/Internal/Logging/LogTests.cs index 1a1e7c59578e6..7689cf4acf454 100644 --- a/dotnet/test/webdriver/Internal/Logging/LogTests.cs +++ b/dotnet/test/webdriver/Internal/Logging/LogTests.cs @@ -21,6 +21,7 @@ namespace OpenQA.Selenium.Tests.Internal.Logging; +[NonParallelizable] public class LogTests { private TestLogHandler testLogHandler; diff --git a/dotnet/test/webdriver/PageLoadingTests.cs b/dotnet/test/webdriver/PageLoadingTests.cs index 162570f7ae924..6a450c70a85b3 100644 --- a/dotnet/test/webdriver/PageLoadingTests.cs +++ b/dotnet/test/webdriver/PageLoadingTests.cs @@ -17,7 +17,6 @@ // under the License. // -using OpenQA.Selenium.Testing.NUnit.Environment; namespace OpenQA.Selenium.Tests; @@ -29,7 +28,10 @@ public class PageLoadingTests : DriverTestFixture [SetUp] public void RestartOriginalDriver() { - Driver = EnvironmentManager.Instance.GetCurrentDriver(); + if (Driver is null) + { + CreateFreshDriver(); + } } [TearDown] @@ -459,7 +461,7 @@ private void AssertPageLoadTimeoutIsEnforced(Action action, long webDriverPageLo private void InitLocalDriver(PageLoadStrategy strategy) { - EnvironmentManager.Instance.CloseCurrentDriver(); + CloseDriver(); if (localDriver != null) { localDriver.Quit(); @@ -467,7 +469,7 @@ private void InitLocalDriver(PageLoadStrategy strategy) PageLoadStrategyOptions options = new PageLoadStrategyOptions(); options.PageLoadStrategy = strategy; - localDriver = EnvironmentManager.Instance.CreateDriverInstance(options); + localDriver = CreateDriverInstance(options); } private class PageLoadStrategyOptions : DriverOptions diff --git a/dotnet/test/webdriver/ProxySettingTests.cs b/dotnet/test/webdriver/ProxySettingTests.cs index 7058d67dea365..0fdedc09c77d8 100644 --- a/dotnet/test/webdriver/ProxySettingTests.cs +++ b/dotnet/test/webdriver/ProxySettingTests.cs @@ -38,9 +38,7 @@ public class ProxySettingTests : DriverTestFixture [SetUp] public void RestartOriginalDriver() { - Driver = EnvironmentManager.Instance.GetCurrentDriver(); proxyServer = new ProxyServer(); - EnvironmentManager.Instance.DriverStarting += EnvironmentManagerDriverStarting; } [TearDown] @@ -57,8 +55,6 @@ public void QuitAdditionalDriver() proxyServer.Quit(); proxyServer = null; } - - EnvironmentManager.Instance.DriverStarting -= EnvironmentManagerDriverStarting; } [Test] @@ -143,7 +139,14 @@ public void CanUseAutoConfigFileThatOnlyProxiesCertainHosts() } } - private void EnvironmentManagerDriverStarting(object sender, DriverStartingEventArgs e) + protected override DriverFactory CreateDriverFactory() + { + DriverFactory factory = base.CreateDriverFactory(); + factory.DriverStarting += DriverFactoryDriverStarting; + return factory; + } + + private void DriverFactoryDriverStarting(object sender, DriverStartingEventArgs e) { if (e.Options is InternetExplorerOptions ieOptions) { @@ -153,7 +156,7 @@ private void EnvironmentManagerDriverStarting(object sender, DriverStartingEvent private void InitLocalDriver(Proxy proxy) { - EnvironmentManager.Instance.CloseCurrentDriver(); + CloseDriver(); if (localDriver != null) { localDriver.Quit(); @@ -161,7 +164,7 @@ private void InitLocalDriver(Proxy proxy) ProxyOptions options = new ProxyOptions(); options.Proxy = proxy; - localDriver = EnvironmentManager.Instance.CreateDriverInstance(options); + localDriver = CreateDriverInstance(options); } private class ProxyOptions : DriverOptions diff --git a/dotnet/test/webdriver/SessionHandlingTests.cs b/dotnet/test/webdriver/SessionHandlingTests.cs index 4c344e29bfafc..53dba670d5fe6 100644 --- a/dotnet/test/webdriver/SessionHandlingTests.cs +++ b/dotnet/test/webdriver/SessionHandlingTests.cs @@ -17,7 +17,6 @@ // under the License. // -using OpenQA.Selenium.Testing.NUnit.Environment; namespace OpenQA.Selenium.Tests; @@ -31,7 +30,7 @@ public void CallingQuitMoreThanOnceOnASessionIsANoOp() Driver.Url = Urls.SimpleTestPage; Driver.Quit(); Driver.Quit(); - Driver = EnvironmentManager.Instance.CreateDriverInstance(); + Driver = CreateDriverInstance(); Driver.Url = Urls.XhtmlTestPage; Driver.Quit(); } @@ -40,12 +39,12 @@ public void CallingQuitMoreThanOnceOnASessionIsANoOp() [NeedsFreshDriver(IsCreatedAfterTest = true)] public void CallingQuitAfterClosingTheLastWindowIsANoOp() { - EnvironmentManager.Instance.CloseCurrentDriver(); - IWebDriver testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + CloseDriver(); + IWebDriver testDriver = CreateDriverInstance(); testDriver.Url = Urls.SimpleTestPage; testDriver.Close(); testDriver.Quit(); - testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + testDriver = CreateDriverInstance(); testDriver.Url = Urls.XhtmlTestPage; Assert.That(testDriver.Title, Is.EqualTo("XHTML Test Page")); testDriver.Quit(); @@ -56,8 +55,8 @@ public void CallingQuitAfterClosingTheLastWindowIsANoOp() [NeedsFreshDriver(IsCreatedAfterTest = true)] public void CallingAnyOperationAfterClosingTheLastWindowShouldThrowAnException() { - EnvironmentManager.Instance.CloseCurrentDriver(); - IWebDriver testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + CloseDriver(); + IWebDriver testDriver = CreateDriverInstance(); try { string url = string.Empty; @@ -75,8 +74,8 @@ public void CallingAnyOperationAfterClosingTheLastWindowShouldThrowAnException() [NeedsFreshDriver(IsCreatedAfterTest = true)] public void CallingAnyOperationAfterQuitShouldThrowAnException() { - EnvironmentManager.Instance.CloseCurrentDriver(); - IWebDriver testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + CloseDriver(); + IWebDriver testDriver = CreateDriverInstance(); try { string url = string.Empty; @@ -97,12 +96,12 @@ public void CallingAnyOperationAfterQuitShouldThrowAnException() [NeedsFreshDriver(IsCreatedAfterTest = true)] public void ShouldBeAbleToStartNewDriverAfterCallingCloseOnOnlyOpenWindow() { - EnvironmentManager.Instance.CloseCurrentDriver(); - IWebDriver testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + CloseDriver(); + IWebDriver testDriver = CreateDriverInstance(); testDriver.Url = Urls.SimpleTestPage; testDriver.Close(); testDriver.Dispose(); - testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + testDriver = CreateDriverInstance(); testDriver.Url = Urls.XhtmlTestPage; Assert.That(testDriver.Title, Is.EqualTo("XHTML Test Page")); testDriver.Close(); @@ -113,8 +112,8 @@ public void ShouldBeAbleToStartNewDriverAfterCallingCloseOnOnlyOpenWindow() [NeedsFreshDriver(IsCreatedAfterTest = true)] public void ShouldBeAbleToDisposeOfDriver() { - EnvironmentManager.Instance.CloseCurrentDriver(); - IWebDriver testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + CloseDriver(); + IWebDriver testDriver = CreateDriverInstance(); testDriver.Url = Urls.SimpleTestPage; testDriver.Dispose(); } @@ -123,8 +122,8 @@ public void ShouldBeAbleToDisposeOfDriver() [NeedsFreshDriver(IsCreatedAfterTest = true)] public void ShouldBeAbleToCallDisposeConsecutively() { - EnvironmentManager.Instance.CloseCurrentDriver(); - IWebDriver testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + CloseDriver(); + IWebDriver testDriver = CreateDriverInstance(); testDriver.Url = Urls.SimpleTestPage; testDriver.Dispose(); testDriver.Dispose(); @@ -134,12 +133,12 @@ public void ShouldBeAbleToCallDisposeConsecutively() [NeedsFreshDriver(IsCreatedAfterTest = true)] public void ShouldBeAbleToCallDisposeAfterQuit() { - EnvironmentManager.Instance.CloseCurrentDriver(); - IWebDriver testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + CloseDriver(); + IWebDriver testDriver = CreateDriverInstance(); testDriver.Url = Urls.SimpleTestPage; testDriver.Quit(); testDriver.Dispose(); - testDriver = EnvironmentManager.Instance.CreateDriverInstance(); + testDriver = CreateDriverInstance(); testDriver.Url = Urls.XhtmlTestPage; Assert.That(testDriver.Title, Is.EqualTo("XHTML Test Page")); testDriver.Quit(); @@ -150,7 +149,6 @@ public void ShouldOpenAndCloseBrowserRepeatedly() { for (int i = 0; i < 5; i++) { - EnvironmentManager.Instance.CloseCurrentDriver(); CreateFreshDriver(); Driver.Url = Urls.SimpleTestPage; Assert.That(Driver.Title, Is.EqualTo("Hello WebDriver")); diff --git a/dotnet/test/webdriver/TimeoutDriverOptionsTests.cs b/dotnet/test/webdriver/TimeoutDriverOptionsTests.cs index 755f4404bc52d..6299b3d3e33bd 100644 --- a/dotnet/test/webdriver/TimeoutDriverOptionsTests.cs +++ b/dotnet/test/webdriver/TimeoutDriverOptionsTests.cs @@ -24,6 +24,7 @@ namespace OpenQA.Selenium.Tests; [TestFixture] public class TimeoutDriverOptionsTests { + private readonly DriverFactory driverFactory = new(EnvironmentManager.Instance); private IWebDriver driver; private readonly TimeSpan defaultScriptTimeout = TimeSpan.FromMilliseconds(30_000); @@ -50,7 +51,7 @@ public void CanSetScriptTimeout() Assert.That(options.PageLoadTimeout, Is.Null); Assert.That(options.ImplicitWaitTimeout, Is.Null); - driver = EnvironmentManager.Instance.CreateDriverInstance(options); + driver = driverFactory.CreateDriver(options); Assert.That(driver.Manage().Timeouts().AsynchronousJavaScript, Is.EqualTo(expectedScriptTimeout)); @@ -73,7 +74,7 @@ public void CanSetPageLoadTimeout() Assert.That(options.ScriptTimeout, Is.Null); Assert.That(options.ImplicitWaitTimeout, Is.Null); - driver = EnvironmentManager.Instance.CreateDriverInstance(options); + driver = driverFactory.CreateDriver(options); Assert.That(driver.Manage().Timeouts().PageLoad, Is.EqualTo(expectedPageLoadTimeout)); @@ -96,7 +97,7 @@ public void CanSetImplicitWaitTimeout() Assert.That(options.ScriptTimeout, Is.Null); Assert.That(options.PageLoadTimeout, Is.Null); - driver = EnvironmentManager.Instance.CreateDriverInstance(options); + driver = driverFactory.CreateDriver(options); Assert.That(driver.Manage().Timeouts().ImplicitWait, Is.EqualTo(expectedImplicitWaitTimeout)); @@ -122,7 +123,7 @@ public void CanSetTimeout() Assert.That(options.PageLoadTimeout, Is.EqualTo(expectedPageLoadTimeout)); Assert.That(options.ImplicitWaitTimeout, Is.EqualTo(expectedImplicitWaitTimeout)); - driver = EnvironmentManager.Instance.CreateDriverInstance(options); + driver = driverFactory.CreateDriver(options); Assert.That(driver.Manage().Timeouts().AsynchronousJavaScript, Is.EqualTo(expectedScriptTimeout)); Assert.That(driver.Manage().Timeouts().PageLoad, Is.EqualTo(expectedPageLoadTimeout)); diff --git a/dotnet/test/webdriver/UnexpectedAlertBehaviorTests.cs b/dotnet/test/webdriver/UnexpectedAlertBehaviorTests.cs index 585559a5982a9..f753796097301 100644 --- a/dotnet/test/webdriver/UnexpectedAlertBehaviorTests.cs +++ b/dotnet/test/webdriver/UnexpectedAlertBehaviorTests.cs @@ -17,8 +17,6 @@ // under the License. // -using OpenQA.Selenium.Testing.NUnit.Environment; - namespace OpenQA.Selenium.Tests; [TestFixture] @@ -29,7 +27,7 @@ public class UnexpectedAlertBehaviorTests : DriverTestFixture [SetUp] public void RestartOriginalDriver() { - EnvironmentManager.Instance.CloseCurrentDriver(); + CloseDriver(); } [TearDown] @@ -41,7 +39,7 @@ public void QuitDriver() localDriver = null; } - EnvironmentManager.Instance.CreateFreshDriver(); + CreateFreshDriver(); } [Test] @@ -106,7 +104,7 @@ private void ExecuteTestWithUnhandledPrompt(UserPromptHandler behavior, string e UnhandledPromptBehavior = behavior, }; - localDriver = EnvironmentManager.Instance.CreateDriverInstance(options); + localDriver = CreateDriverInstance(options); localDriver.Url = Urls.AlertsPage; IWebElement resultElement = localDriver.FindElement(By.Id("text")); localDriver.FindElement(By.Id("prompt-with-default")).Click();