Selenium 4 EdgeDriver cannot run parallel tests under xUnit

173 Views Asked by At

I have a console app which launches 2 Edge windows simultaneously and navigates within them just fine:

// usings
using OpenQA.Selenium.Edge;

// generic driver options
List<string> Options = new List<string>() {
    // "headless", // add this to run the browsers invisibly
    "no-sandbox",
    "incognito",
    "disable-gpu",
    "ignore-certificate-errors",
    "no-default-browser-check",
    "disable-web-security",
    "allow-insecure-localhost",
    "allow-running-insecure-content",
    "acceptInsecureCerts=true",
    "proxy-server='direct://'",
    "proxy-bypass-list=*",
    "disable-extensions",
    "disable-infobars",
    $"--window-size=1024,768",
};

// edge options 1
var options = new EdgeOptions();
options.LeaveBrowserRunning = false;
options.AcceptInsecureCertificates = true;
options.BinaryLocation = @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe";

// add options 1 arguments
Options.ForEach(arg => { if (!String.IsNullOrEmpty(arg)) options.AddArgument(arg); });

// Important: Define profile folder for first browser
options.AddArgument($@"--user-data-dir={Directory.GetCurrentDirectory()}\prof-1");

// edge options 2
var options2 = new EdgeOptions();
options2.LeaveBrowserRunning = false;
options2.AcceptInsecureCertificates = true;
options2.BinaryLocation = @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe";

// add options 1 arguments
Options.ForEach(arg => { if (!String.IsNullOrEmpty(arg)) options2.AddArgument(arg); });

// Important: Define profile folder for second browser
options2.AddArgument($@"--user-data-dir={Directory.GetCurrentDirectory()}\prof-2");

// initialise driver service
using (var _service = OpenQA.Selenium.Edge.EdgeDriverService.CreateDefaultService(Directory.GetCurrentDirectory(), @"msedgedriver.exe"))
{
    _service.Start();

    // initialise first edge driver
    using (var driver = new EdgeDriver(_service, options))
    {
        // define short default wait times
        driver.Manage().Timeouts().ImplicitWait = new TimeSpan(0, 0, 2);
        driver.Manage().Timeouts().PageLoad = new TimeSpan(0, 0, 20);
        driver.Manage().Timeouts().AsynchronousJavaScript = new TimeSpan(0, 0, 10);
        
        // send first browser window to a page
        driver.Navigate().GoToUrl("https://www.google.com/");

        // initialise second edge driver
        using (var driver2 = new EdgeDriver(_service, options2))
        {
            // define short default wait times
            driver2.Manage().Timeouts().ImplicitWait = new TimeSpan(0, 0, 2);
            driver2.Manage().Timeouts().PageLoad = new TimeSpan(0, 0, 20);
            driver2.Manage().Timeouts().AsynchronousJavaScript = new TimeSpan(0, 0, 10);

            // send second browswer window to a page
            driver2.Navigate().GoToUrl("https://www.youtube.com/");

            // wait so the user can see what's happening
            Thread.Sleep(5000);

            // stop browsers
            driver.Quit();
            driver2.Quit();
        }
    }
}

// using blocks will tidy up processes - check Task Manager for `Microsoft Edge WebDriver`

This listing is here.

The problem I have is that when I convert this to an xUnit test, when a second EdgeDriver is instantiated the driver instances fail to maintain a handle on the browser. I’ve implemented this as a test class base and a static class which provides the driver service and options object.

Static class:

private static List<string> Options => new List<string> {
            IsHeadless ? "headless" : "",
            "no-sandbox",
            "inprivate", // "incognito",
            "disable-gpu",
            "ignore-certificate-errors",
            "no-default-browser-check",
            "disable-web-security",
            "allow-insecure-localhost",
            "allow-running-insecure-content",
            "acceptInsecureCerts=true",
            "proxy-server='direct://'",
            "proxy-bypass-list=*",
            "disable-extensions",
            "disable-infobars",
            "remote-debugging-port=9222",
            $"--window-size={WindowSize}",
    };


public static EdgeOptions BrowserOptions
{
    get
    {
        lock (optionsLockObj)
        {
            var _options = new EdgeOptions();
            _options.LeaveBrowserRunning = false;
            _options.AcceptInsecureCertificates = true;
            _options.BinaryLocation = @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe";

            Options.ForEach(arg => { if (!String.IsNullOrEmpty(arg)) _options.AddArgument(arg); });

            _options.AddArgument($@"--user-data-dir={Directory.GetCurrentDirectory()}\prof-{ProfileCounter++}");

            _options.SetLoggingPreference(LogType.Driver, LogLevel.Debug);

            return _options;
        }
    }
}

public static EdgeDriverService Service
{
    get
    {
        lock (serviceLockObj)
        {
            if (_service is null)
            {
                _service = OpenQA.Selenium.Edge.EdgeDriverService.CreateDefaultService(@"../../../driver/", @"msedgedriver.exe");
                _service.UseVerboseLogging = true;
                _service.Start();
            }
        }

        return _service;
    }
}

Base test class test method:

protected void TestBrowser(string testFilePath)
{
    var ops = TestEnvironment.BrowserOptions;
    var prof = ops.Arguments[ops.Arguments.Count-1];
    output.WriteLine($"--user-data-dir: {prof}");

    using (var driver = new EdgeDriver(TestEnvironment.Service, ops))
    {
        driver.Manage().Timeouts().ImplicitWait = new TimeSpan(0, 0, 10);
        driver.Manage().Timeouts().PageLoad = new TimeSpan(0, 2, 0);
        driver.Manage().Timeouts().AsynchronousJavaScript = new TimeSpan(0, 0, 10);

        try
        {
                        // do work
                    }
        finally
        {
            if (driver != null)
                driver.Quit();
        }
    }
}

I have cut out a lot of stuff irrelevant to the question.

What I want to understand is why the xUnit created instances of the test classes (which all inherit the test class method above) would not be able to reference their relative EdgeDriver properly.

1

There are 1 best solutions below

4
ENERGY.SERVICES On

try separatting drivers like this, and maybe if you want to do it more efficient do it with threads.

Maybe You can not access the same driver at the same time in the same instance, so create a new one.

Try this:

// initialise driver service
using (var _service = OpenQA.Selenium.Edge.EdgeDriverService.CreateDefaultService(Directory.GetCurrentDirectory(), @"msedgedriver.exe"))
{
    _service.Start();

    // initialise first edge driver
    using (var driver = new EdgeDriver(_service, options))
    {
        // define short default wait times
        driver.Manage().Timeouts().ImplicitWait = new TimeSpan(0, 0, 2);
        driver.Manage().Timeouts().PageLoad = new TimeSpan(0, 0, 20);
        driver.Manage().Timeouts().AsynchronousJavaScript = new TimeSpan(0, 0, 10);
        
        // send first browser window to a page
        driver.Navigate().GoToUrl("https://www.google.com/");        
    }
}
// initialise second driver service separatelly
using (var _service2 = OpenQA.Selenium.Edge.EdgeDriverService.CreateDefaultService(Directory.GetCurrentDirectory(), @"msedgedriver.exe"))
{
    _service2.Start();

    // initialise second edge driver
    using (var driver = new EdgeDriver(_service2, options2))
    {
        // define short default wait times
        driver.Manage().Timeouts().ImplicitWait = new TimeSpan(0, 0, 2);
        driver.Manage().Timeouts().PageLoad = new TimeSpan(0, 0, 20);
        driver.Manage().Timeouts().AsynchronousJavaScript = new TimeSpan(0, 0, 10);
        
        // send first browser window to a page
        driver.Navigate().GoToUrl("https://www.google.com/");        
    }
}